android - 如何实现更灵活的AsyncTask?

标签 android multithreading android-asynctask ui-thread

虽然使用起来非常方便,但据我所知,AsyncTask有两个重要限制:

任何实例的

  • doInBackground将共享同一工作线程
    线程,即一个长时间运行的AsyncTasks可以阻止所有其他线程。
  • executeonPostExecute和其他“同步”方法必须/将始终在要启动任务的UI线程(即不在线程)上执行。

  • 当我尝试在后台IntentService中重用一些现有的AsyncTasks来负责我的应用程序的客户端-服务器通信时,我遇到了麻烦。随着时间的推移,服务的任务将在工作线程中与UI Activity 的任务进行争夺。同样,它们将迫使服务退回到UI线程上,尽管该服务应在后台安静地执行其工作。
    我将如何消除/规避这些限制?我基本上想实现:
  • 一个非常类似于AsyncTask的框架(因为我需要在那里移植很多关键代码)。
  • 此类任务的每个实例都应在自己的线程上运行doInBackground,而不是对所有实例使用单个工作线程。
    编辑:Thx到VinceFR指出这可以通过简单地调用executeOnExecutor而不是execute来实现。
  • 应该通过调用onPostExecute在启动任务的同一线程上调用类似execute的回调,该线程不必是UI线程。

  • 我想,我不是第一个要求这样的人。因此,我想知道:是否已经可以推荐一些第三方库来完成此任务?如果没有,那么实现此目标的方法是什么?
    提前致谢!

    最佳答案

    解决方案如下所示:

    所有产生AsyncTask的类都可能会相互干扰,它们都会得到自己的Executor,就像这样(使用线程池等进行详细说明):

    private Executor serviceExecutor = new Executor() {
        public void execute(Runnable command) {
            new Thread(command).start();
        }
    };
    

    正如VinceFR所指出的,您可以通过像这样调用它来在给定的AsyncTask上运行Executor(其中payload是您将定期传递给任务的参数):
    task.executeOnExecutor(serviceExecutor, payload);
    

    但是,这破坏了与Gingerbread及更早版本的向后兼容性。另外,如果要支持Honeycomb,则需要确保此调用在UI线程上进行。果冻 bean 将自动处理此问题。

    现在比较棘手的部分:使服务在其自己的线程上运行。由于Android中的许多内容,这似乎比其需要的要难(或者也许我在这里缺少一些信息)。您不能使用IntentService,因为这会在首次将AsyncTask接管并自动完成onHandleIntent回调后自动关闭。

    您需要在服务上设置自己的线程和事件循环:
    public class AsyncService extends Service {
    
    private static final String TAG = AsyncService.class.getSimpleName();
    private class LooperThread extends Thread {
        public Handler threadHandler = null;
    
        public void run() {
            Looper.prepare();
            this.threadHandler = new Handler();
            Looper.loop();
        }
    }
    private LooperThread serviceThread = null;
    private Handler serviceThreadHandler = null;
    
    @Override
    // This happens on the UI thread
    public void onCreate() {
        super.onCreate();
    }
    
    @Override
    // This happens on the UI thread
    public int onStartCommand(Intent intent, int flags, int startId) {
        this.serviceThread = new LooperThread();
        this.serviceThread.start();
        while(this.serviceThread.threadHandler == null) {
            Log.d(TAG, "Waiting for service thread to start...");
        }
        this.serviceThreadHandler = this.serviceThread.threadHandler;
        this.serviceThreadHandler.post(new Runnable() {
            @Override
            public void run() {
                doTheFirstThingOnTheServiceThread();
            }
        });
        return Service.START_STICKY;
    }
    
    // doTheFirstThingOnTheServiceThread
    
    }
    

    无需确保每次AsyncTask返回到UI线程时,您最终都会进入服务线程:
    // This happens on the serviceThread
    private void doTheFirstThingOnTheServiceThread() {
        // do some stuff
    
        // here we can reuse a class that performs some work on an AsyncTask
        ExistingClassWithAsyncOperation someUsefullObject = new ExistingClassWithAsyncOperation();
        // the existing class performs some work on an AsyncTask and reports back via an observer interface
        someUsefullObject.setOnOperationCompleteListener(new OnOperationCompleteListener() {
            @Override
            // This happens on the UI thread (due to an ``AsyncTask`` in someUsefullObject ending)
            public void onOperationComplete() {
                serviceThreadHandler.post(new Runnable() {
                    @Override
                    public void run() {
                        doTheSecondThingOnTheServiceThread();
                    }
                });
            }
        }
        someUsefulObject.performOperation();
    }
    
    // This happens on the serviceThread
    private void doTheSecondThingOnTheServiceThread() {
        // continue working on the serviceThread
    }
    

    所以,这对我有用。我很高兴看到一个更简单的解决方案。请注意,该解决方案要求服务知道UI线程上的ExistingClassWithAsyncOperation将对其进行回调。我并不特别喜欢这种依赖关系,但是现在不知道如何做得更好。但是,我不必重写许多使用AsyncTask执行异步操作的现有类。

    关于android - 如何实现更灵活的AsyncTask?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15427501/

    相关文章:

    android - developer.android.com/training bitmapfun 项目

    android - 在 Android 中下载背景图片时需要帮助吗?

    android - menu.findItem(R.id.*) 为 null- Android

    android - 如何处理 UnsatisfiedLinkError?

    c - 将变量传递给 pthread_create 函数

    c++ - 使用 C/C++ 创建多线程应用程序的最简单方法是什么?

    android - ViewPager 不适用于 Google Glass KitKat [XE16]

    android - 我应该如何选择在 Web、Android 和 iOS 上播放的视频格式?

    java - 这种情况下会出现死锁吗?

    android - 什么构成 AsyncTask 的 "UI interactions"?