xamarin学习笔记A13(安卓Handler异步消息处理)
来源:互联网 发布:手机能做淘宝链接 编辑:程序博客网 时间:2024/06/06 01:32
(每次学习一点xamarin就做个学习笔记和视频来加深记忆巩固知识)
如有不正确的地方,请帮我指正。
安卓异步消息处理简介
有时候需要执行一些耗时的操作,例如从远程服务器读取数据,读取的时间的长度由很多因素决定,我们不希望主线程被阻塞程序无法进行其它工作,而且Android中只能在主线程进行UI操作,不能在子线程操作,如果要根据子线程执行的结果来更新UI时,这时就需要用到安卓异步消息处理机制。
异步消息原理
安卓异步消息处理主要有四个类:Message、Handler、Looper和MessageQueue,
我们直接打交道的是前两个类,后面两个类在内部自动处理的。
如图所示,首先在主线程中创建一个Handler实例对象并重写了HandlerMessage方法,然后在子线程中执行run方法并创建Message对象携带好数据,通过消息对象关联的hander对象的SendMessage方法将Message对象发送到消息队列,Looper会自动去从队列中取消息,取到后自动交给Handler的HandlerMessage方法处理。
下面我提取了Android中这四个类的源码的主要属性和方法,配上个人加的注释(如有注释不对的地方,请大家指正)
Message类
//用于携带数据public final class Message implements Parcelable { public int what;//一个整型标识 public int arg1;//可保存一个整数 public int arg2;//可保存一个整数 public Object obj;//可保存任意数据 long when;//消息应该被处理的时间 Handler target;//保存与它关联的Handlder对象的引用 Runnable callback;//保存处理消息的回调方法的引用 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; public Message() { } 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(); } public long getWhen() {return when;} public void setTarget(Handler target) {this.target = target;} public Handler getTarget() {return target;} public Runnable getCallback() {return callback;} public void sendToTarget() {target.sendMessage(this);}}
MessageQueue类
//消息队列(以Message的when值来排序的链表结构)public final class MessageQueue { private final boolean mQuitAllowed; Message mMessages;//链表中最前头的Message对象(when值最小) private boolean mQuitting; // Indicates whether next() is blocked waiting in pollOnce() with a non-zero timeout. private boolean mBlocked; //一些本地方法 private native static long nativeInit(); private native static void nativeDestroy(long ptr); private native void nativePollOnce(long ptr, int timeoutMillis); private native static void nativeWake(long ptr); MessageQueue(boolean quitAllowed) { mQuitAllowed = quitAllowed; } //从队列中取消息 Message next() { final long ptr = mPtr; if (ptr == 0) {return null;} int nextPollTimeoutMillis = 0; for (;;) { if (nextPollTimeoutMillis != 0) { Binder.flushPendingCommands(); } nativePollOnce(ptr, nextPollTimeoutMillis); synchronized (this) {//以同步的方式取,确保同一时刻只有一个线程访问 final long now = SystemClock.uptimeMillis(); Message prevMsg = null; Message msg = mMessages; if (msg != null && msg.target == null) {//如果消息关联的Handlder对象没有 do { prevMsg = msg; msg = msg.next; } while (msg != null && !msg.isAsynchronous());//那么只取异步消息 } if (msg != null) { if (now < msg.when) {//如果没到消息应该被处理的时间 nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);// 计算一个超时时间来等待 } else {//到达消息应该被处理的时间就返回消息 mBlocked = false; if (prevMsg != null) {prevMsg.next = msg.next;}//取出一个消息后整理好链表 else {mMessages = msg.next;} msg.next = null; msg.markInUse(); return msg; } } else { nextPollTimeoutMillis = -1; } } nextPollTimeoutMillis = 0; } } //添加一个新的消息到队列中 boolean enqueueMessage(Message msg, long when) { if (msg.target == null) {throw new IllegalArgumentException("Message must have a target.");} if (msg.isInUse()) {throw new IllegalStateException(msg + " This message is already in use.");} synchronized (this) {//以同步方式添加消息 if (mQuitting) { IllegalStateException e = new IllegalStateException( msg.target + " sending message to a Handler on a dead thread"); msg.recycle(); return false; } msg.markInUse(); msg.when = when; Message p = mMessages; boolean needWake; if (p == null || when == 0 || when < p.when) {//如果链表为空或者新来消息比队列中所有消息的优先级更高 msg.next = p;//把原先链表中最前头的消息放到新的消息后面 mMessages = msg;//设置新消息为链表中最前头的消息 needWake = mBlocked; } else { needWake = mBlocked && p.target == null && msg.isAsynchronous(); Message prev; for (;;) { prev = p; p = p.next;//从链表第二个开始找合适的位置(第一个已经在上面的when < p.when判断过了) if (p == null || when < p.when) { break;//找到合适链表位置p后退出循环 } if (needWake && p.isAsynchronous()) { needWake = false; } } msg.next = p; prev.next = msg;//这两行代码是把新消息插到prev与p之间 } if (needWake) { nativeWake(mPtr); } } return true; }}
Handler类
//用于处理消息public class Handler { final Looper mLooper; //保存着Looper对象的引用 final MessageQueue mQueue; //保存着Looper对象中MessageQueue对象的引用 final Handler.Callback mCallback; //保存着构造方法传入的回调方法的引用 public interface Callback { //一个接口,规定了消息处理的方法的规范 public boolean handleMessage(Message msg); } public Handler() { this(null, false); } //构造方法 public Handler(Handler.Callback callback, boolean async) {//构造方法 mLooper = Looper.myLooper(); if (mLooper == null) { throw new RuntimeException("Can't create handler inside thread that has not called Looper.prepare()"); } mQueue = mLooper.mQueue; mCallback = callback; mAsynchronous = async; } public void handleMessage(Message msg) { //如果dispatchMessage方法中的msg.callback==null 或 mCallback==null //那么子类应该重写此方法来处理消息 } public void dispatchMessage(Message msg) {//分发消息给回调方法处理 if (msg.callback != null) { handleCallback(msg); } else { if (mCallback != null) { if (mCallback.handleMessage(msg)) { return; } } handleMessage(msg); } } public final boolean sendMessage(Message msg) { //发送一个消息 return sendMessageDelayed(msg, 0); } public final boolean sendMessageDelayed(Message msg, long delayMillis)//以指定的延迟时间发送消息 { if (delayMillis < 0) {delayMillis = 0;} //当前时间加上延迟时间就是消息应该被处理的时间 return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis); } public boolean sendMessageAtTime(Message msg, long uptimeMillis) {//在指定的时间发送消息 MessageQueue queue = mQueue; if (queue == null) { return false;} return enqueueMessage(queue, msg, uptimeMillis); } //将消息发送到消息队列中 private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) { msg.target = this; //通过MessageQueue对象的enqueueMessage方法把消息添加到消息队列 return queue.enqueueMessage(msg, uptimeMillis); }}
Looper类
//用于不断的从队列中取消息,交给消息关联的Handler对象去处理public final class Looper { static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();//以键值对形式存储(key:线程 value:此线程的Looper对象) private static Looper sMainLooper; final MessageQueue mQueue;//自己持有的消息队列 final Thread mThread;//自己所在的线程 private Looper(boolean quitAllowed) {//私有构造方法 mQueue = new MessageQueue(quitAllowed); mThread = Thread.currentThread(); } public static void prepare() { prepare(true); } private static void prepare(boolean quitAllowed) { if (sThreadLocal.get() != null) { throw new RuntimeException("每个线程只能有一个Looper"); } sThreadLocal.set(new Looper(quitAllowed)); } public static void prepareMainLooper() {//准备好主Looper对象 prepare(false); synchronized (Looper.class) { if (sMainLooper != null) { throw new IllegalStateException("The main Looper has already been prepared."); } sMainLooper = myLooper(); } } public static Looper getMainLooper() { synchronized (Looper.class) { return sMainLooper; } } //开启循环 public static void loop() { final Looper me = myLooper(); final MessageQueue queue = me.mQueue; for (;;) { Message msg = queue.next(); //从消息队列中取出一个消息 if (msg == null) { return; } try { msg.target.dispatchMessage(msg);//将消息交给关联的Handlder对象去处理 } finally { } msg.recycleUnchecked(); } } public static @Nullable Looper myLooper() { return sThreadLocal.get(); }//取出Looper public static @NonNull MessageQueue myQueue() { return myLooper().mQueue; } public boolean isCurrentThread() {return Thread.currentThread() == mThread;} public void quit() {mQueue.quit(false);} public @NonNull Thread getThread() {return mThread;} public @NonNull MessageQueue getQueue() {return mQueue;}}
我们直接打交道的是Message类和Handlder类,那么MessageQueue和Looper类是怎么来的,这就要看ActivityThread类程序的入口方法main,贴上部分代码如下:
public final class ActivityThread { //..........省略其它代码 public static void main(String[] args) { //..........省略其它代码 Looper.prepareMainLooper();//创建好Looper对象,它构造方法里同时也创建了MessageQueue对象 ActivityThread thread = new ActivityThread();//创建好主线程 thread.attach(false); if (sMainThreadHandler == null) { sMainThreadHandler = thread.getHandler(); } Looper.loop(); //开启无限循环,不断从MessageQueue中取消息交给消息关联的Handler处理 throw new RuntimeException("Main thread loop unexpectedly exited"); }}
大概了解了这四大类和它们的机制后,接下来就开始做个简单的异步消息处理程序。
//处理消息的类 public class MyHandler : Handler { private Action<Message> _action;//指向一个回调方法的委托 public MyHandler(Action<Message> action) { _action = action;//构造方法中传入处理消息的回调方法 } //重写父类的HandleMessage方法 public override void HandleMessage(Message msg) { //if (_action != null) //{ // _action.Invoke(msg); //} _action?.Invoke(msg); //C#6.0新增判断空值的方式 }}
//模拟从服务器读取数据(实现Java.Lang.IRunnable接口可让线程使用) public class ReadDataTask : Java.Lang.Object, Java.Lang.IRunnable { private Handler _handler; public ReadDataTask(Handler handler) { _handler = handler; } public void Run()//子线程要运行的任务 { try { Java.Lang.Thread.Sleep(4000);// 模拟任务,比如从远程服务器读取数据 Message msg = _handler.ObtainMessage();//创建一个消息对象 msg.What = 123; //设置消息对象的标识 msg.Obj = "已读取到数据";//消息对象携带一个字符串数据 _handler.SendMessage(msg);// 将消息对象发送到主线程的消息队列(MessageQueue)中 } catch (Java.Lang.InterruptedException e) { Log.Debug("ReadInfoTask", e.Message); } } }
上面两个类准备好后,接下来就在Activity中使用了
public class MainActivity : AppCompatActivity,IOnClickListener { private MyHandler _myHandler; private EditText _editText; public void OnClick(View v) { switch (v.Id) { case Resource.Id.button1: Java.Lang.Thread thread = new Java.Lang.Thread(new ReadDataTask(_myHandler)); thread.Start();//启动一个子线程去执行耗时任务 break; } } protected override void OnCreate(Bundle savedInstanceState) { base.OnCreate(savedInstanceState); SetContentView(Resource.Layout.Main); Button btn1 = this.FindViewById<Button>(Resource.Id.button1); btn1.SetOnClickListener(this); _editText = this.FindViewById<EditText>(Resource.Id.editText1); _myHandler = new MyHandler(RefreshUI); //在主线程实例化一个Handler对象 } private void RefreshUI(Message msg)//在主线程更新UI { switch (msg.What) { case 123: string s = Convert.ToString(msg.Obj); _editText.Text = s; break; case 456: //…………………… break; } } }
代码和视频在我上传的CSDN资源中http://download.csdn.net/download/junshangshui/10022514
- xamarin学习笔记A13(安卓Handler异步消息处理)
- 安卓开发:Handler异步消息处理机制使用
- 学习笔记:android中Handler异步消息处理机制
- 安卓学习笔记——多线程和异步消息处理机制
- 异步消息处理 handler
- xamarin学习笔记A03(安卓Activiy)
- xamarin学习笔记A07(安卓Fragment)
- xamarin学习笔记A08(安卓广播)
- xamarin学习笔记A10(安卓SQLite)
- xamarin学习笔记A11(安卓ContentProvider)
- xamarin学习笔记A12(安卓Notification)
- xamarin学习笔记A18(安卓Service)
- xamarin学习笔记A19(安卓AIDL)
- 安卓handler消息处理机制
- 12.安卓Handler处理消息
- 《安卓笔记》Handler消息机制
- Handler--异步消息处理机制
- Handler与异步消息处理
- JavaScript02-页面布局
- python绘制神经网络中的Sigmoid和Tanh激活函数图像(附代码)
- Docker容器间的网络通信
- 原生JS添加节点方法与jQuery添加节点方法的比较及总结
- HashCode和equals方法如何决定对象能否存入Hash容器中
- xamarin学习笔记A13(安卓Handler异步消息处理)
- 乌班图下安装maven
- Redis主从复制
- 数据分析入门书籍,你看过几本
- Python画散点图(Knn中数据)
- 装饰者模式
- C语言Hailstone Sequence雹石序列相关练习
- 音频编码格式的百家争鸣
- php写一个简单的获取点击量的方法