Android UI是线程不安全的,如果在子线程中尝试进行UI操作,程序就有可能会崩溃。Handler的使用过程很简单,通过它可以轻松地将一个任务切换到Handler所在的线程中去执行
Handler 基本使用
- Activity中定义一个Handler的实例,处理消息
public Handler mHandle = new Handler(){
public void handleMessage(Message msg) {
switch (msg.what) {
case 1:
Bitmap bitmap = (Bitmap) msg.obj;
image.setImageBitmap(bitmap);
break;
default:
break;
}
};
};
- 异步获取网络图片
private void getNetWorkImage() {
new Thread(new Runnable() {
@Override
public void run() {
try {
URL imageUrl = new URL("https://www.baidu.com/img/bdlogo.png");
HttpURLConnection conn = (HttpURLConnection) imageUrl.openConnection();
conn.setConnectTimeout(10000);
conn.setRequestMethod("GET");
if(conn.getResponseCode() == 200) {
InputStream is = conn.getInputStream();
Bitmap bitmap = BitmapFactory.decodeStream(is);
Message msg = mHandle.obtainMessage();
msg.what = 1;
msg.obj = bitmap;
mHandle.sendMessage(msg);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}).start();
}
- 在activity销毁时取消所有的消息(内存泄露)
@Override
protected void onDestroy() {
super.onDestroy();
mHandle.removeCallbacks(null);
}
- 内存泄露
内部类会持有外部类的引用,在Activity销毁时会造成内存泄露,所以在destroy时remove所有的消息
也可以使用静态内部类,(缺点比较明显,不能方便的使用外部类变量)
static class TestHandler extends Handler {
WeakReference<Activity> mActivityReference;
TestHandler(Activity activity) {
mActivityReference = new WeakReference<Activity>(activity);
}
@Override
public void handleMessage(Message msg) {
final Activity activity = mActivityReference.get();
if (activity != null) {
mImageView.setImageBitmap(mBitmap);
}
}
}
HandlerThread 基本使用
HandlerThread就是Thread、Looper和Handler的组合实现
public class TestHanderThread extends Activity {
private HandlerThread mHandlerThread = null;
private Handler mThreadHandler = null;
private Handler mUiHandler = null;
private static final String TAG = "TestHanderThread";
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initData();
}
private void initData() {
Log.i(null, "Main Thread id="+Thread.currentThread().getId());
mHandlerThread = new HandlerThread("HandlerWorkThread");
//必须在实例化mThreadHandler之前调运start方法,原因上面源码已经分析了
mHandlerThread.start();
//将当前mHandlerThread子线程的Looper传入mThreadHandler,使得
//mThreadHandler的消息队列依赖于子线程(在子线程中执行)
mThreadHandler = new Handler(mHandlerThread.getLooper()) {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
Log.d(TAG, "在子线程中处理!id="+Thread.currentThread().getId());
//从子线程往主线程发送消息
mUiHandler.sendEmptyMessage(0);
}
};
mUiHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
Log.d(TAG, "在UI主线程中处理!id="+Thread.currentThread().getId());
}
};
//从主线程往子线程发送消息
mThreadHandler.sendEmptyMessage(1);
}
}
Hander、MessageQueue、Looper
Looper负责的就是创建一个MessageQueue,然后进入一个无限循环体不断从该MessageQueue中读取消息,而消息的创建者就是一个或多个Handler
-
Message:消息体,用于装载需要发送的对象。
Message msg = handler.obtainMessage();
消息会进行复用减少内存开销
- handler:它直接继承自Object。作用是:在子线程中发送Message或者Runnable对象到MessageQueue中;在UI线程中接收、处理从MessageQueue分发出来的Message或者Runnable对象。发送消息一般使用Handler的sendMessage()方法,而发出去的消息经过处理后最终会传递到Handler的handlerMessage()方法中。
- MessageQueue:用于存放Message或Runnable对象的消息队列。它由对应的Looper对象创建,并由Looper对象管理。每个线程中都只会有一个MessageQueue对象。
boolean enqueueMessage(Message msg, long when) 负责将消息添加到队列中
Message next() 负责取出消息
- Looper:是每个线程中的MessageQueue的管家,循环不断地管理MessageQueue接收和分发Message或Runnable的工作。调用Looper的loop()方法后,就会进入到一个无限循环中然后每当发现MessageQueue中存在一条消息,就会将它取出,并调用Handler的handlerMessage()方法。每个线程中也只会有一个Looper对象。
使用ThreadLocal来实现Looper的存储(多线程内存共享时,使用ThreadLocal存储的变量在各线程中不一致)
public static void loop() 进行循环
进行无限循环