我们在使用Android时,很多APP打开都会有启动画面(欢迎界面),它会停留若干秒后再进入主界面。
先看一下Demo效果。
源码:GitHub地址
欢迎界面的意义
欢迎界面固然有展示品牌形象的作用,但关于欢迎界面我们需要明白是:
- 理论上界面越快消失越好,让用户尽早使用到APP
- 欢迎界面的停留可能用于广告的展示
- 显示欢迎界面的意义不是为了单纯的“炫”,它是给加载APP运行时需要的数据作掩护
- 欢迎界面显示过程中,应该是全屏的、不能返回的、不能取消的
- 欢迎界面所做的任务如果超时,我们不应该一直停留在欢迎界面上,而是应当直接进入主界面,防止用户等待过久并认为是APP卡死
关于上面第3点的启动时加载数据,情况有不少,比如从服务器拿到一些用户特有的配置(如Taplytics数据)、从本地SharePreference或数据库载入数据到内存等,这些都需要在进入主界面前完成。当然,也有一些在进入主界面前不用必须完成的,比如检测版本更新,如果检测到一半,其它的启动任务完成了,随时可以关闭欢迎界面。
欢迎界面的设计点
在设计欢迎界面时,我们可以得出几点信息:
- 需要定义和实现APP的启动任务,任务分两类,进入主界面前必须完成的和不必须完成的
- APP启动时就执行启动任务并展示欢迎界面,所有进入主界面前必须完成的启动任务全部执行完毕后,关闭欢迎界面,进入主界面并加载主界面的UI和数据
- 启动任务执行时间超时后,直接关闭欢迎界面
流程图如下,倒也没什么复杂。
但实现起来还是有不少要注意的细节,请看下文。
代码的实现
1. 任务接口的定义
/**
* 启动时的任务接口定义
*/
public interface StartTaskInterface {
void execute(AppStarter.OnTaskListener listener); // 启动任务的方法,方法中当任务结束时将回调listener
// 隐藏欢迎界面前,是否需要确保这个任务已经完成
// 如果为true,则此任务是必要执行的,在没完成任务前欢迎界面将一直显示(直到超时)
boolean isNeedDoneBeforeHideWelcomeDialog();
}
2. 我们定义三个任务
/**
* 启动APP时得到配置信息任务(调用API或读取本地数据)
*/
public class GetConfigStartTaskImpl implements StartTaskInterface {
@Override
public void execute(AppStarter.OnTaskListener listener) {
// 这里可根据实际需求替换成网络请求或异步任务
new Handler().postDelayed(() -> {
if (listener != null) {
listener.onFinished("GetConfigFinished");
}
}, 3000); // 假设花了3秒完成请求API得到APP的配置变量
}
@Override
public boolean isNeedDoneBeforeHideWelcomeDialog() {
return true;
}
}
/**
* 显示广告的任务
*/
public class ShowAdsStartTaskImpl implements StartTaskInterface {
@Override
public void execute(AppStarter.OnTaskListener listener) {
// 这里可根据实际需求替换成网络请求或异步任务
new android.os.Handler().postDelayed(() -> {
if (listener != null) {
listener.onFinished("ShowAdsFinished"); // task完成后回调并传入标识,执行结束操作
}
}, 2000); // 假设展示广告时间为2秒
}
@Override
public boolean isNeedDoneBeforeHideWelcomeDialog() {
return true; // 这个任务没完成前,不要关闭欢迎界面
}
}
/**
* 超时任务
*/
public class TimeOutTask implements StartTaskInterface {
private static final int TIMEOUT = 5000; // 我们设定欢迎界面显示的超时时间为5秒
private AppStarter appStarter;
public TimeOutTask(AppStarter appStarter) {
this.appStarter = appStarter;
}
@Override
public void execute(AppStarter.OnTaskListener listener) {
new Handler(Looper.getMainLooper()).postDelayed(new Runnable() {
@Override
public void run() {
appStarter.setOnTaskListener(null);
WelcomeDialogController.getInstance(<