参考:
Android 线程通信(Handler + Message + Looper) 0 - 前言
Handler
使用 Message
类保存消息,在线程之间进行传递
主要内容:
- 创建
Message
对象 - 保存数据
- 设置
Handler
- 释放
Message
和重用Message
- 示例程序
- 回调函数
创建
Message
对象
Message
对象
共有 3
种实现方式
直接创建
可以直接使用构造方法:
Message msg = new Message();
构造方法实现如下:
/** Constructor (but the preferred way to get a Message is to call {@link #obtain() Message.obtain()}).
*/
public Message() {
}
Message.obtain
根据源码可知,Android
更推荐使用方法 Message.obtain()
来获得:
Message msg = Message.obtain();
实现如下:
/**
* Return a new Message instance from the global pool. Allows us to
* avoid allocating new objects in many cases.
*/
public static Message obtain() {
synchronized (sPoolSync) {
if (sPool != null) {
Message m = sPool;
sPool = m.next;
m.next = null;
m.flags = 0; // clear in-use flag
sPoolSize--;
return m;
}
}
return new Message();
}
由源码可知,Android
系统在 Message
类中保持一个静态消息池
方法 obtain
还有多种重载方式:
public static Message obtain(Message orig)
public static Message obtain(Handler h)
public static Message obtain(Handler h, Runnable callback)
public static Message obtain(Handler h, int what)
public static Message obtain(Handler h, int what, Object obj)
public static Message obtain(Handler h, int what, int arg1, int arg2)
public static Message obtain(Handler h, int what,
int arg1, int arg2, Object obj)
这些重载方法均是先调用 obtain()
获取一个 Message
对象,并封装好了大部分需要设置的操作
Handler.obtainMessage
还可以调用 Handler
对象的 obtainMessage
方法获取 Message
对象:
Message msg = handler.obtainMessage();
实现如下:
/**
* Returns a new {@link android.os.Message Message} from the global message pool. More efficient than
* creating and allocating new instances. The retrieved message has its handler set to this instance (Message.target == this).
* If you don't want that facility, just call Message.obtain() instead.
*/
public final Message obtainMessage()
{
return Message.obtain(this);
}
该方法调用了 Message.obtain(Handler h)
Handler.obtainMessage
也有多种重载方式:
public final Message obtainMessage(int what)
public final Message obtainMessage(int what, Object obj)
public final Message obtainMessage(int what, int arg1, int arg2)
public final Message obtainMessage(int what, int arg1, int arg2, Object obj)
其实现也都是调用了 Message.obtain()
的重载方法
保存数据
类 Message
提供了 3
种方式来保存数据
设置成员变量
类 Message
有 7
个 public
类型的成员变量:
public int what;
public int arg1;
public int arg2;
public Object obj;
public Messenger replyTo;
public int sendingUid = -1;
类
Message
分配了两个int
变量(arg1,arg2
)和一个Object
变量,数据量少的情况下可以直接保存数据到这3
个变量中变量
what
:Message
设置这个字段用来标识当前消息的类型变量
replyTo
和sendingUid
可用于 进程间通信。本文讲解线程间通信,可参考:Android 基于Message的进程间通信 Messenger完全解析
setData
同时也可以保存数据到 Bundle
对象,然后使用方法 setData
。其实现如下:
/**
* Sets a Bundle of arbitrary data values. Use arg1 and arg2 members
* as a lower cost way to send a few simple integer values, if you can.
* @see #getData()
* @see #peekData()
*/
public void setData(Bundle data) {
this.data = data;
}
copyFrom
还可以调用函数 copyFrom
,直接从另一个 Message
对象中复制数据(首先待先创建 Message 实例):
/**
* Make this message like o. Performs a shallow copy of the data field.
* Does not copy the linked list fields, nor the timestamp or
* target/callback of the original message.
*/
public void copyFrom(Message o) {
this.flags = o.flags & ~FLAGS_TO_CLEAR_ON_COPY_FROM;
this.what = o.what;
this.arg1 = o.arg1;
this.arg2 = o.arg2;
this.obj = o.obj;
this.replyTo = o.replyTo;
this.sendingUid = o.sendingUid;
if (o.data != null) {
this.data = (Bundle) o.data.clone();
} else {
this.data = null;
}
}
设置
Handler
Handler
创建完 Message
对象后,可以调用 Handler
方法进行发送,也可以在 Message
对象中设置对应的 Handler
对象,然后进行发送,使用方法如下:
Message msg = Message.obtain();
msg.setTarget(handler);
msg.sendToTarget();
方法 setTarget
用于设置对应的 Handler
:
public void setTarget(Handler target) {
this.target = target;
}
方法 sendToTarget
用于发送消息:
/**
* Sends this Message to the Handler specified by {@link #getTarget}.
* Throws a null pointer exception if this field has not been set.
*/
public void sendToTarget() {
target.sendMessage(this);
}
当然可以在使用 obtain
方法获取 Message
对象的同时设置 Handler
对象:
Message msg = Message.obtain(handler);
msg.sendToTarget();
释放
Message
和重用
Message
Message
和重用
Message
当使用完 Message
对象后,可以调用函数 recycle()
释放当前 Message
:
/**
* Return a Message instance to the global pool.
* <p>
* You MUST NOT touch the Message after calling this function because it has
* effectively been freed. It is an error to recycle a message that is currently
* enqueued or that is in the process of being delivered to a Handler.
* </p>
*/
public void recycle() {
if (isInUse()) {
if (gCheckRecycle) {
throw new IllegalStateException("This message cannot be recycled because it "
+ "is still in use.");
}
return;
}
recycleUnchecked();
}
Note:不能再调用 recycle()
方法后再使用该 Message
对象
recycle()
方法调用内部函数 recyclerUnchecked()
,将当前 Message
实例放回到消息池中:
/**
* Recycles a Message that may be in-use.
* Used internally by the MessageQueue and Looper when disposing of queued Messages.
*/
void recycleUnchecked() {
// Mark the message as in use while it remains in the recycled object pool.
// Clear out all other details.
flags = FLAG_IN_USE;
what = 0;
arg1 = 0;
arg2 = 0;
obj = null;
replyTo = null;
sendingUid = -1;
when = 0;
target = null;
callback = null;
data = null;
synchronized (sPoolSync) {
if (sPoolSize < MAX_POOL_SIZE) {
next = sPool;
sPool = this;
sPoolSize++;
}
}
}
示例程序
public class MainActivity extends AppCompatActivity {
private static final String TAG = "MainActivity";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final MyHandler handler = new MyHandler();
new Thread(new Runnable() {
@Override
public void run() {
Message msg = Message.obtain(handler, 1, 100, 200);
msg.sendToTarget();
Message msg2 = Message.obtain(handler, 2, 300, 400);
msg2.sendToTarget();
}
}).start();
}
class MyHandler extends Handler {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
String str = null;
switch (msg.what) {
case 1:
str = String.format(Locale.CHINA, "hello world arg1 = %d arg2 = %d", msg.arg1, msg.arg2);
break;
case 2:
str = String.format(Locale.CHINA, "hi zj arg1 = %d arg2 = %d", msg.arg1, msg.arg2);
break;
}
Log.e(TAG, "handleMessage: " + str);
}
}
}
回调函数
也可以在 Message
对象中定义一个 Runnable
对象,Handler
处理消息时,不会调用方法 handleMessage
处理,而是调用该 Runnable
对象
示例程序如下:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final MyHandler handler = new MyHandler();
new Thread(new Runnable() {
@Override
public void run() {
Message msg = Message.obtain(handler, 1, 100, 200);
msg.sendToTarget();
Message msg2 = Message.obtain(handler, new MyRunnable());
msg2.what = 2;
msg2.arg1 = 300;
msg2.arg2 = 400;
msg2.sendToTarget();
}
}).start();
}
class MyHandler extends Handler {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
String str = null;
switch (msg.what) {
case 1:
str = String.format(Locale.CHINA, "hello world arg1 = %d arg2 = %d", msg.arg1, msg.arg2);
break;
case 2:
str = String.format(Locale.CHINA, "hi zj arg1 = %d arg2 = %d", msg.arg1, msg.arg2);
break;
}
Log.e(TAG, "handleMessage: " + str);
}
}
class MyRunnable implements Runnable {
@Override
public void run() {
Log.e(TAG, "run: MyRunnable " + Thread.currentThread().getName());
}
}
Note:Runnable 对象运行在 Handler 绑定的线程
目前还没理解这有什么用处,后文会有解释