HandlerThread类应用

通常AsyncTask和Handler都是为异步更新UI而诞生的两个类,只是AsyncTask是一个封装后的后台任务类,是方便大家简单处理异步任务后更新UI的操作(如短时间异步任务操作),但它并不适合处理所有的后台异步任务操作,它也存在一下几点问题:

  • 当它在Activity或Fragment作为非静态内部类,一旦它创建了实例,它就会引用了外部类的Activity或Fragment实例,如果这个AsyncTask实例生命周期较长,即使Activity或Fragment 调用了destroyed()方法也不会销毁掉让出内存,从而引起了内存泄漏。
  • 如果它在Activity或Fragment作为静态内部类或单独的一个类,因其它一般需要引用Context去异步更新UI视图,所以它也避免不了对Context判断(以防Context被销毁转为空了)。
  • 它只能一次行执行任务,而不能重复执行使用,并且当一个执行任务消耗太长时间时,否则容易引起ANR异常。
    后面我将会专门写一篇博客介绍这个AsyncTask类的实现原理。
    这时我们可以很好用子线程Handler来去执行消耗时间任务,而让主线程Handler实现异步更新UI,这种方式实现异步更新其实较复杂的,同时需要自己创建一条线程绑定handler,并创建对应的Looper和MessageQueue来实现,如官方给出的实例:
class LooperThread extends Thread {
      public Handler mHandler;

      public void run() {
          //创建Looper和MessageQueue实例
          Looper.prepare();

          mHandler = new Handler() {
          //通过当前的子线程处理消耗时间消息任务
              public void handleMessage(Message msg) {
                  // process incoming messages here
              }
          };
        //启动Looper循环,因此loop()方法的后面代码将不会被执行
          Looper.loop();          
      }
  }

至于为何需要这些代码创建一个用子线程handler来执行消耗时间I的线程类,可以参考我下面这篇博客,它涉及了handler,Looper,MessageQueue三者联系分析:
http://blog.csdn.net/xuguoli_beyondboy/article/details/50396439
谷歌为了方便我们创建一个用子线程handler来执行消耗时间I的线程类来去协作主线程Handler异步更新UI,推出了一个HandlerThread类,它是Thread的子类,但它已经在run方法中创建了Looper和MessageQueue实例,代码如下:

 @Override
    public void run() {
        mTid = Process.myTid();
        //创建绑定了该子线程的Looper和MessageQueue实例
        Looper.prepare();
        synchronized (this) {
            mLooper = Looper.myLooper();
            notifyAll();
        }
        Process.setThreadPriority(mPriority);        
        onLooperPrepared();
        Looper.loop();
        mTid = -1;
    }

HandlerThread类的Demo:
layout/activity_main.xml:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent" android:gravity="center">
  <ProgressBar  android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/progressBar"/>
  <LinearLayout  android:orientation="horizontal" android:layout_width="fill_parent" android:layout_height="fill_parent">
    <LinearLayout  android:orientation="vertical" android:layout_width="0dp" android:layout_height="fill_parent" android:layout_weight="1" android:id="@+id/leftSideLayout">
    </LinearLayout>
    <LinearLayout  android:orientation="vertical" android:layout_width="0dp" android:layout_height="fill_parent" android:layout_weight="1" android:id="@+id/rightSideLayout">
    </LinearLayout>
  </LinearLayout>
</LinearLayout>

为了通过单独的线程Handler来处理耗时而不是涉及UI更新的操作,故创建一个继承HandlerThread类的子类:

package com.scau.beyondboy.handlerdemo;

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Message;
import android.support.v4.util.ArrayMap;
import android.util.Log;
import android.widget.ImageView;

import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/** * Author:beyondboy * Gmail:xuguoli.scau@gmail.com * Date: 15-12-27 * Time: 下午6:44 * 创建HandlerThread子类,单独处理某些耗时的操作 * HandlerThread其实是一个Thread的子类,并在 * run方法中创建绑定自己线程的Looper,MessageQueue实例 */
public class MyWorkerThread extends HandlerThread {
    /**单独处理自己消息池的线程Handler,一般来说此线程不是UI线程,故在处理消息过程中不能更新UI等操作*/
    private Handler mWorkerHandler;
    /*×UI线程的Handler处理UI更新操作*/
    private Handler mResponseHandler;
    private static final String TAG = MyWorkerThread.class.getSimpleName();
    /**用数组Map减少内存开销*/
    private Map<ImageView, String> mRequestMap = new ArrayMap<>();
    private Callback mCallback;
    /*×用于更新ImageView的回调接口,方法会在主线程里面执行*/
    public interface Callback {
         void onImageDownloaded(ImageView imageView, Bitmap bitmap, int side);
    }

    /** * @param responseHandler 设置更新UI的handler * @param callback 回调实例 */
    public MyWorkerThread(Handler responseHandler, Callback callback)
    {
        super(TAG);
        mResponseHandler = responseHandler;
        mCallback = callback;
    }

    /*×插入执行的任务*/
    public void queueTask(String url, int side, ImageView imageView)
    {
        mRequestMap.put(imageView, url);
        Log.i(TAG, url + " added to the queue: "+Thread.currentThread().getId());
        //发送消息绑定的MessageQueue
        mWorkerHandler.obtainMessage(side, imageView)
                .sendToTarget();
    }

    /**创建和当前线程Looper,MessageQueue绑定的Handler实例*/
    public void prepareHandler()
    {
        //创建绑定HandlerThread线程的Looper对象和处理消息的Handler实例
        mWorkerHandler = new Handler(getLooper(), new Handler.Callback()
        {
            //会在HandlerThread子线程中执行,而不是UI线程,返回true,handler重写的handleMessage方法将不会被执行
            @Override
            public boolean handleMessage(Message msg) {
                try {
                    Log.i(TAG,"模拟操作: "+Thread.currentThread().getId());
                    //模拟操作
                    TimeUnit.SECONDS.sleep(2);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                ImageView imageView = (ImageView) msg.obj;
                String side = msg.what ==MainActivity.LEFT_SIDE ? "left side" : "right side";
                Log.i(TAG, String.format("Processing %s, %s", mRequestMap.get(imageView), side));
                handleRequest(imageView, msg.what);
                //不能调用下面方法,否则会抛异常
               //msg.recycle();
                return true;
            }
        });
    }
    /**处理图片请求,该方法还是在HandlerThread子线程中执行*/
    private void handleRequest(final ImageView imageView, final int side) {
        String url = mRequestMap.get(imageView);
        try {
            HttpURLConnection connection =
                    (HttpURLConnection) new URL(url).openConnection();
            final Bitmap bitmap = BitmapFactory
                    .decodeStream((InputStream) connection.getContent());
            mRequestMap.remove(imageView);            
            //发送到UI线程绑定的消息池中,以在UI线程中执行
            mResponseHandler.post(new Runnable()
            {
                @Override
                public void run()
                {
                    mCallback.onImageDownloaded(imageView, bitmap, side);
                }
            });
        } catch (IOException e) {
            e.printStackTrace();
        }
    }   
}

MainActivity类:

package com.scau.beyondboy.handlerdemo;

import android.graphics.Bitmap;
import android.os.Bundle;
import android.os.Handler;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.widget.ImageView;
import android.widget.LinearLayout;

import java.util.Random;
/** * Author:beyondboy * Gmail:xuguoli.scau@gmail.com * Date: 15-12-27 * Time: 下午6:44 * Handler,Looper,MessageQueue实战 */
public class MainActivity extends AppCompatActivity implements MyWorkerThread.Callback {

    private static final String TAG = MainActivity.class.getName();
    private static boolean isVisible;
    //添加左边和右边布局的标记
    public static final int LEFT_SIDE = 0;
    public static final int RIGHT_SIDE = 1;
    private LinearLayout mLeftSideLayout;
    private LinearLayout mRightSideLayout;
    //自定义的处理消息线程,实际为HandlerThread子类
    private MyWorkerThread mWorkerThread;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        isVisible = true;
        mLeftSideLayout = (LinearLayout) findViewById(R.id.leftSideLayout);
        mRightSideLayout = (LinearLayout) findViewById(R.id.rightSideLayout);
        String[] urls = new String[]{"http://avatar.csdn.net/D/D/4/1_xuguoli_beyondboy.jpg",
                "http://avatar.csdn.net/D/D/4/1_xuguoli_beyondboy.jpg",
                "http://avatar.csdn.net/D/D/4/1_xuguoli_beyondboy.jpg",
                "http://avatar.csdn.net/D/D/4/1_xuguoli_beyondboy.jpg"};
        //传进用来发送消息到主线程的MessageQueue和处理主线程消息的handler
        mWorkerThread = new MyWorkerThread(new Handler(), this);
        //自定义处理消息线程启动
        mWorkerThread.start();
        //创建绑定当前线程Handler实例
        mWorkerThread.prepareHandler();
        Random random = new Random();
        //执行任务
        for (String url : urls)
        {
            //queueTask还是在主线程执行而非HandlerThread线程
            mWorkerThread.queueTask(url, random.nextInt(2), new ImageView(this));
        }
    }

    @Override
    protected void onPause()
    {
        isVisible = false;
        super.onPause();
    }

    @Override
    protected void onDestroy()
    {
        //退出当前线程的Looper循环
        mWorkerThread.quit();
        super.onDestroy();
    }

    /**实现callback的回调方法,该方法在主线程执行*/
    @Override
    public void onImageDownloaded(ImageView imageView, Bitmap bitmap, int side)
    {
        Log.i(TAG, "threadid更新视图: " + Thread.currentThread().getId());
        imageView.setImageBitmap(bitmap);
        if (isVisible && side == LEFT_SIDE){
            mLeftSideLayout.addView(imageView);
        } else if (isVisible && side == RIGHT_SIDE){
            mRightSideLayout.addView(imageView);
        }       
    }
}

运行结果如图:

你可能感兴趣的:(asynctask劣,Android异步,handler异步)