zoukankan      html  css  js  c++  java
  • 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

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

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

  • 相关阅读:
    Python 三级菜单
    linux 下按文件类型删除
    linux 做内网端口映射
    ss
    fio
    libXtst.so.6 is needed by teamviewer-12.0.76279-0.i686
    copy 浅复制 与深复制
    Git 使用方法
    关于 爬虫使用 urllib.urlopen 提交默认 User-Agent值
    Python 官方模块文档
  • 原文地址:https://www.cnblogs.com/shineyoung/p/11303148.html
Copyright © 2011-2022 走看看