参考:
Android 线程通信(Handler + Message + Looper) 0 - 前言
Android
使用类 Handler
来发送和处理消息
主要内容:
- 构造函数
- 处理
Message
- 处理
Runnable
- 内存泄漏
构造函数
Handler
提供了 7
种构造函数
public Handler()
public Handler(Callback callback)
public Handler(Looper looper)
public Handler(Looper looper, Callback callback)
public Handler(boolean async)
public Handler(Callback callback, boolean async)
public Handler(Looper looper, Callback callback, boolean async)
下面讲解各参数含义
Callback
类
Handler
提供了一个接口Callback
:/** * Callback interface you can use when instantiating a Handler to avoid * having to implement your own subclass of Handler. * * @param msg A {@link android.os.Message Message} object * @return True if no further handling is desired */ public interface Callback { public boolean handleMessage(Message msg); }
当你不想用子类继承时,可以实现该接口,作为参数传入即可
Looper
提供
Looper
对象作为参数,可以让Handler
将消息传递给指定Looper
的消息队列async
设置
Handler
对象是否同步(这个不太理解它的作用)
实现示例如下,在子线程中创建 Handler
对象,使用接口 Callback
实现 handleMessage
方法,并传入主线程的 Looper
对象:
class MyThread extends Thread implements Handler.Callback {
private static final String TAG = "MyThread";
Handler handler;
@Override
public void run() {
Looper.prepare();
Looper.myLooper().setMessageLogging(new LogPrinter(Log.ERROR, TAG));
handler = new Handler(Looper.getMainLooper(), this);
Log.e(TAG, "run: " + Thread.currentThread().getName());
Looper.loop();
}
@Override
public boolean handleMessage(Message msg) {
Log.e(TAG, "handleMessage: " + Thread.currentThread().getName());
return false;
}
}
然后在主线程中启动线程并发送消息:
MyThread thread = new MyThread();
thread.start();
Log.e(TAG, "onCreate: " + Thread.currentThread().getName());
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
Message msg = Message.obtain(thread.handler, 1, 2, 3);
msg.sendToTarget();
由结果可知,虽然 Handler
在子线程中创建,但由于其绑定的消息队列是主线程的,所以处理消息时也在主线程环境下
处理
Message
Message
Handler
类提供了以下方法来发送消息:
public final boolean sendMessage(Message msg)
public final boolean sendMessageDelayed(Message msg, long delayMillis)
public boolean sendMessageAtTime(Message msg, long uptimeMillis)
public final boolean sendMessageAtFrontOfQueue(Message msg)
其中,参数 delayMillis
表示延迟的时间(以毫秒计);参数 uptimeMillis
表示发送消息的时间,即当前时间加上延迟时间(uptimeMillis = SystemClock.uptimeMillis() + delayMillis
)
如果想要即时处理发送的消息,可以使用方法 sendMessageAtFrontOfQueue
Handler
类也提供了测试消息函数:
public final boolean sendEmptyMessage(int what)
public final boolean sendEmptyMessageDelayed(int what, long delayMillis)
public final boolean sendEmptyMessageAtTime(int what, long uptimeMillis)
参数 what
表示当前消息的类型,参数 delayMillis
和 uptimeMillis
与上面一致
dispatchMessage
发送上面函数后,Handler
会将其加入到消息队列中(如果没有输入 Message
, 会在内部创建),然后在 Looper.loop()
方法中调取消息队列消息,并发送给 Handler
处理:
/**
* Run the message queue in this thread. Be sure to call
* {@link #quit()} to end the loop.
*/
public static void loop() {
final Looper me = myLooper();
if (me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
final MessageQueue queue = me.mQueue;
...
for (;;) {
Message msg = queue.next(); // might block
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}
// This must be in a local variable, in case a UI event sets the logger
final Printer logging = me.mLogging;
if (logging != null) {
logging.println(">>>>> Dispatching to " + msg.target + " " +
msg.callback + ": " + msg.what);
}
...
try {
msg.target.dispatchMessage(msg);
} finally {
if (traceTag != 0) {
Trace.traceEnd(traceTag);
}
}
if (logging != null) {
logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
}
...
}
}
loop()
方法里调用了 Handler
类的 dispatchMessage
函数:
/**
* Handle system messages here.
*/
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
由之前可知,msg.callback
参数是 Runnable
对象,handleCallback
方法实现如下:
private static void handleCallback(Message message) {
message.callback.run();
}
即调用它的 run()
方法体(在 Looper
对象对应的线程实现)
同时,它会判断是否在参数 mCallback
有设置,如果有,则调用接口 Callback.handleMessage
方法;否则,调用子类的 handleMessage
方法;
/**
* Subclasses must implement this to receive messages.
*/
public void handleMessage(Message msg) {
}
处理
Runnable
Runnable
Handler
也提供了函数可以直接运行 Runnable
对象
public final boolean post(Runnable r)
public final boolean postDelayed(Runnable r, long delayMillis)
public final boolean postAtTime(Runnable r, long uptimeMillis)
public final boolean postAtTime(Runnable r, Object token, long uptimeMillis)
public final boolean postAtFrontOfQueue(Runnable r)
参数 delayMillis
和 uptimeMillis
的含义和上面一致
参数 token
用于设置 Message
的 obj
变量,查看其实现:
public final boolean postAtTime(Runnable r, Object token, long uptimeMillis)
{
return sendMessageAtTime(getPostMessage(r, token), uptimeMillis);
}
private static Message getPostMessage(Runnable r, Object token) {
Message m = Message.obtain();
m.obj = token;
m.callback = r;
return m;
}
可以发现,Handler
只是在内部封装了创建 Message
的细节,最终还是调用 Message
类
同样的,即时处理 Runnable
对象函数 postAtFrontOfQueue
应该也是在内部创建一个 Message
类,然后发送到消息队列:
public final boolean postAtFrontOfQueue(Runnable r)
{
return sendMessageAtFrontOfQueue(getPostMessage(r));
}
private static Message getPostMessage(Runnable r) {
Message m = Message.obtain();
m.callback = r;
return m;
}
Note:最终 Runnable
对象在消息队列对应的线程中实现
内存泄漏
参考:
Android Weak Handler:可以避免内存泄漏的Handler库
Handler造成Activity泄漏,用弱引用真的有用么?
这部分参考上面两篇博文(以及评论)
Handler
在使用过程中出现内存泄露的主要原因是由于消息队列中还存在未处理完的消息
Handler
提供了多个方法来查询和移除未处理的消息
public final boolean hasMessages(int what)
public final boolean hasMessages(int what, Object object)
查询消息队列中是否存在相同 what
属性和 obj
属性值的消息
public final void removeCallbacks(Runnable r)
public final void removeCallbacks(Runnable r, Object token)
public final void removeMessages(int what, Object object)
public final void removeCallbacksAndMessages(Object token)
同样是根据参数值来移除消息队列中未处理的消息
static
和 弱引用
如果在内部定义 Handler
子类,可以定义为 static
;同时还可以定义为弱引用
示例程序如下:
public class MainActivity extends AppCompatActivity {
private static final String TAG = "MainActivity";
MyHandler handler;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
handler = new MyHandler(this);
Message msg = Message.obtain(handler);
msg.sendToTarget();
}
private void handler() {
Log.e(TAG, "handler: " + Thread.currentThread().getName());
}
static class MyHandler extends Handler {
private WeakReference<MainActivity> weakReference;
public MyHandler(MainActivity activity) {
weakReference = new WeakReference<MainActivity>(activity);
}
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
Log.e(TAG, "handleMessage: " + Thread.currentThread().getName());
MainActivity activity = weakReference.get();
if (activity != null) {
activity.handler();
}
}
}
}