理解Android的handler机制--从应用到原理再到实践
关于Android的多线程机制,面试的时候总是问到,今天专门写这个博客,目的是把handler说清楚。
分别从下面四个方向说清楚。
由来
问题:为什么有handler?
我们知道java是支持多线程的,而一个APP只有一个UI(即屏幕只有一个),如果每个线程都可以更新UI,呵呵,估计我们的APP就乱套了,所以Android的设计者就想着,更新UI只能在主线程中,子线程是不能更新UI的,子线程如果更新UI,系统就会抛出异常。所以Android就需要提供一种机制,子线程通过这种机制可以在主线程中更新UI。
那么java有没有提供在子线程之间实时通讯的机制??? 由于线程的特性,一个进程内的所有线程够共享同一存储空间,即在多线程中,线程是可以访问同一内存单元,这样很可能出现数据不同步的问题,因此java提供了 synchronized关键字 和 Object 类的wait和notify方法(当然java还提供别的方法),但是此方法对Android更新UI这种特殊场合不是很适用。
因此Android专门提供了异步消息处理机制,用来解决在Android子线程中更新UI的操作。即handler机制。
应用
handler机制是为了在子线程中更新UI的,但是handler的作用不仅仅是为了更新UI的,准确的说是为了异步消息处理,因此从以下三种情况说明消息是如何发送和接受的。
子线程向主线程发送消息
Android是基于Java的,所以也分主线程,子线程!
(1)主线程:实现业务逻辑、UI绘制更新、各子线程串连,类似于将军;
(2)子线程:完成耗时(联网取数据、SD卡数据加载、后台长时间运行)操作,类似于小兵;
对于使用者来说,代码默认执行在主线程中,子线程的代码在new thread内执行的代码。
第一步:在主线程中创建一个handler
private Handler handler = new Handler() { public void handleMessage(Message msg) { switch (msg.what) { case UPDATE_TEXT: // 在这里可以进行UI操作 text.setText("Nice to meet you"); break; default: break; } } };
第二步:开启一个子线程,在子线程里直接使用Handler发送消息即可
new Thread(new Runnable() { @Override public void run() { Message message = new Message(); message.what = UPDATE_TEXT; handler.sendMessage(message); // 将Message对象发送出去 } }).start();
主线程向子线程发送消息
分两种情况:
方法1在子线程里初始化Looper
主线程向子线程发送消息的话,我们需要在子线程里初始化Looper,并在主线程里创建的Handler引用子线程的Looper(Handler中引用的是哪个线程的Looper,就在哪个线程里处理消息),下面看代码:
//方法1 public void method1(){ MyThread thread = new MyThread(); thread.start();//千万别忘记开启这个线程// delay(1000); //在Handler初始化的时候,thread.looper还没有初始化,所以加一个延时 // 或者使用 wait() 方法。 synchronized (thread) { if(thread.looper == null) { try{ thread.wait(); }catch (Exception e){ e.printStackTrace(); } } } handler1 = new Handler(thread.looper){ public void handleMessage(Message msg) { switch (msg.what) { case UPDATE: // 在这里可以进行UI操作 Log.d("当前子线程是--1--->",Thread.currentThread()+""); break; default: break; } }; }; } //子线程 class MyThread extends Thread{ private Looper looper;//取出该子线程的Looper public void run() { Looper.prepare();//创建该子线程的Looper looper = Looper.myLooper();//取出该子线程的Looper // 使用 notify() 方法唤醒。 synchronized (this) { this.notify(); } Looper.loop();//只要调用了该方法才能不断循环取出消息 } }
主线程发送消息:
//下面是主线程发送消息Message message1 = new Message();message1.what = UPDATE;handler1.sendMessage(message1);break;
这种方法有个问题,就是Handler初始化的时候,thread.looper还没有初始化,会导致Crash,上面的代码中加了一个延时解决问题了,或者使用 wait()和notify()方法解决,但有更好的解决办法,就是使用HandlerThread。
方法2使用HandlerThread
Android提供了HandlerThread类,子线程中有handler,代码如下:
//方法2 public void method2(){ //实例化一个特殊的线程HandlerThread,必须给其指定一个名字 HandlerThread thread = new HandlerThread("handler thread"); thread.start();//千万不要忘记开启这个线程 //将mHandler与thread相关联 handler2 = new Handler(thread.getLooper()){ public void handleMessage(android.os.Message msg) { switch (msg.what) { case UPDATE: // 在这里可以进行UI操作 Log.d("当前子线程是--2--->",Thread.currentThread()+""); break; default: break; } }; }; }
子线程向子线程发送消息
创建子线程,该子线程接受并处理消息,(注意,该子线程的创建也可以应用上面的情况)
new Thread(new Runnable() {@Overridepublic void run() {Looper.prepare();childHandler = new Handler() {@Overridepublic void handleMessage(Message msg) {super.handleMessage(msg);switch (msg.what) {case SEND:// 在这里可以进行UI操作Log.d(TAG,"这个消息是从-->>" + msg.obj + "过来的,在" + Thread.currentThread()+ "子线程当中执行的");break;default:break;}}};Looper.loop();//开始轮循}}).start();
发送消息线程:
new Thread(new Runnable() {@Overridepublic void run() {Message msg = childHandler.obtainMessage();msg.what = SEND;msg.obj = ""+ Thread.currentThread();childHandler.sendMessage(msg);}}).start();
以上分析主要参考Android使用Handler实现子线程与子线程、主线程之间通信,但是这偏文章没有写好的源代码,在总结这篇文章的基础上,实现代码并上传github,可直接下载运行。
原理
原理分析,主要查看郭霖的《第一行代码,第二版》。
(1)ActivityThread.main() 函数中,调用 Looper.prepareMainLooper();
(2)Looper.prepareMainLooper(); 的作用是初始化当前线程作为一个主线程。具体内容是,创建一个Looper对象,并将该对象赋值给sThreadLocal变量。
(2.1)在创建Looper对象的时候,其构造函数会创建MessageQueue对象。
(3)最后,ActivityThread.main() 会调用Looper.loop(); 函数。
(4)而Looper.loop();函数会从队列中取出message,并调用Handler. dispatchMessage()函数。
从上面可以看出,其关键是Looper对象。
java实现
理解了handler机制后,我们可不可以用java手写一个handler机制呢?
更多相关文章
- Android开发:Handler异步通信机制全面解析(包含Looper、Message Qu
- Effective Java读书笔记、感悟——1.创建和销毁对象
- 如何检测 Android(安卓)Cursor 泄漏
- FastJson的基本使用
- Android(安卓)Handler主线程和一般线程通信的应用分析
- Android(安卓)UI 卡顿及ANR检测原理
- 你真的懂Android(安卓)Handler吗?(一)
- android应用程序线程的监控
- Android9.0应用弹窗“此应用专为旧版Android打造,因此可能无法正