91超碰碰碰碰久久久久久综合_超碰av人澡人澡人澡人澡人掠_国产黄大片在线观看画质优化_txt小说免费全本

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

怎么在Android中動態替換Application

發布時間:2021-05-14 17:24:36 來源:億速云 閱讀:356 作者:Leah 欄目:移動開發

這期內容當中小編將會給大家帶來有關怎么在Android中動態替換Application,文章內容豐富且以專業的角度為大家分析和敘述,閱讀完這篇文章希望大家可以有所收獲。

在替換Application的過程中,應該注意以下幾點:

  1. 創建RealApplication,維護正常的生命周期,并進行回調。

  2. 對應用中屏蔽掉ProxyApplication,對于下層無感知。在Activity等調用getApplicationContext之后,應該返回RealApplication。

  3. ContentProvider創建時機比較特殊,在滿足正常的初始化順序之后,也要屏蔽ProxyApplication的存在。

方案實現

在AndroidManifest.xml文件中替換Application為ProxyApplication,可以使用自動化方式,或者打包方式,關于實現的具體細節此處不討論。這里主要敘述創建RealApplication的過程。替換了ProxyApplication之后,對于系統而言ProxyApplication就是應用初始化的入口,所有的回調均是在ProxyApplication中發生。我們主要關注attachBaseContext和onCreate的回調。

創建RealApplication

創建RealApplication,我們可以使用反射的方式newInstance創建對象,然后執行回調attachBaseContext。但是對于不同的系統版本,內部執行的細節可能不同,或者有其它相關邏輯的處理,所以我們采用另一種方式進行處理。首先看系統源碼的如何實現,這里選擇8.0.0的系統源碼進行分析,其它版本去http://androidxref.com/查看。

我們知道,Android初始化是從android.app.ActivityThread開始的,所以從ActivityThread開始查看,ActivityThread中存在靜態方法currentActivityThread返回實例。可以參考系統的ActivityThread類:

public static ActivityThread currentActivityThread() {
  return sCurrentActivityThread;
 }

ActivityThread內部存在成員變量AppBindData mBoundApplication。AppBindData是一個靜態內部類,其中包含成員變量LoadedApk info。查看android.app.LoadedApk源代碼,發現創建Application的makeApplication方法。

 public Application makeApplication(boolean forceDefaultAppClass,
   Instrumentation instrumentation) {
  if (mApplication != null) {
   return mApplication;
  }

  Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "makeApplication");

  Application app = null;

  String appClass = mApplicationInfo.className;
  if (forceDefaultAppClass || (appClass == null)) {
   appClass = "android.app.Application";
  }

  try {
   java.lang.ClassLoader cl = getClassLoader();
   if (!mPackageName.equals("android")) {
    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER,
      "initializeJavaContextClassLoader");
    initializeJavaContextClassLoader();
    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
   }
   ContextImpl appContext = ContextImpl.createAppContext(mActivityThread, this);
   app = mActivityThread.mInstrumentation.newApplication(
     cl, appClass, appContext);
   appContext.setOuterContext(app);
  } catch (Exception e) {
   if (!mActivityThread.mInstrumentation.onException(app, e)) {
    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
    throw new RuntimeException(
     "Unable to instantiate application " + appClass
     + ": " + e.toString(), e);
   }
  }
  mActivityThread.mAllApplications.add(app);
  mApplication = app;

  if (instrumentation != null) {
   try {
    instrumentation.callApplicationOnCreate(app);
   } catch (Exception e) {
    if (!instrumentation.onException(app, e)) {
     Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
     throw new RuntimeException(
      "Unable to create application " + app.getClass().getName()
      + ": " + e.toString(), e);
    }
   }
  }

  // Rewrite the R 'constants' for all library apks.
  SparseArray<String> packageIdentifiers = getAssets(mActivityThread)
    .getAssignedPackageIdentifiers();
  final int N = packageIdentifiers.size();
  for (int i = 0; i < N; i++) {
   final int id = packageIdentifiers.keyAt(i);
   if (id == 0x01 || id == 0x7f) {
    continue;
   }

   rewriteRValues(getClassLoader(), packageIdentifiers.valueAt(i), id);
  }

  Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);

  return app;
 }

通過上面的代碼可以發現,如果緩存mApplication不為空,則直接返回。mApplication為空時,則創建RealApplication,并且執行相關的回調,創建RealApplication時,類名是從mApplicationInfo.className中獲取。

添加新創建RealApplication到mActivityThread.mAllApplications。賦值給緩存mApplication。所以我們在調用makeApplication之前,需要將mApplication置為null,否則會直接返回ProxyApplication的實例。

首先,通過android.app.ActivityThread中靜態方法獲取ActivityThread實例,然后,通過ActivityThread實例,獲得LoadedApk實例。為了使makeApplication順利執行,先設置mApplication為null。移除mAllApplications中ProxyApplication的實例。LoadedApk中mApplicationInfo和AppBindData中appInfo都是ApplicationInfo類型,需要分別替換className字段的值為RealApplication的實際類全名。

怎么在Android中動態替換Application 

之后,反射調用系統的makeApplication.

怎么在Android中動態替換Application

這樣,在ProxyApplication.attachBaseContext中,調用makeApplication創建RealApplication,并且內部已經完成對于RealApplication的attchBaseContext的回調。在ProxyApplication.onCreate中只需要回調RealApplication實例的onCreate,即可完成對于RealApplication的創建,已經內部替換以及正常的生命周期的回調。而且在Activity中調用getApplicationContext返回的值,實際上也是LoadedApk中mApplication的值,同時也保證對于Activity等地方屏蔽ProxyApplication的目的。

ContentProvider中getContext

Application和ContentProvider的初始化順序是:Application.attachBaseContext -> ContentProvider.onCreate -> Application.onCreate。ContentProvider中也存在getContext方法,看ContentProvider的源代碼實現:

怎么在Android中動態替換Application

其中mContext被賦值的有兩個地方,一個在構造方法,一個是attchInfo的時候。繼續追蹤源代碼中使用構造方法初始化,或者調用attachInfo的地方,結果在android.app.ActivityThread中找到installProvider方法中存在著調用關系。

怎么在Android中動態替換Application 

可以看出,使用反射調用ContentProvider無參構造方法創建實例,然后調用了attachInfo,傳遞的Context為installProvider方法中的參數,而installProvider的參數是在installContentProviders內部在初始化中傳遞的。

怎么在Android中動態替換Application

可以明確,installContentProviders中調用installProvider時傳遞的Context,也是由方法調用時傳遞的參數。繼續向上追蹤發現ActivityThread.handleBindApplication在初始化ContentProvider時調用了installContentProviders,最終通過attachInfo設置給ContentProvider中的Context的實際類型是Application。

在App初始化時,系統調用makeApplication創建了ProxyApplication實例,同時回調了attachBaseContext(Context context)。所以這個方法返回的就是App初始化時ProxyApplication,調用發生ProxyApplication.attachBaseContext之后,ProxyApplication.onCreate之前。所以我們沒有辦法在這兩個方法生命周期內進行替換為RealApplication。

Android是什么

Android是一種基于Linux內核的自由及開放源代碼的操作系統,主要使用于移動設備,如智能手機和平板電腦,由美國Google公司和開放手機聯盟領導及開發。

上述就是小編為大家分享的怎么在Android中動態替換Application了,如果剛好有類似的疑惑,不妨參照上述分析進行理解。如果想知道更多相關知識,歡迎關注億速云行業資訊頻道。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

威宁| 江北区| 临洮县| 昌图县| 利津县| 吉林省| 肇州县| 冕宁县| 中方县| 驻马店市| 瑞金市| 江陵县| 调兵山市| 双峰县| 霍林郭勒市| 三江| 怀化市| 清苑县| 垦利县| 天峻县| 泰宁县| 乡城县| 曲松县| 靖州| 安图县| 夏津县| 定陶县| 宁阳县| 上思县| 内乡县| 梧州市| 高邮市| 亳州市| 延寿县| 商都县| 阿克陶县| 云南省| 隆昌县| 沙洋县| 枣庄市| 大宁县|