Android异步任务处理

Android异步任务处理

Android主线程(UI线程)不准执行异步任务,以免阻塞主线程。所以异步任务一定是在工作线程中完成,然后,通知主线程,进行返回结果,刷新UI等操作。

1、使用handler

使用handler可以很方便的进行主线程与工作线程的交互,当在线程里创建handler时,handler会自动绑定当前线程

重写@Overried handlerMessage(),可以处理Message。

/**

*

*

*/

@Override

        public void handleMessage(@NonNull Message msg) {

//根据msg.what执行相应命令(不设置,默认为0),msg.obj携带结果信息           

switch (msg.what){

                case 0:

                …执行相应操作

 break;

                default:

            }

        }

常见的做法是在主线程中创建handler,在工作线程中处理完异步任务后发送Message,主线程重写handlerMessage()里处理返回结果。

使用handler进行异步处理时,容易产生内存泄漏问题,固然可以通过将handler设置为静态内部类,解决这个问题,但是将handler设置为静态内部类后就无法引用内部成员变量。内存泄漏原因是activity要销毁时,消息队列里消息没处理完,Message Queue默认引用handler,handler默认引用activity。

所以推荐的做法是:在onDestory()阶段,清空消息队列,取消handler引用。

protected void onDestroy() {

        super.onDestroy();

        if (mHandler != null) {

            mHandler.removeCallbacksAndMessages(null);

            mHandler = null;

        }

     }

(参考资料)

https://juejin.im/post/5a692377518825734e3e71ab

2、使用IntentService(异步任务处理服务)

使用IntentService,IntentService其实是封装了service和handler的类,所以和上述类似,它处理消息是在@Overried

onHandleIntent()

根据传入的intent执行相应的异步处理

IntentService其内部维护一个消息队列,根据传入的intent的时间,先来先服务。前一项服务没处理完,后一项服务不会开始。

官网推荐的IntentService与Activity通信的方式是localBroadcast。

相比handler,其主要优点在于可以在后台执行,不受Activity生命周期影响。(只能通过startActivity()启动IntentService,可以像普通service一样绑定activity,通过Binder通信)

如果说消息队列里没消息了,那么service会暂停,内存不够的情况下有可能被系统杀死。

3、使用handlerThread

听名字就可以猜出来,一个继承了Thread的handler处理类,其内部维护一个消息队列,重写@Overried handlerMessage()处理消息,对应于主线程。

一些情况下,我们需要工作线程处理消息,那么我们就创建一个handlerThread,根据传入消息,执行异步任务。

比较好的理解方式:主线程可以有个handleMessage,我工作线程也想有个,但是新建一个Thread,设置Looper什么的太麻烦,于是新建一个HandlerThread,一些准备工作都做好了,像主线程一样创建handler绑定线程,重写@Overried handlerMessage()处理消息就OK了!

其实创建一个Hhread,手动引用创建一个Looper的效果和创建HandlerThread效果一样

需要注意:为了防止内存泄漏,要像在主线程里的handler一样,在onDestory()阶段,

清空消息队列,取消handler引用。

/**

  *

  *   workHandler: 绑定工作线程的handler

  *   mHandler:绑定主线程的handler

  */

protected void onDestroy() {

        super.onDestroy();

        if (workHandler != null) {

            workHandler.removeCallbacksAndMessages(null);

            workHandler = null;

        }

   if (mHandler != null) {

       mHandler.removeCallbacksAndMessages(null);

       mHandler = null;

   }

    }

4、使用AsyncTask

使用AsyncTask,AsyncTask是一个封装好的轻量级异步任务处理类,轻量级,顾名思义,一些重量级的异步任务还是自己搞个实现,大部分场景下,AsyncTask够用了。

相比AsyncTask,我更喜欢使用handler+Thread解决异步任务。

一个异步任务使用AsyncTask很方便,多个异步任务使用handler+thread更好。

有一种场景非常适合使用AsyncTask:需要显示进度值的场景,使用这个封装好的类,方便理解,节省代码

轻量级异步处理AsyncTask

/**

  * 步骤1:创建AsyncTask子类

  * 注:

  *   a. 继承AsyncTask类

  *   b. 为3个泛型参数指定类型;若不使用,可用java.lang.Void类型代替

  *   c. 根据需求,在AsyncTask子类内实现核心方法

  */

  private class MyTask extends AsyncTask<Params, Progress, Result> {

        ....

      // 方法1:onPreExecute()

      // 作用:执行 线程任务前的操作

      // 注:根据需求复写

      @Override

      protected void onPreExecute() {

           ...

        }

      // 方法2:doInBackground()

      // 作用:接收输入参数、执行任务中的耗时操作、返回 线程任务执行的结果

      // 注:必须复写,从而自定义线程任务

      @Override

      protected String doInBackground(String... params) {

            ...// 自定义的线程任务

            // 可调用publishProgress()显示进度, 之后将执行onProgressUpdate()

             publishProgress(count);

              

         }

      // 方法3:onProgressUpdate()

      // 作用:在主线程 显示线程任务执行的进度

      // 注:根据需求复写

      @Override

      protected void onProgressUpdate(Integer... progresses) {

            ...

        }

      // 方法4:onPostExecute()

      // 作用:接收线程任务执行结果、将执行结果显示到UI组件

      // 注:必须复写,从而自定义UI操作

      @Override

      protected void onPostExecute(String result) {

         ...// UI操作

        }

      // 方法5:onCancelled()

      // 作用:将异步任务设置为:取消状态

      @Override

        protected void onCancelled() {

        ...

        }

  }

/**

  * 步骤2:创建AsyncTask子类的实例对象(即 任务实例)

  * 注:AsyncTask子类的实例必须在UI线程中创建

  */

  MyTask mTask = new MyTask();

/**

  * 步骤3:手动调用execute(Params... params) 从而执行异步线程任务

  * 注:

  *    a. 必须在UI线程中调用

  *    b. 同一个AsyncTask实例对象只能执行1次,若执行第2次将会抛出异常

  *    c. 执行任务中,系统会自动调用AsyncTask的一系列方法:onPreExecute() 、doInBackground()、onProgressUpdate() 、onPostExecute()

  *    d. 不能手动调用上述方法

  */

  mTask.execute();

注意:doInBackground()是在工作线程运行的方法,不能调用UI;onPostExecute()是在主UI运行的方法,可以更新UI

总结一下

Thread + 消息机制

优点:使用非常灵活(自己手写的代码一般也是最多的)一般只在Activity里使用,主线程,工作线程均可实现自己的handler机制

缺点:Activity挂了,也就跟着挂了,需要后台运行那就用IntentService

IntentService + ResultReceiver

优点:在后台运行,一般情况下不会被杀死

缺点:官网推荐采用localBroadcast通信,手写代码较多。

AsyncTask

优点:被封装过,需要显示进度条的情况下非常方便,可以串行,也可以并行

缺点:没那么灵活,只能在主线程里创建

原文地址:https://www.cnblogs.com/shineyoung/p/11303148.html