你真的了解 Instant Run 嗎?
今天是周二,又輪到我寫文章了。
先扯點題外話,我是2010年8月份開始自學Android的,到現在已經快有6年的時間了。當時為了自學我專門買了一本書,叫《Android高級編程》,作者是Reto Meier,這本書現在仍然還在我的書架上,這是我剛拍的一張略顯陳舊的照片:
然后最近在學習Instant Run,看了下Android的官方視頻,我意外地發現,這位幫助我入門的帥哥竟然已經加入Google了。
現在我就想知道《第一行代碼》的作者何時可以加入Google?^_^
扯蛋就先扯到這里,我們來進入今天的正題。
什么是Instant Run?
我們都知道,Android Studio功能非常強大,在各個功能性方面都要優于Eclipse,唯獨在速度方面被吐糟得比較慘。Android Studio團隊為此也是做了很多的優化,在Android Studio 2.0中,對速度方面進行了大幅度的改進:
可以看到,Android Studio 2.0中編譯和部署的速度都有了很大程度的提升,但唯獨安裝速度沒有得到提升,這很正常嘛,畢竟應用程序的安裝快慢是由我們手機的硬件配置來決定的,和開發工具有什么關系呢。
但是Android Studio團隊并不滿足于此,他們想將速度提升到極致,于是在Android Studio 2.0中加入了Instant Run功能。當然,只要你的Android Studio版本在2.0以上,你不需要進行任何學習就可以使用Instant Run,但是如果懂得了它背后的原理,你將可以使用得更好。
傳統情況下,我們修改程序后重新運行一次程序需要經歷 代碼重新編譯 -> 停止程序 -> 重新安裝 -> 重新啟動 這樣一個過程,而Instant Run則嘗試只將程序變更的部分部署到手機上,盡量避免重新安裝或重新啟動程序,以此大大提升調試程序的效率。
當我們第一次運行程序之后,Android Studio中的運行按鈕會變成這個樣子:
可以看到,運行的三角形旁邊多了一個閃電符號,這就說明現在可以使用Instant Run了。
Instant Run主要分為三種類型,hot swap、warm swap和cold swap,Android Studio會根據代碼的修改情況自動選擇使用哪種swap類型,下面我們就來針對這三種swap類型詳細地學習一下。
Hot Swap
hot swap是所有swap方式中效率最高的一種,應用程序不需要重新安裝,也不需要重啟就可以完成程序變更。但是hot swap不會對程序中的對象進行重新初始化,也就是說可能某些場景下需要重啟Activity才能看出具體的變更內容。Android Studio對于hot swap這種情況默認是重啟Activity的,當然你也可以到設置中去改變這一默認行為,具體路徑是 Settings -> Build, Execution, Deployment -> Instant Run -> Restart activity on code changes。
hot swap的適用條件比較少,只有一種情況會被Android Studio視為hot swap類型,就是 修改一個現有方法中的代碼 ,效果如下圖所示:
可以看到,我只改動了一個現有方法的內部代碼,重新運行后編譯和部署的速度都非常快,最關鍵的是,應用程序并沒有重新安裝或重啟,甚至于Activity都沒有重啟(由于我進行了上述的設置),然后修改的代碼就成功替換了。
Warm Swap
warm swap也非常快,這種swap類型同樣 不需要重新安裝或重啟程序就可以完成程序變更,但是warm swap要求必須重啟Activity。你會在界面上看到屏幕很快地閃一下,同時Activity的生命周期會重新執行。
warm swap的適用條件也比較局限, 只有一種情況會被Android Studio視為warm swap類型,就是 修改或刪除一個現有的資源文件 ,效果如下圖所示:
可以看到,我改動了布局文件中的內容,重新運行后速度仍然很快,應用程序并沒有重新安裝或重啟,只是Activity重啟了一下,因為要將修改后的布局內容展示到界面上。
Cold Swap
cold swap相對而言就要更慢一些了,Android Studio會自動記錄我們項目的每次修改,然后將修改的這部分內容打成一個dex文件發送到手機上,盡管這種swap類型仍然不需要去安裝一個全新的APK,但是為了加載這個新的dex文件,整個應用程序必須進行重啟才行。另外,cold swap的工作原理是基于multidex機制來實現的,在不引入外部library的情況下,只有5.0及以上的設備才支持multidex,因此,如果你使用了5.0以下的設備,那么cold swap就無法工作了,這種情況會執行最原始的完整APK安裝過程。
cold swap的適用條件非常多,下面我列出一個詳細的清單,有哪些 情況會被Android Studio視為cold swap類型:
-
添加、刪除或修改一個注解
-
添加、刪除或修改一個字段
-
添加、刪除或修改一個方法
-
添加一個類
-
修改一個類的繼承結構
-
修改一個類的接口實現
-
修改一個類的static修飾符
-
涉及資源文件id的改動
那么我們還是來看一下演示效果吧,如下圖所示:
可以看到,這里我給第二個Button添加了一個新的點擊事件方法,添加一個方法是滿足cold swap條件的,那么我們明顯可以看出,應用程序重新啟動了,但是整體的速度依然很快,整個重新運行的過程在5秒種之內完成的,我的截圖都是實時速度,沒有進行加速播放。
Full APK
除了滿足以上條件的其他程序變更,Instant Run目前都還不支持,主要包括以下一些情況:
-
改變AndroidManifest.xml文件的內容
-
改變被 AndroidManifest.xml文件所引用的資源,比如string.xml中的app_name
-
改變桌面widget的UI相關元素
當程序變更不被Instant Run所支持時,就會執行完整的APK安裝過程,同時Android Studio會給出這樣的提示:
由于這種情況重新運行時間比較長,就不給大家截圖演示了,以前我們使用低于2.0版本的Android Studio開發時,每次都是執行的這種情況。
當然,這只是目前的Instant Run規則,Android Studio團隊還會一直進行優化,增加hot swap和warm swap的條件,減少cold swap和full apk的條件,相信未來的Android Studio會更加好用。
Rerun
盡管Instant Run盡可能地想要變得更智能,但是它也沒有時光倒流的能力。比如hot swap或者warm swap是根本不會重啟程序的,而如果你修改了一些只有在程序啟動的時候才會初始化的代碼,那么Instant Run對此也是無能為力的,因為修改的代碼根本就沒有執行到。
針對這種情況,Android Studio專門提供了一個Rerun按鈕:
中間那個按鈕就是Rerun按鈕,使用這個按鈕來重新運行程序,應用程序會被強制重啟,從而初始化的一些代碼就能夠執行到了。Android Studio無法得知改動的代碼是不是在程序初始化的時候才執行的,而我們卻可以知道,所以確保你理解了Rerun這個按鈕的作用,并在恰當的時機使用它。
補充
hot swap由于其工作原理的限制還有一些特殊問題。hot swap會在應用程序的內部開啟一個服務器,然后由Android Studio自動計算出方法內實現的變更,將變更代碼發送到服務器,服務器再利用類加載器和委托機制將新的代碼實現注入到現有應用程序中,從而完成替換工作。
但是整個過程中,新的代碼實現并沒有被保存到本地,也就是說一旦設備和Android Studio的連接斷掉了(比如拔掉數據線),我們使用hot swap替換的代碼也就隨之不見了。當你再次打開程序的時候,你會看到這樣的提示:
看到這個提示并不用感到驚奇,這就說明你的hot swap代碼失效了,現在的程序仍然使用的老的代碼。遇到這種情況只需要將手機連上電腦,然后在Android Studio中重新運行一下程序就可以解決了。另外只有在debug模式下才可能會出現這個提示,release模式下是不可能出現的,所以不用擔心這個提示會讓用戶感到困惑。