我们 Android 开发永远也摆脱不了性能优化的需求,做的 App 就是给用户用的,随着功能的增加,App启动功能的丰富。
点击启动图标时,我们的 App 启动会出现一个白屏页面。这个非常影响交互体验。这节我们就来看看怎么优化这里
首先,我们来看看 App 的启动方式都有哪些
程序从头开始,系统灭有为该程序创建进程。
一般有两种场景:
1. 程序安装后的第一次启动
2. 应用程序被系统完全终止后再次打开
此时程序仍然驻留在内存之中,只是被系统从后台带入到前台,因此程序可以避免重复对象的初始化,加载布局和渲染。
需要注意的是,如果程序的某些内存被系统清除后,比如调用了 onTrimMemory
方法,则需要重新创建这些对象以相应热启动事件。
它包含热启动和冷启动一系列的操作子集,比热启动稍微消耗多一点。
与热启动的区别:暖启动必须调用 onCreate
方法开始重新创建活动,也可以从传递给 onCreate
方法中保存的实例状态中获取某些对象的恢复。
上面我们说的 App 启动时会有个白屏,那是因为当系统加载并启动 App 时,需要耗费相应的时间,即使时间不到 1s,用户也会感觉到当点击 App 图标时会有“延迟”现象。
为了解决这问题, Google 的做法是在 App 创建的过程中,先展示一个空白页面,让用户体会到点击图标之后立马就有响应;而这个空白页面的颜色则是根据我们在 Manifest 文件中配置的主题背景颜色来决定的;现在一般默认是白色;
这是 Google 官方为了用户体验做的一些操作。但是在我们看来还是有一定的体验缺陷,没办法,产品提的,就算头发掉光,我们也得解决呀。
对此。业界有这么两种解决方式,不过大多数都倾向于第二种
修改系统的 AppTheme 主题。
在应用默认的 Manifest 文件中,设置系统“取消预览(空白窗体)”为 true。或者设置空白窗体为透明。
这两种方式殊途同归,将 Theme 背景改为透明,这样用户在视觉上就看不到空白页了。
替换空白页,从交互和技术上同步入手解决这个问题
1、自定义集成 AppTheme 主题,设置相应的样式。
2、将启动 Activity 主题设置为自定义主题
3、在启动的 Activity 中调用 setTheme 方法,将主题重新设置为原来的系统主题(在 super.onCreate 方法之前调用)。
这里我们就第二种方案实现以下,代码不是很多,这里就直接贴出来了。
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@color/launchBackground"/>
<item android:top="150dp">
<bitmap android:src="@drawable/ic_launcher" android:gravity="top"/>
item>
layer-list>
<style name="AppTheme.LaunchTheme">
- "android:windowBackground"
>@drawable/launch_bg
- "android:windowFullscreen">true
- "windowNoTitle">true
style>
<application
android:theme="@style/AppTheme.LaunchTheme"
android:name=".ui.SplashActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
intent-filter>
activity>
<activity android:name=".MainActivity"/>
application>
package com.wuba.demo.ui;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.os.CountDownTimer;
import android.support.annotation.Nullable;
import android.util.Log;
import android.view.View;
import android.widget.TextView;
import com.wuba.demo.MainActivity;
import com.wuba.demo.R;
/**
* Author silence.
* Time:2020-03-02.
* Desc:App 启动欢迎页(引导页)
*/
public class SplashActivity extends Activity {
private static final String TAG = "SplashActivity";
private CountDownTimer countDownTimer;
private TextView jumpTime;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.acticity_splash);
jumpTime = findViewById(R.id.jump_time);
countDownTimer = new CountDownTimer(3000, 1000) {
@Override
public void onTick(long millisUntilFinished) {
Log.d(TAG, "millisUntilFinished:" + millisUntilFinished);
String lastTime = millisUntilFinished / 1000+1 + "s";
jumpTime.setText(lastTime);
}
@Override
public void onFinish() {
jump2Main();
}
};
jumpTime.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
jump2Main();
}
});
}
private void jump2Main() {
startActivity(new Intent(this, MainActivity.class));
countDownTimer.cancel();
finish();
}
@Override
protected void onResume() {
super.onResume();
countDownTimer.start();
}
}
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/jump_time"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="3s"
android:layout_gravity="right"
android:layout_margin="25dp"
android:textColor="#FFF"
android:textSize="40sp"/>
<LinearLayout
android:id="@+id/go"
android:layout_width="wrap_content"
android:layout_marginBottom="100dp"
android:layout_gravity="bottom|center"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:orientation="horizontal">
<ImageView
android:layout_width="50dp"
android:layout_height="50dp"
android:contentDescription="@string/app_name"
android:src="@drawable/ic_launcher"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="30sp"
android:layout_marginLeft="15dp"
android:textColor="#FFF"
android:text="APP 启动优化"/>
LinearLayout>
FrameLayout>
这里我们从设计和技术的角度解决了 App 启动时的黑白屏问题。但是在我们实际开发中,经常会产品或者测试说这玩意怎么用起来这么卡。这个就只能从技术角度去分析解决了。
在 App 启动的时候,我们经常在自定义的 Application 中初始化相关东西。比如依赖的 SDk ,随着业务越来越多,这块的逻辑也越来越复杂。这就意味着我们 Application 的 onCreate 方法执行时间将会越来越长,从而导致我们界面展示越来越延迟。
这里我们可以将一些功能放在子线程中初去初始化,这样就可以节省我们主线程的时间了,从而提高应用的展示时间。
而界面的卡顿主要是 UI 过度绘制导致的,具体解决方法可以从以下几个方面入手
1、布局中的背景是否必要,没必要可以移除掉
2、是否可以删除多余的布局,减少 View 的层级,尽量使布局扁平化
3、自定义 View 是否进行了相应的裁剪
4、使用 merge 标签可以排除掉一层 ViewGroup 标签
5、使用 ViewStub 标签可以进行布局的懒加载