Android的消息机制主要是指Handler的运行机制,Handler的运行需要底层的MessageQueue和Looper的支撑。对于有开发过Android经验的童鞋都知道,我们一般都是用Handler来更新UI的,更新UI只是handler用法的一部分,下面一起来研究一下handler的神秘面纱。
那么handler是什么?
handler是android给我们用来更新UI的一套机制,也是一套消息处理机制,我们可以通过handler来发送消息,也可以通过它来处理消息
handler主要有以下4种用法
1、sendMessage
2、sendMessageDelayed
3、post(Runnable)
4、postDelayed(Runnable,long)
sendMessage
public class MainActivity extends Activity implements View.OnClickListener {
private Button btn1;
private Button btn2;
private Handler handler = new Handler(){
//这种方式我们在开发中用的比较多,在主线程中去更新UI
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
Log.v("hjz","执行了handleMessage");
}
};
private Handler handler1 = new Handler(new Handler.Callback() {
//创建一个回调Callback,并实现handleMessage
@Override
public boolean handleMessage(Message msg) {
Log.v("hjz","执行了Callback里面的handleMessage");
/**
* 返回false,说明事件继续向下分发,继续调用下面的handleMessage方法
* 返回true,说明自己消耗此事件,到此就结束了,起到拦截作用
* 这种用法似曾相识吧,不错,跟ViewGroup分发事件很类似
*/
return false;
}
}){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
Log.v("hjz","执行了handleMessage");
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
setLister();
}
private void initView() {
btn1 = (Button) findViewById(R.id.btn1);
btn2 = (Button) findViewById(R.id.btn2);
}
private void setLister() {
btn1.setOnClickListener(this);
btn2.setOnClickListener(this);
}
@Override
public void onClick(View v) {
switch (v.getId()){
case R.id.btn1:
new Thread(new Runnable() {
@Override
public void run() {
Message msg = handler.obtainMessage();
msg.what = 1;
handler.sendMessage(msg);
}
}).start();
break;
case R.id.btn2:
new Thread(new Runnable() {
@Override
public void run() {
Message msg = handler1.obtainMessage();
msg.what = 1;
handler1.sendMessage(msg);
}
}).start();
break;
}
}
}
xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
android:orientation="vertical">
<Button
android:id="@+id/btn1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="handler"/>
<Button
android:id="@+id/btn2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="handler1"/>
</LinearLayout>
在Callback中handleMessage返回值为false时,点击btn1 和 btn2打印日志:
07-19 21:16:31.091 9943-9943/com.example.handlerdemo V/hjz: 执行了handleMessage
07-19 21:16:34.341 9943-9943/com.example.handlerdemo V/hjz: 执行了Callback里面的handleMessage
07-19 21:16:34.341 9943-9943/com.example.handlerdemo V/hjz: 执行了handleMessage
在Callback中handleMessage返回值为true时,点击btn1 和 btn2打印日志:
07-19 21:23:18.991 22980-22980/com.example.handlerdemo V/hjz: 执行了handleMessage
07-19 21:23:20.901 22980-22980/com.example.handlerdemo V/hjz: 执行了Callback里面的handleMessage
从打印的日志中也验证了在上面handler1的分析
sendMessageDelayed
case R.id.btn1:
new Thread(new Runnable() {
@Override
public void run() {
Message msg = handler.obtainMessage();
msg.what = 1;
/**
* 第一个参数是一个Message对象
* 第二次参数是延迟时间(单位毫秒)
*/
handler.sendMessageDelayed(msg,1000);
}
}).start();
break;
post(Runnable)
private Handler postHandler = new Handler();
private void setPost(){
new Thread(new Runnable() {
@Override
public void run() {
postHandler.post(new Runnable() {
@Override
public void run() {
Log.v("hjz","postHandler");
}
});
}
}).start();
}
postDelayed(Runnable,long)
private Handler postDelayedHandler = new Handler();
private void setPostDelayed(){
new Thread(new Runnable() {
@Override
public void run() {
postDelayedHandler.postDelayed(new Runnable() {
@Override
public void run() {
Log.v("hjz","postDelayedHandler");
}
},1000);
}
}).start();
}
上面就是handler的4种基本用法,如果这4种都跟进源码里去看,你会发现它们最终都会去调用sendMessageDelayed(getPostMessage(r), delayMillis)这个方法
接着我们一起分析Handler创建,看一下Handler的构造函数
public Handler() {
this(null, false);
}
public Handler(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(); //获取一个Looper对象,那么Looper在什么时候被创建呢?
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread that has not called Looper.prepare()");
}
mQueue = mLooper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
通过源码ActivityThread中main方法
public static void main(String[] args) {
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ActivityThreadMain");
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);
Environment.initForCurrentUser();
// Set the reporter for event logging in libcore
EventLogger.setReporter(new EventLoggingReporter());
AndroidKeyStoreProvider.install();
// Make sure TrustedCertificateStore looks in the right place for CA certificates
final File configDir = Environment.getUserConfigDirectory(UserHandle.myUserId());
TrustedCertificateStore.setDefaultUserDirectory(configDir);
Looper.prepareMainLooper();//这句话创建了一个Looper对象,通过Looper构造方法创建一个MessageQueue对象,并将Looper对象存储在ThreadLocal集合中,供后面在Handler创建时获取对应的Looper对象(需注意拿到对应Looper对象也能拿到Looper对应的MessageQueue对象)
ActivityThread thread = new ActivityThread(); //创建ActivityThread对象
thread.attach(false);
if (sMainThreadHandler == null) {
sMainThreadHandler = thread.getHandler();
}
if (false) {
Looper.myLooper().setMessageLogging(new
LogPrinter(Log.DEBUG, "ActivityThread"));
}
// End of event ActivityThreadMain.
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
Looper.loop();
throw new RuntimeException("Main thread loop unexpectedly exited");
}
一起来看一下上面thread.attach(false)这个方法,源码
private void attach(boolean system) {
sCurrentActivityThread = this;
mSystemThread = system;
if (!system) {
ViewRootImpl.addFirstDrawHandler(new Runnable() {
@Override
public void run() {
ensureJitEnabled();
}
});
android.ddm.DdmHandleAppName.setAppName("<pre-initialized>",
UserHandle.myUserId());
RuntimeInit.setApplicationObject(mAppThread.asBinder());
final IActivityManager mgr = ActivityManagerNative.getDefault();
try {
mgr.attachApplication(mAppThread);
} catch (RemoteException ex) {
// Ignore
}
// Watch for getting close to heap limit.
BinderInternal.addGcWatcher(new Runnable() {
@Override public void run() {
if (!mSomeActivitiesChanged) {
return;
}
Runtime runtime = Runtime.getRuntime();
long dalvikMax = runtime.maxMemory();
long dalvikUsed = runtime.totalMemory() - runtime.freeMemory();
if (dalvikUsed > ((3*dalvikMax)/4)) {
if (DEBUG_MEMORY_TRIM) Slog.d(TAG, "Dalvik max=" + (dalvikMax/1024)
+ " total=" + (runtime.totalMemory()/1024)
+ " used=" + (dalvikUsed/1024));
mSomeActivitiesChanged = false;
try {
mgr.releaseSomeActivities(mAppThread);
} catch (RemoteException e) {
}
}
}
});
} else {
// Don't set application object here -- if the system crashes,
// we can't display an alert, we just want to die die die.
android.ddm.DdmHandleAppName.setAppName("system_process",
UserHandle.myUserId());
try {
mInstrumentation = new Instrumentation();
ContextImpl context = ContextImpl.createAppContext(
this, getSystemContext().mPackageInfo);
mInitialApplication = context.mPackageInfo.makeApplication(true, null);
mInitialApplication.onCreate();
} catch (Exception e) {
throw new RuntimeException(
"Unable to instantiate Application():" + e.toString(), e);
}
}
// add dropbox logging to libcore
DropBox.setReporter(new DropBoxReporter());
//重点来看这里
ViewRootImpl.addConfigCallback(new ComponentCallbacks2() {
@Override
public void onConfigurationChanged(Configuration newConfig) {
synchronized (mResourcesManager) {
// We need to apply this change to the resources
// immediately, because upon returning the view
// hierarchy will be informed about it.
if (mResourcesManager.applyConfigurationToResourcesLocked(newConfig, null)) {
// This actually changed the resources! Tell
// everyone about it.
if (mPendingConfiguration == null ||
mPendingConfiguration.isOtherSeqNewer(newConfig)) {
mPendingConfiguration = newConfig;
//通过一个handler来切换整个activity的生命周期,并实现将handle存储在MessageQueue中
sendMessage(H.CONFIGURATION_CHANGED, newConfig);
}
}
}
}
@Override
public void onLowMemory() {
}
@Override
public void onTrimMemory(int level) {
}
});
}
有兴趣的可以自己研究一下ActivityThread中 private class H extends Handler 这个内部类,里面主要实现了activity相关生命周期切换
通过对源码的分析,我们知道Looper创建是在Acitivity开始启动时就创建了
Looper、MessageQueue和Handler的关系
Looper
1、内部包含一个消息队列(MessageQueue),所有的Handler发送消息都走这个消息队列
2、Looper.Looper方法,就是一个死循环,不断从MessageQueue中取消息,如果有消息就处理消息,没有消息就进入阻塞
MessageQueue
MessageQueue就是一个消息队列,可以添加消息,并可以处理消息
Handler
Handler内部跟Looper进行关联,也就是说在Handler的内部可以找到Looper,找到Looper也就可以找到了MessageQueue;在Handler中发送消息,其实就是向MessageQueue队列中发送消息
总结一下三者的关系:handler负责发送消息,Looper负责接收Handler发送过来的消息,并直接把消息回传给handler本身,MessageQueue就是一个存储消息的容器
先写到这里先,后续会继续去完善