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