日韩无码专区无码一级三级片|91人人爱网站中日韩无码电影|厨房大战丰满熟妇|AV高清无码在线免费观看|另类AV日韩少妇熟女|中文日本大黄一级黄色片|色情在线视频免费|亚洲成人特黄a片|黄片wwwav色图欧美|欧亚乱色一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時(shí)間:8:30-17:00
你可能遇到了下面的問(wèn)題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營(yíng)銷解決方案
深入理解AndroidInstantRun運(yùn)行機(jī)制

Instant Run

創(chuàng)新互聯(lián)專注于企業(yè)營(yíng)銷型網(wǎng)站建設(shè)、網(wǎng)站重做改版、瓊結(jié)網(wǎng)站定制設(shè)計(jì)、自適應(yīng)品牌網(wǎng)站建設(shè)、H5頁(yè)面制作購(gòu)物商城網(wǎng)站建設(shè)、集團(tuán)公司官網(wǎng)建設(shè)、外貿(mào)網(wǎng)站建設(shè)、高端網(wǎng)站制作、響應(yīng)式網(wǎng)頁(yè)設(shè)計(jì)等建站業(yè)務(wù),價(jià)格優(yōu)惠性價(jià)比高,為瓊結(jié)等各大城市提供網(wǎng)站開發(fā)制作服務(wù)。

Instant Run,是android studio2.0新增的一個(gè)運(yùn)行機(jī)制,在你編碼開發(fā)、測(cè)試或debug的時(shí)候,它都能顯著減少你對(duì)當(dāng)前應(yīng)用的構(gòu)建和部署的時(shí)間。通俗的解釋就是,當(dāng)你在Android Studio中改了你的代碼,Instant Run可以很快的讓你看到你修改的效果。而在沒(méi)有Instant Run之前,你的一個(gè)小小的修改,都肯能需要幾十秒甚至更長(zhǎng)的等待才能看到修改后的效果。

傳統(tǒng)的代碼修改及編譯部署流程

傳統(tǒng)的代碼修改及編譯流程如下:構(gòu)建整個(gè)apk → 部署app → app重啟 → 重啟Activity

Instant Run編譯和部署流程

Instant Run構(gòu)建項(xiàng)目的流程:構(gòu)建修改的部分 → 部署修改的dex或資源 → 熱部署,溫部署,冷部署

熱拔插,溫拔插,冷拔插

熱拔插:代碼改變被應(yīng)用、投射到APP上,不需要重啟應(yīng)用,不需要重建當(dāng)前activity。

場(chǎng)景:適用于多數(shù)的簡(jiǎn)單改變(包括一些方法實(shí)現(xiàn)的修改,或者變量值修改)

溫拔插:activity需要被重啟才能看到所需更改。

場(chǎng)景:典型的情況是代碼修改涉及到了資源文件,即resources。

冷拔插:app需要被重啟(但是仍然不需要重新安裝)

場(chǎng)景:任何涉及結(jié)構(gòu)性變化的,比如:修改了繼承規(guī)則、修改了方法簽名等。

首次運(yùn)行Instant Run,Gradle執(zhí)行過(guò)程

一個(gè)新的App Server類會(huì)被注入到App中,與Bytecode instrumentation協(xié)同監(jiān)控代碼的變化。

同時(shí)會(huì)有一個(gè)新的Application類,它注入了一個(gè)自定義類加載器(Class Loader),同時(shí)該Application類會(huì)啟動(dòng)我們所需的新注入的App Server。于是,Manifest會(huì)被修改來(lái)確保我們的應(yīng)用能使用這個(gè)新的Application類。(這里不必?fù)?dān)心自己繼承定義了Application類,Instant Run添加的這個(gè)新Application類會(huì)代理我們自定義的Application類)

至此,Instant Run已經(jīng)可以跑起來(lái)了,在我們使用的時(shí)候,它會(huì)通過(guò)決策,合理運(yùn)用冷溫?zé)岚尾鍋?lái)協(xié)助我們大量地縮短構(gòu)建程序的時(shí)間。

在Instant Run運(yùn)行之前,Android Studio會(huì)檢查是否能連接到App Server中。并且確保這個(gè)App Server是Android Studio所需要的。這同樣能確保該應(yīng)用正處在前臺(tái)。

熱拔插

Android Studio monitors: 運(yùn)行著Gradle任務(wù)來(lái)生成增量.dex文件(這個(gè)dex文件是對(duì)應(yīng)著開發(fā)中的修改類) Android Studio會(huì)提取這些.dex文件發(fā)送到App Server,然后部署到App(Gradle修改class的原理,請(qǐng)戳鏈接)。

App Server會(huì)不斷監(jiān)聽(tīng)是否需要重寫類文件,如果需要,任務(wù)會(huì)被立馬執(zhí)行。新的更改便能立即被響應(yīng)。我們可以通過(guò)打斷點(diǎn)的方式來(lái)查看。

溫拔插

溫拔插需要重啟Activity,因?yàn)橘Y源文件是在Activity創(chuàng)建時(shí)加載,所以必須重啟Activity來(lái)重載資源文件。

目前來(lái)說(shuō),任何資源文件的修改都會(huì)導(dǎo)致重新打包再發(fā)送到APP。但是,google的開發(fā)團(tuán)隊(duì)正在致力于開發(fā)一個(gè)增量包,這個(gè)增量包只會(huì)包裝修改過(guò)的資源文件并能部署到當(dāng)前APP上。

所以溫拔插實(shí)際上只能應(yīng)對(duì)少數(shù)的情況,它并不能應(yīng)付應(yīng)用在架構(gòu)、結(jié)構(gòu)上的變化。

注:溫拔插涉及到的資源文件修改,在manifest上是無(wú)效的(這里的無(wú)效是指不會(huì)啟動(dòng)Instant Run),因?yàn)?,manifest的值是在APK安裝的時(shí)候被讀取,所以想要manifest下資源的修改生效,還需要觸發(fā)一個(gè)完整的應(yīng)用構(gòu)建和部署。

冷拔插

應(yīng)用部署的時(shí)候,會(huì)把工程拆分成十個(gè)部分,每部分都擁有自己的.dex文件,然后所有的類會(huì)根據(jù)包名被分配給相應(yīng)的.dex文件。當(dāng)冷拔插開啟時(shí),修改過(guò)的類所對(duì)應(yīng)的.dex文件,會(huì)重組生成新的.dex文件,然后再部署到設(shè)備上。

之所以能這么做,是依賴于Android的ART模式,它能允許加載多個(gè).dex文件。ART模式在android4.4(API-19)中加入,但是Dalvik依然是選擇,到了android5.0(API-21),ART模式才成為系統(tǒng)默認(rèn)選擇,所以Instant Run只能運(yùn)行在API-21及其以上版本。

使用Instant Run一些注意點(diǎn)

Instant Run是被Android Studio控制的。所以我們只能通過(guò)IDE來(lái)啟動(dòng)它,如果通過(guò)設(shè)備來(lái)啟動(dòng)應(yīng)用,Instant Run會(huì)出現(xiàn)異常情況。在使用Instant Run來(lái)啟動(dòng)Android app的時(shí)候,應(yīng)注意以下幾點(diǎn):

如果應(yīng)用的minSdkVersion小于21,可能多數(shù)的Instant Run功能會(huì)掛掉,這里提供一個(gè)解決方法,通過(guò)product flavor建立一個(gè)minSdkVersion大于21的新分支,用來(lái)debug。

Instant Run目前只能在主進(jìn)程里運(yùn)行,如果應(yīng)用是多進(jìn)程的,類似微信,把webView抽出來(lái)單獨(dú)一個(gè)進(jìn)程,那熱、溫拔插會(huì)被降級(jí)為冷拔插。

在Windows下,Windows Defender Real-Time Protection可能會(huì)導(dǎo)致Instant Run掛掉,可用通過(guò)添加白名單列表解決。

暫時(shí)不支持Jack compiler,Instrumentation Tests,或者同時(shí)部署到多臺(tái)設(shè)備。

結(jié)合Demo深度理解

為了方便大家的理解,我們新建一個(gè)項(xiàng)目,里面不寫任何的邏輯功能,只對(duì)application做一個(gè)修改:

首先,我們先反編譯一下APK的構(gòu)成,使用的工具:d2j-dex2jar 和jd-gui。

我們要看的啟動(dòng)的信息就在這個(gè)instant-run.zip文件里面,解壓instant-run.zip,我們會(huì)發(fā)現(xiàn),我們真正的業(yè)務(wù)代碼都在這里。

從instant-run文件中我們猜想是BootstrapApplication替換了我們的application,Instant-Run代碼作為一個(gè)宿主程序,將app作為資源dex加載起來(lái)。

那么InstantRun是怎么把業(yè)務(wù)代碼運(yùn)行起來(lái)的呢?

Instant Run如何啟動(dòng)app

按照我們上面對(duì)instant-run運(yùn)行機(jī)制的猜想,我們首先看一下appliaction的分析attachBaseContext和onCreate方法。

attachBaseContext()

 
 
 
 
  1. protected void attachBaseContext(Context context) {
  2.        if (!AppInfo.usingApkSplits) {
  3.             String apkFile = context.getApplicationInfo().sourceDir;
  4.             long apkModified = apkFile != null ? new File(apkFile).lastModified() : 0L;
  5.             createResources(apkModified);
  6.             setupClassLoaders(context, context.getCacheDir().getPath(), apkModified);
  7.        }
  8.        createRealApplication();
  9.        super.attachBaseContext(context);
  10.        if (this.realApplication != null) {
  11.             try {
  12.                  Method attachBaseContext = ContextWrapper.class.getDeclaredMethod("attachBaseContext", new Class[] { Context.class });
  13.                  attachBaseContext.setAccessible(true);
  14.                  attachBaseContext.invoke(this.realApplication, new Object[] { context });
  15.             } catch (Exception e) {
  16.                  throw new IllegalStateException(e);
  17.             }
  18.       }
  19. }

我們依次需要關(guān)注的方法有:

createResources → setupClassLoaders → createRealApplication → 調(diào)用realApplication的attachBaseContext方法

createResources()

 
 
 
 
  1. private void createResources(long apkModified) {
  2.        FileManager.checkInbox();
  3.        File file = FileManager.getExternalResourceFile();
  4.        this.externalResourcePath = (file != null ? file.getPath() : null);
  5.        if (Log.isLoggable("InstantRun", 2)) {
  6.             Log.v("InstantRun", "Resource override is " + this.externalResourcePath);
  7.        }
  8.        if (file != null) {
  9.             try {
  10.                  long resourceModified = file.lastModified();
  11.                  if (Log.isLoggable("InstantRun", 2)) {
  12.                       Log.v("InstantRun", "Resource patch last modified: " + resourceModified);
  13.                       Log.v("InstantRun", "APK last modified: " + apkModified
  14.                            + " "
  15.                            + (apkModified > resourceModified ? ">" : "<")
  16.                            + " resource patch");
  17.                  }
  18.                  if ((apkModified == 0L) || (resourceModified <= apkModified)) {
  19.                       if (Log.isLoggable("InstantRun", 2)) {
  20.                             Log.v("InstantRun", "Ignoring resource file, older than APK");
  21.                       }
  22.                       this.externalResourcePath = null;
  23.                  }
  24.           } catch (Throwable t) {
  25.                  Log.e("InstantRun", "Failed to check patch timestamps", t);
  26.           }
  27.      }

說(shuō)明:該方法主要是判斷資源resource.ap_是否改變,然后保存resource.ap_的路徑到externalResourcePath中。

setupClassLoaders()

 
 
 
 
  1. private static void setupClassLoaders(Context context, String codeCacheDir, long apkModified) {
  2.        List dexList = FileManager.getDexList(context, apkModified);
  3.        Class server = Server.class;
  4.        Class patcher = MonkeyPatcher.class;
  5.        if (!dexList.isEmpty()) {
  6.             if (Log.isLoggable("InstantRun", 2)) {
  7.                  Log.v("InstantRun", "Bootstrapping class loader with dex list " + join('\n', dexList));
  8.             }
  9.             ClassLoader classLoader = BootstrapApplication.class.getClassLoader();
  10.             String nativeLibraryPath;
  11.             try {
  12.                   nativeLibraryPath = (String) classLoader.getClass().getMethod("getLdLibraryPath", new Class[0]).invoke(classLoader, new Object[0]);
  13.                   if (Log.isLoggable("InstantRun", 2)) {
  14.                        Log.v("InstantRun", "Native library path: " + nativeLibraryPath);
  15.                   }
  16.             } catch (Throwable t) {
  17.             Log.e("InstantRun", "Failed to determine native library path " + t.getMessage());
  18.             nativeLibraryPath = FileManager.getNativeLibraryFolder().getPath();
  19.       }
  20.       IncrementalClassLoader.inject(classLoader, nativeLibraryPath, codeCacheDir, dexList);
  21.       }

說(shuō)明,該方法是初始化一個(gè)ClassLoaders并調(diào)用IncrementalClassLoader。

IncrementalClassLoader的源碼如下:

  1. public class IncrementalClassLoader extends ClassLoader {
  2.       public static final boolean DEBUG_CLASS_LOADING = false;
  3.       private final DelegateClassLoader delegateClassLoader;
  4.       public IncrementalClassLoader(ClassLoader original, String nativeLibraryPath, String codeCacheDir, List dexes) {
  5.            super(original.getParent());
  6.            this.delegateClassLoader = createDelegateClassLoader(nativeLibraryPath, codeCacheDir, dexes, original);
  7.       }
  8. public Class findClass(String className) throws ClassNotFoundException {
  9.      try {
  10.           return this.delegateClassLoader.findClass(className);
  11.      } catch (ClassNotFoundException e) {
  12.           throw e;
  13.      }
  14. }
  15. private static class DelegateClassLoader extends BaseDexClassLoader {
  16.      private DelegateClassLoader(String dexPath, File optimizedDirectory, String libraryPath, ClassLoader parent) {
  17.           super(dexPath, optimizedDirectory, libraryPath, parent);
  18.      }
  19.      public Class findClass(String name) throws ClassNotFoundException {
  20.           try {
  21.                 return super.findClass(name);
  22.           } catch (ClassNotFoundException e) {
  23.                 throw e;
  24.           }
  25.      }
  26. }
  27. private static DelegateClassLoader createDelegateClassLoader(String nativeLibraryPath, String codeCacheDir, List dexes,
  28. ClassLoader original) {
  29.       String pathBuilder = createDexPath(dexes);
  30.       return new DelegateClassLoader(pathBuilder, new File(codeCacheDir), nativeLibraryPath, original);
  31. }
  32. private static String createDexPath(List dexes) {
  33.       StringBuilder pathBuilder = new StringBuilder();
  34.       boolean first = true;
  35.       for (String dex : dexes) {
  36.            if (first) {
  37.                  first = false;
  38.            } else {
  39.                  pathBuilder.append(File.pathSeparator);
  40.            }
  41.            pathBuilder.append(dex);
  42.       }
  43.       if (Log.isLoggable("InstantRun", 2)) {
  44.            Log.v("InstantRun", "Incremental dex path is " + BootstrapApplication.join('\n', dexes));
  45.       }
  46.       return %

    網(wǎng)站欄目:深入理解AndroidInstantRun運(yùn)行機(jī)制
    URL標(biāo)題:http://www.5511xx.com/article/dhhscog.html