HandlerThread类应用
Posted xuguoli_beyondboy
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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);
运行结果如图:
以上是关于HandlerThread类应用的主要内容,如果未能解决你的问题,请参考以下文章