yujun411522的专栏

本文出自:【yujun411522的博客】

关于android内消息通信和handler的知识在之前的Handler中已经简要介绍过了,这里介绍在native层的实现机制。

相信大家都知道一个标准的Looper线程的写法:

public MyLooperThread extends Thread{private Handler mHandler;public void run(){//在实例化handler之前一定要先调用Looper.prepare()方法//1 Looper.prepare()方法Looper.prepare();//2 实例化handler//mHandler = new Handler(){public void handleMessage(Message msg){//处理msg操作}};//3 Looper.loop()不断从消息队列中取出来信息Looper.loop();}}

典型的三个操作:

1 调用Looper.prepare方法,进入准备阶段。

2 实例化Handler对象。

3 调用Looper.loop方法,进入循环。

注意,三者的顺序不能有错,下面会介绍

7.1 Looper.prepare进入准备阶段

先看Looper类中prepare方法:

public class Looper { // sThreadLocal.get() will return null unless you've called prepare().static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();final MessageQueue mQueue;//内部维护一个消息队列final Thread mThread;//对应的线程volatile boolean mRun;//运行状态private static Looper mMainLooper = null; // guarded by Looper.class,主线程的Looperpublic static void prepare() {if (sThreadLocal.get() != null) {//之前已经设置过Looper对象了,报异常,说明只能设置一次throw new RuntimeException("Only one Looper may be created per thread");}sThreadLocal.set(new Looper());//为sThreadLocal变量设置Looper,这个Looper必须有,且只能有一个,不能重复设置}}

sThreadLocal是一个用来存储当前线程状态的一个成员变量,存储范围为线程内部。在调用prepare方法时,如果之前线程设置Looper对象就报异常,如果没有设置Looper就为sThreadLocal设置一个new Looper()对象,再看Looper的构造函数:

private Looper() {//私有方法,不允许外部访问它mQueue = new MessageQueue();//构造一个MessageQueue对象,Looper中维护了一个消息队列,这一点很重要mRun = true;//设置mRun为truemThread = Thread.currentThread();//mThread设置为当前线程}

其中重要的就是MessageQueue消息队列的创建,看它的构造方法:

MessageQueue() {nativeInit();//这是一个本地方法}nativeInit是一个本地方法,对应的实现方法在android_os_MessageQueue.cpp文件中

先看NativeMessageQueue类:

class NativeMessageQueue {public:NativeMessageQueue();~NativeMessageQueue();inline sp<Looper> getLooper() { return mLooper; }//返回该Looper变量,这个Looper类是native中的Looper类,不是java层的void pollOnce(int timeoutMillis);//后面会分析,进行询问void wake();//后面会分析,向管道写入"W"private:sp<Looper> mLooper;//维护一个Native层的Looper变量};

再来看MessageQueue中nativeInit方法中的的实现android_os_MessageQueue_nativeInit函数:

static void android_os_MessageQueue_nativeInit(JNIEnv* env, jobject obj) {//obj为java层的MessageQueue对象//1 创建一个NativeMessageQueue对象,这个是native层的NativeMessageQueue* nativeMessageQueue = new NativeMessageQueue();if (! nativeMessageQueue) {jniThrowRuntimeException(env, "Unable to allocate native queue");return;}//2 将NativeMessageQueue和 java层的MessageQueue对象 关联起来,实际就是讲nativeMessagQueue对象保存到MessageQueue中的mPtr变量中android_os_MessageQueue_setNativeMessageQueue(env, obj, nativeMessageQueue);}

两个主要工作: 1 创建NativeMessageQueue对象 ;2 将java层的MessageQueue对象和NativeMessageQueue关联起来

7.1.1 创建NativeMessageQueue对象

看NativeMessageQueue的构造函数:

NativeMessageQueue::NativeMessageQueue() {mLooper = Looper::getForThread();//调用getForThread,看返回值是否为nullif (mLooper == NULL) {//如果返回值为null,则创建一个Looper并设置mLooper = new Looper(false);Looper::setForThread(mLooper);//}}

先看Looper::getForThread函数是否为null,如果为null,构造一个Looper对象,并调用setForThread设置为线程唯一的一个Looper,这一部分工作和java层中的Looper.prepare()方法相同。那么再看一下native层的Looper对象是如何实例化的,看它的构造函数:

Looper::Looper(bool allowNonCallbacks) :mAllowNonCallbacks(allowNonCallbacks), mSendingMessage(false),mResponseIndex(0), mNextMessageUptime(LLONG_MAX) {int wakeFds[2];//创建一个管道,读写端分别为wakeFds[0]和wakeFds[1]int result = pipe(wakeFds);mWakeReadPipeFd = wakeFds[0];//读端mWakeWritePipeFd = wakeFds[1];//写端result = fcntl(mWakeReadPipeFd, F_SETFL, O_NONBLOCK);//设置非阻塞方式result = fcntl(mWakeWritePipeFd, F_SETFL, O_NONBLOCK);//设置非阻塞方式mEpollFd = epoll_create(EPOLL_SIZE_HINT);//监听管道struct epoll_event eventItem;memset(& eventItem, 0, sizeof(epoll_event)); // zero out unused members of data field unioneventItem.events = EPOLLIN;eventItem.data.fd = mWakeReadPipeFd;result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mWakeReadPipeFd, & eventItem);//只监听mWakeReadPipeFd ,也就是读端}

7.1.2 将java层的MessageQueue对象和NativeMessageQueue关联起来

关联工作由android_os_MessageQueue_setNativeMessageQueue函数来完成:

勇气执着的背负起那厚重的行囊,奔向远方。

yujun411522的专栏

相关文章:

你感兴趣的文章:

标签云: