Android性能优化(一)启动优化

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/qq_34895720/article/details/97127762

欢迎来到格调小窝

一. 初识启动加速

应用的启动分为冷启动、热启动、温启动,而启动最慢、挑战最大的就是冷启动;系统和App本身都有很多工作需要从头开始! 应用在冷启动之前,要执行三个任务:

  1. 加载启动App;
  2. App启东之后立即展示出一个空白的Window;
  3. 创建App的进程

而这三个任务执行完毕之后会马上执行以下任务:

  1. 创建App对象;
  2. 启动Main Thread;
  3. 创建启动Activity的对象;
  4. 填充加载布局Views
  5. 执行第一次绘制屏幕过程measure -> layout -> draw,展示界面;

而一旦App进程完成了第一次绘制,系统进程就会用Main Activity替换已经展示的Background Window,此时用户就可以使用App了。

作为普通应用,App进程的创建等环节我们是无法主动控制的,== 可以优化的也就是Application、Activity创建以及回调等过程。==
同样,Google给出了启动加速的方向:
1.利用提前展示出来的Window,快速展示出来一个界面,给用户快速启动的体验;
2.避免在启动时做过多的耗时操作
3.避免I/O操作、反序列化、网络操作、布局嵌套等。

备注:方向1属于治标不治本,只是表面上快;方向2、3可以真实的加快启动速度。

二. 启动加速之主题切换

应用启动页白屏(StartingWindow)优化
StartingWindow 的处理方式:

1.使用系统默认的 StartingWindow : 用户点了应用图标启动应用,马上弹出系统默认的 StartingWindow(就是做动画的那个 Window) ,等应用加载好第一帧之后,StartingWindow 消失,显示应用第一帧,无缝衔接,体验还不错,这也是通常大部分 Android 应用的场景;比如大部分 Android 系统的自带应用,即刻、汽车之家等
2.自己定制简单的 StartingWindow : 用户点了应用图标启动应用,弹出应用自己定制的StartingWindow,等应用加载好第一帧之后,定制的 StartingWindow 消失,显示应用主界面,由于 StartingWindow 是自己定制的,启动的时候 Decode Bitmap 或者 Inflate 自定义 Layout 会有一定的耗时,但是总的来说与系统默认的差别不大,用户体验优;这样的应用包括淘宝、京东、微博、今日头条、美团等
在styles.xml文件中添加以下代码

    <!-- 应用启动页(StartingWindow)的theme -->
    <style name="AppTheme.StartingWindowTheme" parent="AppTheme">
        <!-- 可以设置成纯颜色(设置一个和Activity UI相似的背景) -->
        <!--<item name="android:windowBackground">@color/startingwindow_bgcolor</item>-->
         <!--也可以设置成一张图片 -->
        <item name="android:windowBackground">@drawable/startingwindow_bg</item>
    </style>

在colors.xml文件中添加以下代码【根据实际情况来添加,如果使用纯颜色作为启动页白屏的背景的话,则需要添加】


    <!-- 应用启动页(StartingWindow)的theme的背景色 -->
    <color name="startingwindow_bgcolor">#00bfff</color>

在AndroidManifest.xml中给首页activity(第一个页面,一般是欢迎界面)设置自定义的theme

扫描二维码关注公众号,回复: 7568466 查看本文章
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
          package="com.why.project.androidstartingwindowdemo">

    <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">
        <!--将首页的them设置成自定义的样式-->
        <activity android:name=".MainActivity"
                  android:theme="@style/AppTheme.StartingWindowTheme">
            <intent-filter>
                <action android:name="android.intent.action.MAIN"/>

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

</manifest>

在Activity中恢复原有的style样式【否则的话,当activity的布局文件设置背景色为透明的时候,就会发现窗口的背景还是那张图片】

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setTheme(R.style.AppTheme);//恢复原有的样式
        setContentView(R.layout.activity_main);
    }
}

3.把 StartingWindow 禁掉或者设置透明 : 用户点了应用图标启动应用,由于 StartingWindow 被禁掉或者被设置透明,所以会出现点击图标后,除了图标黑一下之外没有任何响应,过个 1-N 秒(取决于应用第一帧的加载速度),直接显示应用主界面。这样的毒瘤应用包括:微信、微信读书、UC 浏览器、支付宝、工商银行、米家等。

三. 启动加速之Application

1.将友盟、Bugly、听云、GrowingIO、BlockCanary等组件放在子线程中初始化
InitializeService.start(this);
2.延迟地图定位、ImageLoader、自有统计等组件的初始化:地图及自有统计延迟4秒,此时应用已经打开;而ImageLoader
因为调用关系不能异步以及过久延迟,初始化从Application延迟到SplashActivity;而EventBus因为再Activity中使用所以必须在Application中初始化。
注意:欢迎页面的2秒停留可以利用,把耗时操作延迟到这个时间间隔里。

四.IntentService与Service的区别

1.Service:

  • Service服务是长期运行在后台;
  • 不是单独的线程,它跟线程没有任何关系,所以不能进行耗时操作;
  • 如果直接把耗时操作放在Service中的onStartCommand()中,可能发生ANR,如果有耗时操作,就必须开启一个单独的线程来处理;

为了解决这样的问题,就引入了IntentService;

2.IntentService:

  • 启动方式和Service一样,都是startService();
  • 继承于Service,包含Service所有特性,包括生命周期,是处理异步请求的一个类,;
  • 一般自定义一个InitializeService继承Service,然后复写onHandleIntent()方法,在这个方法中初始化这些第三方的,来执行耗时操作;
  • 可以启动多次IntentService,每一个耗时操作以工作队列在onHandleIntent()方法中执行,执行完第一个再去执行第二个,以此类推;
  • 所有的请求都在单线程中,不会阻塞主线程,同一个时间只处理同一个请求;
  • 不需要像在Service中一样,手动开启线程,任务执行完成后不需要手动调用stopSelf()方法来停止服务,系统会自动关闭服务;

举个栗子:

service要在AndroidManifest里注册一下:

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

Application中启动服务:

public class BaseApplication extends Application {
    @Override
    public void onCreate() {
        super.onCreate();
        //initLeakCanary();                //Square公司内存泄漏检测工具
        //在子线程中初始化
        InitializeService.start(this);
    }
}

initApplication()方法里换成你要初始化的SDK

public class InitializeService extends IntentService {

    private static final String ACTION_INIT = "initApplication";

     public InitializeService() {
        super("InitializeService");
    }
 
    public static void start(Context context) {
        Intent intent = new Intent(context, InitializeService.class);
        intent.setAction(ACTION_INIT);
        context.startService(intent);
    }

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

    private void initApplication() {
        initBugly();                                    //初始化腾讯bug管理平台
    }

    /**
     * 初始化腾讯bug管理平台
     * 子线程进行初始化SDK操作
     */
    private void initBugly() {
        /* Bugly SDK初始化
        * 参数1:上下文对象
        * 参数2:APPID,平台注册时得到,注意替换成你的appId
        * 参数3:是否开启调试模式,调试模式下会输出'CrashReport'tag的日志
        * 注意:如果您之前使用过Bugly SDK,请将以下这句注释掉。
        */
        CrashReport.UserStrategy strategy = new CrashReport.UserStrategy(getApplicationContext());
        strategy.setAppVersion(AppUtils.getAppVersionName());
        strategy.setAppPackageName(AppUtils.getAppPackageName());
        strategy.setAppReportDelay(20000);                          //Bugly会在启动20s后联网同步数据

        /*  第三个参数为SDK调试模式开关,调试模式的行为特性如下:
            输出详细的Bugly SDK的Log;
            每一条Crash都会被立即上报;
            自定义日志将会在Logcat中输出。
            建议在测试阶段建议设置成true,发布时设置为false。*/

        CrashReport.initCrashReport(getApplicationContext(), "126dde5e58", true ,strategy);


    }
}

猜你喜欢

转载自blog.csdn.net/qq_34895720/article/details/97127762