面试 - handle使用及原理(1)
Handler定义以及作用
handler
是andorid
的一套消息传递机制,用于跨线程通信,主要用于工作线程与主线程间的交互。andorid
的UI
操作需要在主线程上操作,一般耗时都放到其它的子线程下操作。耗时操作返回的结果在UI
线程先的展示需要跨线程通信 这个时候就可以使用handler
来通信了
Handler使用流程图
Handler原理图
几个关键的类:
-
Message:数据单元,
MessageQueue
的一个个数据。 -
Looper:
MessageQueue
跟Handler
的通信中间人。两个作用:不断循环从MessageQueue
中取出Message
,将Message
发送给对应的Handler
。 -
MessageQueue:数据结构(先进先出)存储
Message
-
Handler:线程间通行的中间人,
Message
信息的逻辑处理者,将Message
发送到MessageQueue
,处理Looper
发送过来的Message
基础使用
public class MainActivity extends AppCompatActivity {
//关键代码1
private static class MyHander extends Handler{
private final WeakReference<MainActivity> mActivity ;
public MyHander(MainActivity activity){
mActivity = new WeakReference<MainActivity>(activity);
}
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
if (null != mActivity.get()) {
switch (msg.what){
case 1:
//关键代码3
mActivity.get().toNotify();
break;
default:
break;
}
}
}
}
MyHander myHander;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//关键代码2
myHander = new MyHander(this);
Button button = findViewById(R.id.btn);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//关键代码3
Message message = myHander.obtainMessage();
message.what = 1;
message.obj = getString(R.string.text);
myHander.sendMessageDelayed(message,5000);
}
});
}
public void toNotify() {
....逻辑操作
}
}
关键代码1: 先定义MyHanlder
继承Handler
关键代码2:新建myHandler
对象,将MainActivity
传入MyHandler
,MyHandler
弱引用MainActivity
,所以MyHandler # handleMessage()
处理需要if (null != mActivity.get())
做一下对象null判断
关键代码3:构建Message
,可以从缓存池中获取,也可以直接自己new Message
,并发送myHander.sendMessageDelayed(message,5000)
其实平时的写法有些同学是在
MainActivity
中直接定义匿名内部类MyHander
那种做法会调来内存泄漏的风险。因为匿名内部类引用着外部类,导致外部类被挟持,这就有可能导致内存泄漏了。
上面这种用法可以避免handler
挟持了外部类MainActivity
的引用
handler发送数据的两种不同的形式
-
sendxxx()
的方法
看一下源码几种方法的区别:
public final boolean sendMessage(Message msg)
{
return sendMessageDelayed(msg, 0);
}
public final boolean sendEmptyMessage(int what)
{
return sendEmptyMessageDelayed(what, 0);
}
public final boolean sendEmptyMessageDelayed(int what, long delayMillis) {
Message msg = Message.obtain();
msg.what = what;
return sendMessageDelayed(msg, delayMillis);
}
public final boolean sendEmptyMessageAtTime(int what, long uptimeMillis) {
Message msg = Message.obtain();
msg.what = what;
return sendMessageAtTime(msg, uptimeMillis);
}
public final boolean sendMessageDelayed(Message msg, long delayMillis)
{
if (delayMillis < 0) {
delayMillis = 0;
}
return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}
public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
MessageQueue queue = mQueue;
if (queue == null) {
RuntimeException e = new RuntimeException(
this + " sendMessageAtTime() called with no mQueue");
Log.w("Looper", e.getMessage(), e);
return false;
}
return enqueueMessage(queue, msg, uptimeMillis);
}
从上面可以看到,方法的最后都是调用到了sendMessageAtTime(Message msg, long uptimeMillis)
,看了一下上面的方法大家都懂各个方法的区别了。
主要是要注意一下使用的时候sendMessageAtTime(Message msg, long uptimeMillis)
跟sendMessageDelayed(Message msg, long delayMillis)
的区别,一个是当前的时刻,一个 当前的时刻+delayMillis
2.postxxx()
的方法
看一下源码几种方法的区别:
public final boolean post(Runnable r)
{
return sendMessageDelayed(getPostMessage(r), 0);
}
public final boolean postAtFrontOfQueue(Runnable r)
{
return sendMessageAtFrontOfQueue(getPostMessage(r));
}
public final boolean postDelayed(Runnable r, long delayMillis)
{
return sendMessageDelayed(getPostMessage(r), delayMillis);
}
public final boolean postDelayed(Runnable r, Object token, long delayMillis)
{
return sendMessageDelayed(getPostMessage(r, token), delayMillis);
}
public final boolean postAtTime(Runnable r, long uptimeMillis)
{
return sendMessageAtTime(getPostMessage(r), uptimeMillis);
}
public final boolean postAtTime(Runnable r, Object token, long uptimeMillis)
{
return sendMessageAtTime(getPostMessage(r, token), uptimeMillis);
}
对应使用了sendxxx
的方法,主要看一下getPostMessage()
这个方法
这里有个坑 要记得看一下:
Handler.post(Runnable)
其实就是生成一个what = 0
的Message
如果你先调用Handler.post(Runnable)
再调用发送任何一条what = 0
的Message
会导致原来的被remove
掉,从而看到一脸懵逼 具体的等下代码解析再看一下https://www.cnblogs.com/coding-way/p/5110125.html
源码解析
从主线程开始入手吧~
####ActivityThread
public final class ActivityThread extends ClientTransactionHandler {
final H mH = new H();
final Handler getHandler() {
return mH;
}
class H extends Handler {
......
public void handleMessage(Message msg) {
if (DEBUG_MESSAGES) Slog.v(TAG, ">>> handling: " + codeToString(msg.what));
switch (msg.what) {
case BIND_APPLICATION:
......
break;
}
case EXIT_APPLICATION:
......
break;
}
}
public static void main(String[] args) {
Process.setArgV0("<pre-initialized>");
......
//关键代码1
Looper.prepareMainLooper();
......
ActivityThread thread = new ActivityThread();
thread.attach(false, startSeq);
//关键代码2
if (sMainThreadHandler == null) {
sMainThreadHandler = thread.getHandler();
}
.......
//关键代码3
Looper.loop();
}
关键代码1:先调用Looper.prepareMainLooper()
关键代码2:获取sMainThreadHandler
,获取ActivityThread
的mH
对象,mH
对象实现了handleMessage(Message msg)
方法
关键代码3:Looper.loop()
开启循环
我们先看一下关键代码1 看一下Looper
这个类以及对象的调用方法()
Looper(部分源码)
public final class Looper {
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
private static Looper sMainLooper; // guarded by Looper.class
final MessageQueue mQueue;
final Thread mThread;
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
public static @Nullable Looper myLooper() {
return sThreadLocal.get();
}
public static void prepareMainLooper() {
prepare(false);
synchronized (Looper.class) {
if (sMainLooper != null) {
throw new IllegalStateException("The main Looper has already been prepared.");
}
sMainLooper = myLooper();
}
}
public static void prepare() {
prepare(true);
}
private static void prepare(boolean quitAllowed) {
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
sThreadLocal.set(new Looper(quitAllowed));
}
public static void loop() {
final Looper me = myLooper();
if (me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
final MessageQueue queue = me.mQueue;
......
for (;;) {
Message msg = queue.next(); // might block
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}
......
try {
msg.target.dispatchMessage(msg);
}
......
}
}
}
Looper.prepareMainLooper()
:这个方法的相关调用流prepare(false)
->sThreadLocal.set(new Looper(quitAllowed));
->myLooper()
->sThreadLocal.get()
这里产生了一个looper
并设置到sThreadLocal
中,获取的时候也是从sThreadLocal
中去获取。而且在prepare(false)
中做判断,如果已经存在就不能再调用该方法,也就是说 一个线程中只能存在一个Looper
,且一个Looper
只能拥有一个mQueue
,则说明Looper
跟MessageQueue
是一对一关系Looper.loop()
:这个方法的相关调用流程me
->me.mQueue
->(for (;;)-> queue.next()->msg.target.dispatchMessage(msg)
)
开启死循环不断的轮训MessageQueue
,msg.target
其实返回的是Handler
,使用Handler
发送数据
(关于ThreadLocal相关的,后面再加以补充)
接下来我们看一下Handler
发送数据dispatchMessage
这个方法
Handler (部分源码)
public class Handler {
public Handler(Looper looper, Callback callback, boolean async) {
mLooper = looper;
mQueue = looper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
public interface Callback {
public boolean handleMessage(Message msg);
}
public void handleMessage(Message msg) {
}
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
private static void handleCallback(Message message) {
message.callback.run();
}
public final boolean post(Runnable r)
{
return sendMessageDelayed(getPostMessage(r), 0);
}
public final boolean sendEmptyMessageDelayed(int what, long delayMillis) {
Message msg = Message.obtain();
msg.what = what;
return sendMessageDelayed(msg, delayMillis);
}
private static Message getPostMessage(Runnable r) {
Message m = Message.obtain();
m.callback = r;
return m;
}
private static Message getPostMessage(Runnable r, Object token) {
Message m = Message.obtain();
m.obj = token;
m.callback = r;
return m;
}
}
这里你可以看到
dispatchMessage(Message msg)
中有三种不同的调用
handleCallback(msg)
:这个是处理Handler.postxxx(Runnable r,xx)
发送的信息处理,最终回到用到r
的run
方法里面做逻辑处理handleMessage(msg)
跟mCallback.handleMessage(msg)
:都是用于处理Handler.sendxxx()
发送的信息,不同点在于,实例化Handler
有没有传入mCallback
对象,有的话则在mCallback.handleMessage
进行逻辑处理,没有的话则在handleMessage
进行逻辑处理
看一下Message
这个类的一些属性
Message(部分源码)
public final class Message implements Parcelable {
public int what;
public int arg1;
public Object obj;
long when;
Bundle data;
Handler target;
Runnable callback;
Message next;
}
Message
拥有Handler
对象,所以来自不同的Handler
对象发送的Message
信息将自己也传入进来。
###总结
Handler并将本身传入到Messag中并发送到MessageQueue中,Looper开启轮训不断轮训MessageQueue的消息,将Message取出并使用Handler对象回调其本身的方法去进行逻辑操作。
Looper: 在第一次实例化的时候存到ThreadLocal变量中,并且获取的时候有则返回无则创建,所以一个线程只存在一个Looper。
MessageQueue: 是在Looper的构造函数中创建的,并且作为其成员变量,一个线程有且只有一个MessageQueue
Handler: 可以创建多个,线程中并没有限制其创建的个数,并且在Message中挟持着对应的Handler,所以不同的Message会对应交由自己的挟持的Handaler进行逻辑的操作
Handler各种面试题一览
(大家可以参考一下网友的这篇文章)https://blog.csdn.net/feather_wch/article/details/81136078
上一篇: Android的Handler机制原理
下一篇: Android异步消息处理和应用