Android性能优化篇之程序启动时间性能优化

Android性能优化篇之程序启动时间性能优化_第1张图片
image

引言

1. Android性能优化篇之内存优化--内存泄漏

2.Android性能优化篇之内存优化--内存优化分析工具

3.Android性能优化篇之UI渲染性能优化

4.Android性能优化篇之计算性能优化

5.Android性能优化篇之电量优化(1)——电量消耗分析

6.Android性能优化篇之电量优化(2)

7.Android性能优化篇之网络优化

8.Android性能优化篇之Bitmap优化

9.Android性能优化篇之图片压缩优化

10.Android性能优化篇之多线程并发优化

11.Android性能优化篇之数据传输效率优化

12.Android性能优化篇之程序启动时间性能优化

13.Android性能优化篇之安装包性能优化

14.Android性能优化篇之服务优化

介绍

程序的启动速度是用户体验中很重要的一部分。启动时间越短,用户会耐心的使用你们公司的应用,如果时间过长,用户很有可能会切换到其他应用去了。我们从下面几个问题来开始分析和解决程序启动慢的问题。

  • APP应用有几种启动方式?
  • 启动方式有那些不同?
  • 启动时间消耗到哪里去了?
  • 有哪些工具可以查看启动过程中时间的消耗?
  • 针对启动过慢的优化建议有哪些?
1.APP应用有几种启动方式?

启动分为两种方式:

(1).冷启动

应用从桌面上启动,且后台没有进程的缓存,这是系统就需要新创建一个进程并且分配资源。

(2).热启动

app在后台有进程缓存

2.启动方式有那些不同?

对于冷启动来说,多了一个创建进程,这块也是我们优化的重点。热启动不需要重新分配进程,也不会Application了,直接走的就是app的入口Activity,这样就速度快很多.

3.启动时间消耗到哪里去了?

当用户点击桌面图标开始,系统会立即为这个APP创建独立的专属进程,然后显示启动窗口,直到APP在自己的进程里面完成了程序的创建以及主线程完成了Activity的初始化显示操作,再然后系统进程就会把启动窗口替换成APP的显示窗口。
我们来看下启动的流程描述:

创建APP进程-->显示启动窗口(displsy start window)-->Application从构造方法开始--->attachBaseContext()--->onCreate()
Activity构造方法--->onCreate()--->设置显示界面布局,设置主题、背景等等属性
--->[onStart()--->onResume()--->显示里面的view(测量、布局、绘制,显示到界面上)](窗口替换)
Android性能优化篇之程序启动时间性能优化_第2张图片
image2.png

流程中很多步骤是系统控制的,我们能够控制的和关注的点有以下几个:

(1).Application的onCreate,一般应用中通用主件和初始化都放在这里(耗时主因)
(2).Activity的onCreate,UI布局和渲染(耗时主因)
(3).显示启动窗口到窗口替换之间,会出现白屏的过度画面,体验太差(视主题而定,必须优化)

上面分析出来启动耗时的主因和启动白屏的点,这些都是我们需要解决的问题。在给出解决方案前,我们先来看下关于启动性能的评估工具有哪些?任何更好的定位问题的所在。

4.有哪些工具可以查看启动过程中时间的消耗?
(1).display time

从Android KitKat版本开始,Logcat中会输出从程序启动到某个Activity显示到画面上所花费的时间。这个方法比较适合测量程序的启动时间。


Android性能优化篇之程序启动时间性能优化_第3张图片
image1.png
(2).Traceview

TraceView 在[Android性能优化篇之内存优化--内存优化分析工具]中已经 讲过,这里就不分析了,我们来看下使用代码生成trace文件。

    Debug.startMethodTracing("perform");
    Debug.stopMethodTracing();
Android性能优化篇之程序启动时间性能优化_第4张图片
image3.png
  • 在下方的方法区点击"Real Time/Call", 按照方法每次调用耗时降序排.
  • 耗时超过500ms都是值得注意的.
(3).adb shell

使用命令行来启动app,同时进行时间测量。单位:毫秒

adb shell am start -W [PackageName]/[PackageName.MainActivity]
adb shell am start -W com.skcodestack.performanceoptimization/com.skcodestack.performanceoptimization.speed.SplashActivity

ThisTime: 165 指当前指定的MainActivity的启动时间
TotalTime: 165 整个应用的启动时间,Application+Activity的使用的时间。
WaitTime: 175 包括系统的影响时间---比较上面大。

5.针对启动过慢的优化建议有哪些?
(1).Application的onCreate 中优化

在Application初始化的地方做太多繁重的事情是可能导致严重启动性能问题,Application里面的初始化操作不结束,其他任意的程序操作都无法进行。

    @Override
    public void onCreate() {
        super.onCreate();
        CrashReport.initCrashReport(getApplicationContext(), BUGLY_APP_ID, false);
        SharedPreferences sharedPreferences =  getCacheSharedPreferences();
        //皮肤管理初始化
        SkinManager.getInstance().init(this);
        //初始化
        ToastUtils.init(this);
        //数据库管理
        DaoManager.init(this);
    }
Application中初始化优化的方案有两种:
  • 不需要立刻初始化的,延迟加载
  • 需要初始化的,开启线程初始化
延迟加载

当我们想要使用时,在进行初始化

    static SharedPreferences mSp = null;
    public static synchronized  SharedPreferences getAppSharedPreFerences(Context context){
        if(mSp == null){
            mSp = context.getApplicationContext().getSharedPreferences(NAME,MODE_PRIVATE);
        }
        return mSp;
    }
开启线程初始化

我们这里使用IntentService

    public class InitIntentService extends IntentService {
    // TODO: Rename actions, choose action names that describe tasks that this
    // IntentService can perform, e.g. ACTION_FETCH_NEW_ITEMS
    private static final String ACTION_FOO = "com.skcodestack.performanceoptimization.speed.action.FOO";
    public InitIntentService() {
        super("InitIntentService");
    }
    /**
     * Starts this service to perform action Foo with the given parameters. If
     * the service is already performing a task this action will be queued.
     *
     * @see IntentService
     */
    // TODO: Customize helper method
    public static void startActionFoo(Context context) {
        Intent intent = new Intent(context, InitIntentService.class);
        intent.setAction(ACTION_FOO);
        context.startService(intent);
    }

    @Override
    protected void onHandleIntent(Intent intent) {
        if (intent != null) {
            final String action = intent.getAction();
            if (ACTION_FOO.equals(action)) {
                handleActionFoo();
            } 
        }
    }

    /**
     * Handle action Foo in the provided background thread with the provided
     * parameters.
     */
    private void handleActionFoo() {
        //初始化 app 
        ....        
    }
}

    @Override
    public void onCreate() {
        super.onCreate();
        InitIntentService.startActionFoo(this);
    }
(2).Activity的onCreate中优化

提升Activity的创建速度是优化APP启动速度的首要关注目标。从桌面点击APP图标启动应用开始,程序会显示一个启动窗口等待Activity的创建加载完毕再进行显示。在Activity的创建加载过程中,会执行很多的操作,例如设置页面的主题,初始化页面的布局,加载图片,获取网络数据,读写Preference等等。任何一个环节出现性能问题都可能导致画面不能及时显示,影响了程序的启动速度。

有几条优化建议:
  • 优化布局耗时:一个布局层级越深,里面包含需要加载的元素越多,就会耗费更多的初始化时间。关于布局性能的优化,在渲染优化的文章中已经讲过。
  • 异步延迟加载:一开始只初始化最需要的布局,异步加载图片,非立即需要的组件可以做延迟加载。
  • 预加载:在前一个显示时预加载下一个显示页面中需要用到的数据(常常用到Spalsh调整主页面时使用)
(3).闪屏优化

在应用启动时,屏幕会显示一个空白的窗口(颜色基于主题), 直至activity渲染完毕.

第一种,自定义一张图片,把这张图片通过设置主题的方式显示为启动闪屏,代码执行到主页面的onCreate的时候设置为程序正常的主题。

    
    
        
    




    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setTheme(R.style.SplashTheme);  
        startActivity(new Intent(this,SpeedMainActivity.class));
        finish();
    }
第二种,就是上面提到的预加载数据+延时加载布局,我们将Splash页面和主页面合并成一个页面,先显示Splash(尽量简单),然后等异步加载的主页数据完成(设定欢迎界面的友好时间),就显示主页面。

下面我们一起来看下代码:

    
    
    
    

MainActivity:

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_splash_and_main);

        FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
        final SplashFragment splashFragment = new SplashFragment();
        FragmentTransaction fragmentTransaction = transaction.replace(R.id.frame, splashFragment);
        fragmentTransaction.commit();

        final ViewStub viewStub = (ViewStub) findViewById(R.id.content_viewstub);
        //当窗体加载完毕时,执行
        getWindow().getDecorView().post(new Runnable() {
            @Override
            public void run() {
                //加载布局
                viewStub.inflate();
                //开始延迟加载
                mHandler.postDelayed(new DelayRunnable(SplashAndMainActivity.this,splashFragment),2000);
            }
        });
    }
    /**
     * 延迟操作
     */
    private   static  class DelayRunnable implements Runnable{
        private WeakReference mContextRef;
        private WeakReference mFragmentRef;

        public DelayRunnable(Context context,SplashFragment fragment) {
            this.mContextRef = new WeakReference(context);
            this.mFragmentRef = new WeakReference(fragment);
        }

        @Override
        public void run() {
            if(mContextRef != null){
                FragmentActivity activity = (FragmentActivity) mContextRef.get();
                if(mFragmentRef != null && activity != null && mFragmentRef.get() != null){
                    SplashFragment fragment = mFragmentRef.get();
                    FragmentTransaction transaction = activity.getSupportFragmentManager().beginTransaction();
                    transaction.remove(fragment);
                    transaction.commit();
                }   
            }
        }
    }
下面我们主要讲解预加载的实现:
总结:Application的onCreate中不要做耗时操作,首屏Activity尽量简化。

你可能感兴趣的:(Android性能优化篇之程序启动时间性能优化)