引言
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(测量、布局、绘制,显示到界面上)](窗口替换)
流程中很多步骤是系统控制的,我们能够控制的和关注的点有以下几个:
(1).Application的onCreate,一般应用中通用主件和初始化都放在这里(耗时主因)
(2).Activity的onCreate,UI布局和渲染(耗时主因)
(3).显示启动窗口到窗口替换之间,会出现白屏的过度画面,体验太差(视主题而定,必须优化)
上面分析出来启动耗时的主因和启动白屏的点,这些都是我们需要解决的问题。在给出解决方案前,我们先来看下关于启动性能的评估工具有哪些?任何更好的定位问题的所在。
4.有哪些工具可以查看启动过程中时间的消耗?
(1).display time
从Android KitKat版本开始,Logcat中会输出从程序启动到某个Activity显示到画面上所花费的时间。这个方法比较适合测量程序的启动时间。
(2).Traceview
TraceView 在[Android性能优化篇之内存优化--内存优化分析工具]中已经 讲过,这里就不分析了,我们来看下使用代码生成trace文件。
Debug.startMethodTracing("perform");
Debug.stopMethodTracing();
- 在下方的方法区点击"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尽量简化。