美文网首页
Android常用异步任务执行方法

Android常用异步任务执行方法

作者: redspider110 | 来源:发表于2017-06-06 16:17 被阅读0次

Handler原理及基本概念

  • Message 意为消息,发送到Handler进行处理的对象,携带描述信息和任意数据。
  • MessageQueue 意为消息队列,Message的集合。
  • Looper 有着一个很难听的中文名字,消息泵,用来从MessageQueue中抽取Message,发送给Handler进行处理。
  • Handler 处理Looper抽取出来的Message。
    也就是所有的消息处理都是串行执行的
    他们之间的关系:
每个 Thread 只对应一个 Looper  
每个 Looper 只对应一个 MessageQueue
每个 MessageQueue 中有 N 个 Message
每个 Message 最多指定一个 Handler 来处理事件
每个 Thread 可以对应多个 Handler

在如下操作中都是基于UI主线程,在异步任务中使用Handler机制更新UI必须用new Handler();来初始化。

// 默认使用UI主线程的Looper
Handler mHandler = new Handler();
mHandler.post(new Runnable(){});

Thread创建与销毁

在Android开发中经常会使用到线程,一想到线程,很多同学就立即使用
new Thread(){...}.start();这样的方式。这样如果在一个Activity中多次调用上面的代码,那么将创建多个匿名线程,程序运行的越久可能会越来越慢。因此,需要一个Handler来启动一个线程,以及删除一个线程。
保证线程不会重复的创建。

使用HandlerThread和Handler配合实现异步后台任务

特点

  • 由2个Handler和1个HandlerThread来实现
  • 后台线程串行执行

代码示例:

// UI线程的Handler
Handler mHandler = new Handler(){
    @Override
    public void handleMessage(Message msg) {
        super.handleMessage(msg);
        // 处理UI更新
};

HandlerThread mBackThread = new HandlerThread("mybackthread");
mBackThread.start();
// 后台线程的Handler
Handler mBackHandler = new Handler(mBackThread.getLooper());
mBackHandler.post(new Runnable() {
    @Override
    public void run() {
        // 后台线程执行耗时操作,异步
        ...
        // mHandler发消息,回到主线程更新UI
        mHandler.sendMessage(msg);
    }
});

注意mBackHandler的初始化必须在mBackThread.start();之后,否则拿不到这个线程的looper。
这种模式通过mBackHandler.post(new Runnable() {})来实现后台异步任务执行,所有后台任务都是通过HandlerThread这个线程执行的,但是HandlerThread是串行执行任务的,也就是每次post后进入队列排队执行。
HandlerThread的退出:

@Override
protected void onDestroy() {
    super.onDestroy();
    if(mBackThread != null){
        mBackThread.quitSafely();
        try {
            mBackThread.join();
            mBackThread = null;
            mBackHandler = null;
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

AsyncTask实现异步任务执行

查看源码AsyncTask只是对Thread和Handler的一个封装。

基本概念

  • 3个泛型参数
    AsyncTask <Params, Progress, Result>
    Params: 指定的是我们传递给异步任务执行时的参数的类型
    Progress: 指定的是我们的异步任务在执行的时候将执行的进度返回给UI线程的参数的类型
    Result: 指定的是异步任务执行完后返回给UI线程的结果的类型
    我们在定义一个类继承AsyncTask类的时候,必须指定好这三个泛型的类型,如果都不指定的话,则都将其写成Void
  • 4个执行步骤
    onPreExecute():UI Thread当中执行,这个方法是在执行异步任务之前的时候执行,我们可以在异步任务执行前做UI提示
    doInBackground(Params... params):这个方法就是来处理异步任务的方法,执行耗时操作。这个方法也是必须要实现的抽象方法。
    onProgressUpdate(Progess... values):UI Thread当中执行,用来更新进度条等
    onPostExecute(Result... result):UI Thread当中执行,当异步任务执行完之后,将doInBackground结果返回给这个方法来更新UI
  • 2种执行方式
    后台线程可以设置为串行或者并行执行
    串行execute(Params... params)
    并行executeOnExecutor(Executor exec, Params... params)
    注意:各SDK版本execute默认执行方式不统一,1.5中顺序执行,1.6到 2.3中并行执行,3.0以后又改回串行执行,并添加并行执行接口executeOnExecutor

注意事项

  • 必须在UI线程中加载和创建,以及调用execute
  • 不能做特别耗时的操作,建议只几秒内的异步任务
  • 一个AsyncTask对象只能被执行一次,即只能调用一次execute,否则会抛出异常报错
    Caused by: java.lang.IllegalStateException: Cannot execute task: the task has already been executed (a task can be executed only once)
  • 不能在程序中主动调用4个步骤

代码示例

// 初始化AsyncTask及执行
protected void function() {
    ...
    // 串行执行,识别一张bitmap,每次执行前都需要重新new一个对象
    mClassifierAsyncTask = new ClassifierAsyncTask();    
    mClassifierAsyncTask.execute(bitmap);
}

// 自定义AsyncTask任务类,实现doInBackground
private ClassifierAsyncTask mClassifierAsyncTask;
private class ClassifierAsyncTask extends AsyncTask<Bitmap , Void, String >{

    @Override
    protected void onPreExecute() {
        super.onPreExecute();
        mTvResult.setText(getString(R.string.classifying));
    }

    @Override
    protected String doInBackground(Bitmap... bitmaps) {
        if(mMyTfClassifier == null) {
            mMyTfClassifier = new MyTfClassifier(MainActivity.this);
        }
        String result = mMyTfClassifier.recognizeImage(bitmaps[0]);
        return result;
    }

    @Override
    protected void onPostExecute(String result) {
        super.onPostExecute(result);
        mTvResult.setText(result);
    }
}

存在的问题

Activity屏幕旋转或销毁时,如果AsyncTask没有执行完毕就会存在内存泄露。特别是屏幕旋转时AsyncTask没有执行完毕,会导致屏幕异常。

相关文章

  • Android常用异步任务执行方法

    Handler原理及基本概念 Message 意为消息,发送到Handler进行处理的对象,携带描述信息和任意数据...

  • 第39条:用handler块降低代码分散程度

    为用户界面编码时,一种常用的范式就是”异步执行任务“。异步方法在执行完任务后,需要以某种手段通知相关代码。常用的技...

  • AsyncTask源码解析

    AsyncTask异步任务,方便我们在Android在子线程执行任务,在主线程执行结果,避免ANR。 AsyncT...

  • 浅谈Android异步任务

    异步任务无处不在,在Android中 耗时操作 如网络请求 IO操作 复杂计算都是这一范畴,那么...执行异步任务...

  • Android_AsyncTask个人笔记

    title: Android_AsyncTask 目的 ​ 异步任务允许你在用户的接口上执行异步工作。将线程阻...

  • 【Android】深入解析 AsyncTask 源码

    前言:AsyncTask 是 Android SDK 中提供的一个用于执行异步任务的框架,在 Android 兴起...

  • Android - 多个异步任务执行类

    用于 Android 需要同步或异步执行多个异步任务,并且需要统一回调的情形。思路很简单,通过一个队列保存异步任务...

  • Android AsyncTask基础

    AsyncTask是Android为了简化异步操作而封装的异步任务操作抽象类。当我们需要在程序中执行耗时的异步操作...

  • 【javaScript练习】2021-02-23

    javaScript 作用域,异步执行,requestAnimationFrame 微任务,宏任务,异步执行 Ar...

  • js执行顺序总结

    流程图 首先执行同步任务,异步任务会插入到异步队列中。同步任务执行完毕,查询是否有异步任务,回到主任务执行。 微任...

网友评论

      本文标题:Android常用异步任务执行方法

      本文链接:https://www.haomeiwen.com/subject/wkqifxtx.html