Android优化提升应用启动速度及Splash页面的设计

作者:冬日毛毛雨 时间:2022-02-18 06:02:27 

目录
  • 1.启动分为两种方式

  • 2.如何测量一个应用的启动时间

  • 3.应用启动的流程

  • 4.减少应用的启动时间的耗时

  • 5.如何设计延迟加载DelayLoad

1.启动分为两种方式

  • 1) 冷启动:当直接从桌面上直接启动,同时后台没有该进程的缓存,这个时候系统就需要重新创建一个新的进程并且分配各种资源。

  • 2) 热启动:app后台有该进程的缓存,这时候启动的进程就属于热启动。

  • 热启动不需要重新分配进程,也不会Application了,直接走的就是app的入口Activity,这样速度就很快

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

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

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

例: adb shell am start -W com.haocai.app/.activity.GuideActivity

Android优化提升应用启动速度及Splash页面的设计

Android优化提升应用启动速度及Splash页面的设计

热启动耗时:

打印的结果为:

  • ThisTime activity启动耗时

  • TotalTime 应用自身启动耗时=ThisTime+应用application等资源启动时间

  • WaitTime 系统启动应用耗时=TotalTime+系统资源启动时间

3.应用启动的流程

Application从构造方法开始 ---> attachBaseContext() ---> onCreate()
Activity
构造方法 ---> onCreate() ---> 设置显示界面布局,设置主题、背景等等属性 ---> onStart()
---> onResume() ---> 显示里面的View(测量、布局、绘制,显示到界面上)

从构造方法我们知道,启动耗时的主要花费在各个启动流程中

4.减少应用的启动时间的耗时

根据应用的启动流程,我们从而得到以下减少应用启动耗时操作的建议:

  • 不要在Application的构造方法、attachBaseContext()onCreate()里面进行初始化耗时操作。

  • MainActivity,由于用户只关心最后显示的这一帧,对我们的布局的层次要求减 自定义控件的测量、布局、绘制的时间。 同时 不要在onCreateonStartonResume当中的做耗时操作。

  • 对于SharedPreference的初始化

因为它初始化的时候是需要将数据全部读取出来放到内存当中。

  • 优化1:可以尽可能减少sp文件数量(IO需要时间)

  • 优化2:像这样的初始化最好放到线程里面

  • 优化3:大量的数据缓存到数据库中

app启动的耗时主要在:Application初始化 + MainActivity的界面加载绘制时间。

由于MainActvity的业务和布局复杂度非常高,甚至该界面必须要有一些初始化的数据才能显示。
那么这个时候MainActivity就可能半天都出不来,这就给用户感觉App太卡了。

常规方法:

1.我们要做的就是给用户赶紧利落的体验。点击app就立马弹出我们的界面。
于是乎想到使用SplashActivity--非常简单的一个欢迎页面上面都不干就只显示一个图片。
2.但是SplashActivity启动之后,还是需要跳到MainActivityMainActivity还是需要从头开始加载布局和数据。
想到SplashActivity里面可以去做一些MainActivity的数据的预加载。然后需要通过意图传到MainActivity

更好的优化:

耗时的问题:Application+Activity的启动及资源加载时间;预加载的数据花的时间。

如果我们能让这两个时间重叠在一个时间段内并发地做这两个事情就省时间了。

比如:SplashActivityMainActivity合为一个。

一进来还是显示MainActivitySplashActivity可以变成一个SplashFragment,然后放一个FrameLayout作为根布局直接显示SplashFragment界面。
SplashFragment里面非常之简单,就是现实一个图片,启动非常快。

SplashFragment显示完毕后再将它remove。同时在splash的2S的友好时间内进行网络数据缓存。
这个时候我们才看到MainActivity,就不必再去等待网络数据返回了。

新问题SplashViewContentView加载放到一起来做了 ,这可能会影响应用的启动时间?

解决:可以使用ViewStub延迟加载MainActivity当中的View来达到减轻这个影响。
viewStub的设计就是为了防止MainActivity的启动加载资源太耗时了。延迟进行加载,不影响启动,用户友好。
但是viewStub加载也需要时间。等到主界面出来以后。
viewStub.inflate(xxxx);

5.如何设计延迟加载DelayLoad

第一时间想到的就是在onCreate里面调用Handler.postDelayed()方法;
问题一:这个延时时间如何控制
不同的机器启动速度不一样,这个时间如何控制?
假设,先需要splash做一个2s动画,然后在MainActivity中主界面加载完成之后,关闭splash页面

如果这样写:


       mHandler.postDelayed(new Runnable() {
           @Override
           public void run() {
               mProgressBar.setVisibility(View.GONE);
               iv.setVisibility(View.VISIBLE);
           }
       }, 2500);

是无法在准确监听页面加载完的

问题:什么时候应用已经启动并加载完成,界面已经显示出来了。
采用onResume执行完了之后才显示完毕?不行。

建议采用getDecorView() 获取上级view 然后添加视图

综合上诉方案,以下是关键代码:


public class MainActivity extends AppCompatActivity {

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

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

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

/**
        *这么写不好判断视图有没有加载完
        */
       //      mHandler.postDelayed(new Runnable() {
//          @Override
//          public void run() {
//              mProgressBar.setVisibility(View.GONE);
//              iv.setVisibility(View.VISIBLE);
//          }
//      }, 2500);

viewStub = (ViewStub) findViewById(R.id.content_viewstub);

//1.判断当窗体加载完毕的时候,立马再加载真正的布局进来
       getWindow().getDecorView().post(new Runnable() {

@Override
           public void run() {
               // 开启延迟加载
               mHandler.post(new Runnable() {

@Override
                   public void run() {
                       //将viewstub加载进来
                       viewStub.inflate();
                   }
               });
           }
       });

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

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

static class DelayRunnable implements Runnable {

private WeakReference<Context> contextWeakReference;
       private WeakReference<SplashFragment> splashFragmentWeakReference;

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

@Override
       public void run() {
           //移除Fragment
           if (contextWeakReference != null) {
               SplashFragment splashFragment = splashFragmentWeakReference.get();
               if (splashFragment == null) {
                   return;
               }
               FragmentActivity activity = (FragmentActivity) contextWeakReference.get();
               FragmentTransaction transaction = activity.getSupportFragmentManager().beginTransaction();
               transaction.remove(splashFragment);
               transaction.commit();
           }

}
   }
}

activity_main.xml:


<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
   android:layout_width="match_parent"
   android:layout_height="match_parent"
  >

<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" >
   </FrameLayout>

</RelativeLayout>

Android优化提升应用启动速度及Splash页面的设计

ps:测试数据是在老款三星手机下所得耗时数据。
不过相较于SplashActivity+MainActivity启动速度优化还是挺明显的。大家可以在自己手机上试试。

来源:https://juejin.cn/post/7036981414893453319

标签:Android,启动速度,Splash,性能优化
0
投稿

猜你喜欢

  • Android通过json向MySQL中读写数据的方法详解【写入篇】

    2022-07-20 19:12:39
  • mybatis-plus 新增/修改如何实现自动填充指定字段

    2023-11-28 22:20:53
  • iOS新浪微博、腾讯微博分享功能实例

    2023-06-16 09:15:53
  • Android Support Annotations资料整理

    2021-09-21 13:39:33
  • C#中添加窗口的步骤详解

    2021-12-19 16:30:29
  • Mybatis实现单个和批量定义别名typeAliases

    2023-02-11 06:27:03
  • Android12四大组件之Activity生命周期变化详解

    2022-05-04 15:47:57
  • Android入门之TabHost与TabWidget实例解析

    2022-12-07 23:03:42
  • java多线程Future和Callable类示例分享

    2021-09-02 09:49:37
  • 用c#获得当前用户的Application Data文件夹位置

    2022-02-13 10:05:22
  • SpringMVC使用RESTful接口案例详解

    2022-08-08 23:41:52
  • springboot自定义过滤器的方法

    2021-07-29 05:36:53
  • C语言实现扫雷游戏源代码

    2021-10-17 14:20:44
  • Flutter开发技巧RadialGradient中radius计算详解

    2023-10-05 17:42:22
  • 亲手教你SpringBoot中的多数据源集成问题

    2023-08-19 02:57:20
  • java对象序列化与反序列化的默认格式和json格式使用示例

    2021-12-07 18:22:23
  • SpringBoot自定义maven-plugin插件整合asm代码插桩

    2021-05-24 02:15:49
  • 一文详解Spring如何控制Bean注入的顺序

    2022-09-10 18:33:22
  • Redis6搭建集群并在SpringBoot中使用RedisTemplate的实现

    2023-10-31 14:48:05
  • 解决在Unity中使用FairyGUI遇到的坑

    2023-10-27 13:04:24
  • asp之家 软件编程 m.aspxhome.com