Android消息机制之Handler
Android为何要出示Handler
Android提议大家不要在UI进程中实行用时实际操作,由于这非常容易造成ANR出现异常(在Android源代码中我们可以见到,UI假如对客户的实际操作超出5秒无响应,便会报ANR出现异常)。因而,一些用时实际操作都是会在子进程中进行。在我们在子进程中获得了数据信息,要将其表明到UI中,要是没有Handler,这将难以进行。因而,Android往往出示Handler,便是为了更好地处理子进程浏览UI的难题。
为何Android不允许在子进程中浏览UI呢?显而易见那样做不安全,线程同步浏览UI是不安全的(学过电脑操作系统的朋友应当都掌握进程相互独立,这儿我不详解了)。有些人便会讲了,能够根据设定信号量来处理啊。这中方式不是不能,由于这类方式会使浏览UI的逻辑性复杂化;次之这会减少UI的浏览高效率。而应用Handler就非常简单高效率。Handler是同一个Message来通信的。
Handler的使用方法
应用Handler时,必须重写handleMessage方式,在handleMessage中接纳新进程发过来的Message,并做相对的解决。在新进程中则是根据Message来传送信息,Message中通常也带上着必须传送的数据信息及其信息的种类。也要注重一点,假如当今进程有Looper就不用实行Looper.prepare(),要是没有,就必须在新进程内实行Looper.prepare(),不然会出错。实际应用编码以下:
public class MainActivity extends AppCompatActivity { private Handler mHandler=new Handler(){ @Override public void handleMessage(Message msg) { switch (msg.what) { case 1: //实行必须改动的UI实际操作 break; default: break; } } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); new Thread(new Runnable() { @Override public void run() {//在新进程中实行用时实际操作 //假如当今进程有Looper就不用实行Looper.prepare(); Looper.prepare(); try { Thread.sleep(1000);//睡眠质量一秒 } catch (InterruptedException e) { e.printStackTrace(); } //实际操作进行以后根据推送Message,来通告Handler开展UI实际操作 Message msg=new Message(); msg.what=1; /*这些是伪代码,value 是想根据Message传送的值 Bundle data=new Bundle(); data.putSerializable("key",value); msg.setData(data); */ //设定好数据信息后,推送信息 mHandler.sendMessage(msg); } }).start(); } }
Handler的內部体制
Handler建立的时候会选用Looper来创建信息循环系统。因此 ,当今进程务必要有Looper。当Handler建立进行后,其內部的Looper及其MessageQueue既能够和Handler一起协调工作了。Handler根据sendMessage将信息发给內部的MessageQueue,而MessageQueue会启用queue.enqueueMessage(msg, uptimeMillis)方式,它的源代码以下:
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"); Log.w(TAG, e.getMessage(), e); msg.recycle(); return false; } msg.markInUse(); msg.when = when; Message p = mMessages; boolean needWake; if (p == null || when == 0 || when < p.when) { // New head, wake up the event queue if blocked. msg.next = p; mMessages = msg; needWake = mBlocked; } else { // Inserted within the middle of the queue. Usually we don't have to wake // up the event queue unless there is a barrier at the head of the queue // and the message is the earliest asynchronous message in the queue. needWake = mBlocked && p.target == null && msg.isAsynchronous(); Message prev; for (;;) { prev = p; p = p.next; 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; }
根据源代码,大家发觉,queue.enqueueMessage(msg, uptimeMillis)将信息放进了MessageQueue里。Looper则会一直解决MessageQueue中的信息。