ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

Android 的应用冷优化

2022-01-20 14:03:28  阅读:179  来源: 互联网

标签:install val bilibili 应用 哔哩 fun Android 优化


应用启动分类

冷启动

用户点击屏幕上的应用图标,经过展示启动窗口创建进程展示应用几个过程

热启动

用户进程已经创建,如果响应了低内存事件,例如在 onTrimMemory 中清除资源,则需要重新初始化

如何检测应用启动时长

  • 通过 adb shell am start -S -W $packageName/.MainActivity 启动检测
  • 通过显示调用 reportFullDrawn 根据业务需求,通知系统完成加载
  • 通过 android-sdk/platform-tools/systrace 下 systrace.py 通过 Python systrace.py --time=10 -o launch.html sched gfx view wm 查看每个函数的耗时
  • 通过 Android Studio Profiler 启动应用查看

为什么会出现白屏

在应用启动过程中 ActivityStack 的 startActivityLocked 方法中会判断当前应用的启动模式,若为冷启动,则调用 ActivityRecord 中 windowContainerController 的 showStartingWindow 方法,添加启动白屏页

2018-04-26_start_activity.png

通过 WindowMangerService 调用 mPolicy 的 addSplashScreen 方法,创建了一个 PhoneWindow 添加到窗口上

关键代码

if (theme != context.getThemeResId() || labelRes != 0) {
    try {
        context = context.createPackageContext(packageName, CONTEXT_RESTRICTED);
        context.setTheme(theme);
    } catch (PackageManager.NameNotFoundException e) {
        // Ignore
    }
}

final PhoneWindow win = new PhoneWindow(context);
win.setIsStartingWindow(true);

win.setLayout(WindowManager.LayoutParams.MATCH_PARENT,
        WindowManager.LayoutParams.MATCH_PARENT);

wm = (WindowManager) context.getSystemService(WINDOW_SERVICE);
view = win.getDecorView();

if (DEBUG_SPLASH_SCREEN) Slog.d(TAG, "Adding splash screen window for "
    + packageName + " / " + appToken + ": " + (view.getParent() != null ? view : null));

wm.addView(view, params);

如何优化

启动优化步骤分类

  • 白屏的视觉优化
  • MultiDex 优化
  • 逻辑代码优化
  • 首页布局优化

白屏的优化

对于白屏启动页面的优化,根据上述的代码分析,可以通过设置主题,为 windowBackground 添加与启动页一致的图片,视觉上可以骗过用户

MultiDex 优化

着应用的不断迭代,内部的方法数会不断增加,最终超过方法数上限。而官方也退出了 MultiDex的方案来解决,也就是意味着分包。在低版本手机 DVM 上,我们需要手动调用 MultiDex.install 加载主 Dex 以外的文件,可能造成 ANR

低版本启动的优化

面对这个问题,我们可以采用 Facebook 提出的方案。创建一个新的进程在 Application 的 attachBaseContext 中调用 MultiDex.install,主进程可以通过多种手段阻塞等到加载结束之后再进入应用

class App : Application() {

    override fun attachBaseContext(base: Context) {
        super.attachBaseContext(base)

        if (isAsyncLaunchProcess().not()) {
            val thread = DexInstallDeamonThread(base)
            thread.start()

            synchronized(lock) {
                try {
                    lock.wait()
                } catch (e: InterruptedException) {
                    e.printStackTrace()
                }
            }

            thread.exit()
        }
    }

    fun isAsyncLaunchProcess(): Boolean {
        val processName = SystemUtils.getCurrentProcessName(this)
        return processName != null && processName.contains(":install")
    }

    private class DexInstallDeamonThread(private val base: Context) :
        Thread() {
        private var handler: Handler? = null
        private var looper: Looper? = null

        @SuppressLint("HandlerLeak")
        override fun run() {
            Looper.prepare()
            looper = Looper.myLooper()
            handler = object : Handler() {
                override fun handleMessage(msg: Message) {
                    synchronized(lock) { lock.notify() }
                }
            }
            val messenger = Messenger(handler)
            val intent = Intent(base, MultiInstallActivity::class.java)
            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
            intent.putExtra("MESSENGER", messenger)
            base.startActivity(intent)
            Looper.loop()
        }

        fun exit() {
            if (looper != null) looper!!.quit()
        }
    }
}
class MultiInstallActivity : AppCompatActivity() {
    private var messenger: Messenger? = null
    public override fun onCreate(savedInstanceState: Bundle?) {
        requestWindowFeature(Window.FEATURE_NO_TITLE)
        super.onCreate(savedInstanceState)
        window.setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN)
        setContentView(R.layout.activity_install)
        val from = intent
        messenger = from.getParcelableExtra("MESSENGER")
        thread {
            try {
                Log.d(TAG, "start install")
                MultiDex.install(application)
                Thread.sleep(5000L)
                Log.d(TAG, "finish install")
                messenger?.send(Message.obtain())
            } catch (e: Exception) {
                e.printStackTrace()
            }
            runOnUiThread {
                finish()
                exitProcess(0)
            }
        }
    }

    override fun onBackPressed() {
        //无法退出
    }

    companion object {
        private const val TAG = "MultiInstallActivity"
    }
}
<activity
    android:name="com.weex.multidexinstall.MultiInstallActivity"
    android:launchMode="singleTask"
    android:process=":install" />

逻辑代码优化

在应用启动过程中,我们一般会在 Application 的 onCreate 中加载 SDK 以及读取 SharedPreference 中的值等耗时操作

  • 对于 SharedPreference 可以替换为 MMKV

首页布局优化

对于布局优化,比较常见的一些技术如

  • ViewStub
  • merge 标签
  • 使用ConstraintLayout 替换原来的布局标签

相关教程

Android基础系列教程:

Android基础课程U-小结_哔哩哔哩_bilibili

Android基础课程UI-布局_哔哩哔哩_bilibili

Android基础课程UI-控件_哔哩哔哩_bilibili

Android基础课程UI-动画_哔哩哔哩_bilibili

Android基础课程-activity的使用_哔哩哔哩_bilibili

Android基础课程-Fragment使用方法_哔哩哔哩_bilibili

Android基础课程-热修复/热更新技术原理_哔哩哔哩_bilibili

本文转自 https://juejin.cn/post/7054214019749511205,如有侵权,请联系删除。

标签:install,val,bilibili,应用,哔哩,fun,Android,优化
来源: https://www.cnblogs.com/jiajia246/p/15826077.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有