28

谁动了我的Activity?

 4 years ago
source link: http://network.51cto.com/art/202001/609171.htm
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

  ZRVBF3R.jpg!web

前言

不知道大家有没有想过这样一个问题,日常开发中最常用到的通过 startActivity() 唤起一个新的 Activity,所创建的 Activity 对象到底被谁持有引用了?新启动的 Activity 对象在其生命周期中理应是一直被持有引用,不然系统 gc 的时候就会被回收掉,那么其中的引用关系是怎样的呢?

为了搞清楚整个问题,笔者便开始了翻找源码之旅(Android Q),首先得弄清楚 Activity 实例是如何被创建的。

Activity 对象的创建

Activity 的启动是一个跨进程通信的过程,对客户端而言,Activity 的创建会回调到ActivityThread 中的 handleLaunchActivity() 方法:

@Override 
public Activity handleLaunchActivity(ActivityClientRecord r, 
      PendingTransactionActions pendingActions, Intent customIntent){ 
  ··· 
  final Activity a = performLaunchActivity(r, customIntent); 
  ··· 
  return a; 
} 

接着在 performLaunchActivity() 方法里找到了 Acitivity 实例的创建:

private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) { 
    ··· 
    ContextImpl appContext = createBaseContextForActivity(r); 
    Activity activity = null; 
    try { 
      // 注解1:通过 ClassLoader 以及目标 Activity 的类名来创建新的 Activity 实例 
        java.lang.ClassLoader cl = appContext.getClassLoader(); 
      activity = mInstrumentation.newActivity( 
             cl, component.getClassName(), r.intent); 
      ··· 
    } ··· 
} 

Activity 相关的创建工作交由给了 Instrumentation 类处理:

public Activity newActivity(ClassLoader cl, String className, 
      Intent intent) 
      throws InstantiationException, IllegalAccessException, 
      ClassNotFoundException { 
  String pkg = intent != null && intent.getComponent() != null 
              ? intent.getComponent().getPackageName() : null; 
  return getFactory(pkg).instantiateActivity(cl, className, intent); 
} 

最终的创建工作由进一步交由工厂类 AppComponentFactory 实现:

public @NonNull Activity instantiateActivity(@NonNull ClassLoader cl, @NonNull String className, 
      @Nullable Intent intent) 
      throws InstantiationException, IllegalAccessException, ClassNotFoundException { 
  return (Activity) cl.loadClass(className).newInstance(); 
} 

到这里,Activity 对象的创建过程已经很清晰了:通过 ClassLoader 对象以及类名获取到目标 Activity 的 Class 对象, 再调用 Class 对象的 newInstance() 方法创建了实例。

用图形关系表示如下:

2mYVNfr.jpg!web

Activity 对象的引用关系

在清楚了 Activity 对象的创建过程后,让我们回到一开始的 ActivityThread 的performLaunchActivity() 方法中,接着往下看:

private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) { 
  ··· 
   ContextImpl appContext = createBaseContextForActivity(r); 
   Activity activity = null; 
   ··· 
  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, 
             r.assistToken); 
       ··· 
        // 注解2:ActivityClientRecord 对象持有 Activity 实例的引用 
      r.activity = activity; 
     } 
      r.setState(ON_CREATE); 
 
    // 注解3:将 ActivityClientRecord 对象添加到 mActivities 集合中 
    synchronized (mResourcesManager) { 
       mActivities.put(r.token, r); 
    } 
 
  } ··· 
 
  return activity; 
} 

在这里,我们似乎找到了想要的答案:

新建的 Activity 对象会被传进来的 ActivityClientRecord 对象所持有,接着该ActivityClientRecord 对象会被添加到一个名为 mActivities 的集合当中所持有。

ActivityClientRecord 是 ActivityThread 的一个静态内部类,用于记录 Activity 相关的信息。其对象的创建过程可以在 LaunchActivityItem 类(Api 28 之后)中找到:

frameworks/base/core/java/android/app/servertransaction/LaunchActivityItem.java:

@Override 
public void execute(ClientTransactionHandler client, IBinder token, 
        PendingTransactionActions pendingActions){ 
  Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "activityStart"); 
  ActivityClientRecord r = new ActivityClientRecord(token, mIntent, mIdent, mInfo, 
      mOverrideConfig, mCompatInfo, mReferrer, mVoiceInteractor, mState, mPersistentState, 
       mPendingResults, mPendingNewIntents, mIsForward, 
       mProfilerInfo, client, mAssistToken); 
   client.handleLaunchActivity(r, pendingActions, null /* customIntent */); 
   Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER); 
} 

再来看一下这个 mActivities 集合:

frameworks/base/core/java/android/app/ActivityThread.java:

··· 
final ArrayMap<IBinder, ActivityClientRecord> mActivities = new ArrayMap<>(); 
··· 

mActivities 是一个 map 集合,为 ActivityThread 对象的一个成员变量。既然是一个集合,自然也可以在 Activity 销毁方法回调中找到移除集合内元素的操作:

/** Core implementation of activity destroy call. */ 
ActivityClientRecord performDestroyActivity(IBinder token, boolean finishing, 
     int configChanges, boolean getNonConfigInstance, String reason){ 
  ActivityClientRecord r = mActivities.get(token); 
  ··· 
  synchronized (mResourcesManager) { 
    mActivities.remove(token); 
  } 
  StrictMode.decrementExpectedActivityCount(activityClass); 
  return r; 
} 

图形关系表示如下:

6rIjE3J.jpg!web

既然 Activity 的对象是间接被 ActivityThread 对象所持有引用,那么该 ActivityThread 对象理应是单例的形式存在,那么该单例 ActivityThread 对象又是如何被创建以及持有的呢?

ActivityThread 对象的创建

一个新的应用进程创建时,会调用 ActivityThread 的静态主方法 main(),在这里,我们找到了答案:

frameworks/base/core/java/android/app/ActivityThread.java:

··· 
// 注解 4:静态的 ActivityThread 成员变量,用于实现单例 
private static volatile ActivityThread sCurrentActivityThread; 
··· 
 
// 注解 5: ActivityThread 的主方法入口,由 RuntimeInit 调用 
public static void main(String[] args) { 
    ··· 
    Looper.prepareMainLooper(); 
    ··· 
    // 注解 6: 新建一个 ActivityThread 对象 
    ActivityThread thread = new ActivityThread(); 
    thread.attach(false, startSeq); 
    ··· 
    Looper.loop(); 
 
    throw new RuntimeException("Main thread loop unexpectedly exited"); 
} 
··· 
 
private void attach(boolean system, long startSeq) { 
    // 注解 7: ActivityThread 对象由静态成员变量所引用 
    sCurrentActivityThread = this; 
    mSystemThread = system; 
    if (!system) { 
        android.ddm.DdmHandleAppName.setAppName("<pre-initialized>", 
                                                UserHandle.myUserId()); 
        RuntimeInit.setApplicationObject(mAppThread.asBinder()); 
        final IActivityManager mgr = ActivityManager.getService(); 
        try { 
            mgr.attachApplication(mAppThread, startSeq); 
        } catch (RemoteException ex) { 
            throw ex.rethrowFromSystemServer(); 
        } 
        ··· 
    } ··· 
} 

由上面的代码可知,一个新的应用进程创建时,main() 方法里新建一个 ActivityThread 对象赋予给 ActivityThread 类的一个静态成员变量 sCurrentActivityThread,从而形成一个应用进程对应一个 ActivityThread 对象(单例) 的关系。

Mfyume2.jpg!web

总结

每一个新启动的 Activity,其对象实例通过 Class 类的 newInstance 方法创建后,被包裹在一个 ActivityClientRecord 对象中然后添加到进程唯一的 ActivityThread 对象的成员变量 mActivitys 里。换言之,Activity 对象的持有和释放都是由 ActivityThread 来管理的。

最后,笔者想额外重申两点:

源码中,Activity 对象会在多个方法都有传递关系,比较复杂,笔者才疏学浅,可能会漏掉一些别的重要的引用关系没有分析,欢迎大家指正。

上文的 framework 源码用的是截稿前最新的 Android Q 版本,不同的 Android 系统版本这部分相关的源码都会有所改动,不能详细一一对比分析,望大家见谅。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK