Android 线程通信(Handler + Message + Looper) 1 - Message

2017-11-01 12:46:38来源:CSDN作者:u012005313人点击

分享

参考:

Android 线程通信(Handler + Message + Looper) 0 - 前言

android.os.Message


Handler 使用 Message 类保存消息,在线程之间进行传递


主要内容:

  1. 创建 Message 对象
  2. 保存数据
  3. 设置 Handler
  4. 释放 Message 和重用 Message
  5. 示例程序
  6. 回调函数

创建 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 种方式来保存数据

设置成员变量

Message7public 类型的成员变量:

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 个变量中

  • 变量 whatMessage 设置这个字段用来标识当前消息的类型

  • 变量 replyTosendingUid 可用于 进程间通信本文讲解线程间通信,可参考: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

创建完 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 对象后,可以调用函数 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 对象

示例程序如下:

@Overrideprotected 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 绑定的线程

目前还没理解这有什么用处,后文会有解释

微信扫一扫

第七城市微信公众平台