Android系统线程间通信方式之Handler机制

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/litao55555/article/details/82972238

一篇比较好的博客:https://blog.csdn.net/Y_C_C/article/details/80605501

1. Handler的用法分析

public class DownloadActivity extends AppCompatActivity implements View.OnClickListener {
    private TextView downloadTV;
    private Button downloadBtn;
    private Handler handler = new Handler() {					//主线程创建Handler并复写handleMessage
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            downloadTV.setText("下载完成");
        }
    };
		public void onClick(View v) {
        switch (v.getId()){
            case R.id.download_btn:
                new Thread(new Runnable() {						//子线程使用handler执行sendEmptyMessage发送Message(消息为空,可以使用Message.what指定消息类型,Message.obj指定消息主体)
                    @Override
                    public void run() {
                        try {
                            Thread.sleep(5000);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                       handler.sendEmptyMessage(1);
                    }
                }).start();
                break;
        }
    }
}

主线程创建Handler并复写handleMessage
子线程使用handler执行sendEmptyMessage发送Message(消息为空,可以使用Message.what指定消息类型,Message.obj指定消息主体)

由上可知创建实例化对象的两种方式:

方式1:
private Handler handler = new Handler() {					//主线程创建Handler并复写handleMessage
    @Override
    public void handleMessage(Message msg) {
        super.handleMessage(msg);
        downloadTV.setText("下载完成");
    }
};
方式2:
private MyHandler handler = new MyHandler();
public class MyHandler extends Handler {					//主线程创建Handler并复写handleMessage
    @Override
    public void handleMessage(Message msg) {
        super.handleMessage(msg);
        downloadTV.setText("下载完成");
    }
};

Handler用法总结:
首先定义一个继承自Handler的MyHandler并复写handleMessage方法,主线程实例化MyHandler,子线程调用Handler.sendMessage发送消息,回调主线程的Handler.handleMessage

2. Handler的源码分析 — 分析sendEmptyMessage如何回调handleMessage

2.1 Handler发送消息到Message的过程 — sendEmptyMessage

//Handler.java
Handler.sendMessage
	sendMessageDelayed
		sendMessageAtTime
			enqueueMessage
				msg.target = this;				//1. 将Handler保存到Message.target
				queue.enqueueMessage			//queue为MessageQueue
//MessageQueue.java
boolean enqueueMessage(Message msg, long when) {
	/*for循环找到MessageQueue最后一个Message*/
	for (;;) {
	      prev = p;
	      p = p.next;
	      if (p == null || when < p.when) {
	          break;
	      }
	      if (needWake && p.isAsynchronous()) {
	          needWake = false;											//表明MessageQueue不为空
	      }
	  }
	  msg.next = p;		//p为空
	  prev.next = msg;	//prev为最后一个Message,2. 将msg放到MessageQueue的尾部
	}
	if (needWake) {
      nativeWake(mPtr);
  }
}

总结:执行sendMessage时会调用enqueueMessage将消息的发送者Handler保存到Message.target,最后将Message放入MessageQueue的尾部(MessageQueue是单向链表形式存在的)

2.2 Looper取出Message的过程 — handleMessage

好文:https://m.2cto.com/kf/201610/556770.html
Activity主线程对应:ActivityThread.main

public final class ActivityThread {
	public static void main(String[] args) {
		...
    Looper.prepareMainLooper();												//第一步:执行Looper.prepare()创建Looper
    ActivityThread thread = new ActivityThread();
    thread.attach(false);
    if (sMainThreadHandler == null) {
        sMainThreadHandler = thread.getHandler();
    }
    AsyncTask.init();
    Looper.loop();																		//第二步:执行Looper.loop()进入死循环处理消息
  }
}

分析:Looper.prepareMainLooper();

public final class Looper {
  public static void prepareMainLooper() {
    prepare(false);
    synchronized (Looper.class) {
      sMainLooper = myLooper();		//从ThreadLocal中取出创建的Looper
    }
  }
  private static void prepare(boolean quitAllowed) {
    sThreadLocal.set(new Looper(quitAllowed));				//创建一个Looper,保存在ThreadLocal中
  }
  private Looper(boolean quitAllowed) {
      mQueue = new MessageQueue(quitAllowed);					//创建MessageQueue保存到Looper.mQueue
      mThread = Thread.currentThread();
  }
}

分析:Looper.loop();

public final class Looper {
	public static void loop() {
    final Looper me = myLooper();
    final MessageQueue queue = me.mQueue;
    for (;;) {
        Message msg = queue.next(); 				//取出MessageQueue中的Message,如果MessageQueue为空则会阻塞,直到下一次执行sendMessage放入一个Message到MessageQueue中执行nativeWake唤醒
        msg.target.dispatchMessage(msg);		//msg.target即为Message的发送者Handler
    }
  }
}

public class Handler {
    public void dispatchMessage(Message msg) {
        if (msg.callback != null) {
            handleCallback(msg);
        } else {
            if (mCallback != null) {
                if (mCallback.handleMessage(msg)) {
                    return;
                }
            }
            handleMessage(msg);						//回调Handler.handleMessage
        }
    }
}

总结:执行Looper.loop()会循环从MessageQueue取出Message,从Message.target找出Message的发送者Handler,回调Handler.handleMessage处理消息

3. 几个问题

3.1 MessageQueue为空会怎么样

在执行Looper.loop()的过程中会执行Message msg = queue.next();如果MessageQueue为空则会阻塞

public final class MessageQueue {
	Message next() {
		int nextPollTimeoutMillis = 0;
    for (;;) {
        nativePollOnce(ptr, nextPollTimeoutMillis);
        /*取出MessageQueue最后一个消息*/
        if (msg != null && msg.target == null) {
            do {
                prevMsg = msg;
                msg = msg.next;
            } while (msg != null && !msg.isAsynchronous());
        }
        /*如果MessageQueue不为空*/
        if (msg != null) {
            if (now < msg.when) {
                // Next message is not ready.  Set a timeout to wake up when it is ready.
                nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
            } else {
                // Got a message.
                mBlocked = false;
                if (prevMsg != null) {
                    prevMsg.next = msg.next;
                } else {
                    mMessages = msg.next;
                }
                msg.next = null;
                if (false) Log.v("MessageQueue", "Returning message: " + msg);
                return msg;
            }
        /*如果MessageQueue为空*/
        } else {
            // No more messages.
            nextPollTimeoutMillis = -1;
        }
		}
}

当MessageQueue为空时会导致nextPollTimeoutMillis = -1;当下一次for循环执行nativePollOnce时,最后会执行

frameworks\base\core\jni\android_os_MessageQueue.cpp:
void NativeMessageQueue::pollOnce(JNIEnv* env, int timeoutMillis) {
    mInCallback = true;
    mLooper->pollOnce(timeoutMillis);
    mInCallback = false;
    if (mExceptionObj) {
        env->Throw(mExceptionObj);
        env->DeleteLocalRef(mExceptionObj);
        mExceptionObj = NULL;
    }
}
system\core\libutils\Looper.cpp:
int Looper::pollOnce(int timeoutMillis, int* outFd, int* outEvents, void** outData) {
    int result = 0;
    for (;;) {
        result = pollInner(timeoutMillis);
    }
}
int Looper::pollInner(int timeoutMillis) {
		int eventCount = epoll_wait(mEpollFd, eventItems, EPOLL_MAX_EVENTS, timeoutMillis);
}

可以看到这里使用到了Linux的epoll机制
epoll机制:
epoll的作用:用来监测某目录下多个文件是否被修改,若被修改则读取修改的内容
epoll的用法:
a. epoll_create //创建epoll,返回文件句柄fd,以后可以通过文件句柄操作文件
b. 若要检测多个文件,则需要对每个文件,执行epoll_ctl(…,EPOLL_CTL_ADD,…),表示监测此文件
c. epoll_wait //等待某个文件可用,当检测数据,有数据时epoll就会返回;当检测空间,有空间时epoll就会返回
d. epoll_ctl(…,EPOLL_CTL_DEL,…),表示不再想监测某文件

其中在Looper构造函数中执行:

int wakeFds[2];
int result = pipe(wakeFds);
mWakeReadPipeFd = wakeFds[0];
mWakeWritePipeFd = wakeFds[1];
mEpollFd = epoll_create(EPOLL_SIZE_HINT);
result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mWakeReadPipeFd, & eventItem);

表示:MessageQueue为空时,会使用epoll机制休眠监测mWakeReadPipeFd的数据,当文件句柄mWakeReadPipeFd有数据时会被唤醒

在下一次执行sendMessage时会执行nativeWake

//MessageQueue.java
boolean enqueueMessage(Message msg, long when) {
	...
	if (needWake) {
      nativeWake(mPtr);
  }
}

nativeWake最终会JNI调用:
void NativeMessageQueue::wake() {
    mLooper->wake();
}

system/core/libutils/Looper.cpp
void Looper::wake() {
	nWrite = write(mWakeWritePipeFd, "W", 1);		//发送唤醒的信号
}

当向pipe管道写端mWakeWritePipeFd写入唤醒信号1时,读端mWakeReadPipeFd会收到信号1,由epoll机制可知从MessageQueue取Message所在的线程会被唤醒
pipe管道原理:https://blog.csdn.net/centor/article/details/76736601
总结:
当MessageQueue为空时,执行MessageQueue.next取出下一个Message时会休眠,休眠采用epoll机制监听pipe管道读端mWakeReadPipeFd的数据,若无数据则休眠
当下一次执行sendMessage时会执行nativeWake,向pipe管道写端mWakeWritePipeFd写入唤醒信号,此时执行MessageQueue.next的线程被唤醒

3.2 在主线程中不需要执行Looper.prepare()创建Looper,不需要执行Looper.loop()让Looper开始工作,Looper什么时候创建的

Activity里面有一个成员变量ActivityThread,就是Activity的UI主线程
ActivityThread的main方法会执行Looper.prepareMainLooper()创建Looper,执行Looper.loop()让Looper循环工作起来

ActivityThread.main
	Looper.prepareMainLooper();
		sMainLooper = myLooper();
			return sThreadLocal.get();
	Looper.loop();		//Activity主线程执行的最后一行代码

3.3 为什么在主线程执行死循环Looper.loop()时不卡顿

参考:https://blog.csdn.net/u012045061/article/details/50631581
执行Looper.loop();后主线程结束,在生命周期内写的方法都是在这个死循环内的,所以不会卡死

3.4 子线程创建的Looper和主线程创建的Looper冲突吗

不冲突,每个线程对应一个Looper,每个Looper对应一个MessageQueue,每个MessageQueue有多个Message,每个Message最多指定一个Handler处理消息

Handler原理总结:

a. 一个线程对应一个Looper,一个Looper对应一个MessageQueue,一个MessageQueue有多个Message,每个Message最多指定一个Handler处理消息
b. 线程1执行Handler.sendMessage()方法,会将线程2创建的Handler保存到Message.target中,并将Message放入MessageQueue
//Looper.prepare()方法,会new Looper()并将new MessageQueue()保存到Looper.mQueue中
c. Looper.loop()方法,不断从MessageQueue中取出Message,交给Message.target(即Handler)的handleMessage处理,从而回调线程2创建的Handler复写的handleMessage方法
//若MessageQueue为空则会使用epoll机制休眠,直到下一个Message放入MessageQueue执行nativeWake()被唤醒

猜你喜欢

转载自blog.csdn.net/litao55555/article/details/82972238
今日推荐