王学岗性能优化————APP启动优化(黑白屏问题的解决,trace工具的使用,热启动与冷启动的区别)

一:手机启动
在这里插入图片描述
这个时候会启动HomeActivity;而各种APP图标就是HomeActivity中的控件,这些控件是可以点击的。与之对应的是,Launcher(继承了Activity)中有onClick(View view)方法。我们点击这个onClick方法的时候,就会把这个应用的相关信息传入传入到一个Intent里面。Object tag=v.getTag(); final Intent intent =((ShortCutInfo)tag).intent;点击哪个应用,哪个应用就是v,v.getTag();就是获得这个应用的tag.。
然后调用startActivity(intent);启动对应的app.,在这里的intent是一个进程信息。这个时候会通知我们的系统,我要打开这个进程。系统中的AMS会把该进程装进虚拟机的内存中,并且开辟堆、栈、常量池、方法区等等内存。还记得不,后台有一个孵化器(zygote)进程,zygote通过fork的方式开启一个叫SystemServer,SystemServer开启ActivityThread进程。注意:此之前的操作是由系统完成的,我们是无法优化的(当然,你如果足够的牛,可以重新写一个android系统优化)。
ActivityThread里面有一个main(String[] args)方法,该方法有如下代码

ActivityThread thread=new ActivityThread();
thread.attach(false)

自己启动了自己,在thread.attach(false)方法里会绑定application(此时的application在makeapplication方法中创建并且已经有了包等信息,紧接着会执行application的onCreate方法)。我们从这里就可以进行优化了。 这个时候会做一系列事情,最后创建Activity(Activity的onCreate方法执行)。我们的启动优化过程就是从Application的初始化,到Activity的onCreate()结束。
如果不做启动优化我们可能出现很多问题,比如白屏问题,我们启动一个app的时候会出现一个白屏。白屏持续数秒,这是一个很不好的用户体验。另外还有黑屏问题,与白屏相似。
我们来看下黑白屏的根源在哪里?
当我们新建一个项目的时候,app会有一个默认的主题。

 <!-- Base application theme. -->
    <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
        <!-- Customize your theme here. -->
        <item name="colorPrimary">@color/colorPrimary</item>
        <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
        <item name="colorAccent">@color/colorAccent</item>
    </style>

如果代码里没有parent="Theme.AppCompat.Light.DarkActionBar",就是黑屏,如果有这句代码就是白屏。如果你手机性能很好,看不出来,也有办法,你在Application类的onCreate()方法里延迟三秒Thread.sleep(3000);
我们查找Theme.AppCompat.Light.DarkActionBar的父类,一直查找下去,会发现他有一个叫Platform.AppCompat.Light的父类。在该父类的部分代码如下:

 <style name="Platform.AppCompat.Light" parent="android:Theme.Light">
        <item name="android:windowNoTitle">true</item>

        <!-- Window colors -->
        <item name="android:colorForeground">@color/foreground_material_light</item>
        <item name="android:colorForegroundInverse">@color/foreground_material_dark</item>
        <item name="android:colorBackground">@color/background_material_light</item>
        <item name="android:colorBackgroundCacheHint">@color/abc_background_cache_hint_selector_material_light</item>
        <item name="android:disabledAlpha">@dimen/abc_disabled_alpha_material_light</item>
        <item name="android:backgroundDimAmount">0.6</item>
        <item name="android:windowBackground">@color/background_material_light</item>

我们看最后一个属性

<item name="android:windowBackground">@color/background_material_light</item>

白屏的颜色就是这个@color/background_material_light颜色。问题出在这里。
先在我们修改下,在styles里增加一个属性

<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
        //在这里定义自己的颜色,你也可以定义自己的图片
        <item name="android:windowBackground">@color/colorAccent</item>
        <!-- Customize your theme here. -->
        <item name="colorPrimary">@color/colorPrimary</item>
        <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
        <item name="colorAccent">@color/colorAccent</item>
    </style>

京东就是这么干的,启动的时候加载一张图片,这张图片要显示几秒钟,他们在Application类的onCreate()中Thread.sleep( );了几秒钟。这样起到了一个打广告的效果
也可以改成透明颜色

 <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
 //改成透明
         <item name="android:windowIsTranslucent">true</item>
        <!-- Customize your theme here. -->
        <item name="colorPrimary">@color/colorPrimary</item>
        <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
        <item name="colorAccent">@color/colorAccent</item>
    </style>

改成透明效果后会有一个等待。但即使改成透明,也是会消耗内存的。我们看下腾讯QQ是怎么解决这个问题的。

<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
        <item name="android:windowBackground">@null</item>
        //禁止预览为真
        <item name="android:windowDisablePreview">true</item>
        <!-- Customize your theme here. -->
        <item name="colorPrimary">@color/colorPrimary</item>
        <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
        <item name="colorAccent">@color/colorAccent</item>
    </style>

这种效果和我们的透明效果是一样的,会有一个等待效果。但不消耗内存。
但这样也有不好的地方,肯能导致每个启动activity都出现等待结果,我们可以单独抽出来一个主题,运用到入口Activity.

<resources>

    <!-- Base application theme. -->
    <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
        <!-- Customize your theme here. -->
        <item name="colorPrimary">@color/colorPrimary</item>
        <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
        <item name="colorAccent">@color/colorAccent</item>
    </style>
    //声明启动的style,注意style必须继承AppCompat
    <style name="AppTheme.LauncherStyle">
        <item name="android:windowBackground">@null</item>
        <item name="android:windowDisablePreview">true</item>
    </style>
</resources>

在xml文件中配置

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

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity"
            android:theme="@style/AppTheme.LauncherStyle">
            <intent-filter>
                <action android:name="android.intent.action.MAIN"/>

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

</manifest>

还没有完,还需要在代码中设置

package com.example.acer.testfanshe;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //设置主题,注意要加下划线
        setTheme(R.style.AppTheme_LauncherStyle);
    }
}

二:我们启动优化可以从三个地方入手,一个是Application的onCreate(),一个是Activity的onCreate(),一个是xml文件。

介绍一个性能测试方法

 @Override
    public void onCreate() {
        super.onCreate();
        Debug.startMethodTracing("文件路径");
        /**
         * do something
         */
        Debug.stopMethodTracing();
    }

会生成一个文件,这个文件可以在as中打开。查看执行时间长的那些方法,然后进行优化。在onCreate()方法里不要做过多的事情,向开启OkHttpClient这些事情可以使用懒加载,下载图片等网络请求可以开启一个线程。
注意开启线程的时候可能会报这个错误,java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()在Application的onCreate()中,如果我们想开启线程节约时间,需要注意以下几个问题
(1)里面使用到的网络请求夹包可能会创建Handler,这是不允许的。不能在这个方法里创建Handler.
(2)不能有UI操作
(3)对异步要求不高;如果我们开启的线程执行时间较长,这个时候主线程已经执行完Application 的onCreate();去执行其它的代码,比如 Activity的onCreate();这个时候,在纸箱Activity的onCreate()方法里可能就会报空指针异常。
介绍一个查看Activity启动耗时的方法:Dispalayed关键字
在这里插入图片描述
另外也可以在命令行中输入如下命令查看

adb shell am start -W 包名/.xxxActivity

输入该命令后启动Activity,cmd会打印输出如下

C:\Users\acer>adb shell am start -W com.example.acer.testfanshe/.MainActivity
Starting: Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] cmp=com.ex
mple.acer.testfanshe/.MainActivity }
Warning: Activity not started, its current task has been brought to the front
Status: ok
Activity: com.example.acer.testfanshe/.MainActivity
ThisTime: 5791
TotalTime: 5791
WaitTime: 20043
Complete

ThisTime表示最后一个Activity启动的时间,TotalTime表示所有Activity启动的时间,因为我们程序里只有一个MainActivity,所有他们两个是相等的。waitTime包括系统启动+Activity启动的时间在这里插入图片描述
热启动与冷启动的区别
冷启动:app的信息加载到内存
热启动:app的信息不需要加载到内存,app信息已经在内存中存在了。因为后台进程一直存在。app shell ps命令可以查看该进程是否在内存中。

猜你喜欢

转载自blog.csdn.net/qczg_wxg/article/details/89503207