zoukankan      html  css  js  c++  java
  • Android常用异步任务执行方法

    Handler原理及基本概念

    • Message 意为消息,发送到Handler进行处理的对象,携带描述信息和任意数据。
    • MessageQueue 意为消息队列,Message的集合。
    • Looper 有着一个很难听的中文名字,消息泵,用来从MessageQueue中抽取Message,发送给Handler进行处理。
    • Handler 处理Looper抽取出来的Message。

    在如下操作中都是基于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没有执行完毕,会导致屏幕异常。

  • 相关阅读:
    C库函数笔记
    曼彻斯特及差分曼彻斯特编码
    VS2008 由于应用程序配置不正确,应用程序未能启动。重新安装应用程序可能会纠正这个问题。
    刚子扯谈:酒装狗熊胆
    poj1410
    新游戏《真·方块无双》发布-穿越混世过险境,运筹方块化无双
    hdu4267 A Simple Problem with Integers
    【转载】变量的存储类型
    【转载】硬盘存储原理和内部结构
    【转载】让windows使用linux系统的命令
  • 原文地址:https://www.cnblogs.com/redspider110/p/6952642.html
Copyright © 2011-2022 走看看