Android性能优化之提高App启动速度和Splash页面设计

原创 2017年01月03日 19:54:44

1 App的启动

1.1 启动方式

通常来说,在安卓中应用的启动方式分为两种:冷启动和热启动。

(1)冷启动:当启动应用时,后台没有该应用的进程,这时系统会重新创建一个新的进程分配给该应用,这个启动方式就是冷启动。
(2)热启动:当启动应用时,后台已有该应用的进程(例:按back键、home键,应用虽然会退出,但是该应用的进程是依然会保留在后台,可进入任务列表查看),所以在已有进程的情况下,这种启动会从已有的进程中来启动应用,这个方式叫热启动。

1.2 特点

(1)冷启动:冷启动因为系统会重新创建一个新的进程分配给它,所以会先创建和初始化Application类,再创建和初始化MainActivity类(包括一系列的测量、布局、绘制),最后显示在界面上。

(2)热启动:热启动因为会从已有的进程中来启动,所以热启动就不会走Application这步了,而是直接走MainActivity(包括一系列的测量、布局、绘制),所以热启动的过程只需要创建和初始化一个MainActivity就行了,而不必创建和初始化Application,因为一个应用从新进程的创建到进程的销毁,Application只会初始化一次。

上面说的启动是点击app的启动图标来启动的,而另外一种方式是进入最近使用的列表界面来启动应用,这种不应该叫启动,应该叫恢复。

1.3 应用启动的流程

这里写图片描述

由图分析可总结Activity大概启动流程:启动虚拟机—>启动AMS —>通过Zygote创建ApplicationProcess进程–>Application的构造器方法——>attachBaseContext()——>onCreate()——>Activity的构造方法——>onCreate()——>配置主题中背景等属性——>onStart()——>onResume()——>测量布局绘制显示在界面上。

2 测量一个应用的启动时间

2.1 测量方法

adb shell am start -W [PackageName]/[PackageName.MainActivity]

执行成功后将返回三个测量到的时间:
(1)ThisTime:指当前指定的MainActivity的启动时间
(2)TotalTime:整个应用的启动时间,Application+Activity的使用的时间。
(3)WaitTime:一般比TotalTime大点,包括系统影响的耗时

2.2 测量结果

adb shell am start -W com.guesslive.caixiangji/com.guesslive.caixiangji.activity.MainActivity

(1)优化前

Activity: com.guesslive.caixiangji/.activity.MainActivity
ThisTime: 1363
TotalTime: 1363
WaitTime: 1391
Complete

(2)Application优化后

Activity: com.guesslive.caixiangji/.activity.BootActivity
ThisTime: 521
TotalTime: 521
WaitTime: 547
Complete

(3)MainActivity&SplashFragment 优化后

Activity: com.guesslive.caixiangji/.activity.MainActivity
ThisTime: 340
TotalTime: 340
WaitTime: 366
Complete

3 减少应用启动时的耗时

主要是在Application初始化 + MainActivity的界面加载绘制时间。
(1)不要在Application的构造方法、attachBaseContext()、onCreate()里面进行初始化耗时操作。使用IntentService代替初始化工作。
(2)MainActivity,由于用户只关心最后的显示的这一帧,对我们的布局的层次要求要减少,自定义控件的话测量、布局、绘制的时间。不要在onCreate、onStart、onResume当中做耗时操作。
(3)对于SharedPreference的初始化。因为他初始化的时候是需要将数据全部读取出来放到内存当中。
(4)SplashActivity和MainActivity合为一个优化。
(5)合理使用延迟加载DelayLoad。达到效果:应用已经启动并加载完成,界面已经显示出来了,然后我们再去做其他的事情

4 综合方案

4.1 Application

public class MainApplication extends Application {

    @Override
    public void onCreate() {
        super.onCreate();

        InitializeService.start(this);//启动服务执行耗时操作
    }
}
/**
 * 启动初始化Service
 */
public class InitializeService extends IntentService {

    // IntentService can perform, e.g. ACTION_FETCH_NEW_ITEMS
    public static final String ACTION_INIT_WHEN_APP_CREATE = "com.guesslive.caixiangji.service.action.app.create";
    public static final String EXTRA_PARAM = "com.guesslive.caixiangji.service.extra.PARAM";

    public InitializeService() {
        super("InitializeService");
    }

    /**
     * 启动调用
     * @param context
     */
    public static void start(Context context) {
        Intent intent = new Intent(context, InitializeService.class);
        intent.setAction(ACTION_INIT_WHEN_APP_CREATE);
        context.startService(intent);
    }

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

    /**
     * 启动初始化操作
     */
    private void performInit(String param) {
        initImageLoader();//初始化图片加载控件
        initRealm();//初始化Realm数据库
        initUser();//初始化用户(Realm数据库)
        initPush();//初始化推送
        initTuSdk();//初始化图sdk
        initQiNiu();//初始化七牛
        initQiyu();//网易七鱼
        initLogger();//注释启动,打开屏蔽打印
    }
}

4.2 MainActivity&SplashFragment

(1)MainActivity.java

public class MainActivity extends FragmentActivity {

    private Handler mHandler = new Handler();
    private SplashFragment splashFragment;
    private ViewStub viewStub;

    private ImageView iv;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        viewStub = (ViewStub)findViewById(R.id.content_viewstub);

        //首先加载并显示splash页面
        splashFragment = new SplashFragment();
        FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
        transaction.replace(R.id.frame, splashFragment);
        transaction.commit();

        //1.判断当窗体加载完毕的时候,立马再加载真正的布局进来
        getWindow().getDecorView().post(new Runnable() {
            @Override
            public void run() {
                // 开启延迟加载
                mHandler.post(new Runnable() {
                    @Override
                    public void run() {
                        viewStub.inflate();//将viewstub加载进来,记载完毕后控件使用正常

//                      iv = (ImageView) findViewById(R.id.iv);
                    }
                } );
            }
        });

        //2.判断当窗体加载完毕的时候执行,延迟一段时间做动画。
        getWindow().getDecorView().post(new Runnable() {
            @Override
            public void run() {
                // 开启延迟加载,实现fragment里面的动画效果
                mHandler.postDelayed(new DelayRunnable(MainActivity.this, splashFragment) ,2000);
//              mHandler.post(new DelayRunnable());//不开启延迟加载
            }
        });

        //3.同时进行异步加载数据


    }

    static class DelayRunnable implements Runnable{
        private WeakReference<Context> contextRef;
        private WeakReference<SplashFragment> fragmentRef;

        public DelayRunnable(Context context, SplashFragment f) {
            contextRef = new WeakReference<Context>(context);
            fragmentRef = new WeakReference<SplashFragment>(f);
        }

        @Override
        public void run() {
            // 移除splash页面
            if(contextRef!=null){
                SplashFragment splashFragment = fragmentRef.get();
                if(splashFragment==null){
                    return;
                }
                FragmentActivity activity = (FragmentActivity) contextRef.get();
                FragmentTransaction transaction = activity.getSupportFragmentManager().beginTransaction();
                transaction.remove(splashFragment);
                transaction.commit();
            }
        }
    }

    @Override
    protected void onResume() {
        super.onResume();
    }
}

(2)activity_main.xml

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.example.applicationstartoptimizedemo.MainActivity" >

    <ViewStub 
        android:id="@+id/content_viewstub"
        android:layout="@layout/activity_main_viewstub"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>

    <FrameLayout
        android:id="@+id/frame"
        android:layout_width="match_parent"
        android:layout_height="match_parent" >
        <!-- android:background="@mipmap/bg_boot" 设置背景图-->
    </FrameLayout>

</RelativeLayout>

(3)activity_main_viewstub.xml

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/content"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

    <ProgressBar
        android:id="@+id/progressBar1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center" />

    <ImageView
        android:id="@+id/iv"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:scaleType="fitStart"
        android:src="@drawable/content" />

</FrameLayout>

(4)SplashFragment.java

public class SplashFragment extends Fragment {

    @Override
    @Nullable
    public View onCreateView(LayoutInflater inflater,
            @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        return inflater.inflate(R.layout.fragment_splash, container,false);
    }
}

4.3 给Window加上背景避免白屏

(1)bg_splash.xml

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
    <!-- 底层白色 -->
    <item android:drawable="@color/white" />

    <!-- 顶层Logo居中 -->
    <item>
        <bitmap
            android:gravity="center"
            android:src="@drawable/ic_github" />
    </item>
</layer-list>

(2)SplashTheme

<style name="SplashTheme" parent="AppTheme">
        <item name="android:windowBackground">@drawable/bg_splash</item>
</style>

(3)ActivityManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.guesslive.caixiangji">

    <application
        android:name=".application.MainApplication"
        android:allowBackup="true"
        android:hardwareAccelerated="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"  
        android:theme="@style/AppTheme">

        <activity
            android:name=".activity.MainActivity"
            android:screenOrientation="portrait"
            android:theme="@style/SplashTheme">

            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

        <service
            android:name=".service.InitializeService"
            android:exported="false"/>

    </application>

</manifest>

5 结语

实际场景可能远比这个复杂,这只是其中一种分析思路,还有其他思路欢迎私信。

6 参考链接

Android App优化之提升你的App启动速度之实例挑战

Android优化应用启动速度

相关文章推荐

App启动界面效果设计

每个Android应用启动之后都会出现一个Splash启动界面,大多数的Splash界面都是会等待一定时间,然后切换到下一个界面。但如果app启动时间过长,可使用启动界面让用户耐心等待这段枯燥的时间。...

android 打开app先显示欢迎界面后自动跳到主界面

public class WelcomeActivity extends Activity{ private final long SPLASH_LENGTH = 2000; ...

App应用之启动界面SplashActivity

android的启动界面: 当前比较成熟一点的应用基本上都会在进入应用之显示一个启动界面. 这个启动界面或简单,或复杂,或简陋,或华丽,用意不同,风格也不同. 下面来观摩几个流行的应用的...

Android性能优化系列之App启动优化

Android性能优化系列之布局优化Android性能优化系列之内存优化Android性能优化系列之apk瘦身应用的启动速度缓慢是我们在开发过程中经常会遇到的问题,比如启动缓慢导致的黑屏,白屏问题,本...

Android性能优化第(八)篇---App启动速度优化上

应用的启动速度缓慢这是很多开发者都遇到的一个问题,比如启动缓慢导致的黑屏,白屏问题,大部分的答案都是做一个透明的主题,或者是做一个Splash界面,但是这并没有从根本上解决这个问题。那么如何从根本上解...

Delphi7高级应用开发随书源码

  • 2003年04月30日 00:00
  • 676KB
  • 下载

Android开机启动速度优化 && app启动速度优化

众所周知Android开机启动速度较慢,于是如何加快启动速度便成为一个值得讨论的问题。在查阅过许多资料后(特别是Google Group的android-platform),我整理总结出下面几点基本看...

layer-list和level-list标签

LayerDrawable应该是drawable里面用得比较多的一个Drawable:   一个LayerDrawable是一个可以管理一组drawable对象的drawable。在LayerD...

Android性能优化之Splash页面设计

目前SplashActivity的设计目前市场上的应用在启动时基本上都会先启动一个SplashActivity,作为一个欢迎界面,为什么这样设计呢? 个人总结有三个优点:1、可以给用户更好的体验比...
  • yaohui_
  • yaohui_
  • 2016年08月31日 13:54
  • 435

Android性能优化之Splash页应该这样设计

目前SplashActivity的设计目前市场上的应用在启动时基本上都会先启动一个SplashActivity,作为一个欢迎界面,为什么这样设计呢? 个人总结有三个优点:1、可以给用户更好的体验比如...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Android性能优化之提高App启动速度和Splash页面设计
举报原因:
原因补充:

(最多只允许输入30个字)