Android中的线程工具类学习:AsyncTask、HandlerThread、IntentService

首先是AsyncTask

这是一个用于异步处理数据的线程操作类。由于Android中存在UI线程的概念,只有在UI线程中才能对View(肉眼可见的地方)进行修改和调整。UI线程中是不能做一些耗时地操作的,比如说访问网络(http请求)、从SD卡读写数据(I/O操作)亦或者是比较复杂的数据运算,这些都是不能放在UI线程中进行的(会导致ANR异常)。

为了解决这个问题,Android系统提供了这个异步操作类。(以下是部分代码)

public abstract class AsyncTask<Params, Progress, Result> {

    /**
     * Override this method to perform a computation on a background thread. The
     * specified parameters are the parameters passed to {@link #execute}
     * by the caller of this task.
     *
     * This method can call {@link #publishProgress} to publish updates
     * on the UI thread.
     *
     * @param params The parameters of the task.
     *
     * @return A result, defined by the subclass of this task.
     *
     * @see #onPreExecute()
     * @see #onPostExecute
     * @see #publishProgress
     */
    @WorkerThread
    protected abstract Result doInBackground(Params... params);

    /**
     * <p>Runs on the UI thread after {@link #doInBackground}. The
     * specified result is the value returned by {@link #doInBackground}.</p>
     * 
     * <p>This method won't be invoked if the task was cancelled.</p>
     *
     * @param result The result of the operation computed by {@link #doInBackground}.
     *
     * @see #onPreExecute
     * @see #doInBackground
     * @see #onCancelled(Object) 
     */
    @SuppressWarnings({"UnusedDeclaration"})
    @MainThread
    protected void onPostExecute(Result result) {
    }
}

这里注意到doInBackground方法上的注解@WorkerThread和onPostExecute方法上的@MainThread,这两个注解就提示了我们,这两个方法是运行不同的线程上的。

通常我们会把耗时操作放在doInBackground方法中,然后将执行结果Result返回。从上面的注释中我们可以看到onPostExecute会跟在doInBackground之后执行,不同的是onPostExecute方法是在UI线程中执行的,在这里我们对View(肉眼可见的界面)进行操作了。还有onPostExecute方法中有一个Result参数,这个参数就是doInBackground方法中返回的Result,我们可以根据这个Result做相关的UI操作。

例子:

    public class DecodeBitmapTask extends AsyncTask<String, Integer, Bitmap> {

        private ImageView imageView;

        public VideoShotTask(ImageView imageView) {
            this.imageView = imageView;
        }

        @Override
        protected Bitmap doInBackground(String... params) {

            String sourcePath = params[0];
            Bitmap bitmap = BitmapFactory.decodeFile(sourcePath);

            return bitmap;
        }

        @Override
        protected void onPostExecute(Bitmap result) {

            if (imageView != null && result != null) {
                imageView.setImageBitmap(result);
            }

            this.cancel(true);//执行完成之后可以取消任务
        }
    }

这就是一个从sd卡中加载图片,并绘制到ImageView上的过程。

使用上面这个类的方法也很简单

DecodeBitmapTask dbt = new DecodeBitmap(传入一个ImageView);
dbt.execute("传入一个图片资源路径");

这样就可以实现工作线程(子线程)与UI线程(主线程)之间的配合啦。

ps:当然AsyncTask的功能不止于此,我这里只是做个简单的例子。

 

HandlerThread

就像它的名字一样,它是由Handler和Thread有机结合起来的一个类。它区别于我们直接通过new Thread的方式创建线程,HandlerThread创建的线程是可以反复重用的,也就减少了因为new新的实例而导致的内存开销。而且它Handler中功能,使得我们对线程的使用更加的灵活。

   //首先创建一个HandlerThread对象
   HandlerThread mHT = new HandlerThread("传入线程的名字");

   //随后启动线程
   mHT.start();

   //根据HandlerThread的Looper来创建一个Handler对象
   Handler workHandler = new Handler( mHT.getLooper() ) {
       @Override
       public void handleMessage(Message msg) {
           //这里是运行在工作线程中,而不是UI线程
           switch(msg.what){
              case 2:
                //do something。。。 
                break;
           }   
       }
   });

  //这里通过传统的Handler发送消息的方式,来触发线程
  Message msg = Message.obtain();
  msg.what = 2; //消息的标识
  msg.obj = "B"; // 消息的存放
  workHandler.sendMessage(msg);

  // 最后不需要用的时候,结束线程,即停止线程的消息循环
  mHT.quit();

如此一来,我们就可以通过Handler来操作、执行工作线程。这样做的好处就是减少了我们new Thread的操作,这样可以大大的减少内存泄漏的风险和过多的内存开销。

 

IntentService

这是一个Service与HandlerThread的结合体。首先我们知道Service是android的四大组件之一,长期在后台处理数据。但是它并不是一个线程,如果在Service中执行耗时操作就会产生ANR异常,那么当一个Service需要处理比较多的耗时任务时,就需要单独开启一个工作线程来完成。IntentService就是基于这种应用场景而诞生的。

IntentService继承自Service

    //IntentService源码节选
    @Override
    public void onCreate() {
        // TODO: It would be nice to have an option to hold a partial wakelock
        // during processing, and to have a static startService(Context, Intent)
        // method that would launch the service & hand off a wakelock.

        super.onCreate();
        HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
        thread.start();

        mServiceLooper = thread.getLooper();
        mServiceHandler = new ServiceHandler(mServiceLooper);
    }

    /**
     * This method is invoked on the worker thread with a request to process.
     * Only one Intent is processed at a time, but the processing happens on a
     * worker thread that runs independently from other application logic.
     * So, if this code takes a long time, it will hold up other requests to
     * the same IntentService, but it will not hold up anything else.
     * When all requests have been handled, the IntentService stops itself,
     * so you should not call {@link #stopSelf}.
     *
     * @param intent The value passed to {@link
     *               android.content.Context#startService(Intent)}.
     *               This may be null if the service is being restarted after
     *               its process has gone away; see
     *               {@link android.app.Service#onStartCommand}
     *               for details.
     */
    @WorkerThread
    protected abstract void onHandleIntent(@Nullable Intent intent);

在它的onCreate方法中可以看到,它的内部其实就是通过封装HandlerThread来实现工作线程的。当我们要使用它时,需要先继承IntentService,然后实现它的抽象方法onHandleIntent方法。(由于它也是一个Service,别忘了在AndroidManifest中配置它)

public class TestIntentService extends IntentService {
    /**
     * Creates an IntentService.  Invoked by your subclass's constructor.
     *
     * @param name Used to name the worker thread, important only for debugging.
     */
    public TestIntentService(String name) {
        super(name);
    }

    @Override
    protected void onHandleIntent(@Nullable Intent intent) {
        //do something。。。
        //此时也是运行在工作线程(子线程)中哦
        //Intent用于传递我们需要的数据,每一次通过startService方法触发,都会按顺序执行,不会无序执行
    }
}

在我们使用这个IntentService的时候,就是这样:

Intent intent = new Intent(MainActivity.this, TestIntentService.class);
startService(intent);//intent当中记得要存放你需要传递的参数哦

就像我上面的注释中说的那样,每次startService,都会按照顺序去执行,并不会像我们new Thread那样,顺序完全随机。并且它与Service不同的地方在于,它不需要手动执行stopService方法来终止服务。因为在它的源码中:

    //在IntentService的内部类中可以看出来
    //每一次执行完任务,都会自己调用stopSelf方法
    private final class ServiceHandler extends Handler {
        public ServiceHandler(Looper looper) {
            super(looper);
        }

        @Override
        public void handleMessage(Message msg) {
            onHandleIntent((Intent)msg.obj);
            stopSelf(msg.arg1);
        }
    }

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章