Android多线程消息处理机制(四) Message、MessageQueue源码解析和Handler综合使用

先分析完Message,MessageQueue源码

/**
 * 获取Message的最好办法是调用Message.obtain()或Handler.obtainMessage()方法
 * 这将会从message pool中获取,避免硬创建导致过大的开销。
 */
public final class Message implements Parcelable {
    
    public int what;
    public int arg1; 
    public int arg2;
    public Object obj;

    /*package*/ int flags;//还可以用这个属性存放参数?

    /*package*/ long when;//还可以用这个属性存放参数?
    
    /*package*/ Bundle data;//还可以用这个属性存放参数?
    
    /*package*/ Handler target;//指定其处理场所,即宿主handler
    
    /*package*/ Runnable callback;//message可以包含回调
    
    // sometimes we store linked lists of these things
	// next?message在messageQueue中是链式存储?
    /*package*/ Message next;

    private static final Object sPoolSync = new Object();//对象锁
    private static Message sPool;
    private static int sPoolSize = 0;

    private static final int MAX_POOL_SIZE = 50;//message pool最大数量50个

    private static boolean gCheckRecycle = true;

    /**
     * 从全局池中返回一个新的消息实例。使我们能够避免在许多情况下分配新的对象.
     */
    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();
    }

    /**
     * 从消息池中获取一个message,设置orig的全部属性,浅克隆
     */
    public static Message obtain(Message orig) {
        Message m = obtain();
        m.what = orig.what;
        m.arg1 = orig.arg1;
        m.arg2 = orig.arg2;
        m.obj = orig.obj;
        m.replyTo = orig.replyTo;
        m.sendingUid = orig.sendingUid;
        if (orig.data != null) {
            m.data = new Bundle(orig.data);
        }
        m.target = orig.target;
        m.callback = orig.callback;

        return m;
    }

    /**
     * 获取message,指定target为h
     */
    public static Message obtain(Handler h) {
        Message m = obtain();
        m.target = h;
        return m;
    }

    /**
     * 获取message,指定特定的handler和callback
     */
    public static Message obtain(Handler h, Runnable callback) {
        Message m = obtain();
        m.target = h;
        m.callback = callback;

        return m;
    }

    /**
     * 将消息实例回收返回到全局消息池.
     * 在调用此函数后,你不能触摸这个消息,因为它已被释放了。
	 * 这是回收的消息,目前正在排队或是在被传递到处理过程中
     */
    public void recycle() {
        if (isInUse()) {
            if (gCheckRecycle) {
                throw new IllegalStateException("This message cannot be recycled because it "
                        + "is still in use.");
            }
            return;
        }
        recycleUnchecked();
    }

    /**
     * 回收一个message,放到消息池中
     */
    void recycleUnchecked() {
        // 清空所有的属性值
        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++;
            }
        }
    }

    /**浅拷贝参数message o到当前的message对象中,
     * 但不拷贝linked list、timestamptarget、callback等属性的值。
     */
    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;
        }
    }

    /**
     * 设置一个任意数据的bundle数据包。如果没有复杂的数据需要传递,
	 * 你可以使用what,arg1,arg2,obj等的开销的属性传递。
     */
    public void setData(Bundle data) {
        this.data = data;
    }

    /**
     * 发送消息到你指定的handler的handleMessage()实现方法中执行,
	 * 如果没有指定message的target属性,则会抛异常
     */
    public void sendToTarget() {
        target.sendMessage(this);
    }

    /** 
	 * 构造方法,不推荐使用,优先Message.obtain()方法.
     */
    public Message() {
    }

    //...
}

总结:
1、Message就是数据对象,类似于java里面的bean。
2、创建方式很多,可以浅克隆,可以调用无参构造方法,可以obtain等,obtain是最推荐的,效率高。
3、Message有what、arg1、arg2、obj等属性存储普通数据,复杂的可以使用Bundle方式存储传递。
4、Message有个next属性,类型也是Message类型的,你猜猜是什么?看完下文你就会懂的。




下面看看MessageQueue部分源码:

/**
 * 这是个低级别的消息队列类,由looper持有以及消息分发。
 * message不能直接的添加到这个队列中,而是通过handler对象关联的looper处理的。
 * 你可以通过Looper.myQueue()获取当前线程的消息队列引用。
 */
public final class MessageQueue {

    // message queue是否可以退出
    private final boolean mQuitAllowed;
	
	/**
	 * MessageQueue中的message都存放在mMessages中,这只是个链表头。
	 * 因为Message中有Message类型的next属性。回头看看Message源码
	 */
	Message mMessages;

	
	//此方法是messageQueue最核心的方法,handler.sendMessageXXXXXX()等方法最终调用的都是这个方法,
	//即经过一系列的处理,把message添加到messageQueue中
	boolean enqueueMessage(Message msg, long when) {
        
        //...
		
        synchronized (this) {
            //...

            msg.markInUse();
            msg.when = when;
            Message p = mMessages;//把链表头赋给p
            boolean needWake;
            if (p == null || when == 0 || when < p.when) {
			    //如果链表头为null,或者新的message是when为0,或者新message的when在链表中靠前
                // New head, wake up the event queue if blocked.
                msg.next = p;
                mMessages = msg;
                needWake = mBlocked;
            } else {
                /**
				 * 插入队列的中间。通常情况下,我们不需要唤醒事件队列,
				 * 除非队列头上有一个障碍,消息是队列中最早的异步消息。
				 */
                needWake = mBlocked && p.target == null && msg.isAsynchronous();
                Message prev;
                for (;;) {
                    prev = p;
                    p = p.next;
					//循环迭代,找到新message的when合适的位置
                    if (p == null || when < p.when) {
                        break;
                    }
                    if (needWake && p.isAsynchronous()) {
                        needWake = false;
                    }
                }
                msg.next = p; // invariant: p == prev.next
                prev.next = msg;
            }

            // We can assume mPtr != 0 because mQuitting is false.
            if (needWake) {
			    //调用底层,唤醒队列
                nativeWake(mPtr);
            }
        }
        return true;
    }
    
}

MessageQueue这个类我们平常很少接触到,但里面有一个重点需要了解,就是上面这个方法。
通过这个方法,handler把message添加到消息队列中。这些消息有即时的(0延时),有延时的。这些message在消息队列中是怎么存放的呢?

when < p.when
新message的when与链表中某个message的when对比,时间小的放在前面。明白了吧?MessageQueue依据延时的长短,从小到大排序排序。


下面看handler用法demo:
方法一:

/**
 * handler最普通的用法
 * 
 * @author duke
 *
 */
public class MainActivity extends Activity {

	private Handler mHandler = new Handler() {
		public void handleMessage(android.os.Message msg) {
			toast(String.valueOf(msg.obj));
		};
	};

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
	}

	public void testHandler(View view) {
		new Thread() {
			public void run() {
				mHandler.obtainMessage(200, "技术也是世界的,我们一起分享").sendToTarget();
			};
		}.start();
	}

	public void toast(String msg) {
		Toast toast = Toast.makeText(this, msg, Toast.LENGTH_SHORT);
		toast.setGravity(Gravity.CENTER, 0, 0);
		toast.show();
	}
}

方法二:

/**
 * handler第二种用法
 * 注意:在oncreate、onstart、onresume期间没有getMainLooper(),
 * 关于在子线程中创建handler,参考:<a target=_blank href="http://blog.csdn.net/fesdgasdgasdg/article/details/52081773" target="_blank">http://blog.csdn.net/fesdgasdgasdg/article/details/52081773</a>
 * 也可以不传递looper,handler或自己获取当前线程的looper。
 * 此种方法没有实现handler的handleMessage方法
 * @author duke
 *
 */
public class MainActivity2 extends Activity {

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
	}
	
	private Handler mHandler;

	public void testHandler(View view) {
		mHandler = new Handler(getMainLooper());
		new Thread() {
			public void run() {
				mHandler.post(new Runnable() {
					@Override
					public void run() {
						toast("技术也是世界的,我们一起分享2");
					}
				});
			};
		}.start();
	}

	public void toast(String msg) {
		Toast toast = Toast.makeText(this, msg, Toast.LENGTH_SHORT);
		toast.setGravity(Gravity.CENTER, 0, 0);
		toast.show();
	}
}
方法三:
/**
 * handler最普通的用法
 * new一个Callback,让他来帮助handler处理message
 * @author duke
 *
 */
public class MainActivity3 extends Activity {

	private Handler mHandler = new Handler(new Callback() {

		@Override
		public boolean handleMessage(Message msg) {
			toast(String.valueOf(msg.obj));
			//注意这儿返回true与false的区别
			return true;
		}
	});

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
	}

	public void testHandler(View view) {
		new Thread() {
			public void run() {
				mHandler.obtainMessage(200, "技术也是世界的,我们一起分享3").sendToTarget();
			};
		}.start();
	}

	public void toast(String msg) {
		Toast toast = Toast.makeText(this, msg, Toast.LENGTH_SHORT);
		toast.setGravity(Gravity.CENTER, 0, 0);
		toast.show();
	}
}

方法四:

/**
 * handler最普通的用法
 * new一个callback,同时实现handler的handleMessage方法,同时处理消息
 * @author duke
 *
 */
public class MainActivity4 extends Activity {

	private Handler mHandler = new Handler(new Callback() {

		@Override
		public boolean handleMessage(Message msg) {
			toast(String.valueOf(msg.obj));
			//注意这儿返回true与false的区别
			return false;
		}
	}){
		@Override
		public void handleMessage(Message msg){
			//上面返回false,这儿同时也能处理消息
			toast(String.valueOf(msg.obj));
		}
	};

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
	}

	public void testHandler(View view) {
		new Thread() {
			public void run() {
				mHandler.obtainMessage(200, "技术也是世界的,我们一起分享4").sendToTarget();
			};
		}.start();
	}

	public void toast(String msg) {
		Toast toast = Toast.makeText(this, msg, Toast.LENGTH_SHORT);
		toast.setGravity(Gravity.CENTER, 0, 0);
		toast.show();
	}
}

方法五:

/**
 * handler最普通的用法
 * message中包含一个callback
 * @author duke
 *
 */
public class MainActivity5 extends Activity {

	private Handler mHandler = new Handler();

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main5);
	}

	public void testHandler(View view) {
		new Thread() {
			public void run() {
				Message msg = Message.obtain(mHandler, new Runnable() {
					@Override
					public void run() {
						toast("技术也是世界的,我们一起分享5");
					}
				});
				mHandler.sendMessage(msg);
			};
		}.start();
	}

	public void toast(String msg) {
		Toast toast = Toast.makeText(this, msg, Toast.LENGTH_SHORT);
		toast.setGravity(Gravity.CENTER, 0, 0);
		toast.show();
	}
}



是不是又看到了不少新鲜用法?

完了,Android多线程消息处理机制共四个章节,几乎都介绍完了。个人感觉介绍的很完整,相对于新手来说略有深度。


  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值