先写一个简单的子线程调用Handler的方式:
private Handler handler = new Handler(){
@Override
public void handleMessage(@NonNull Message msg) {
super.handleMessage(msg);
mTxt.setText(msg.obj.toString());
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mTxt= findViewById(R.id.txt);
new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
Message message = Message.obtain();
message.obj="123456";
handler.sendMessage(message);
}
});
}}
我们从handler.sendMessage(Message)看起
先总结一下,再详细分析:handler.sendMessage()这个方法只是将message在messageQueue中按执行时间的先后形成一个单链表,只是一个存储message操作:
#Handler
public final boolean sendMessage(@NonNull Message msg) {
return sendMessageDelayed(msg, 0);
}
public final boolean sendMessageDelayed(@NonNull Message msg, long delayMillis) {
if (delayMillis < 0) {
delayMillis = 0;
}
return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}
public boolean sendMessageAtTime(@NonNull Message msg, long uptimeMillis) {
MessageQueue queue = mQueue;//这个Queue在Looper中拿到,后面会讲
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);
}
private boolean enqueueMessage(@NonNull MessageQueue queue, @NonNull Message msg,
long uptimeMillis) {
//可以看到msg.target就是对应的Handler
msg.target = this;
msg.workSourceUid = ThreadLocalWorkSource.getUid();
if (mAsynchronous) {
msg.setAsynchronous(true);
}
//这里开始调用MessageQueue的enqueueMessage方法把message存成单链表
return queue.enqueueMessage(msg, uptimeMillis);
}
我们看看messageQueue的enqueusMessage如何按执行时间存储message成单链表?
#MessageQueue
boolean enqueueMessage(Message msg, long when) {
// 判断有没有 target
if (msg.target == null) {
throw new IllegalArgumentException("Message must have a target.");
}
// 有没有在使用
if (msg.isInUse()) {
throw new IllegalStateException(msg + " This message is already in use.");
}
// 对当前消息队列加锁。
synchronized (this) {
// 判断消息队列是否弃用(通常因为线程已死)
if (mQuitting) {
IllegalStateException e = new IllegalStateException(
msg.target + " sending message to a Handler on a dead thread");
Log.w(TAG, e.getMessage(), e);
msg.recycle();
return false;
}
// 标记消息正在使用中
msg.markInUse();
msg.when = when;
Message p = mMessages; //这个是拿到表头,第一次是null
boolean needWake;
// 第一次添加数据到队列中,或者当前 msg 的时间=0,或者小于表头msg的时间,就将此msg放在前面
if (p == null || when == 0 || when < p.when) {
// New head, wake up the event queue if blocked.
// 把当前 msg 添加到链表的第一个
msg.next = p;
mMessages = msg;
needWake = mBlocked;
} else {
// 不是第一次添加数据,并且 msg 的时间 大于 mMessages(头指针) 的时间
// Inserted within the middle of the queue. Usually we don't have to wake
// up the event queue unless there is a barrier at the head of the queue
// and the message is the earliest asynchronous message in the queue.
needWake = mBlocked && p.target == null && msg.isAsynchronous();
Message prev;
//通过死循环找到自己要插入的位置
for (;;) {
// 不断的遍历找到合适的位置
prev = p;
p = p.next;
//知道找到链表最后一个元素或者时间比它大的时候break,所以也不是死循环
if (p == null || when < p.when) {
break;
}
if (needWake && p.isAsynchronous()) {
needWake = false;
}
}
//跳出循环后,
// 把当前 msg 插入到列表中
msg.next = p; // invariant: p == prev.next
prev.next = msg;
}
// We can assume mPtr != 0 because mQuitting is false.
if (needWake) {
nativeWake(mPtr);
}
}
return true;
}
文字总结:MessageQueue的enqueueMessage()方法就是将发送过来的信息按执行的时间顺序排一个单链表。
Handler的创建
上面的sendMessage()只是存储message,不做任何的操作,我们知道handler主要作用是切换到主线程更新UI,所以我们继续探索handler的创建。
handler的创建有两种,一种是直接在主线程创建,一种是在子线程种创建,但是在子线程中创建,要在前面加Looper.prepare()和在后面添加Looper.loop()。那么为什么主线中就不用呢?我们来分析分析。
//主线程中创建handler
private Handler handler = new Handler(){
@Override
public void handleMessage(@NonNull Message msg) {
super.handleMessage(msg);
mTxt.setText(msg.obj.toString());
}
};
new Thread(new Runnable() {
@Override
public void run() {
Message message = Message.obtain();
message.obj="123456";
handler.sendMessage(message);
}
}).start();
//子线程中创建handler
new Thread(){
@Override
public void run() {
//作用是每一个线程绑定一个Looper
Looper.prepare();
Handler handler = new Handler();
//作用是获得当前线程的Looper,然后拿到这个Looper的MessageQueue,之后遍历MesQueue拿到message,然后调用message的traget就是Handler调用dispatchMessage(方法)。
Looper.loop();
}
}.start();
主线程不用写Looper.perpare、loop代码,是因为在activity启动的时候,ActvityThread类已经实现了Looper的prepare和loop方法
public static void main(String[] args) {
// ... 省略部分代码
Looper.prepareMainLooper();
ActivityThread thread = new ActivityThread();
thread.attach(false);
if (sMainThreadHandler == null) {
sMainThreadHandler = thread.getHandler();
}
Looper.loop();
throw new RuntimeException("Main thread loop unexpectedly exited");
}
现在我们来看看Looper类的prepare()、loop()方法:
#Looper
//创建一个全局唯一ThreadLocal对象
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
public static void prepareMainLooper() {
//调用prepare();
prepare(false);
synchronized (Looper.class) {
if (sMainLooper != null) {
throw new IllegalStateException("The main Looper has already been prepared.");
}
//拿到主线程关联的Looper
sMainLooper = myLooper();
}
}
private static void prepare(boolean quitAllowed) {
//先判断是否能在当前线程拿到Looper,来看是否创建
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
//在当前线程绑定唯一Looper
sThreadLocal.set(new Looper(quitAllowed));
}
#ThreadLocal
public void set(T value) {
//获取当前线程
Thread t = Thread.currentThread();
//拿到当前线程的ThreadLocalMap
ThreadLocalMap map = getMap(t);
if (map != null)
//在map中存储传进来的value,this是调用sThreadLocal
map.set(this, value);
else
createMap(t, value);
}
ThreadLocalMap getMap(Thread t) {
//返回当前线程的ThreadLocalMap
return t.threadLocals;
}
文字总结:Looper.perpare()方法主要是通过ThreadLocal类的set()方法拿到当前线程的一个ThreadLocalmap来存储Looper,以此来达到一个线程绑定一个Looper。
看看Looper.loop()
#Looper
public static void loop() {
//获得当前类的Looper
1. final Looper me = myLooper();
//从Looper中拿到MessageQueue
2.final MessageQueue queue = me.mQueue;
// 一个死循环
for (;;) {
// 不断的从消息队列里面取消息
3. Message msg = queue.next(); // might block
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}
try {
// 通过 target 去 dispatchMessage 而 target 就是绑定的 Handler
4. msg.target.dispatchMessage(msg);
}
// 消息回收循环利用
5. msg.recycleUnchecked();
}
}
//1.获取当前线程的Looper
public static @Nullable Looper myLooper() {
return sThreadLocal.get();
}
#ThreadLocal类
//获取当前线程的Looper
public T get() {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null) {
ThreadLocalMap.Entry e = map.getEntry(this);
if (e != null) {
@SuppressWarnings("unchecked")
T result = (T)e.value;
return result;
}
}
return setInitialValue();
}
2.从Looper获取MessageQuesue
#Looper
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
//3.在MessageQueue遍历单链表拿到所有msg
Message next() {
for (;;) {
synchronized (this) {
// Try to retrieve the next message. Return
final long now = SystemClock.uptimeMillis();
Message prevMsg = null;
Message msg = mMessages;
if (msg != null && msg.target == null) {
// Stalled by a barrier. Find the next
do {
prevMsg = msg;
msg = msg.next;
} while (msg != null && !msg.isAsynchron
}
if (msg != null) {
if (now < msg.when) {
// Next message is not ready. Set a
nextPollTimeoutMillis = (int) Math.m
} else {
// Got a message.
mBlocked = false;
if (prevMsg != null) {
prevMsg.next = msg.next;
} else {
mMessages = msg.next;
}
msg.next = null;
if (DEBUG) Log.v(TAG, "Returning mes
msg.markInUse();
return msg;
}
}
}
4.执行Handler的dispatchMessage()在下面分析:
看看Handler类
public Handler() {
this(null, false);
}
public Handler(@Nullable Callback callback) {
this(callback, false);
}
//可以指定在主线程的Looper,Handler就是在主线程中创建。
public Handler(@NonNull Looper looper) {
this(looper, null, false);
}
public Handler(@NonNull Looper looper, @Nullable Callback callback) {
this(looper, callback, false);
}
public Handler(@Nullable Callback callback, boolean async) {
if (FIND_POTENTIAL_LEAKS) {
final Class<? extends Handler> klass = getClass();
if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&
(klass.getModifiers() & Modifier.STATIC) == 0) {
Log.w(TAG, "The following Handler class should be static or leaks might occur: " +
klass.getCanonicalName());
}
}
//在创建handler之前,就已经有绑定线程的Looper,所以直接拿
mLooper = Looper.myLooper();
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread " + Thread.currentThread()
+ " that has not called Looper.prepare()");
}
mQueue = mLooper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
public Handler(@NonNull Looper looper, @Nullable Callback callback, boolean async) {
mLooper = looper;
mQueue = looper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
public interface Callback {
boolean handleMessage(@NonNull Message msg);
}
public void handleMessage(@NonNull Message msg) {
}
4.执行Handler的dispatchMessage()
public void dispatchMessage(@NonNull Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
//执行Handler接口mCallback的handleMessage方法
if (mCallback.handleMessage(msg)) {
return;
}
}
执行handler的handleMessage方法
handleMessage(msg);
}
}
//执行msg的callback接口实例的run方法
private static void handleCallback(Message message) {
message.callback.run();
}
再看看Message类:
//直接new Message()就是创建一个Message
public Message() {
}
//如果调用的是Message.obtain()则是从线程池中拿一个message返回。
public static Message obtain() {
synchronized (sPoolSync) {
if (sPool != null) {
Message m = sPool;
sPool = m.next;
m.next = null;
m.flags = 0; // clear in-use flag
sPoolSize--;
return m;
}
}
return new Message();
}
//这里传进来一个Handler和Runnable会在distachmessage中执行Runnable。
public static Message obtain(Handler h, Runnable callback) {
Message m = obtain();
m.target = h;
m.callback = callback;
return m;
}
5.执行消息回收
void recycleUnchecked() {
// Mark the message as in use while it remains in the recycled object pool.
// Clear out all other details.
flags = FLAG_IN_USE;
what = 0;
arg1 = 0;
arg2 = 0;
obj = null;
replyTo = null;
sendingUid = UID_NONE;
workSourceUid = UID_NONE;
when = 0;
target = null;
callback = null;
data = null;
synchronized (sPoolSync) {
if (sPoolSize < MAX_POOL_SIZE) {
next = sPool;
sPool = this;
sPoolSize++;
}
}
}
总结:
-
Handler在创建之前会有一个Looper绑定当前的线程,所以在创建Handler的时候就可以拿到Looper和MessageQueue。之后调用loop()方法,拿到当前的线程的looper和messageQueue,然后遍历调用单链表message,并拿到message的handler来执行distachMessage()方法,此方法会先判断msg有没有callback(runnable),然后执行这个runnable的run方法,在判断handler是否有callback接口实例,然后执行里面的handlerMessage方法,并return.最后在执行handler本身的handelMessage()方法。
-
handler的sendMessage(msg),会调用sendMessageDelay()方法确定message发送的时间,然后调用MessageQueue的enqueueMessage()方法,把message按执行时间从小到大排成一个单链表。
Handler是怎么导致内存泄漏?(JVM,垃圾检测)
在java中非静态内部类和匿名内部类都会隐式持有当前类的外部引用,由于Handler是非静态内部类所以其持有当前Activity的隐式引用,如果Handler没有被释放,其所持有的外部引用也就是Activity也不可能被释放,导致activtiy被回收不了。
正确写法:
private static class MyHandler extends Handler{
//持有弱引用HandlerActivity,GC回收时会被回收掉.
private final WeakReference<HandlerActivity> mActivty;
public MyHandler(HandlerActivity activity){
mActivty =new WeakReference<HandlerActivity>(activity);
}
@Override
public void handleMessage(Message msg) {
HandlerActivity activity=mActivty.get();
super.handleMessage(msg);
if(activity!=null){
//执行业务逻辑
}
}
}
为什么强引用会造成内存泄漏?
答:因为强引用造成JVM的垃圾回收器也不能回收。(直接new出来的对象)
补:弱引用Jvm的垃圾回收器可以回收。
如何判断是否被回收?
根搜索法,Root根开始搜索形成一个环。不在环之内就会被收回。JVM与垃圾回收
网友评论