初识性能优化


初识性能优化

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第22天,点击查看活动详情

性能优化系列文章

初识性能优化 - 掘金 (juejin.cn)

探析Android中的四类性能优化 - 掘金 (juejin.cn)

浅谈Android的流畅性优化——归因分析 - 掘金 (juejin.cn)

浅谈Android的流畅性优化——案例分享 - 掘金 (juejin.cn)

前置知识

  • 有Android开发基础

前言

性能优化一词相信大家都经常听到,今天我们就简单的来认识以下性能优化,了解做性能优化的必要性以及优化的分类。

为什么要进行性能优化

下图来自于 FaceBook,这是他们对 Android 性能以及用户日活跃度两个指标的统计。我们可以清晰的看到性能和用户日活是正相关的,软件的性能越好,那么表现出来的业务数据也会更好。所以说,我们技术上的指标提升,同时也会使得业务指标的提升,这是业务方面我们需要做性能优化的理由。

而从另一个角度——硬件发展的角度来看,我们会发现当代的芯片的性能提升速度其实在是不断的下滑的。无论是 Intel 和 ADM 的x86架构的芯片,还是 ARM 的arm 架构的芯片,近年来都呈现放缓的趋势。

即使ARM平台由于其架构和工艺双重不断迭代的缘故,其性能在最近几年间提升的速度很快,最明显的表现就是我们一代代的手机的处理器之间增强的幅度很大,但是这也无法阻止技术变更的规律,它的优化幅度就是在不断的变弱,直到最后的挤牙膏。

当然多核技术也对芯片性能带来了优化,但是同时也对芯片大小和电池性能有限制,所以这项技术也是处于瓶颈了。

综上所述,从硬件发展的角度来看,硬件的发展逐渐趋于停止,我们需要做好软件的性能优化,才能在未来硬件发展停滞的时候,做好用户体验的提升。

所以说,无论是从业务指标或者是硬件能力上来讲,我们去做好性能优化都是很必要的。

什么是性能优化

性能优化是什么?其实就是要实现三点:快、稳、省。

  • 何为快?

    快就是指,打开App时候很快、打开页面很快、播放视频音乐很快以及滑动得很顺畅。这些都被称之为快,核心要义是指:用户很快能接收到系统的回馈

  • 何为稳?

    稳的意思是,系统很稳定。软件不会出现异常的bug、不会闪退和ANR,这些都是稳的体现。

  • 何为省?

    省的意思是空间和数据的节省。具体体现为安装包的大小、安装后使用所占用的存储空间大小以及网络数据的读取量大小。把这些都给省下来就是省的要义。

基于以上的三点目标,我们其实可以将性能优化简单的分为以下四类

  1. 流畅性优化,响应快,流畅性高
  2. 资源优化,最小的负载带来最大的收益
  3. 稳定性优化,稳定的实现功能,减少不必要的打断
  4. 系统级优化,充分挖掘系统的资源,让APP在有限的资源内能够有更高的流畅性。(较难,较为底层)

上述四类优化在此暂不做详细阐述,上述的稳定性优化是等级最高的,上线之前必须排除所有已知的bug,这是众所周知的。而流畅性优化是较为常见的、开发者闷都会去完善的优化。下面我们就来举一些例子,看一下我们之前的哪些文章中提到的属于流畅性优化。

  • 隐性的滑动冲突

    与滑动冲突的首次邂逅一文中,我们提到了一个较为隐性的滑动冲突,就是下面左图中的上下滑动突变为左右滑动的问题。而解决之后,在同一方向任意滑动都不会出现滑动突变的问题了,这大大的提高了滑动的流畅性,同时也是实现了交互的稳定性。

  • 启动白屏

    我们知道,如果我们未对自己的项目的APP做白屏优化,那么在APP首次启动的时候,都会出现一个短暂的白屏。这是因为APP首次开启主进程,且通过各类初始化的时候,是需要一定的执行事件的,而这个执行时间就显现出来就是白屏效果。

    而一个没有实际画面的白屏,对于用户来说是一种卡顿、不流畅的体现,所以各大厂家会使用 APP 的 Logo 或者是其他动画形式的做一个启动页。将这种启动页代替白屏就可以在感器上减少卡顿感。

    下面展示我做的一个启动页效果,更详细的文章在极简抖音中的优化点

  • 启动速度优化

    上述的启动页是可以让用户减少卡顿感,但这终究是一个视觉上面的欺骗,但是在数据指标上面,我们的启动时间没有真的减少。对于小型APP来说,未优化的时候启动时间不会很长,但是对于大型APP来说,就会有很大的影响了,让用户等一个启动页等超过2s,用户也会觉得卡顿的。

    所以,我们需要做好启动优化。启动优化的点很多,但是总结为一点就是:减少不必要的初始化。我们可以对各进程做分类加载,把一些加载异步化等等。

    下面附上我做不同进程区别加载的操作,详细解释依旧在极简抖音中的优化点一文中。

    public class App extends Application {
    
        private static Context context;
    
        private static String sCurProcessName = null;
        private String processName;
        private String packageName;
    
        /**
         * Set the base context for this ContextWrapper.  All calls will then be
         * delegated to the base context.  Throws
         * IllegalStateException if a base context has already been set.
         *
         * @param base The new base context for this wrapper.
         */
        @Override protected void attachBaseContext(Context base) {
            super.attachBaseContext(base);
            processName = getCurProcessName(base);
            packageName = getPackageName();
        }
    
        private boolean isMainProcess() {
            return !TextUtils.isEmpty(packageName) && TextUtils.equals(packageName, processName);
        }
    
        @Override
        public void onCreate() {
            super.onCreate();
            context = getApplicationContext();
            if (isMainProcess()){
                MMKV.initialize(this);
                MMKV.mmkvWithID("MyID", MMKV.SINGLE_PROCESS_MODE, GlobalConstant.MMKV_KEY);
                //载入Dokit监测
                new DoKit.Builder(this)
                        .productId(context.getString(R.string.value_dokit_pid))
                        .build();
                //使用订阅索引,加快编译速度
                EventBus.builder().addIndex(new MyEventBusIndex()).installDefaultEventBus();
                // 抖音授权
                String clientkey = context.getString(R.string.value_client_key);
                DouYinOpenApiFactory.init(new DouYinOpenConfig(clientkey));
                //初始化
                MyUtil.initialize(this);
                //设置UI工具
                RxTool.init(this);
                //网络缓存
                RetrofitCache.getInstance().init(this);
            }else {
                QbSdk.initX5Environment(getContext(), new QbSdk.PreInitCallback() {
                    @Override
                    public void onCoreInitFinished() {
                        // 内核初始化完成,可能为系统内核,也可能为系统内核
                    }
    
                    /**
                     * 预初始化结束
                     * 由于X5内核体积较大,需要依赖网络动态下发,所以当内核不存在的时候,默认会回调false,此时将会使用系统内核代替
                     * @param isX5 是否使用X5内核
                     */
                    @Override
                    public void onViewInitFinished(boolean isX5) {
                        LogUtil.i("是否使用腾讯内核:" + isX5);
    
                    }
                });
            }
    
            //设置打印开关
            LogUtil.setIsLog(true);
            //注册Activity生命周期
            registerActivityLifecycleCallbacks(ActivityUtil.getActivityLifecycleCallbacks());
    
        }
    
        public static Context getContext() {
            return context;
        }
    
        private static String getCurProcessName(Context context) {
            ...
        }
    
        private static String getProcessName(int pid) {
            ...
        }
    
    }
  • 多进程预加载

    在Android里面,每打开一个进程就会默认去跑 Application 类,所以如果我们在使用的时候才去开启进程,就会使得页面首次开启的时候较为缓慢。为解决这个问题,我们可以让进程在后台预先开启,这样就能减少我们首次开启多进程功能的启动时间了。

    下面示例是后台启动多进程的代码,详情请参阅极简抖音中的优化点一文。

    //在对应的生命周期启用即可
    private void startHideService(){
        Intent intent = new Intent(this, PreLoadService.class);
        this.startService(intent);
    }
    
    private void stopHideService(){
        Intent intent = new Intent(this, PreLoadService.class);
        this.stopService(intent);
    }

上述这些都是我们有实现的流畅性优化点,它可以能让我们的APP使用体验更加的极致,同时也是对我们技术的考验。

相信大家学到这里,会了解到了为何需要性能优化且什么是性能优化了,今天的分享就到此结束,欢迎关注,点赞,大家一起学习!

参考

【Android 客户端专场 学习资料三】第四届字节跳动青训营 - 掘金 (juejin.cn)

极简抖音中的优化点|青训营笔记 - 掘金 (juejin.cn)


文章作者: DYJ
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 DYJ !
评论
  目录