Android JNI知识简介-阿里云开发者社区

开发者社区> 开发与运维> 正文

Android JNI知识简介

简介:
转载请注明出处:http://blog.csdn.net/singwhatiwanna/article/details/17361775

前言

上周对Android中的事件派发机制进行了分析,这次博主要对消息队列和Looper的源码进行简单的分析。大家耐心看下去,其实消息队列的逻辑比事件派发机制简单多了,所以大家肯定会很容易看懂的。

概念

1. 什么是消息队列

消息队列在android中对应MessageQueue这个类,顾名思义,消息队列中存放了大量的消息(Message)

2.什么是消息

消息(Message)代表一个行为(what)或者一串动作(Runnable),有两处会用到Message:Handler和Messenger

3.什么是Handler和Messenger

Handler大家都知道,主要用来在线程中发消息通知ui线程更新ui。Messenger可以翻译为信使,可以实现进程间通信(IPC),Messenger采用一个单线程来处理所有的消息,而且进程间的通信都是通过发消息来完成的,感觉不能像AIDL那样直接调用对方的接口方法(具体有待考证),这是其和AIDL的主要区别,也就是说Messenger无法处理多线程,所有的调用都是在一个线程中串行执行的。Messenger的典型代码是这样的:new Messenger(service).send(msg),它的本质还是调用了Handler的sendMessage方法

4.什么是Looper

Looper是循环的意思,它负责从消息队列中循环的取出消息然后把消息交给目标处理

5.线程有没有Looper有什么区别?

线程如果没有Looper,就没有消息队列,就无法处理消息,线程内部就无法使用Handler。这就是为什么在子线程内部创建Handler会报错:"Can't create handler inside thread that has not called Looper.prepare()",具体原因下面再分析。

6.如何让线程有Looper从而正常使用Handler?

在线程的run方法中加入如下两句:

Looper.prepare();

Looper.loop();

这一切不用我们来做,有现成的,HandlerThread就是带有Looper的线程。

想用线程的Looper来创建Handler,很简单,Handler handler = new Handler(thread.getLooper()),有了上面这几步,你就可以在子线程中创建Handler了,好吧,其实android早就为我们想到这一点了,也不用自己写,IntentService把我们该做的都做了,我们只要用就好了,具体怎么用后面再说。

消息队列和Looper的工作机制

一个Handler会有一个Looper,一个Looper会有一个消息队列,Looper的作用就是循环的遍历消息队列,如果有新消息,就把新消息交给它的目标处理。每当我们用Handler来发送消息,消息就会被放入消息队列中,然后Looper就会取出消息发送给它的目标target。一般情况,一个消息的target是发送这个消息的Handler,这么一来,Looper就会把消息交给Handler处理,这个时候Handler的dispatchMessage方法就会被调用,一般情况最终会调用Handler的handleMessage来处理消息,用handleMessage来处理消息是我们常用的方式。

源码分析

1. Handler发送消息的过程

[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1.    public final boolean sendMessage(Message msg)  
  2.    {  
  3.        return sendMessageDelayed(msg, 0);  
  4.    }  
  5.   
  6. public final boolean sendMessageDelayed(Message msg, long delayMillis)  
  7.    {  
  8.        if (delayMillis < 0) {  
  9.            delayMillis = 0;  
  10.        }  
  11.        return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);  
  12.    }  
  13.   
  14. public boolean sendMessageAtTime(Message msg, long uptimeMillis) {  
  15.     MessageQueue queue = mQueue;  
  16.     if (queue == null) {  
  17.         RuntimeException e = new RuntimeException(  
  18.                 this + " sendMessageAtTime() called with no mQueue");  
  19.         Log.w("Looper", e.getMessage(), e);  
  20.         return false;  
  21.     }  
  22.     return enqueueMessage(queue, msg, uptimeMillis);  
  23. }  
  24.   
  25. private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {  
  26.        msg.target = this;  
  27.        if (mAsynchronous) {  
  28.            msg.setAsynchronous(true);  
  29.        }  
  30.        //这里msg被加入消息队列queue  
  31.        return queue.enqueueMessage(msg, uptimeMillis);  
  32.    }  

2.Looper的工作过程

[java] view plaincopy在CODE上查看代码片派生到我的代码片
  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.      //从Looper中取出消息队列  
  7.      final MessageQueue queue = me.mQueue;  
  8.   
  9.      // Make sure the identity of this thread is that of the local process,  
  10.      // and keep track of what that identity token actually is.  
  11.      Binder.clearCallingIdentity();  
  12.      final long ident = Binder.clearCallingIdentity();  
  13.   
  14.      //死循环,循环的取消息,没有新消息就会阻塞  
  15.      for (;;) {  
  16.          Message msg = queue.next(); // might block 这里会被阻塞,如果没有新消息  
  17.          if (msg == null) {  
  18.              // No message indicates that the message queue is quitting.  
  19.              return;  
  20.          }  
  21.   
  22.          // This must be in a local variable, in case a UI event sets the logger  
  23.          Printer logging = me.mLogging;  
  24.          if (logging != null) {  
  25.              logging.println(">>>>> Dispatching to " + msg.target + " " +  
  26.                      msg.callback + ": " + msg.what);  
  27.          }  
  28.   
  29.          //将消息交给target处理,这个target就是Handler类型  
  30.          msg.target.dispatchMessage(msg);  
  31.   
  32.          if (logging != null) {  
  33.              logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);  
  34.          }  
  35.   
  36.          // Make sure that during the course of dispatching the  
  37.          // identity of the thread wasn't corrupted.  
  38.          final long newIdent = Binder.clearCallingIdentity();  
  39.          if (ident != newIdent) {  
  40.              Log.wtf(TAG, "Thread identity changed from 0x"  
  41.                      + Long.toHexString(ident) + " to 0x"  
  42.                      + Long.toHexString(newIdent) + " while dispatching to "  
  43.                      + msg.target.getClass().getName() + " "  
  44.                      + msg.callback + " what=" + msg.what);  
  45.          }  
  46.   
  47.          msg.recycle();  
  48.      }  
  49.  }  

3.Handler如何处理消息

[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. /** 
  2.  * Subclasses must implement this to receive messages. 
  3.  */  
  4. public void handleMessage(Message msg) {  
  5. }  
  6.   
  7. /** 
  8.  * Handle system messages here. 
  9.  */  
  10. public void dispatchMessage(Message msg) {  
  11.     if (msg.callback != null) {  
  12.         //这个方法很简单,直接调用msg.callback.run();  
  13.         handleCallback(msg);  
  14.     } else {  
  15.         //如果我们设置了callback会由callback来处理消息  
  16.         if (mCallback != null) {  
  17.             if (mCallback.handleMessage(msg)) {  
  18.                 return;  
  19.             }  
  20.         }  
  21.         //否则消息就由这里来处理,这是我们最常用的处理方式  
  22.         handleMessage(msg);  
  23.     }  
  24. }  
我们再看看msg.callback和mCallback是啥东西

/*package*/ Runnable callback;   

现在已经很明确了,msg.callback是个Runnable,什么时候会设置这个callback:handler.post(runnable),相信大家都常用这个方法吧

[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1.  /** 
  2.  * Callback interface you can use when instantiating a Handler to avoid 
  3.  * having to implement your own subclass of Handler. 
  4.  * 
  5.  * @param msg A {@link android.os.Message Message} object 
  6.  * @return True if no further handling is desired 
  7.  */  
  8. public interface Callback {  
  9.     public boolean handleMessage(Message msg);  
  10. }  
  11.       
  12. final Callback mCallback;  

而mCallback是个接口,可以这样来设置 Handler handler = new Handler(callback),这个callback的意义是什么呢,代码里面的注释已经说了,可以让你不用创建Handler的子类但是还能照样处理消息,恐怕大家常用的方式都是新new一个Handler然后override其handleMessage方法来处理消息吧,从现在开始,我们知道,不创建Handler的子类也可以处理消息。多说一句,为什么创建Handler的子类不好?这是因为,类也是占空间的,一个应用class太多,其占用空间会变大,也就是应用会更耗内存。

HandlerThread简介

[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. @Override  
  2. public void run() {  
  3.     mTid = Process.myTid();  
  4.     Looper.prepare();  
  5.     synchronized (this) {  
  6.         mLooper = Looper.myLooper();  
  7.         notifyAll();  
  8.     }  
  9.     Process.setThreadPriority(mPriority);  
  10.     onLooperPrepared();  
  11.     Looper.loop();  
  12.     mTid = -1;  
  13. }  
HandlerThread继承自Thread,其在run方法内部为自己创建了一个Looper,使用上HandlerThread和普通的Thread不一样,无法执行常见的后台操作,只能用来处理新消息,这是因为Looper.loop()是死循环,你的code根本执行不了,不过貌似你可以把你的code放在super.run()之前执行,但是这好像不是主流玩法,所以不建议这么做。

IntentService简介

[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. public void onCreate() {  
  2.     // TODO: It would be nice to have an option to hold a partial wakelock  
  3.     // during processing, and to have a static startService(Context, Intent)  
  4.     // method that would launch the service & hand off a wakelock.  
  5.   
  6.     super.onCreate();  
  7.     HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");  
  8.     thread.start();  
  9.   
  10.     mServiceLooper = thread.getLooper();  
  11.     mServiceHandler = new ServiceHandler(mServiceLooper);  
  12. }  
IntentService继承自Service,它是一个抽象类,其被创建的时候就new了一个HandlerThread和ServiceHandler,有了它,就可以利用IntentService做一些优先级较高的task,IntentService不会被系统轻易杀掉。使用IntentService也是很简单,首先startService(intent),然后IntentService会把你的intent封装成Message然后通过ServiceHandler进行发送,接着ServiceHandler会调用onHandleIntent(Intent intent)来处理这个Message,onHandleIntent(Intent intent)中的intent就是你startService(intent)中的intent,ok,现在你需要做的是从IntentService派生一个子类并重写onHandleIntent方法,然后你只要针对不同的intent做不同的事情即可,事情完成后IntentService会自动停止。所以,IntentService是除了Thread和AsyncTask外又一执行耗时操作的方式,而且其不容易被系统干掉,建议关键操作采用IntentService。

在子线程创建Handler为什么会报错?

[java] view plaincopy在CODE上查看代码片派生到我的代码片
  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.     //获取当前线程的Looper  
  11.     mLooper = Looper.myLooper();  
  12.     //报错的根本原因是:当前线程没有Looper  
  13.     if (mLooper == null) {  
  14.         throw new RuntimeException(  
  15.             "Can't create handler inside thread that has not called Looper.prepare()");  
  16.     }  
  17.     mQueue = mLooper.mQueue;  
  18.     mCallback = callback;  
  19.     mAsynchronous = async;  
  20. }  
如何避免这种错误:在ui线程使用Handler或者给子线程加上Looper。

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

分享:
开发与运维
使用钉钉扫一扫加入圈子
+ 订阅

集结各类场景实战经验,助你开发运维畅行无忧

其他文章