75

Android 消息机制 Handler 原理解析

 4 years ago
source link: https://www.tuicool.com/articles/jIfm2yq
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

UFjUJjY.png!web

E7zAr2Z.gif

本文字数: 4454

预计阅读时间: 15分钟

在Android中,Handler一直是一个热点,在开发过程中,它的使用频率很高,而且在Android源码中Handler都是常客。那么Handler是如何工作的呢,并且在使用时为何有一些特殊规定需要遵守呢,异步传递消息时消息是如何保存与分发的呢?今天我们从源码角度看一下Handler的设计与实现。

需求背景

在Android开发中,经常会遇到需要在不同线程之间切换的需要,比如网络请求(Android为了防止出现ANR异常,所以规定在Main Thread中不能进行网络请求,且最好不要进行耗时操作),子线程通信等等。此外,Android在设计之初,为了安全和用户体验考虑,规定了只允许在Main Thread里面进行UI更新,而不能在子线程里面进行,否则会抛出异常。这个时候,就需要用到Android的消息传递机制 — Handler。在Android中,Handler消息传递机制主要依赖于Handler,Message,MessageQueue,Looper。其中:

Handler负责消息的发送与接收处理。

Message负责消息的封装,他本身可以看做消息的载体。

MessageQueue:是一个消息队列,所有需要发送的消息用类似于链表的形式进行存储,并且依据于消息消费的时间为标志确定存储位置。

Looper:进行消息循环与消息分发。

简单使用如下:

1 Handler handler =  new Handler() {

2 @Override

3 public   void   handleMessage (Message msg)   {

4 super .handleMessage(msg);

5 LogUtils.d( "腾讯云Imi  handler out --" );

6 if (TLSService.getInstance() !=  null && TLSService.getInstance().getLastUserIdentifier() !=  null ) {

7 isIMNotinit =  false ;

8 presenter.getUnreadNum(getContext());

9 presenter.getConversation(getContext(),  true );

10 LogUtils.d( "腾讯云Imi  handler" );

11 }

12 }

13

};

在使用Handler时,创建一个Handler并重写其 h andleMessage  方法 ,参数Message中包含了传递的信息,信息来源等等,可以根据msg.what判断消息来源并做相应处理。 但不建议这样直接创建,如果这样在Activity中创建的话,当activity被finish之后,可能有消息还在继续发送,而此时的message中保留有activity中handler的引用,而这个handler里面有这个被finish的activity的隐式引用,导致此activity无法被销毁,这样就会有内存泄漏的风险。 解决办法一般是不让Handler内部类不持有外部activity的强引用,如下所示:

1 private static class   MyHandler   extends   Handler   {

2 private WeakReference<Context> mContextReference;

3

4 public   MyHandler (Context c)   {

5 mContextReference =  new WeakReference<Context>(c);

6 }

7

8 @Override

9 public   void   handleMessage (Message msg)   {

10 final Context c = mContextReference.get();

11 if (c !=  null ) {

12 if (CommonUtils.notEmpty(msg.obj.toString())) {

13 Intent intent =  new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);

14 Uri uri = Uri.fromFile( new File(msg.obj.toString()));

15 intent.setData(uri);

16 c.sendBroadcast(intent);  // 发送广播通知相册

17 }

18 Toast.makeText(c,  "图片下载完成" , Toast.LENGTH_SHORT).show();

19 }

20 }

21 }

22 private static class   MyHandler   extends   Handler   {

23 private WeakReference<Context> mContextReference;

24

25 public   MyHandler (Context c)   {

26 mContextReference =  new WeakReference<Context>(c);

27 }

28

29 @Override

30 public   void   handleMessage (Message msg)   {

31 final Context c = mContextReference.get();

32 if (c !=  null ) {

33 if (CommonUtils.notEmpty(msg.obj.toString())) {

34 Intent intent =  new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);

35 Uri uri = Uri.fromFile( new File(msg.obj.toString()));

36 intent.setData(uri);

37 c.sendBroadcast(intent);  // 发送广播通知相册

38 }

39 Toast.makeText(c,  "图片下载完成" , Toast.LENGTH_SHORT).show();

40 }

41 }

42 }

43 private static class   MyHandler   extends   Handler   {

44 private WeakReference<Context> mContextReference;

45

46 public   MyHandler (Context c)   {

47 mContextReference =  new WeakReference<Context>(c);

48 }

49

50 @Override

51 public   void   handleMessage (Message msg)   {

52 final Context c = mContextReference.get();

53 if (c !=  null ) {

54 if (CommonUtils.notEmpty(msg.obj.toString())) {

55 Intent intent =  new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);

56 Uri uri = Uri.fromFile( new File(msg.obj.toString()));

57 intent.setData(uri);

58 c.sendBroadcast(intent);  // 发送广播通知相册

59 }

60 Toast.makeText(c,  "图片下载完成" , Toast.LENGTH_SHORT).show();

61 }

62 }

63

}

把Handler设置为静态类,静态类不持有外部类的对象,所以activity销毁的时候不会受到Handler的限制,并且在Handler里面用到activity是持有的弱引用,不影响外部activity的销毁。

消息发送

上面是Handler接收到消息之后的最终处理,接下来看看消息发送的情况。Handler有多个方法用来应对不同情景的数据发送,以下为几个例子:

1. sen dEmptyMessageDelayed(int what, long delayMillis)  ,带有消息来源的延时消息发送。

1 public   final   boolean   sendEmptyMessageDelayed ( int  what,  long  delayMillis)   {

2 Message msg = Message.obtain();

3 msg.what = what;

4 return sendMessageDelayed(msg, delayMillis);

5

}

2. sendEmptyMessage(int what)  只包含来源身份信息的空消息发送。

1

public final boolean sendEmptyMessage ( int  what)

2

{

3 return sendEmptyMessageDelayed(what,  0 );

4

}

3. sendEmptyMessageDelayed(int what, long delayMillis) 延时空消息发送

1 public   final   boolean   sendEmptyMessageDelayed ( int  what,  long  delayMillis)   {

2 Message msg = Message.obtain();

3 msg.what = what;

4 return sendMessageDelayed(msg, delayMillis);

5

}

4. sendMessageAtFrontOfQueue(Message msg) 把消息放入队列头部,其实实现是把延时发送消息设置为0。

1 public   final   boolean   sendMessageAtFrontOfQueue (Message msg)   {

2 MessageQueue queue = mQueue;

3 if (queue ==  null ) {

4 RuntimeException e =  new RuntimeException(

5 this" sendMessageAtTime() called with no mQueue" );

6 Log.w( "Looper" , e.getMessage(), e);

7 return false ;

8 }

9 return enqueueMessage(queue, msg,  0 );

10

}

可以看到,所有方法都调用到了 sendMessageAtTime 方法,只是参数不同而已。

1 public   boolean   sendMessageAtTime (Message msg,  long  uptimeMillis)   {

2 MessageQueue queue = mQueue;

3 if (queue ==  null ) {

4 RuntimeException e =  new RuntimeException(

5 this" sendMessageAtTime() called with no mQueue" );

6 Log.w( "Looper" , e.getMessage(), e);

7 return false ;

8 }

9 return enqueueMessage(queue, msg, uptimeMillis);

10

}

方法参数Message信息与消息消费时间。判断了是否存在 MessageQueue  ,为空则会报错,存在则把消息根据时间放入queue中,再看看这个 MessageQueue  是什么时候初始化的。

1 public   Handler (Callback callback,  boolean  async)   {

2 if (FIND_POTENTIAL_LEAKS) {

3 final Class<? extends Handler> klass = getClass();

4 if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&

5 (klass.getModifiers() & Modifier.STATIC) ==  0 ) {

6 Log.w(TAG,  "The following Handler class should be static or leaks might occur: " +

7 klass.getCanonicalName());

8 }

9 }

10

11 mLooper = Looper.myLooper();

12 if (mLooper ==  null ) {

13 throw new RuntimeException(

14 "Can't create handler inside thread that has not called Looper.prepare()" );

15 }

16 mQueue = mLooper.mQueue;

17 mCallback = callback;

18 mAsynchronous = async;

19

}

通过跟踪我们可以发现,用来存储消息的 MessageQueue  是在Handler初始化的时候初始化的, mQ ueu e = mLooper.mQueue  ; 且这个mLooper也是这个时候通过 Looper.myLooper() ;初始化的,我们现在去Looper里面看看这个初始化过程:

1 public static @Nullable Looper  myLooper ()   {

2 return sThreadLocal.get();

3

}

可以发现,是从一个ThreadLocal里面拿到的Looper对象,继续查看是在哪里进行Looper对象的设置的。

1 private   static   void   prepare ( boolean  quitAllowed)   {

2 if (sThreadLocal.get() !=  null ) {

3 throw new RuntimeException( "Only one Looper may be created per thread" );

4 }

5 sThreadLocal.set( new Looper(quitAllowed));

6 }

7

8 private   Looper ( boolean  quitAllowed)   {

9 mQueue =  new MessageQueue(quitAllowed);

10 mThread = Thread.currentThread();

11

}

通过跟踪观察可以发现,Looper是在通过 Looper.prepare()  方法把Looper对象放入ThreadLocal对象里面的,并且在此时创建了MessageQueue对象。 所以当我们在子线程使用Handler的时候,在创建Handler前必须要先调用 Looper.prepare()  方法的原因了,因为在创建Handler的时候会进行Looper的初始化。 如果没有先调用 Looper.prepare()  的话, sThreadLocal.get()  的值就为空,就会抛出RuntimeException。 此外有个特例就是,如果我们在Main Thread里面使用Handler的话则不需要使用 Looper.prepare()  就可以直接创建Handler使用了,其实这是因为在Android程序创建的时候已经调用过这个方法了。 Android程序刚开始的入口是ActivityThread的main方法,在里面可以看到相关的设定:

1 public   static   void   main (String[] args)   {

2 Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER,  "ActivityThreadMain" );

3 SamplingProfilerIntegration.start();

4

5 // CloseGuard defaults to true and can be quite spammy.  We

6 // disable it here, but selectively enable it later (via

7 // StrictMode) on debug builds, but using DropBox, not logs.

8 CloseGuard.setEnabled( false );

9

10 Environment.initForCurrentUser();

11

12 // Set the reporter for event logging in libcore

13 EventLogger.setReporter( new EventLoggingReporter());

14

15

16 final File configDir = Environment.getUserConfigDirectory(UserHandle.myUserId());

17 TrustedCertificateStore.setDefaultUserDirectory(configDir);

18

19 Process.setArgV0( "<pre-initialized>" );

20

21 Looper.prepareMainLooper();

22

23 ActivityThread thread =  new ActivityThread();

24 thread.attach( false );

25

26 if (sMainThreadHandler ==  null ) {

27 sMainThreadHandler = thread.getHandler();

28 }

29

30 if ( false ) {

31 Looper.myLooper().setMessageLogging( new

32 LogPrinter(Log.DEBUG,  "ActivityThread" ));

33 }

34

35 // End of event ActivityThreadMain.

36 Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);

37 Looper.loop();

38

39 throw new RuntimeException( "Main thread loop unexpectedly exited" );

40

}

我们可以看到,在ActivityThread的main方法里面,调用了 Looper.prepareMainLooper() ;方法创建Looper对象,并且最后还调用了 Looper.loop() ; 方法进行消息循环,这也是在Main Thread里面调用为何不需要提前用Looper.prepare()就可以直接使用的原因了。我们再看看 Looper.prepareMainLooper()  是怎么创建Looper对象的:

1 public   static   void   prepareMainLooper ()   {

2 prepare( false );

3 synchronized (Looper.class) {

4 if (sMainLooper !=  null ) {

5 throw new IllegalStateException( "The main Looper has already been prepared." );

6 }

7 sMainLooper = myLooper();

8 }

9

}

在prepareMainLooper方法里面调用了prepare方法,并且Main Thread里面和其他子线程里面都保证了只能创建一次Looper对象,即一个线程只能有一个Looper对象,否则会抛出 IllegalStateException  异常。

到此对Handler,Looper的创建做一个总结:

在子线程创建使用Handler的时候必须先调用 Looper.prepare()  方法创建Looper,Looper里面创建的对象由一个ThreadLocal对象进行存储,主线程创建使用Handler的时候 不需要提前调用Looper.prepare()方法 ,因为在程序开始的时候在ActivityThread的main方法里面已经调用过 Looper.prepareMainThread()  方法了。 每个线程里面只能调用 Looper.prepare()  方法一次,只能创建一个Looper对象,否则会抛出异常。

Handler创建的时候,会调用Looper的方法去实例化Looper和MessageQueue对象。

消息存储与消息循环

几乎所有的发送消息的方法最后都调用了 sendMessageAtTime  方法,在这个发放中判断了是否存在MessageQueue对象之后调用了 enqueueMessage  方法,在这个方法中,把 msg.targt  设置为此Handler对象,注意,这里是用于之后在MessageQueue里面消费消息时找到对应的处理此消息的Handler,然后调用MessageQueue的 enqueueMessage()  方法,此方法主要是用于把消息放入MessageQueue里面,即入队操作。

1 boolean   enqueueMessage (Message msg,  long  when)   {

2 if (msg.target ==  null ) {

3 throw new IllegalArgumentException( "Message must have a target." );

4 }

5 if (msg.isInUse()) {

6 throw new IllegalStateException(msg +  " This message is already in use." );

7 }

8

9 synchronized ( this ) {

10 if (mQuitting) {

11 IllegalStateException e =  new IllegalStateException(

12 msg.target +  " sending message to a Handler on a dead thread" );

13 Log.w(TAG, e.getMessage(), e);

14 msg.recycle();

15 return false ;

16 }

17

18 msg.markInUse();

19 msg.when = when;

20 Message p = mMessages;

21 boolean needWake;

22 if (p ==  null || when ==  0 || when < p.when) {

23 // New head, wake up the event queue if blocked.

24 msg.next = p;

25 mMessages = msg;

26 needWake = mBlocked;

27else {

28

29

30 // and the message is the earliest asynchronous message in the queue.

31 needWake = mBlocked && p.target ==  null && msg.isAsynchronous();

32 Message prev;

33 for (;;) {

34 prev = p;

35 p = p.next;

36 if (p ==  null || when < p.when) {

37 break ;

38 }

39 if (needWake && p.isAsynchronous()) {

40 needWake =  false ;

41 }

42 }

43 msg.next = p;  // invariant: p == prev.next

44 prev.next = msg;

45 }

46

47 // We can assume mPtr != 0 because mQuitting is false.

48 if (needWake) {

49 nativeWake(mPtr);

50 }

51 }

52 return true ;

53

}

Message消息通过MessageQueue的 enqueueMessage  方法进行入队操作,在此方法中先判断 msg.target  是否存在,当前消息是否在使用中,是否收到退出信息等的检测,全部正常才进行入队,从上面代码我们可以看到,MessageQueue是通过类似于链表的形式存储Message消息的,且是通过消费时间进行排序的,通过前面我们可以知道,入队用于排序的时间是Message的消费时间,即 System.currentTime()+delayMillis  ;循环遍历消息队列,找到 msg.when  应该插入的地方,插入链表,完成消息的入队操作。 这里还需要注意的是 nativeWake(mPtr)  ;方法,这个方法是用通过JNI实现的,即在底层通过C实现的,然后通过JNI调用,在底层中维持了一个 mWakeEventFd  文件,这个文件是专门用于进程和线程之间通信的,并且通过 epoll  监控。 这里在入队完成之后会调用此方法,通过此方法会向 MwakeEventFD  文件写入一个 uint64_t  ,这个是用于唤醒消息循环线程的,在后面消息取出的时候进行详细说明。

通过上面的方法就完成了消息发送过程,接下来则是消息循环过程,当消息的消费时间到了之后取出相应的消息进行消费。通过上面的时候我们知道在线程中使用完Handler之后需要调用Looper.loop()完成整个过程,在主线程不需要我们操作是因为ActivityThread里面已经调用过了,在 loop()  里面做的就是消息的阻塞等待。

1 public   static   void   loop ()   {

2 final Looper me = myLooper();

3 if (me ==  null ) {

4 throw new RuntimeException( "No Looper; Looper.prepare() wasn't called on this thread." );

5 }

6 final MessageQueue queue = me.mQueue;

7

8

9 // and keep track of what that identity token actually is.

10 Binder.clearCallingIdentity();

11 final long ident = Binder.clearCallingIdentity();

12

13 for (;;) {

14 Message msg = queue.next();  // might block

15 if (msg ==  null ) {

16 // No message indicates that the message queue is quitting.

17 return ;

18 }

19

20

21 final Printer logging = me.mLogging;

22 if (logging !=  null ) {

23 logging.println( ">>>>> Dispatching to " + msg.target +  " " +

24 msg.callback +  ": " + msg.what);

25 }

26

27 final long slowDispatchThresholdMs = me.mSlowDispatchThresholdMs;

28

29 final long traceTag = me.mTraceTag;

30 if (traceTag !=  0 && Trace.isTagEnabled(traceTag)) {

31 Trace.traceBegin(traceTag, msg.target.getTraceName(msg));

32 }

33 final long start = (slowDispatchThresholdMs ==  0 ) ?  0 : SystemClock.uptimeMillis();

34 final long end;

35 try {

36 msg.target.dispatchMessage(msg);

37 end = (slowDispatchThresholdMs ==  0 ) ?  0 : SystemClock.uptimeMillis();

38finally {

39 if (traceTag !=  0 ) {

40 Trace.traceEnd(traceTag);

41 }

42 }

43 if (slowDispatchThresholdMs >  0 ) {

44 final long time = end - start;

45 if (time > slowDispatchThresholdMs) {

46 Slog.w(TAG,  "Dispatch took " + time +  "ms on "

47 + Thread.currentThread().getName() +  ", h=" +

48 msg.target +  " cb=" + msg.callback +  " msg=" + msg.what);

49 }

50 }

51

52 if (logging !=  null ) {

53 logging.println( "<<<<< Finished to " + msg.target +  " " + msg.callback);

54 }

55

56 // Make sure that during the course of dispatching the

57 // identity of the thread wasn't corrupted.

58 final long newIdent = Binder.clearCallingIdentity();

59 if (ident != newIdent) {

60 Log.wtf(TAG,  "Thread identity changed from 0x"

61 + Long.toHexString(ident) +  " to 0x"

62 + Long.toHexString(newIdent) +  " while dispatching to "

63 + msg.target.getClass().getName() +  " "

64 + msg.callback +  " what=" + msg.what);

65 }

66

67 msg.recycleUnchecked();

68 }

69

}

从代码中我们可以看出,这是个无限循环方法等待获取可以处理的消息,在循环里面,通过 do-while  找到一个不为空且是asynchronous的消息,找到之后检测这个消息是否到了执行时间,如果不到的话,通过 Math.min(msg.when - now, Integer.MAX_VALUE)  ;设置等待时间,如果这个消息找到了,且到了执行时间了,那么就取出此消息,并把链表中此消息删除,把这个消息通过msg.markInUse();标志为使用中,把这个找到的消息返回给Looper的loop方法,进行消息分发。 如果到了链表尾部还是没有符合的消息,则进入阻塞等待过程。

另外在此方法中还得注意 nativePollOnce(ptr, nextPollTimeoutMillis)  ;这个方法也是JNI调用C++实现的。 之前说到在通过Handler发送消息的时候,会向mWakeEventFd文件写一个 uint_64  ,而 nativePollOnce  方法则阻塞监听mWakeEventFd文件以及唤醒消息循环线程的。 当有消息发送的时候就会写入一个 uint_64  ,而 nativePollOnce  里面则是一直监听这个文件,当有写入操作发生时,就会唤醒 epoll_ wait 即消息循环线程,线程就会去取出队列里面的消息去执行操作,当队列里面没有消息的时候,又会继续等待,当下次有信息写入的时候则再次唤醒线程去取出队列消息。 这样就完成一次消息循环。

继续看上面的取出消息之后的处理,上面说到取出消息之后loop()方法是调用了msg.target.dispatchMessage方法进行消息处理,而msg.target是之前设置的目标Handler,现在去Handler里面看看dispatchMessage的处理:

1 public   void   dispatchMessage (Message msg)   {

2 if (msg.callback !=  null ) {

3 handleCallback(msg);

4else {

5 if (mCallback !=  null ) {

6 if (mCallback.handleMessage(msg)) {

7 return ;

8 }

9 }

10 handleMessage(msg);

11 }

12

}

这里就是如何处理信息了,如果为Message设置了callback的话则直接 message.callback.run()  处理消息,如果有设置 Handler的callback  ,也进行分发; 如果都没有的话,那就直接调用 handleMessage(msg) ;还记得我们最开是的时候写的简单使用Handler的例子么,里面重写了一个方法,就是handleMessage(msg);所以到这里就清楚了,前面发出的消息就是在这里进行处理的。 另外还有很多经常用的方法都是通过包装的Handler来进行的,比如:

1. Activity.runOnUiThread(Runnable action)

1 public   final   void   runOnUiThread (Runnable action)   {

2 if (Thread.currentThread() != mUiThread) {

3 mHandler.post(action);

4else {

5 action.run();

6 }

7

}

这个是Activity的方法,用于在切换到主线程运行,可以看到内部实现是判断当前线程是否是主线程,如果是的话直接运行,不是的话用 mHandler.post 发送出去,而mHandler是申明在主线程的Handler,经过发送之后再主线程的Handler里面完成调用。

2. View.post() 

1 public   boolean   post (Runnable action)   {

2 final AttachInfo attachInfo = mAttachInfo;

3 if (attachInfo !=  null ) {

4 return attachInfo.mHandler.post(action);

5 }

6

7

8 // Assume that the runnable will be successfully placed after attach.

9 getRunQueue().post(action);

10 return true ;

11

}

View.pos t() 用于异步更新view,也是找到主线程Handler,然后通过Handler发送消息,在主线程更新Handler。另外还有很多经典方法都是用Handler更新数据的,最典型的是Android官方提供的异步工具AsyncTask,用它可以进行异步请求或者异步下载数据,下载图片等等,AsyncTask就是用Handler实现的多线程异步工具,开启子线程进行数据请求,然后通过Handler发送数据消息,最好在主线程里面处理收到的消息,完成异步请求。

总结

在使用Handler的时候,主线程不需要调用 Looper.prepare() 创建Looper,因为在程序开始的时候在ActivityTask里面的main方法里面调用了 Looper.prepareMainLooper() 创建了Looper对象,子线程中需要先调用 Looper.prepare() 创建Looper对象。每个线程只能有一个Looper对象。在创建Looper的时候会初始化MessageQueue对象,因为在创建Handler的时候需要是用到Looper对象以及MessageQueue对象,并且在Looper中保存示例是放在ThreadLocal里面的。

初始完成之后用Handler发送信息,包括信息数据Message以及delayMillis,之后调用MessageQueue的 enqueueMessage() 把消息按类似于链表结构并按照时间顺序排列,此时还会调用 nat iveWake(mPtr) 方法向底层的 mWakeEventFd 文件写入 uint64_t ,唤醒消息循环线程。子线程发送完数据之后调用 Looper.loop() ,死循环等待到时间处理的消息出队,Looper取到消息之后,就进行消息分发,根据设置的callback进行处理消息,如果没有设置则调用Handler的handleMessage处理消息。MessageQueue的next方法负责进行消息出队操作,无限循环检查是否有到时间的消息,如果有则把他出队,如果没有则循环阻塞。

出队消息然后交给Looper的loop方法进行消息分发。在消息出队的时候会调用 nativePollOnce(ptr, nextPollTimeoutMillis) 方法,这个方法是用来通过 epoll 监听 mWakeEventFd 文件的,当监听到有uint64写入文件的时候唤醒消息循环线程取出消息并处理,没有消息的时候沉睡等待下次 uint64 的写入。这样就完成了一次消息的收发。

也许你还想看

(▼点击文章标题或封面查看)

加入搜狐技术作者天团

千元稿费等你来!

戳这里!☛

f6B73yB.jpg!web

ZbiAZrV.gif


Recommend

  • 73
    • www.cocoachina.com 6 years ago
    • Cache

    iOS 消息转发机制Demo解析

    website upgrading… 京ICP备110065...

  • 91

    前言 在Android开发的多线程应用场景中,Handler机制十分常用 今天,我将图文详解 Handler机制 的工作原理,希望你们会喜欢 目录 1. 定义 一套 Android 消息传递机制 2. 作用 在多线程的应用场景中,将工作线

  • 70

  • 57
    • segmentfault.com 5 years ago
    • Cache

    Handler机制情景分析

    一. 概述 在整个Android的源码世界里,有两大利剑,其一是Binder IPC机制,,另一个便是消息机制(由Handler/Looper/MessageQueue等构成的). Android有大量的消息驱动方式来进行交互,比如Android的四剑客Activity, Se...

  • 27

    Android 的消息机制Handler,是在开发过程中都会用到的,它可以轻松的从子线程切换到主线程,大部分的时候我们将Handler会用在更新UI的操作.那么Handler是如何做到不同线程通信的呢? 如何切换线程的呢?本篇文章带领大家来轻松的实现一个Handl...

  • 43
    • www.tuicool.com 4 years ago
    • Cache

    Handler机制

    Handler机制 Handler在我们日常开发中会经常用到,它主要用于处理异步消息,当发出一个消息之后,首先进入到一个消息队列,发送消息的函数即可返回,而另外一个部分在消息队列中逐一取出,然后对消息进行处理。 虽然经...

  • 8
    • yuanfentiank789.github.io 3 years ago
    • Cache

    Android消息机制2-Handler(Native层)

    Android消息机制2-Handler(Native层) - JackPeng博客 本文基于Android 6.0的源代码,来分析native层的消息处理机制 相关源码 framework/base/core/java/andorid/os/MessageQue...

  • 5
    • yuanfentiank789.github.io 3 years ago
    • Cache

    Android消息机制3-Handler(实战)

    本文基于Android 6.0的源代码,来分析Handler的用法 相关源码 framework/base/core/java/andorid/os/HandlerThread.java 一、HandlerThread

  • 10
    • yuanfentiank789.github.io 3 years ago
    • Cache

    Android消息机制1-Handler(Java层)

    Android消息机制1-Handler(Java层) - JackPeng博客 本文基于Android 6.0的源代码,来分析Java层的handler消息处理机制 相关源码 framework/base/core/java/andorid/os/Handler...

  • 4

    Android IntentService完全解析 当Service遇到Handler ...

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK