1 前言
在《深入理解Handler源码框架(Android情报系统)》这篇文章中详细描述了Handler框架的实现原理以及应用场景。本文将在理解Handler架构基础上,定位源码,详细解析Handler在Android系统中的重要作用。
1)Looper.loop()为什么不会引起ANR?
2)Message如何防止OOM和内存抖动?
3)Handler在Android系统中有哪些应用?
深入理解Handler源码框架(Android情报系统)
2 Message享元模式
Message 引起OOM似乎还没有遇到过,但是Message 要占用内存就有可能引起这个问题,平时使用时候注意点就行了。这里主要讲一下Message的享元模式。
享元模式(Flyweight Pattern)主要用于减少创建对象的数量,以减少内存占用和提高性能。这种类型的设计模式属于结构型模式,它提供了减少对象数量从而改善应用所需的对象结构的方式。享元模式尝试重用现有的同类对象,如果未找到匹配的对象,则创建新对象。
在有大量对象时,有可能会造成内存溢出,我们把其中共同的部分抽象出来,如果有相同的业务请求,直接返回在内存中已有的对象,避免重新创建。Message 就是利用了享元模式来实现内存复用,先看一下源码。
当我们调用Message.obtain(),如果消息池sPool不为空,则选择sPool的第一个消息进行复用,否则创建一个新消息。这也是Message防止内存抖动的方法
请注意:sPool里的消息是通过recycleUnchecked()处理后可复用的消息,并不是正在使用的消息,否则直接复用正在使用消息,会引起致命错误。
请拿出小本本记下来:使用Message是使用Message.obtain()函数来创建对象
public final class Message implements Parcelable {
public int what;
public int arg1;
public int arg2;
public Object obj;
Message next;
private static Message sPool;
private static int sPoolSize = 0;
private static final int MAX_POOL_SIZE = 50;
public Message() {
}
/** @hide */
public static final Object sPoolSync = new Object();
/**
* Return a new Message instance from the global pool. Allows us to
* avoid allocating new objects in many cases.
*/
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();
}
/**
* Recycles a Message that may be in-use.
* Used internally by the MessageQueue and Looper when disposing of queued Messages.
*/
@UnsupportedAppUsage
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++;
}
}
}
……
}
3 你可能不知道的那点事
上篇文章中我们讲了Handler主要用于线程间的通信,而我们平时可能主要用于子线程向主线程发送消息从而更新UI。这个实际应用表明了什么?至少说明Activity是工作在主线程的(其实Service也是工作在主线程的),也就说明其实APP能够正常运行,Handler框架在这里起到了很重要的作用。听起来是这么回事,但是源码如何实现的呢?下面我们慢慢道来,首先了解下Android的启动流程,如下图所示,System Server 是启动APP的基础。
System Server 是Zygote进程 fork 的第一个Java 进程。SystemServer是Android系统的核心之一,大部分Android提供的服务都运行在这个进程里,SystemServer中运行的服务总共有80多种。为了防止应用进程对系统造成破坏,Android的应用进程没有权限直接访问设备的底层资源,只能通过SystemService中的代理访问。通过Binder,用户进程在使用SystemService中的服务并没有太多不便变之处。(PS:Binder是Android进程通信的重要机制,以后会进行讲解)
下面源码可以看到SystemServer()的构函数并没有做什么工作,因此还需要看下run()函数做了哪些工作。
/**
* The main entry point from zygote.
*/
public static void main(String[] args) {
new SystemServer().run();
}
public SystemServer() {
// Check for factory test mode.
mFactoryTestMode = FactoryTest.getMode();
mRuntimeRestart = "1".equals(SystemProperties.get("sys.boot_completed"));
mRuntimeStartElapsedTime = SystemClock.elapsedRealtime();
mRuntimeStartUptime = SystemClock.uptimeMillis();
}
System Server启动流程集中于run()
函数,主要做了以下工作:(划重点Looper)
- 配置环境参数,比如系统时间、默认时区、语言、load一些Library等等;
- 启动系统线程,比如 ”UI thread”, “InputReader”, “InputDispatch” 等;
- 启动系统服务:AMS、WMS、PMS等80多种系统服务;
- 初始化Looper:这里初始化主线程使用的Looper。
看一下源码run()函数。大家可以看到熟悉的Looper,Handler框架是从此时就开始应用了。
Looper.prepareMainLooper();
Looper.loop();
private void run() {
try {
……
// Prepare the main looper thread (this thread).
android.os.Process.setThreadPriority(
android.os.Process.THREAD_PRIORITY_FOREGROUND);
android.os.Process.setCanSelfBackground(false);
Looper.prepareMainLooper();
Looper.getMainLooper().setSlowLogThresholdMs(
SLOW_DISPATCH_THRESHOLD_MS, SLOW_DELIVERY_THRESHOLD_MS);
……
// Initialize the system context.
createSystemContext();
// Create the system service manager.
mSystemServiceManager = new SystemServiceManager(mSystemContext);
mSystemServiceManager.setStartInfo(mRuntimeRestart,
mRuntimeStartElapsedTime, mRuntimeStartUptime);
LocalServices.addService(SystemServiceManager.class, mSystemServiceManager);
// Prepare the thread pool for init tasks that can be parallelized
SystemServerInitThreadPool.get();
} finally {
traceEnd(); // InitBeforeStartServices
}
// Start services.
try {
traceBeginAndSlog("StartServices");
startBootstrapServices();
startCoreServices();
startOtherServices();
SystemServerInitThreadPool.shutdown();
} catch (Throwable ex) {
Slog.e("System", "******************************************");
Slog.e("System", "************ Failure starting system services", ex);
throw ex;
} finally {
traceEnd();
}
// Loop forever.
Looper.loop();
throw new RuntimeException("Main thread loop unexpectedly exited");
}
Looper.prepareMainLooper()实现如下,这个函数就是创建主线程的Looper:
/**
* Initialize the current thread as a looper, marking it as an
* application's main looper. The main looper for your application
* is created by the Android environment, so you should never need
* to call this function yourself. See also: {@link #prepare()}
*/
public static void prepareMainLooper() {
prepare(false);
synchronized (Looper.class) {
if (sMainLooper != null) {
throw new IllegalStateException("The main Looper has already been prepared.");
}
sMainLooper = myLooper();
}
}
/**
* Returns the application's main looper, which lives in the main thread of the application.
*/
public static Looper getMainLooper() {
synchronized (Looper.class) {
return sMainLooper;
}
}
3.1 APP 主线程
为了更好的理解APP 主线程和Handler框架的关系,首先让我们先了解一下APP的启动流程如下:
当我们在手机桌面点击应用图标(优酷APP)时 ,Launcher(桌面应用APP)会通过Binder向AMS请求打开优酷APP,AMS 通过socket向Zygote进行发出请求,zygote进程 创建应用程序进程(优酷),优酷APP进行启动就绪后告知AMS,AMS最终通过ActivityThread启动Activity。根据上图所示,APP 主线程主要指ActivityThread ,因此我们先看一下源码是如何实现的。通过源码可以确定ActivityThread 创建的主线程的Looper和Handler。
static volatile Handler sMainThreadHandler; // set once in main()
public static void main(String[] args) {
……
Looper.prepareMainLooper();
……
ActivityThread thread = new ActivityThread();
thread.attach(false, startSeq);
if (sMainThreadHandler == null) {
sMainThreadHandler = thread.getHandler();
}
……
Looper.loop();
}
上面源码中sMainThreadHandler = thread.getHandler();
这个sMainThreadHandler 的实现类就是H()。首先看一下BIND_APPLICATION消息做了什么工作。
class H extends Handler {
……
public void handleMessage(Message msg) {
switch (msg.what) {
case BIND_APPLICATION:
AppBindData data = (AppBindData)msg.obj;
handleBindApplication(data);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
break;
case EXIT_APPLICATION:
if (mInitialApplication != null) {
mInitialApplication.onTerminate();
}
Looper.myLooper().quit();
break;
……
case BIND_SERVICE:
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "serviceBind");
handleBindService((BindServiceData)msg.obj);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
break;
……
case RELAUNCH_ACTIVITY:
handleRelaunchActivityLocally((IBinder) msg.obj);
break;
}
}
}
H()接收到BIND_APPLICATION时调用ActivityThread#handleBindApplication
private void handleBindApplication(AppBindData data) {
// Register the UI Thread as a sensitive thread to the runtime.
VMRuntime.registerSensitiveThread();
……
Application app;
……
try {
……
// If the app is being launched for full backup or restore, bring it up in
// a restricted environment with the base application class.
app = data.info.makeApplication(data.restrictedBackupMode, null);
mInitialApplication = app;
……
}
try {
mInstrumentation.callApplicationOnCreate(app);
} catch (Exception e) {
……
}
} finally {
……
}
}
handleBindApplication中调用Instrumentatio#makeApplication函数,该函数中根据app信息中Application类的路径加载并创建对象,然后调用Instrumentatio#callApplicationOnCreate函数。
callApplicationOnCreate中调用Application对象的onCreate函数。我们在应用开发中常用的Application的onCreate就是这里调用的。
public void callApplicationOnCreate(Application app) {
app.onCreate();
}
现在我们知道了APP启动是这个主线程处理的,那我们熟悉的Activity还没有启动呢!现在让我们来看一下ActivityThread#handleRelaunchActivity函数,这个函数最终会调用ActivityThread#performLaunchActivity
@Override
public void handleRelaunchActivity(ActivityClientRecord tmp,
PendingTransactionActions pendingActions) {
……
handleRelaunchActivityInner(r, configChanges, tmp.pendingResults, tmp.pendingIntents,
pendingActions, tmp.startsNotResumed, tmp.overrideConfig, "handleRelaunchActivity");
……
}
private void handleRelaunchActivityInner(ActivityClientRecord r, int configChanges,
List<ResultInfo> pendingResults, List<ReferrerIntent> pendingIntents,
PendingTransactionActions pendingActions, boolean startsNotResumed,
Configuration overrideConfig, String reason) {
……
handleLaunchActivity(r, pendingActions, customIntent);
}
@Override
public Activity handleLaunchActivity(ActivityClientRecord r,
PendingTransactionActions pendingActions, Intent customIntent) {
……
final Activity a = performLaunchActivity(r, customIntent);
……
return a;
}
/** Core implementation of activity launch. */
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
ActivityInfo aInfo = r.activityInfo;
……
ContextImpl appContext = createBaseContextForActivity(r);
Activity activity = null;
try {
java.lang.ClassLoader cl = appContext.getClassLoader();
activity = mInstrumentation.newActivity(
cl, component.getClassName(), r.intent);
StrictMode.incrementExpectedActivityCount(activity.getClass());
r.intent.setExtrasClassLoader(cl);
r.intent.prepareToEnterProcess();
if (r.state != null) {
r.state.setClassLoader(cl);
}
} catch (Exception e) {
}
try {
Application app = r.packageInfo.makeApplication(false, mInstrumentation);
……
if (activity != null) {
activity.attach(appContext, this, getInstrumentation(), r.token,
r.ident, app, r.intent, r.activityInfo, title, r.parent,
r.embeddedID, r.lastNonConfigurationInstances, config,
r.referrer, r.voiceInteractor, window, r.configCallback);
activity.mStartedActivity = false;
int theme = r.activityInfo.getThemeResource();
if (theme != 0) {
activity.setTheme(theme);
}
activity.mCalled = false;
if (r.isPersistable()) {
mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
} else {
mInstrumentation.callActivityOnCreate(activity, r.state);
}
r.activity = activity;
}
r.setState(ON_CREATE);
mActivities.put(r.token, r);
}
……
return activity;
}
ActivityThread#performLaunchActivity函数中主要做了以下几件事
1)创建Activity对象;
2)初始化activity对象的上下文
3)为当前activity创建窗口。
4)调用Instrumentation#callActivityOnCreate。
/**
* Perform calling of an activity's {@link Activity#onCreate}
* method. The default implementation simply calls through to that method.
*
* @param activity The activity being created.
* @param icicle The previously frozen state (or null) to pass through to onCreate().
*/
public void callActivityOnCreate(Activity activity, Bundle icicle) {
prePerformCreate(activity);
activity.performCreate(icicle);
postPerformCreate(activity);
}
通过上文讲解,可以确定ActivityThread实现了Application和Activity的启动工作。其实除了Application和Activity,ActivityThread还对Service 、Receiver、GC等系统组件都进行了相应的管理,而这些工作都是通过Handler框架实现的。
3.2 ANR 和Looper.loop()的关系
3.2.1什么是ANR
ANR全称:Application Not Responding,也就是应用程序无响应。
3.2.2 产生原因
Android系统中,ActivityManagerService(简称AMS)和WindowManagerService(简称WMS)会检测App的响应时间,如果App在特定时间无法相应屏幕触摸或键盘输入时间,或者特定事件没有处理完毕,就会出现ANR。
以下四个条件都可以造成ANR发生:
- InputDispatching Timeout:5秒内无法响应屏幕触摸事件或键盘输入事件
- BroadcastQueue Timeout :在执行前台广播(BroadcastReceiver)的
onReceive()
函数时10秒没有处理完成,后台为60秒。- Service Timeout :前台服务20秒内,后台服务在200秒内没有执行完毕。
- ContentProvider Timeout :ContentProvider的publish在10s内没进行完。
3.2.3 源码分析
3.2.2描述了四种产生ANR的原因,Looper.loop()即是死循环又是会阻塞,它和ANR的产生有关系吗?其实就相当于你问情报系统会不会引起街头战争一样。唯一的关系是系统通过Handler发送和处理ANR消息。下面通过源码来理解InputDispatching Timeout情况下ANR的产生与处理过程。
ActivityManagerService#inputDispatchingTimedOut函数用于检测触摸或者键盘等输入事件是否超时,如果超时了则会通过mHandler发送ANR消息进行处理。这里的mHandler处于主线程。
mHandler = new MainHandler(mHandlerThread.getLooper());
@Override
public long inputDispatchingTimedOut(int pid, final boolean aboveSystem, String reason) {
……
if (inputDispatchingTimedOut(proc, null, null, aboveSystem, reason)) {
return -1;
}
return timeout;
}
/**
* Handle input dispatching timeouts.
* Returns whether input dispatching should be aborted or not.
*/
public boolean inputDispatchingTimedOut(final ProcessRecord proc,
final ActivityRecord activity, final ActivityRecord parent,
final boolean aboveSystem, String reason) {
if (proc != null) {
……
mHandler.post(new Runnable() {
@Override
public void run() {
mAppErrors.appNotResponding(proc, activity, parent, aboveSystem, annotation);
}
});
}
return true;
}
AppErrors #appNotResponding用于处理上述四种ANR消息,这里可以看到如果是isSilentANR,则直接杀掉APP,如果是需要显示对话框,则会mService.mUiHandler.sendMessage(msg);其中mService就是ActivityManagerService
mUiHandler = mInjector.getUiHandler(this);
final void appNotResponding(ProcessRecord app, ActivityRecord activity,
ActivityRecord parent, boolean aboveSystem, final String annotation) {
ArrayList<Integer> firstPids = new ArrayList<Integer>(5);
SparseArray<Boolean> lastPids = new SparseArray<Boolean>(20);
……
boolean isSilentANR;
synchronized (mService) {
……
synchronized (mService) {
mService.mBatteryStatsService.noteProcessAnr(app.processName, app.uid);
if (isSilentANR) {
app.kill("bg anr", true);
return;
}
// Set the app's notResponding state, and look up the errorReportReceiver
makeAppNotRespondingLocked(app,
activity != null ? activity.shortComponentName : null,
annotation != null ? "ANR " + annotation : "ANR",
info.toString());
// Bring up the infamous App Not Responding dialog
Message msg = Message.obtain();
msg.what = ActivityManagerService.SHOW_NOT_RESPONDING_UI_MSG;
msg.obj = new AppNotRespondingDialog.Data(app, activity, aboveSystem);
mService.mUiHandler.sendMessage(msg);
}
}
综上所述,AMS首先判断输入事件是否超时,如果超时了mHandler发消息统一处理ANR,如果是需要显示ANR对话框,则mUiHandler发消息给自己,然后弹出对话框。由此可见,loop()不会引起ANR。
这里的mHandler和mUiHandler都是运行在主线程,只是处理的具体事务方向不同。我们平时也可以参考这里不要把所有的消息都用一个handler处理。
3.3 消息机制之同步屏障
Message分为3中:普通消息(同步消息)、屏障消息(同步屏障)和异步消息。
我们通常使用的都是普通消息,而屏障消息就是在消息队列中插入一个屏障,在屏障之后的所有普通消息都会被挡着,不能被处理。不过异步消息却例外,屏障不会挡住异步消息,因此可以这样认为:屏障消息就是为了确保异步消息的优先级,设置了屏障后,只能处理其后的异步消息,同步消息会被挡住,除非撤销屏障。
**
Message next() {
// Return here if the message loop has already quit and been disposed.
// This can happen if the application tries to restart a looper after quit
// which is not supported.
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();
}
//1、如果有消息被插入到消息队列或者超时时间到,就被唤醒,否则阻塞在这。
nativePollOnce(ptr, nextPollTimeoutMillis);
synchronized (this) {
// Try to retrieve the next message. Return if found.
final long now = SystemClock.uptimeMillis();
Message prevMsg = null;
Message msg = mMessages;
//2.第一个消息是屏障消息则会跳过同步消息去寻找下一个异步消息。
if (msg != null && msg.target == null) {
// Stalled by a barrier. Find the next asynchronous message in the queue.
do {
prevMsg = msg;
msg = msg.next;
} while (msg != null && !msg.isAsynchronous());
}
//找到异步消息或者同步消息的时候
if (msg != null) {
if (now < msg.when) {
// Next message is not ready. Set a timeout to wake up when it is ready.
nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
} else {
// Got a message.
mBlocked = false;
if (prevMsg != null) {
//3.有屏障消息也就是异步消息处理的时候
//将异步消息从mMessages去除 ,同步屏障依旧存在
prevMsg.next = msg.next;
} else {
//普通消息时候,消息队列头直接指向下一个消息
//也就是mMessages中移除当前普通消息
mMessages = msg.next;
}
msg.next = null;
if (DEBUG) Log.v(TAG, "Returning message: " + msg);
msg.markInUse();
return msg;
}
} else {
// No more messages.
nextPollTimeoutMillis = -1;
}
// Process the quit message now that all pending messages have been handled.
if (mQuitting) {
dispose();
return null;
}
// If first time idle, then get the number of idlers to run.
// Idle handles only run if the queue is empty or if the first message
// in the queue (possibly a barrier) is due to be handled in the future.
if (pendingIdleHandlerCount < 0
&& (mMessages == null || now < mMessages.when)) {
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(TAG, "IdleHandler threw exception", t);
}
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;
}
}
3.3.2 同步屏障应用场景
日常的应用开发中,很少会用到同步屏障。那么,同步屏障在系统源码中有哪些使用场景呢?Android 系统中需要优先处理的消息就可以设置为异步消息,然后应用同步屏障机制。由于 UI 更新相关的消息是优先级最高的,在 View 更新时,draw、requestLayout、invalidate 等很多地方都应用了同步屏障。让我们来看一下源码
ViewRootImpl#scheduleTraversals函数用于更新UI,首先发送了屏障消息。
void scheduleTraversals() {
if (!mTraversalScheduled) {
mTraversalScheduled = true;
//设置同步屏障
mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
mChoreographer.postCallback(
Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
if (!mUnbufferedInputDispatch) {
scheduleConsumeBatchedInput();
}
notifyRendererOfFramePending();
pokeDrawLockIfNeeded();
}
}
Choreographer#postCallback最终向主线程发送了一个异步消息mHandler.sendMessageAtTime(msg, dueTime);
public void postCallback(int callbackType, Runnable action, Object token) {
postCallbackDelayed(callbackType, action, token, 0);
}
public void postCallbackDelayed(int callbackType,
Runnable action, Object token, long delayMillis) {
if (action == null) {
throw new IllegalArgumentException("action must not be null");
}
if (callbackType < 0 || callbackType > CALLBACK_LAST) {
throw new IllegalArgumentException("callbackType is invalid");
}
postCallbackDelayedInternal(callbackType, action, token, delayMillis);
}
private void postCallbackDelayedInternal(int callbackType,
Object action, Object token, long delayMillis) {
if (DEBUG_FRAMES) {
Log.d(TAG, "PostCallback: type=" + callbackType
+ ", action=" + action + ", token=" + token
+ ", delayMillis=" + delayMillis);
}
synchronized (mLock) {
final long now = SystemClock.uptimeMillis();
final long dueTime = now + delayMillis;
mCallbackQueues[callbackType].addCallbackLocked(dueTime, action, token);
if (dueTime <= now) {
scheduleFrameLocked(now);
} else {
Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_CALLBACK, action);
msg.arg1 = callbackType;
msg.setAsynchronous(true);
mHandler.sendMessageAtTime(msg, dueTime);
}
}
}
最后,当需要移除同步屏障的时候需要调用 ViewRootImpl#unscheduleTraversals()
void unscheduleTraversals() {
if (mTraversalScheduled) {
mTraversalScheduled = false;
mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier);
mChoreographer.removeCallbacks(
Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
}
}
3.4 Fragment添加过程
Activity添加Fragment一般通过以下方法来实现,代码很简单。这里我们要通过分析源码来分析一下commit()之后,Avtivity是否立即添加Fragment成功?是与不是对我们开发应用有什么影响?
supportFragmentManager.beginTransaction()
.add(R.id.nav_host_fragment_container,HomeFragment())
.commit()
下面直接看源码FragmentManagerImpl#beginTransaction(),这里只是返回BackStackRecord对象。
public FragmentTransaction beginTransaction() {
return new BackStackRecord(this);
}
FragmentTransaction#add 和FragmentTransaction#replace 最终都是调用FragmentTransaction#doAddOp,因此我们的重点是看doAddOp函数,doAddOp重点是调用了addOp(new Op(opcmd, fragment));这里的cmd是指OP_REPLACE、OP_ADD、OP_ATTACH、OP_DETACH、OP_SHOW、OP_HIDE、OP_REMOVE等
public FragmentTransaction add(@NonNull Fragment fragment, @Nullable String tag) {
doAddOp(0, fragment, tag, OP_ADD);
return this;
}
public FragmentTransaction replace(@IdRes int containerViewId, @NonNull Fragment fragment) {
return replace(containerViewId, fragment, null);
}
public FragmentTransaction replace(@IdRes int containerViewId, @NonNull Fragment fragment,
@Nullable String tag) {
doAddOp(containerViewId, fragment, tag, OP_REPLACE);
return this;
}
void doAddOp(int containerViewId, Fragment fragment, @Nullable String tag, int opcmd) {
……
addOp(new Op(opcmd, fragment));
}
FragmentTransaction#addOp其实就是添加fragment到ArrayList<Op> mOps中。这里我们发现一个问题,这里fragment只是放到了容器里和Activity没有半毛钱关系。
static final class Op {
int mCmd;
Fragment mFragment;
int mEnterAnim;
int mExitAnim;
int mPopEnterAnim;
int mPopExitAnim;
Lifecycle.State mOldMaxState;
Lifecycle.State mCurrentMaxState;
Op() {
}
Op(int cmd, Fragment fragment) {
this.mCmd = cmd;
this.mFragment = fragment;
this.mOldMaxState = Lifecycle.State.RESUMED;
this.mCurrentMaxState = Lifecycle.State.RESUMED;
}
Op(int cmd, @NonNull Fragment fragment, Lifecycle.State state) {
this.mCmd = cmd;
this.mFragment = fragment;
this.mOldMaxState = fragment.mMaxState;
this.mCurrentMaxState = state;
}
}
ArrayList<Op> mOps = new ArrayList<>();
……
ArrayList<Runnable> mCommitRunnables;
void addOp(Op op) {
mOps.add(op);
op.mEnterAnim = mEnterAnim;
op.mExitAnim = mExitAnim;
op.mPopEnterAnim = mPopEnterAnim;
op.mPopExitAnim = mPopExitAnim;
}
我们继续来看BackStackRecord#commit,最后调用了FragmentManagerImpl#enqueueAction
public int commit() {
return commitInternal(false);
}
int commitInternal(boolean allowStateLoss) {
……
mManager.enqueueAction(this, allowStateLoss);
return mIndex;
}
FragmentManagerImpl#enqueueAction调用了FragmentManagerImpl#scheduleCommit();
public void enqueueAction(OpGenerator action, boolean allowStateLoss) {
if (!allowStateLoss) {
checkStateLoss();
}
synchronized (this) {
if (mDestroyed || mHost == null) {
if (allowStateLoss) {
// This FragmentManager isn't attached, so drop the entire transaction.
return;
}
throw new IllegalStateException("Activity has been destroyed");
}
if (mPendingActions == null) {
mPendingActions = new ArrayList<>();
}
mPendingActions.add(action);
scheduleCommit();
}
}
FragmentManagerImpl#scheduleCommit没有直接将Fragment添加到Fragment,而是发送了一个Runnable消息给主线程。
void scheduleCommit() {
synchronized (this) {
boolean postponeReady =
mPostponedTransactions != null && !mPostponedTransactions.isEmpty();
boolean pendingReady = mPendingActions != null && mPendingActions.size() == 1;
if (postponeReady || pendingReady) {
mHost.getHandler().removeCallbacks(mExecCommit);
mHost.getHandler().post(mExecCommit);
updateOnBackPressedCallbackEnabled();
}
}
}
FragmentManagerImpl#mExecCommit调用了doPendingDeferredStart();等函数来创建Fragment。
Runnable mExecCommit = new Runnable() {
@Override
public void run() {
execPendingActions();
}
};
public boolean execPendingActions() {
ensureExecReady(true);
boolean didSomething = false;
while (generateOpsForPendingActions(mTmpRecords, mTmpIsPop)) {
mExecutingActions = true;
try {
removeRedundantOperationsAndExecute(mTmpRecords, mTmpIsPop);
} finally {
cleanupExec();
}
didSomething = true;
}
updateOnBackPressedCallbackEnabled();
doPendingDeferredStart();
burpActive();
return didSomething;
}
FragmentManagerImpl#doPendingDeferredStart 最终会调用FragmentManagerImpl#moveToState,在这里可以看到熟悉的Fragment生命周期了
void moveToState(Fragment f, int newState, int transit, int transitionStyle,
boolean keepActive) {
// Fragments that are not currently added will sit in the onCreate() state.
if ((!f.mAdded || f.mDetached) && newState > Fragment.CREATED) {
newState = Fragment.CREATED;
}
if (f.mRemoving && newState > f.mState) {
if (f.mState == Fragment.INITIALIZING && f.isInBackStack()) {
// Allow the fragment to be created so that it can be saved later.
newState = Fragment.CREATED;
} else {
// While removing a fragment, we can't change it to a higher state.
newState = f.mState;
}
}
// Defer start if requested; don't allow it to move to STARTED or higher
// if it's not already started.
if (f.mDeferStart && f.mState < Fragment.STARTED && newState > Fragment.ACTIVITY_CREATED) {
newState = Fragment.ACTIVITY_CREATED;
}
// Don't allow the Fragment to go above its max lifecycle state
// Ensure that Fragments are capped at CREATED instead of ACTIVITY_CREATED.
if (f.mMaxState == Lifecycle.State.CREATED) {
newState = Math.min(newState, Fragment.CREATED);
} else {
newState = Math.min(newState, f.mMaxState.ordinal());
}
if (f.mState <= newState) {
// For fragments that are created from a layout, when restoring from
// state we don't want to allow them to be created until they are
// being reloaded from the layout.
if (f.mFromLayout && !f.mInLayout) {
return;
}
if (f.getAnimatingAway() != null || f.getAnimator() != null) {
// The fragment is currently being animated... but! Now we
// want to move our state back up. Give up on waiting for the
// animation, move to whatever the final state should be once
// the animation is done, and then we can proceed from there.
f.setAnimatingAway(null);
f.setAnimator(null);
moveToState(f, f.getStateAfterAnimating(), 0, 0, true);
}
switch (f.mState) {
case Fragment.INITIALIZING:
……
// fall through
case Fragment.CREATED:
……
// fall through
case Fragment.ACTIVITY_CREATED:
……
// fall through
case Fragment.STARTED:
……
}
} else if (f.mState > newState) {
switch (f.mState) {
case Fragment.RESUMED:
……
// fall through
case Fragment.STARTED:
……
// fall through
case Fragment.ACTIVITY_CREATED:
……
case Fragment.CREATED:
……
}
}
if (f.mState != newState) {
Log.w(TAG, "moveToState: Fragment state for " + f + " not updated inline; "
+ "expected state " + newState + " found " + f.mState);
f.mState = newState;
}
}
综上所述,从beginTransaction()开始,我们获得了一个BackStackRecord对象,接着执行一系列对Fragment的操作,但最终是通过Handler发送Runnable给主线程来实际管理Fragment和Activity的联系。因为消息队列的执行时间和commit()函数执行完成的时间不是同步的,因此存在commit执行完成,而Fragment还没有创建完成的情况。
也就是说commit之后,val homeFragment=supportFragmentManager.getFragment(Bundle(),"home")不一定能够立即获取到homeFragment。这一点使我们开发过程中需要注意和解决的。
参考文献:
[1] https://www.jianshu.com/p/9ecea420eb52
[2] https://www.jianshu.com/p/db198a499747
[3] https://www.jianshu.com/p/327f583f970b
[4] https://www.jianshu.com/p/388166988cef
[5] https://blog.csdn.net/start_mao/article/details/98963744
[6] https://blog.csdn.net/chengkun_123/article/details/72548373