由Instant Run引发的问题及其解决方案

时间:2022-10-29 18:37:18


众所周知,Android作为移动市场占有率第一的系统,之前一直没有自己的编辑器,曾今Java出身的我一直在用eclipse,后来转向Android后eclipse用的更是手到擒来,但是google肯定不甘心自己开发的系统用别人的编辑器,so,Android studio就诞生了,最初Android studio各种问题,各种bug被开发者所吐槽,但是随着google的大量投入修补升级,Android studio也变得越来越稳定,Android studio的方便快捷让开发者一使用边喜欢上了。去年google 发布了Android studio2.0的版本,里面新增了instant run,它能大大提高了我们构造,编译的速度。但是问题也随之而来。


问题1,第一次启动长时间白屏


对于这个问题,郭霖大神已经给出解决,,对于郭霖在这篇文章末尾提到的release版本在安装的过程中也有短暂的空白,它的解决方案是修改style,使其app初始化的过程变透明,点击查看启动白屏,这样虽然也解决了短暂白屏的问题,但是给用的感觉是点了app启动图标,短暂的时间内没有反应,这里我给出更好的解决方案

先看看效果:

由Instant Run引发的问题及其解决方案由Instant Run引发的问题及其解决方案由Instant Run引发的问题及其解决方案

从左往右依次为优化结果。

可以看到图1有很明显的白屏,这是我们遇到的问题

图2是把白屏变成透明的了,虽然看不到白屏了,但是点了应用图标感觉要等1-2s启动页才能出来

图3为最终优化结果,出现白屏的原因是因为系统加载了默认的主题,所以我们只需要自定义主题,设置背景图片并在启动页的activity上引用自定义的主题即可。

style.xml的代码

<resources>
<!-- Base application theme. -->
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
<!-- Customize your theme here. -->
<item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
<item name="colorAccent">@color/colorAccent</item>
</style>
<style name="AppTheme.Login" parent="AppTheme">
<item name="android:windowBackground">@drawable/guid</item>
</style>
</resources>
清单文件引用theme的代码:

<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".GuidActivity"
android:theme="@style/AppTheme.Login">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name=".MainActivity" />
</application>

打开instant run运行,个别机型(oppo r11)出现闪退

一款app在正式发布之前都要经过很多的调式,但是我在使用instant run 热启动模式运行的时候在oppo r11的测试机上出现了app一打开就闪退的问题,在oppo r9,vivo y55a,vivo x9,mx5,模拟器上运行都是ok的。

oppo r11上运行报错如下:

 FATAL EXCEPTION: main
Process: com.zhaocd.test, PID: 23532
java.lang.RuntimeException: Unable to instantiate activity ComponentInfo{com.zhaocd.test/com.zhaocd.test.GuidActivity}: java.lang.ClassNotFoundException: Didn't find class "com.zhaocd.test.GuidActivity" on path: DexPathList[[zip file "/data/app/com.zhaocd.test-1/base.apk"],nativeLibraryDirectories=[/data/app/com.zhaocd.test-1/lib/arm64, /system/lib64, /vendor/lib64]]
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2721)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2880)
at android.app.ActivityThread.-wrap12(ActivityThread.java)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1617)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:185)
at android.app.ActivityThread.main(ActivityThread.java:6493)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:916)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:806)
Caused by: java.lang.ClassNotFoundException: Didn't find class "com.zhaocd.test.GuidActivity" on path: DexPathList[[zip file "/data/app/com.zhaocd.test-1/base.apk"],nativeLibraryDirectories=[/data/app/com.zhaocd.test-1/lib/arm64, /system/lib64, /vendor/lib64]]
at dalvik.system.BaseDexClassLoader.findClass(BaseDexClassLoader.java:56)
at java.lang.ClassLoader.loadClass(ClassLoader.java:380)
at java.lang.ClassLoader.loadClass(ClassLoader.java:312)
at android.app.Instrumentation.newActivity(Instrumentation.java:1079)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2711)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2880) 
at android.app.ActivityThread.-wrap12(ActivityThread.java) 
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1617) 
at android.os.Handler.dispatchMessage(Handler.java:102) 
at android.os.Looper.loop(Looper.java:185) 
at android.app.ActivityThread.main(ActivityThread.java:6493) 
at java.lang.reflect.Method.invoke(Native Method) 
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:916) 
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:806)


纳尼,竟然说在dexPathList中GuidActivity不存在,在其他机型上明明是好的,于是想到可能是instant run搞的鬼,把app卸载了,重新安装,这样你所有的代码都会执行了吧,但是重新安装还是出现这样的错,这又是为什么呢?最后通过对比发现即使第一次安装instant run也只编译了部分代码,证据如下:

由Instant Run引发的问题及其解决方案由Instant Run引发的问题及其解决方案

图1图2

图1是直接在Android studio上run运行起来的,图2是打包后将apk复制到手机,从手机上安装的,发现app的大小竟然差了一半,这又是为何?

然后我在setting中取消了instant run的勾选,再次运行,成功安装,没有闪退。

所以问题就出在instant run上了,抱着严谨好学的心态,开始查找官方文档,我们知道正常的一次app运行的过程包括:构建整个apk——>部署app——>app重启——>activity重启。而instant run为了提高效率,把app运行的过程重构:只构建修改的部分——>部署修改的部分或资源——>热部署,温部署,冷部署。

热部署(hot swap): 方法内简单的修改,无需重启app和activity,部署很快。

温部署(warm swap):修改了方法或者资源文件,无需重启app,但要重启activity,部署快

冷部署(cold swap):修改了清单文件,注解,签名,示例或者静态方法,需要重启app,重启activity


根据对官方文档的理解,app第一次安装时间比较长,但是不应该出现只编译部分代码的情况,查看oppo r11的Android版本为7.1.1,那和Android版本有没有用关系呢,是不是因为Android版本太高了,在我自己新建了一个7.1.1的模拟器运行,也没有出现r11上闪退的问题,oppo用的是colorOS的系统,是深度定制过的,有没有可能是这个原因呢?现在这个问题只是针对r11这个机型有问题,其他机型没问题,解决办法只能是暂时不使用instant run启动了。先作此记录,以后找到更好的解决办法或者问题的根本原因在作补充。