1.消息队列(Handler, MessageQueue,Message,Looper)
1.1Handler的作用:
(1)android中最常见的,刷新ui,这里基本就是在主线程创建handler (2)不用刷新ui,仅仅是传递处理消息,包括线程间传递消息和线程内部传递消息,这里基本就是在子线程创建handler。如下:
new Thread(new Runnable() {
@Override public void run() {
Looper.prepare();
handler2 = new Handler(){
@Override public void handleMessage(Message msg) {
if (msg.arg1==1) {
Toast.makeText(MainActivity.this,"hanlder2",Toast.LENGTH_SHORT).show();
}
System.out.println("handler2========="+Thread.currentThread().getName());
super.handleMessage(msg);
}
};
Message message = handler2.obtainMessage();
message.arg1 = 1;
handler2.sendMessage(message);
Looper.loop();
}
}
).start();
1.2Looper.perpare()分析
在子线程中创handler必须调用先调用Looper.perpare(),再创建handler最后调用Looper.loop()。深入到源码就可以看见prepare方法中其实就是在子线程中创建了一个Looper放到threadlocal中,这里也间接说明了一个线程最多只能创建一个looper对象,一个handler也有且只有一个looper和它相对应的。
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));
}
2 Handler消息处理机制的工作流程:
handler把消息Messagr发送到消息队列MessageQueue里,然后Looper通过死循环不断的从消息队列中获取到Message,由于Message的target是handler,于是就转到handleMessage方法中去处理。从源码角度来分析这个过程:
2.1从activity启动入口ActivityThread.Main()开始分析
main方法中会调用Looper.prepareMainLooper方法来创建Looper对象,Looper的构造函数中又会创建MessageQueue对象。
public static void main(String[] args) {
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ActivityThreadMain");
SamplingProfilerIntegration.start();
Looper.prepareMainLooper();
ActivityThread thread = new ActivityThread();
thread.attach(false);
if (sMainThreadHandler == null) {
sMainThreadHandler = thread.getHandler();
}
if (false) {
Looper.myLooper().setMessageLogging(new LogPrinter(Log.DEBUG, "ActivityThread"));
}
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
Looper.loop();
throw new RuntimeException("Main thread loop unexpectedly exited");
}
prepareMainLooper()源码如下,在prepare中可以看见是创建了Looper对象。
public static void prepareMainLooper() {
prepare(false);
synchronized (Looper.class) {
if (sMainLooper != null) {
throw new IllegalStateException("The main Looper has already been prepared.");
}
sMainLooper = myLooper();
}
}
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));
}
来看Looper的构造方法,里面创建了消息队列MesageQueue对象。
private Looper(Boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
2.2Mesage消息的发送过程。
public final Boolean sendMessage(Message msg)
{
return sendMessageDelayed(msg, 0);
}
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);
}
private Boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
msg.target = this;
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}
可以看到sendMessage最后是走到queue.enqueueMessage(msg, uptimeMillis)方法到消息队列排队,queue就是looper的构造函数中创建的messagequeue,上面的message的target其实就是handler,到此handler就把mesage发送到messagequeue了。
2.3消息在消息队列中的排队过程
msg.markInUse();
msg.when = when;
Message p = mMessages;
Boolean needWake;
if (p == null || when == 0 || when < p.when) {
msg.next = p;
mMessages = msg;
needWake = mBlocked;
} else {
needWake = mBlocked && p.target == null && msg.isAsynchronous();
Message prev;
for (;;) {
prev = p;
p = p.next;
if (p == null || when < p.when) {
break;
}
if (needWake && p.isAsynchronous()) {
needWake = false;
}
}
msg.next = p;
prev.next = msg;
}
从上面可以看到mesagequeue内部其实就是个单链表,用mMessage表示当前待处理的消息。(1)应用首次调用sendMessage时,当前待处理的消息为null,则p为空,则会执行;(2)当前传入msg的when小于当前待处理msg的when,及当前传入的消息要先于当前待处理mMessages得到处理,所以传入的msg赋值为mMessages,而下一个待处理消息才为原先的待处理消息。(3)当消息的时间(when)比当前待处理的消息的时间(when)大,这个时候就会移动链表,根据时间先后,插入到合适的位置
2.4Looper.loop()从消息队列中取消息并处理的过程
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();
msg.target.dispatchMessage(msg);
}
}
可以很清楚的看到最后是走到了handleMessage方法的。
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
2.5其他子线程更新ui的方法底层实现,其实都是调用Handler.senMessage实现的
- (1).Handler的post()方法
public final boolean post(Runnable r)
{
return sendMessageDelayed(getPostMessage(r), 0);
}
- (2)View的post()方法
public Boolean post(Runnable action) {
final AttachInfo attachInfo = mAttachInfo;
if (attachInfo != null) {
return attachInfo.mHandler.post(action);
ViewRootImpl.getRunQueue().post(action);
return true;
}
}
- (3)Activity的runOnUiThread()方法
public final void runOnUiThread(Runnable action) {
if (Thread.currentThread() != mUiThread) {
mHandler.post(action);
} else {
action.run();
}
}
3.Activity一些比较难的知识点
3.1setResult和finish的顺序关系
Activity-A中用startActivityForResult()方法启动了Activity-B,并且在B中通过setResult()方法给A返回值,这个过程的生命周期执行过程为:
B---onBackPressed
B---finish
B---onPause
A---onActivityResult
A---onRestart
A---onStart
A---onResume
B---onStop
B---onDestroy
3.2onSaveInstanceState()和onRestoreInstanceState()
正常情况下是不会触发这两个方法,当activity被系统破坏例如屏幕旋转时会触发。onSaveInstanceState(),系统在用户离开Activity时调用它保存数据到bundle对象,然后,如果系统在被销毁之后必须重新创建Activity实例,它会将相同的Bundle对象传递给您的Activity的onRestoreInstanceState()方法以及您的onCreate() 方法。
static final String STATE_SCORE = "playerScore";
static final String STATE_LEVEL = "playerLevel";
...
@Override
public void onSaveInstanceState(Bundle savedInstanceState) {
// 保存用户自定义的状态
savedInstanceState.putInt(STATE_SCORE, mCurrentScore);
savedInstanceState.putInt(STATE_LEVEL, mCurrentLevel);
// 调用父类交给系统处理,这样系统能保存视图层次结构状态
super.onSaveInstanceState(savedInstanceState);
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); // 记得总是调用父类
// 检查是否正在重新创建一个以前销毁的实例
if (savedInstanceState != null) {
// 从已保存状态恢复成员的值
mCurrentScore = savedInstanceState.getInt(STATE_SCORE);
mCurrentLevel = savedInstanceState.getInt(STATE_LEVEL);
} else {
// 可能初始化一个新实例的默认值的成员
}
...
}
public void onRestoreInstanceState(Bundle savedInstanceState) {
// 总是调用超类,以便它可以恢复视图层次超级
super.onRestoreInstanceState(savedInstanceState);
// 从已保存的实例中恢复状态成员
mCurrentScore = savedInstanceState.getInt(STATE_SCORE);
m
3.3onNewIntent()和onConfigurationChanged()
onConfigurationChanged:当系统的配置信息发生改变时,系统会调用此方法。注意,只有在配置文件AndroidManifest中处理了configChanges属性对应的设备配置,该方法才会被调用。如果发生设备配置与在配置文件中设置的不一致,则Activity会被销毁并使用新的配置重建。
横竖屏幕切换的配置:android:configChanges="orientation|screenSize"
onNewIntent的触发时机:第一种情况:activity launchMode为singleTask或者singleInstance的时候,activity第二次被启动的时候会调用onNewIntent。第二种情况:activity launchMode为singleTop singleTask singleInstance的时候,也就是栈顶复用acitivity再次被启动时会调用。其实说白了就是在栈中只有一个activity实例的情况下,再次进入activity会执行onNewIntent方法。