Handler
放入消息主要函数
Handler工作流程
1. 子线程调用Handler的boolean sendMessage()方法,最终调用MessageQueue中的boolean enqueueMessage(Message msg, long when) 方法,将msg放入到MessageQueue消息队列中
2. Loop调用public static void loop() 方法,loop()方法会执行一个死循环,不断的调用Message msg = queue.next();方法获取消息,获取到消息后,通过msg.target.dispatchMessage(msg);方法派遣消息,然后dispatchMessage这个方法最终会调用Handler的handlerMessage方法执行我们自己写的逻辑
-
public
final
class Looper {
-
public static void loop() {
-
final Looper me = myLooper();
-
...
-
final MessageQueue queue = me.mQueue;
-
...
-
for (;;) {
-
//相当于获取消息
-
Message msg = queue.next();
// might block
-
...
-
try {
-
//获取消息后,派遣消息
-
msg.target.dispatchMessage(msg);
-
...
-
}
-
...
-
}
-
}
-
}
-
-
public
class Handler {
-
public void dispatchMessage(@NonNull Message msg) {
-
if (msg.callback !=
null) {
-
handleCallback(msg);
-
}
else {
-
if (mCallback !=
null) {
-
if (mCallback.handleMessage(msg)) {
-
return;
-
}
-
}
-
//触发handleMessage处理消息,需要自己实现的方法
-
handleMessage(msg);
-
}
-
}
-
}
一个线程只有一个Loop,原理?
应用开始启动的时候,首先会调用ActivityThread的main方法,main方法会执行一个Looper.prepareMainLooper();初始化Looper
Looper能启动的原因,是因为loop是因为main方法中调用的loop方法,这个方法是一个死循环,这个死循环会不断的轮询msg
1. 如何初始化Looper的?
main方法中调用Looper.prepareMainLooper();
-
public
final
class Looper {
-
private
static Looper sMainLooper;
//主Looper
-
static
final ThreadLocal<Looper> sThreadLocal =
new ThreadLocal<Looper>();
-
-
@Deprecated
-
public static void prepareMainLooper() {
-
prepare(
false);
//向ThreadLocal中初始化一个Looper
-
synchronized (Looper.class) {
-
if (sMainLooper !=
null) {//保证了一个线程只能创建一个
Looper
-
throw new IllegalStateException("The main Looper has already been prepared.");
-
}
-
sMainLooper = myLooper();
//sMainLooper的值从ThreadLocal中获取
-
}
-
}
-
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));
-
}
-
private Looper(boolean quitAllowed) {
-
mQueue =
new MessageQueue(quitAllowed);
-
mThread = Thread.currentThread();
-
}
-
-
public
static
@Nullable
Looper myLooper() {
-
return sThreadLocal.get();
-
}
-
}
2.Handler内存泄漏
1. 原因
Handler在调用sendMessage的时候,这个方法会调用到Handler的enqueueMessage方法,这个方法会将Handler赋值给msg的target
MessageQueue持有msg,这时msg对象会持有Handler的引用,Handler中有 this Activity,那么this Activity中大量内存都不会释放,就会造成大量的内存泄漏
如果是一个延迟消息,那么这个消息会一直在MessageQueue中,msg-Handler-this Activity ,那么内存就一直没办法回收
-
public
class Handler {
-
private boolean enqueueMessage(@NonNull MessageQueue queue, @NonNull Message msg,
-
long uptimeMillis) {
-
msg.target =
this;
-
msg.workSourceUid = ThreadLocalWorkSource.getUid();
-
-
if (mAsynchronous) {
-
msg.setAsynchronous(
true);
-
}
-
return queue.enqueueMessage(msg, uptimeMillis);
-
}
-
}
2. 解决办法
①将handler声明为静态类,②用软引用或弱引用来持有activity
③在destroy方法里面清理handler中的所有Message
3. 为什么主线程可以new handler?如何在子线程中new handler
①为什么主线程中可以new Handler
在应用启动的时候,Looper就被初始化好了,在ActivityThread调用Looper.prepareMainLooper();//初始化Looper,在调用Handler的构造器时,会将Looper传给Handler的Looper,构造器没有添加Looper,默认添加主线程的Looper
new Looper源码
-
public
class Handler {
-
private
static
final
boolean FIND_POTENTIAL_LEAKS =
false;
-
private
static
final String TAG =
"Handler";
-
private
static Handler MAIN_THREAD_HANDLER =
null;
-
...
-
@UnsupportedAppUsage
-
final Looper mLooper;
-
final MessageQueue mQueue;
-
@UnsupportedAppUsage
-
final Callback mCallback;
-
final
boolean mAsynchronous;
-
@UnsupportedAppUsage
-
IMessenger mMessenger;
-
...
-
-
@Deprecated
-
public Handler() {
-
this(
null,
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());
-
}
-
}
-
-
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;
-
}
-
}
②如何在子线程中new Handler
用法
-
HandlerThread handlerThread =
new HandlerThread(
"name");
-
handlerThread.start();
-
Handler handler =
new Handler(handlerThread.getLooper()) {
-
@Override
-
public void handleMessage(@NonNull Message msg) {
-
super.handleMessage(msg);
-
//...自己实现的方法
-
}
-
};
上述代码对应源码解析
-
public
class HandlerThread extends Thread {
-
int mPriority;
-
int mTid = -
1;
-
Looper mLooper;
-
private
@Nullable Handler mHandler;
-
-
public HandlerThread(String name) {
-
super(name);
-
mPriority = Process.THREAD_PRIORITY_DEFAULT;
-
}
-
public HandlerThread(String name, int priority) {
-
super(name);
-
mPriority = priority;
-
}
-
-
protected void onLooperPrepared() {
-
}
-
-
@Override
-
public void run() {
-
mTid = Process.myTid();
-
Looper.prepare();
-
synchronized (
this) {
-
mLooper = Looper.myLooper();
-
notifyAll();
-
}
-
Process.setThreadPriority(mPriority);
-
onLooperPrepared();
-
Looper.loop();
-
mTid = -
1;
-
}
-
-
public Looper getLooper() {
-
if (!isAlive()) {
-
return
null;
-
}
-
-
// If the thread has been started, wait until the looper has been created.
-
synchronized (
this) {
-
while (isAlive() && mLooper ==
null) {
-
try {
-
wait();
-
}
catch (InterruptedException e) {
-
}
-
}
-
}
-
return mLooper;
-
}
-
-
@NonNull
-
public Handler getThreadHandler() {
-
if (mHandler ==
null) {
-
mHandler =
new Handler(getLooper());
-
}
-
return mHandler;
-
}
-
-
public boolean quit() {
-
Looper looper = getLooper();
-
if (looper !=
null) {
-
looper.quit();
-
return
true;
-
}
-
return
false;
-
}
-
-
public boolean quitSafely() {
-
Looper looper = getLooper();
-
if (looper !=
null) {
-
looper.quitSafely();
-
return
true;
-
}
-
return
false;
-
}
-
-
public int getThreadId() {
-
return mTid;
-
}
-
}
-
-
public
class Handler {
-
...
-
public Handler(@NonNull Looper looper) {
-
this(looper,
null,
false);
-
}
-
@UnsupportedAppUsage
-
public Handler(@NonNull Looper looper, @Nullable Callback callback, boolean async) {
-
mLooper = looper;
-
mQueue = looper.mQueue;
-
mCallback = callback;
-
mAsynchronous = async;
-
}
-
...
-
}
4. 子线程中维护的Looper,消息队列中无消息的时候应该怎么处理?有什么作用?主线程呢?
①当消息队列中没有消息的时候,怎么处理
当消息队列中没有消息的时候,在调用next()函数的时候会休眠,应该调用Looper类的quitSafely()函数,让loop()函数退出;
②作用
当loop()函数退出,这时线程就会退出,线程所占用的资源就都会被释放
如果需要重新发送消息,这时重新创建一个子线程对应的Handler就好,重新创建Looper
Looper类对应源代码如下
-
public
final
class Looper {
-
...
-
public static void loop() {
-
final Looper me = myLooper();
-
...
-
for (;;) {
-
//相当于获取消息
-
Message msg = queue.next();
-
if (msg ==
null) {
-
return;
//退出loop()函数
-
}
-
...
-
}
-
}
-
}
-
-
public
final
class MessageQueue {
-
...
-
@UnsupportedAppUsage
-
Message next() {
-
final
long ptr = mPtr;
-
if (ptr ==
0) {
-
return
null;
-
}
-
int pendingIdleHandlerCount = -
1;
// -1 only during first iteration
-
int nextPollTimeoutMillis =
0;
-
for (;;) {
-
if (nextPollTimeoutMillis !=
0) {
-
Binder.flushPendingCommands();
-
}
-
nativePollOnce(ptr, nextPollTimeoutMillis);
//睡眠
-
synchronized (
this) {
-
...
-
if (msg !=
null) {
-
...
-
}
else {
-
nextPollTimeoutMillis = -
1;
-
}
-
if (mQuitting) {
-
dispose();
-
return
null;
//这里会退出死循环,返回null
-
}
-
...
-
}
-
...
-
}
-
...
-
}
-
...
-
}
Looper类的quitSafety()方法对应源码
-
public
final
class Looper {
-
...
-
public void quitSafely() {
-
mQueue.quit(
true);
-
}
-
...
-
}
-
-
public
final
class MessageQueue {
-
...
-
void quit(boolean safe) {
-
if (!mQuitAllowed) {
-
throw
new IllegalStateException(
"Main thread not allowed to quit.");
-
}
-
-
synchronized (
this) {
-
if (mQuitting) {
-
return;
-
}
-
mQuitting =
true;
-
-
if (safe) {
-
removeAllFutureMessagesLocked();
-
}
else {
-
removeAllMessagesLocked();
-
}
-
-
//唤醒因为没有消息而睡眠的线程
-
nativeWake(mPtr);
-
}
-
}
-
...
-
private void removeAllMessagesLocked() {
-
Message p = mMessages;
-
while (p !=
null) {
-
Message n = p.next;
-
p.recycleUnchecked();
-
p = n;
-
}
-
mMessages =
null;
-
}
-
//移除掉所有的Message
-
private void removeAllFutureMessagesLocked() {
-
final
long now = SystemClock.uptimeMillis();
-
Message p = mMessages;
-
if (p !=
null) {
-
if (p.when > now) {
-
removeAllMessagesLocked();
-
}
else {
-
Message n;
-
for (;;) {
-
n = p.next;
-
if (n ==
null) {
-
return;
-
}
-
if (n.when > now) {
-
break;
-
}
-
p = n;
-
}
-
p.next =
null;
-
do {
-
p = n;
-
n = p.next;
-
p.recycleUnchecked();
-
}
while (n !=
null);
-
}
-
}
-
}
-
}
③主线程没有消息怎样处理
会一直休眠,必须不可以退出
5. 既然可以存在多个Handler往MessageQueue中添加数据(发消息时各个Handler可能处于不同线程),如何保证线程安全?取消息呢
①多个Handler发消息,如何保证线程安全?
Looper中的MessageQueue是唯一的,多个Handler中的MessageQueue是来自于Looper中的MessageQueue,线程和Looper一一对应,Looper和MessageQueue一一对应,每一个线程只有一个MessageQueue
而且向MessageQueue中添加消息需要加锁,以此来保证线程安全
对应源码
-
public
final
class Looper {
-
...
-
@UnsupportedAppUsage
-
final MessageQueue mQueue;
-
...
-
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));
-
}
-
...
-
private Looper(boolean quitAllowed) {
-
mQueue =
new MessageQueue(quitAllowed);
-
mThread = Thread.currentThread();
-
}
-
}
-
-
public
class Handler {
-
...
-
@UnsupportedAppUsage
-
final Looper mLooper;
-
final MessageQueue mQueue;
-
@UnsupportedAppUsage
-
final Callback mCallback;
-
final
boolean mAsynchronous;
-
@UnsupportedAppUsage
-
IMessenger mMessenger;
-
...
-
@UnsupportedAppUsage
-
public Handler(@NonNull Looper looper, @Nullable Callback callback, boolean async) {
-
mLooper = looper;
-
mQueue = looper.mQueue;
-
mCallback = callback;
-
mAsynchronous = async;
-
}
-
}
-
-
public
final
class MessageQueue {
-
@UnsupportedAppUsage
-
Message mMessages;
-
...
-
boolean enqueueMessage(Message msg, long when) {
-
...
-
synchronized (
this) {
-
...
-
}
-
...
-
}
-
}
②取消息,如何保证线程安全
取消息的时候,锁的是MessageQueue,以此来保证取消息线程安全
-
public
final
class MessageQueue {
-
@UnsupportedAppUsage
-
Message next() {
-
...
-
for (;;) {
-
...
-
synchronized (
this) {
-
...
-
}
-
}
-
}
-
}
6. 我们使用Message的时候,应该如何创建它?
使用 Message message = Message.obtain(); 创建,这里运用了享元设计模式
-
public
final
class Message implements Parcelable {
-
private
static Message sPool;
-
...
-
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();
-
}
-
...
-
@UnsupportedAppUsage
-
void recycleUnchecked() {
-
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++;
-
}
-
}
-
}
-
}
-
-
public
final
class Looper {
-
public static void loop() {
-
...
-
for (;;) {
-
...
-
msg.recycleUnchecked();
-
...
-
}
-
}
-
}
7.handler的消息阻塞是怎么实现的,为什么主线程不会阻塞
Looper对象调用loop方法的next()方法会阻塞
当一个消息进入队列中的时候,会唤醒阻塞的loop()方法
-
public
final
class MessageQueue {
-
boolean enqueueMessage(Message msg, long when) {
-
if (msg.target ==
null) {
-
throw
new IllegalArgumentException(
"Message must have a target.");
-
}
-
synchronized (
this) {
-
if (msg.isInUse()) {
-
throw
new IllegalStateException(msg +
" This message is already in use.");
-
}
-
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;
-
boolean needWake;
-
//将msg插入到消息队列的头部,并将mMessages指向当前msg
-
if (p ==
null || when ==
0 || when < p.when) {
-
// New head, wake up the event queue if blocked.
-
msg.next = p;
-
mMessages = msg;
-
needWake = mBlocked;
-
}
else {
-
needWake = mBlocked && p.target ==
null && msg.isAsynchronous();
-
Message prev;
-
//队列以时间顺序,从头到尾依次较小,将当前msg插入到合适的位置mMessages
-
for (;;) {
-
prev = p;
-
p = p.next;
-
if (p ==
null || when < p.when) {
-
break;
-
}
-
if (needWake && p.isAsynchronous()) {
-
needWake =
false;
-
}
-
}
-
msg.next = p;
// invariant: p == prev.next
-
prev.next = msg;
-
}
-
if (needWake) {
-
nativeWake(mPtr);
-
}
-
}
-
return
true;
-
}
-
}
转载:https://blog.csdn.net/qq_43204550/article/details/116541351