Future理解:异步执行,返回Future,获取返回值

App.java

    // 线程池(处理异步任务)
    //避免重复创建资源(比如每个页面都新建线程池会浪费内存)
    private static final ExecutorService executorService = Executors.newCachedThreadPool();

    public static ExecutorService getExecutorService() {
        return executorService;
    }

BaseFragment.java

    // 2. 执行有返回值的异步任务(比如获取数据,返回 Future 可后续获取结果)
    public <T> Future<T> runAsync(Callable<T> callable) {
        return App.getExecutorService().submit(callable);
    }

要理解 public <T> Future<T> runAsync(Callable<T> callable) 的调用方式,核心是抓住两点:
Callable<T>:带返回值的异步任务(和无返回值的 Runnable 区别);
Future<T>:异步任务的 “结果凭证”,可通过它获取任务返回值、取消任务、判断任务状态。
下面结合 LSPosed 的实际场景(比如 “异步统计模块作用域中已勾选的应用数量”),举一个完整且贴合源码的调用例子:
第一步:明确调用场景
假设在 AppListFragment 中,需要异步统计当前模块已勾选的应用总数(耗时操作,避免阻塞 UI),然后在主线程显示结果。
第二步:完整调用代码(在 AppListFragment 中)

// AppListFragment 继承自 BaseFragment,可直接调用 runAsync(Callable<T>)
public class AppListFragment extends BaseFragment implements MenuProvider {
    // ... 其他已有代码(如 scopeAdapter、binding 等)

    // 假设在某个按钮点击事件中触发统计(也可在 onViewCreated 等生命周期中调用)
    private void countCheckedApps() {
        // 1. 调用 BaseFragment 的 runAsync(Callable<T>),传入带返回值的异步任务
        // Callable<Long> 表示:异步任务返回 Long 类型结果(已勾选应用数)
        Future<Long> countFuture = runAsync(() -> {
            // -------------- 异步任务开始(运行在子线程,耗时操作放这)--------------
            // 从 scopeAdapter 中获取已勾选的应用列表(可能是耗时操作,比如读取配置)
            Set<ScopeAdapter.ApplicationWithEquals> checkedList = scopeAdapter.checkedList;
            
            // 统计数量(这里可扩展更复杂的逻辑,比如过滤系统应用、黑名单应用)
            long checkedCount = 0;
            for (ScopeAdapter.ApplicationWithEquals app : checkedList) {
                // 模拟耗时(比如额外查询应用信息,实际开发中可去掉)
                Thread.sleep(10); 
                checkedCount++;
            }
            
            // 返回统计结果(Callable 必须实现 call() 方法,返回泛型 T 类型)
            return checkedCount;
            // -------------- 异步任务结束 --------------
        });

        // 2. 处理异步结果(两种方式:阻塞获取 / 非阻塞监听,推荐非阻塞)
        // 方式1:非阻塞(通过主线程 Handler 延迟查询 Future,不卡UI)
        App.getMainHandler().postDelayed(() -> {
            if (countFuture.isDone() && !countFuture.isCancelled()) { // 任务已完成且未取消
                try {
                    // 通过 Future.get() 获取异步任务的返回值(此时已无阻塞,因为 isDone 为 true)
                    long result = countFuture.get();
                    // 在UI线程显示结果(调用 BaseFragment 的 showHint 方法)
                    showHint("已勾选应用数:" + result, true);
                } catch (Exception e) {
                    // 处理异常(如任务执行失败、被中断)
                    showHint("统计失败:" + e.getMessage(), false);
                }
            } else if (countFuture.isCancelled()) {
                showHint("统计已取消", true);
            }
        }, 500); // 延迟 500ms 查询结果(可根据实际任务耗时调整)

        // 方式2:阻塞获取(不推荐,会卡UI,仅作对比)
        // 注意:绝对不能在主线程直接调用 countFuture.get()!会导致UI卡死
        /*
        new Thread(() -> {
            try {
                long result = countFuture.get(); // 阻塞直到任务完成
                // 切换回主线程显示结果
                runOnUiThread(() -> showHint("已勾选应用数:" + result, true));
            } catch (Exception e) {
                runOnUiThread(() -> showHint("统计失败:" + e.getMessage(), false));
            }
        }).start();
        */
    }

    // 假设在某个按钮点击时触发统计
    private void initView() {
        binding.someButton.setOnClickListener(v -> countCheckedApps());
    }
}

第三步:关键细节拆解

  1. Callable<T> 的实现
    这里用 Lambda 表达式简化 Callable<Long> 的实现(完整写法是 new Callable<Long>() { @Override public Long call() throws Exception { ... } });
    call() 方法中是异步执行的逻辑(子线程),可以做耗时操作(如读取配置、统计数据、网络请求);
    call() 可以抛出异常,后续通过 Future.get() 捕获。
  2. Future<T> 的核心用法
    countFuture.isDone():判断任务是否已完成(返回 true 表示执行结束,不管成功失败);
    countFuture.isCancelled():判断任务是否被取消;
    countFuture.get():获取任务返回值(阻塞方法,必须在子线程调用,或确保 isDone() == true 时调用);
    countFuture.cancel(true):取消任务(参数 true 表示中断正在执行的任务)。
  3. 为什么要这么调用?
    异步统计:避免在主线程做循环统计(如果应用数多,会导致 UI 卡顿);
    结果回调:通过 Future 拿到统计结果后,切换回主线程更新 UI(符合 Android 主线程更新 UI 的规范);
    异常处理:捕获 call() 中抛出的异常,避免 App 崩溃。
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容