Future理解:異步執(zhí)行,返回Future,獲取返回值

App.java

    // 線程池(處理異步任務(wù))
    //避免重復(fù)創(chuàng)建資源(比如每個頁面都新建線程池會浪費(fèi)內(nèi)存)
    private static final ExecutorService executorService = Executors.newCachedThreadPool();

    public static ExecutorService getExecutorService() {
        return executorService;
    }

BaseFragment.java

    // 2. 執(zhí)行有返回值的異步任務(wù)(比如獲取數(shù)據(jù),返回 Future 可后續(xù)獲取結(jié)果)
    public <T> Future<T> runAsync(Callable<T> callable) {
        return App.getExecutorService().submit(callable);
    }

要理解 public <T> Future<T> runAsync(Callable<T> callable) 的調(diào)用方式,核心是抓住兩點:
Callable<T>:帶返回值的異步任務(wù)(和無返回值的 Runnable 區(qū)別);
Future<T>:異步任務(wù)的 “結(jié)果憑證”,可通過它獲取任務(wù)返回值、取消任務(wù)、判斷任務(wù)狀態(tài)。
下面結(jié)合 LSPosed 的實際場景(比如 “異步統(tǒng)計模塊作用域中已勾選的應(yīng)用數(shù)量”),舉一個完整且貼合源碼的調(diào)用例子:
第一步:明確調(diào)用場景
假設(shè)在 AppListFragment 中,需要異步統(tǒng)計當(dāng)前模塊已勾選的應(yīng)用總數(shù)(耗時操作,避免阻塞 UI),然后在主線程顯示結(jié)果。
第二步:完整調(diào)用代碼(在 AppListFragment 中)

// AppListFragment 繼承自 BaseFragment,可直接調(diào)用 runAsync(Callable<T>)
public class AppListFragment extends BaseFragment implements MenuProvider {
    // ... 其他已有代碼(如 scopeAdapter、binding 等)

    // 假設(shè)在某個按鈕點擊事件中觸發(fā)統(tǒng)計(也可在 onViewCreated 等生命周期中調(diào)用)
    private void countCheckedApps() {
        // 1. 調(diào)用 BaseFragment 的 runAsync(Callable<T>),傳入帶返回值的異步任務(wù)
        // Callable<Long> 表示:異步任務(wù)返回 Long 類型結(jié)果(已勾選應(yīng)用數(shù))
        Future<Long> countFuture = runAsync(() -> {
            // -------------- 異步任務(wù)開始(運(yùn)行在子線程,耗時操作放這)--------------
            // 從 scopeAdapter 中獲取已勾選的應(yīng)用列表(可能是耗時操作,比如讀取配置)
            Set<ScopeAdapter.ApplicationWithEquals> checkedList = scopeAdapter.checkedList;
            
            // 統(tǒng)計數(shù)量(這里可擴(kuò)展更復(fù)雜的邏輯,比如過濾系統(tǒng)應(yīng)用、黑名單應(yīng)用)
            long checkedCount = 0;
            for (ScopeAdapter.ApplicationWithEquals app : checkedList) {
                // 模擬耗時(比如額外查詢應(yīng)用信息,實際開發(fā)中可去掉)
                Thread.sleep(10); 
                checkedCount++;
            }
            
            // 返回統(tǒng)計結(jié)果(Callable 必須實現(xiàn) call() 方法,返回泛型 T 類型)
            return checkedCount;
            // -------------- 異步任務(wù)結(jié)束 --------------
        });

        // 2. 處理異步結(jié)果(兩種方式:阻塞獲取 / 非阻塞監(jiān)聽,推薦非阻塞)
        // 方式1:非阻塞(通過主線程 Handler 延遲查詢 Future,不卡UI)
        App.getMainHandler().postDelayed(() -> {
            if (countFuture.isDone() && !countFuture.isCancelled()) { // 任務(wù)已完成且未取消
                try {
                    // 通過 Future.get() 獲取異步任務(wù)的返回值(此時已無阻塞,因為 isDone 為 true)
                    long result = countFuture.get();
                    // 在UI線程顯示結(jié)果(調(diào)用 BaseFragment 的 showHint 方法)
                    showHint("已勾選應(yīng)用數(shù):" + result, true);
                } catch (Exception e) {
                    // 處理異常(如任務(wù)執(zhí)行失敗、被中斷)
                    showHint("統(tǒng)計失?。? + e.getMessage(), false);
                }
            } else if (countFuture.isCancelled()) {
                showHint("統(tǒng)計已取消", true);
            }
        }, 500); // 延遲 500ms 查詢結(jié)果(可根據(jù)實際任務(wù)耗時調(diào)整)

        // 方式2:阻塞獲取(不推薦,會卡UI,僅作對比)
        // 注意:絕對不能在主線程直接調(diào)用 countFuture.get()!會導(dǎo)致UI卡死
        /*
        new Thread(() -> {
            try {
                long result = countFuture.get(); // 阻塞直到任務(wù)完成
                // 切換回主線程顯示結(jié)果
                runOnUiThread(() -> showHint("已勾選應(yīng)用數(shù):" + result, true));
            } catch (Exception e) {
                runOnUiThread(() -> showHint("統(tǒng)計失敗:" + e.getMessage(), false));
            }
        }).start();
        */
    }

    // 假設(shè)在某個按鈕點擊時觸發(fā)統(tǒng)計
    private void initView() {
        binding.someButton.setOnClickListener(v -> countCheckedApps());
    }
}

第三步:關(guān)鍵細(xì)節(jié)拆解

  1. Callable<T> 的實現(xiàn)
    這里用 Lambda 表達(dá)式簡化 Callable<Long> 的實現(xiàn)(完整寫法是 new Callable<Long>() { @Override public Long call() throws Exception { ... } });
    call() 方法中是異步執(zhí)行的邏輯(子線程),可以做耗時操作(如讀取配置、統(tǒng)計數(shù)據(jù)、網(wǎng)絡(luò)請求);
    call() 可以拋出異常,后續(xù)通過 Future.get() 捕獲。
  2. Future<T> 的核心用法
    countFuture.isDone():判斷任務(wù)是否已完成(返回 true 表示執(zhí)行結(jié)束,不管成功失敗);
    countFuture.isCancelled():判斷任務(wù)是否被取消;
    countFuture.get():獲取任務(wù)返回值(阻塞方法,必須在子線程調(diào)用,或確保 isDone() == true 時調(diào)用);
    countFuture.cancel(true):取消任務(wù)(參數(shù) true 表示中斷正在執(zhí)行的任務(wù))。
  3. 為什么要這么調(diào)用?
    異步統(tǒng)計:避免在主線程做循環(huán)統(tǒng)計(如果應(yīng)用數(shù)多,會導(dǎo)致 UI 卡頓);
    結(jié)果回調(diào):通過 Future 拿到統(tǒng)計結(jié)果后,切換回主線程更新 UI(符合 Android 主線程更新 UI 的規(guī)范);
    異常處理:捕獲 call() 中拋出的異常,避免 App 崩潰。
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容