标签:
从一接触Android开始,就听说了消息机制,那时候对消息机制的理解也只是看看别人博客,了解一些概念和相关的类而已,并没有深入的去了解和探究。直到最近,重新过了一遍消息机制和相关源码,这里做简单的整理和记录,毕竟好记性不如烂笔头。如果有什么问题,还请大家指出。(注:源码版本 4.0)
基础示例:
public class MainActivity extends AppCompatActivity {
public static final String TAG = MainActivity.class.getSimpleName();
//报内存泄露警告的handler
private Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {//处理发送过来的消息
if (msg.arg1 == 1) {
Log.i(TAG, "1消息已被接收");
}
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
sendMessageToHandler();
}
/**
* 向Handler发送消息
*/
private void sendMessageToHandler() {
new Thread(new Runnable() {
@Override
public void run() {
Message message = Message.obtain();
message.arg1 = 1;
handler.sendMessage(message);
}
}).start();
}
}
使用过Handler的朋友都知道,上面的使用方式Android Lint会给出内存泄露警告,具体内容如下:
This Handler class should be static or leaks might occur (anonymous android.os.Handler) less...
Since this Handler is declared as an inner class, it may prevent the outer class from being garbage collected. If the Handler is using a Looper or MessageQueue for a thread other than the main thread, then there is no issue. If the Handler is using the Looper or MessageQueue of the main thread, you need to fix your Handler declaration, as follows: Declare the Handler as a static class; In the outer class, instantiate a WeakReference to the outer class and pass this object to your Handler when you instantiate the Handler; Make all references to members of the outer class using the WeakReference object.
Handler
该类负责Message
的发送和处理
发送消息的核心源码如下:
public boolean sendMessageAtTime(Message msg, long uptimeMillis)
{
boolean sent = false;
MessageQueue queue = mQueue;
if (queue != null) {
msg.target = this;
//关键代码。发送消息的实质,其实是向消息队列中插入一条消息
sent = queue.enqueueMessage(msg, uptimeMillis);
}
else {
RuntimeException e = new RuntimeException(
this + " sendMessageAtTime() called with no mQueue");
Log.w("Looper", e.getMessage(), e);
}
return sent;
}
处理消息的核心源码如下:
//该方法对Message进行了分发处理
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
...
private final void handleCallback(Message message) {
message.callback.run();
}
...
public interface Callback {
public boolean handleMessage(Message msg);
}
...
public void handleMessage(Message msg) {
}
Message
该类负责Message对象的创建和释放
Message的创建obtain()
//该方法有很多的重载方法,都是在此方法的基础上扩展而来,其他方法不再列举
public static Message obtain() {
synchronized (sPoolSync) {
if (sPool != null) {
Message m = sPool;
sPool = m.next;
m.next = null;
sPoolSize--;
return m;
}
}
return new Message();
}
Message的释放
public void recycle() {
clearForRecycle();
synchronized (sPoolSync) {
if (sPoolSize < MAX_POOL_SIZE) {
next = sPool;
sPool = this;
sPoolSize++;
}
}
}
void clearForRecycle() {
flags = 0;
what = 0;
arg1 = 0;
arg2 = 0;
obj = null;
replyTo = null;
when = 0;
target = null;
callback = null;
data = null;
}
ThreadLocal
ThreadLocal的作用是提供线程内的局部变量,这种变量在线程的生命周期内起作用,减少同一个线程内多个函数或者组件之间一些公共变量的传递的复杂度。这里给出参考博客链接:http://qifuguang.me/2015/09/02/[Java%E5%B9%B6%E5%8F%91%E5%8C%85%E5%AD%A6%E4%B9%A0%E4%B8%83]%E8%A7%A3%E5%AF%86ThreadLocal/
ThreadLocal中的set()
//获取当前线程的Values对象,如果当前线程的Values不存在,则重新实例化一个
//否则将value添加到table数组中
public void set(T value) {
Thread currentThread = Thread.currentThread();
Values values = values(currentThread);
if (values == null) {
values = initializeValues(currentThread);
}
values.put(this, value);
}
ThreadLocal中的get()
public T get() {
// Optimized for the fast path.
Thread currentThread = Thread.currentThread();
Values values = values(currentThread);
if (values != null) {
Object[] table = values.table;
int index = hash & values.mask;
if (this.reference == table[index]) {
//Values中的put()方法是将索引和值在相邻位置进行存储的,具体实现查看put()源码
return (T) table[index + 1];
}
} else {
values = initializeValues(currentThread);
}
return (T) values.getAfterMiss(this);
}
Values 中的put()
void put(ThreadLocal<?> key, Object value) {
cleanUp();
// Keep track of first tombstone. That‘s where we want to go back
// and add an entry if necessary.
int firstTombstone = -1;
for (int index = key.hash & mask;; index = next(index)) {
Object k = table[index];
if (k == key.reference) {
// Replace existing entry.
table[index + 1] = value;
return;
}
if (k == null) {
if (firstTombstone == -1) {
// Fill in null slot.
table[index] = key.reference;
table[index + 1] = value;
size++;
return;
}
//数组中相邻的位置存储索引和值
// Go back and replace first tombstone.
table[firstTombstone] = key.reference;
table[firstTombstone + 1] = value;
tombstones--;
size++;
return;
}
// Remember first tombstone.
if (firstTombstone == -1 && k == TOMBSTONE) {
firstTombstone = index;
}
}
}
Looper
该类是一个循环控制器
Looper的准备
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
...
private Looper() {
mQueue = new MessageQueue();//创建消息队列对象
mRun = true;
mThread = Thread.currentThread();//获取当前线程
}
...
public static void prepare() {
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
//将当前线程的Looper对象传递给ThreadLocal
sThreadLocal.set(new Looper());
}
Looper循环控制器的启动
public static Looper myLooper() {
//从ThreadLocal中获取Looper对象,这里可看出他们操作的是同一个ThreadLocal对象
return sThreadLocal.get();
}
...
public static void loop() {
//启动loop方法必须有looper对象,否则会报下面的异常
Looper me = myLooper();
if (me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn‘t called on this thread.");
}
//获取Looper中的消息队列
MessageQueue queue = me.mQueue;
// Make sure the identity of this thread is that of the local process,
// and keep track of what that identity token actually is.
Binder.clearCallingIdentity();
final long ident = Binder.clearCallingIdentity();
//无限循环,从MessageQueue中不断的获取Message
while (true) {
Message msg = queue.next(); // might block
if (msg != null) {
//唯一退出循环的条件
if (msg.target == null) {
// No target is a magic identifier for the quit message.
return;
}
long wallStart = 0;
long threadStart = 0;
// This must be in a local variable, in case a UI event sets the logger
Printer logging = me.mLogging;
if (logging != null) {
logging.println(">>>>> Dispatching to " + msg.target + " " +
msg.callback + ": " + msg.what);
wallStart = SystemClock.currentTimeMicro();
threadStart = SystemClock.currentThreadTimeMicro();
}
//分发Message到Handler中进行处理
msg.target.dispatchMessage(msg);
if (logging != null) {
long wallTime = SystemClock.currentTimeMicro() - wallStart;
long threadTime = SystemClock.currentThreadTimeMicro() - threadStart;
logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
if (logging instanceof Profiler) {
((Profiler) logging).profile(msg, wallStart, wallTime,
threadStart, threadTime);
}
}
// Make sure that during the course of dispatching the
// identity of the thread wasn‘t corrupted.
final long newIdent = Binder.clearCallingIdentity();
if (ident != newIdent) {
Log.wtf(TAG, "Thread identity changed from 0x"
+ Long.toHexString(ident) + " to 0x"
+ Long.toHexString(newIdent) + " while dispatching to "
+ msg.target.getClass().getName() + " "
+ msg.callback + " what=" + msg.what);
}
//释放Message
msg.recycle();
}
}
}
退出Looper quite()
//向MessageQueue中插入一个target为null的Message,会退出Looper
//退出loop()的唯一条件 if (msg.target == null){return;}
public void quit() {
Message msg = Message.obtain();
// NOTE: By enqueueing directly into the message queue, the
// message is left with a null target. This is how we know it is
// a quit message.
mQueue.enqueueMessage(msg, 0);
}
MessageQueue
该类负责Message的插入,取出,以及移除
插入Message方法enqueueMessage()源码
//Handler中的sendMessage()方法最终会调用此方法,所以说发送消息其实是向MessageQueue中插入一条消息
final boolean enqueueMessage(Message msg, long when) {
if (msg.isInUse()) {
throw new AndroidRuntimeException(msg
+ " This message is already in use.");
}
if (msg.target == null && !mQuitAllowed) {
throw new RuntimeException("Main thread not allowed to quit");
}
final boolean needWake;
synchronized (this) {
if (mQuiting) {
RuntimeException e = new RuntimeException(
msg.target + " sending message to a Handler on a dead thread");
Log.w("MessageQueue", e.getMessage(), e);
return false;
} else if (msg.target == null) {
mQuiting = true;
}
msg.when = when;
//Log.d("MessageQueue", "Enqueing: " + msg);
Message p = mMessages;
if (p == null || when == 0 || when < p.when) {
msg.next = p;
mMessages = msg;
needWake = mBlocked; // new head, might need to wake up
} else {
Message prev = null;
while (p != null && p.when <= when) {
prev = p;
p = p.next;
}
msg.next = prev.next;
prev.next = msg;
needWake = false; // still waiting on head, no need to wake up
}
}
if (needWake) {
nativeWake(mPtr);
}
return true;
}
取出和移除
final Message next() {
int pendingIdleHandlerCount = -1; // -1 only during first iteration
int nextPollTimeoutMillis = 0;
//又一个无限循环
for (;;) {
if (nextPollTimeoutMillis != 0) {
Binder.flushPendingCommands();
}
nativePollOnce(mPtr, nextPollTimeoutMillis);
//当有Message时,取出Message,否则该方法将会一直堵塞
synchronized (this) {
// Try to retrieve the next message. Return if found.
final long now = SystemClock.uptimeMillis();
final Message msg = mMessages;
if (msg != null) {
final long when = msg.when;
if (now >= when) {
mBlocked = false;
mMessages = msg.next;
msg.next = null;
if (false) Log.v("MessageQueue", "Returning message: " + msg);
msg.markInUse();
return msg;
} else {
nextPollTimeoutMillis = (int) Math.min(when - now, Integer.MAX_VALUE);
}
} else {
nextPollTimeoutMillis = -1;
}
// If first time, then get the number of idlers to run.
if (pendingIdleHandlerCount < 0) {
pendingIdleHandlerCount = mIdleHandlers.size();
}
if (pendingIdleHandlerCount == 0) {
// No idle handlers to run. Loop and wait some more.
mBlocked = true;
continue;
}
if (mPendingIdleHandlers == null) {
mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCount, 4)];
}
mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers);
}
// Run the idle handlers.
// We only ever reach this code block during the first iteration.
for (int i = 0; i < pendingIdleHandlerCount; i++) {
final IdleHandler idler = mPendingIdleHandlers[i];
mPendingIdleHandlers[i] = null; // release the reference to the handler
boolean keep = false;
try {
keep = idler.queueIdle();
} catch (Throwable t) {
Log.wtf("MessageQueue", "IdleHandler threw exception", t);
}
//当有Message时,返回Message后,删除Message
if (!keep) {
synchronized (this) {
mIdleHandlers.remove(idler);
}
}
}
// Reset the idle handler count to 0 so we do not run them again.
pendingIdleHandlerCount = 0;
// While calling an idle handler, a new message could have been delivered
// so go back and look again for a pending message without waiting.
nextPollTimeoutMillis = 0;
}
}
首先,使用Handler必须保证其所在的线程中具有Looper对象,但是有的朋友会说,我在Activity中并没有创建Looper对象,但是我也可以使用Handler啊。其实Activity所在的主线程(ActivityThread)也就是UI线程是特殊的线程,该线程在创建的时候就已经创建了Looper对象,看源码
ActivityThread的main()方法
public static void main(String[] args) {
SamplingProfilerIntegration.start();
// CloseGuard defaults to true and can be quite spammy. We
// disable it here, but selectively enable it later (via
// StrictMode) on debug builds, but using DropBox, not logs.
CloseGuard.setEnabled(false);
Process.setArgV0("<pre-initialized>");
Looper.prepareMainLooper();//准备工作
if (sMainThreadHandler == null) {
sMainThreadHandler = new Handler();
}
ActivityThread thread = new ActivityThread();
thread.attach(false);
if (false) {
Looper.myLooper().setMessageLogging(new
LogPrinter(Log.DEBUG, "ActivityThread"));
}
Looper.loop();//启动循环控制器
throw new RuntimeException("Main thread loop unexpectedly exited");
}
Looper中的prepareMainLooper()方法是专门用与主线程的
public static void prepareMainLooper() {
prepare();//最后还是调用了prepare(),从而创建了Looper对象,并设置给了ThreadLocal
setMainLooper(myLooper());
myLooper().mQueue.mQuitAllowed = false;
}
private synchronized static void setMainLooper(Looper looper) {
mMainLooper = looper;
}
以上工作准备完成后,Looper,ThreadLocal已经创建完毕,并且建立了关联关系。接下来创建Handler对象,获取Message对象(Message.obtain()),使用Handler中的sendMessage()方法向MessageQueue中插入Message(enqueueMessage()),这时候Looper对象中处于堵塞状态的next()方法检测到Message后,将其从MessageQueue中取出,传递给Handler的dispatchMessage()方法后,清除该Message(msg.recycle();),最后dispatchMessage()方法,将Message分发到run()方法或者handlerMessage(Message msg)中进行处理。
最后来一张消息机制的示意图
内存泄露会在什么情况下产生呢?这里给出一个示例
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mHandler.postDelayed(new Runnable() {
@Override
public void run() {
Log.i(TAG,"post delay");
}
},10*60*1000);
finish();
}
示例中,当Activity被finish()掉,Message 将存在于消息队列中长达10分钟的时间才会被执行到。这个Message持有一个对Handler的引用,Handler也会持有一个对于外部类(SampleActivity)的隐式引用,这些引用在Message被执行前将一直保持,这样会保证Activity的上下文不被垃圾回收机制回收,同时也会泄露应用程序的资源(views and resources)。
Handler的警告提示中已经说明,因为静态匿名内部类不会持有外部类的隐式引用,因此我们创建一个静态的Handler子类。如果需要调用外部类(例如:Activity)的方法,就让Handler持有一个Activity的弱引用(WeakReference),这样就不会泄露Activity的上下文了。示例:
public class MainActivity extends AppCompatActivity {
public static final String TAG = MainActivity.class.getSimpleName();
private MyHandler myHandler = new MyHandler(this);
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
sendMessageToHandler();
}
/**
* 向Handler发送消息
*/
private void sendMessageToHandler() {
new Thread(new Runnable() {
@Override
public void run() {
Message message = Message.obtain();
message.arg2 = 2;
myHandler.sendMessage(message);
}
}).start();
}
/**
* MyHandler的处理方法
*
* @param msg 消息
*/
private void handlerMessage(Message msg) {
if (msg.arg2 == 2) {
Log.i(MainActivity.TAG, "2已接收到消息");
}
}
private static class MyHandler extends Handler {
//弱引用,避免Handler持有外部类的引用,即MainActivity的引用,
// 这样会导致MainActivity的上下文及资源无法被回收,引发内存泄露的情况发生
private WeakReference<MainActivity> weakReference;
public MyHandler(MainActivity mainActivity) {
weakReference = new WeakReference<>(mainActivity);
}
@Override
public void handleMessage(Message msg) {
MainActivity mainActivity = weakReference.get();
mainActivity.handlerMessage(msg);
}
}
}
参考:
http://qifuguang.me/2015/09/02/[Java%E5%B9%B6%E5%8F%91%E5%8C%85%E5%AD%A6%E4%B9%A0%E4%B8%83]%E8%A7%A3%E5%AF%86ThreadLocal/ http://developer.51cto.com/art/201204/332155.htm
标签:
原文地址:http://blog.csdn.net/a254830856/article/details/51199588