前言:闪屏界面在许多APP上都有,比如淘宝,支付宝,微信等
分析SplashActivity前首先来看下面这段代码:
private int len = 3;
Timer timer = new Timer();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_start);
timer.schedule(task, 1000, 1000);
}
TimerTask task = new TimerTask() {
@Override
public void run() {
runOnUiThread(new Runnable() {
@Override
public void run() {
len--;
if (len < 0) {
timer.cancel();
Intent intent = new Intent(StartActivity.this, MainActivity.class);
startActivity(intent);
finish();
}
}
});
}
};
这是最简单的闪屏代码了,逻辑上是在3秒后启动MainActivity,如果看懂后接着就可以进入正文了。
GifFun是有开源版本和非开源版本之分,核心是在main模块中,其中开源版本在opensource模块中,通过查看Manifest文件可以知道OpenSourceSplashActivity为点击APP后第一个启动的Activity。查看对应的资源文件activity_splash.xml,里面就一个id为logo的ImageView,而OpenSourceSplashActivity的代码非常简洁:
logoView = logo
就是把logo赋值给SplashActivity的logoView,因此进入SplashActivity查看。
在activity中我们通过setContentView制定activity的布局。比如:
setContentView(R.layout.activity_login)
GifFun中的BaseActivity重写了setContentView方法:
override fun setContentView(layoutResID: Int) {
super.setContentView(layoutResID)
setupViews()
}
即在指定布局的同时,调用了setupViews方法,回到SplashActivity,可以看到重写了setupViews方法
override fun setupViews() {
startInitRequest()
}
既是开始初始化的网络请求,通过查看 startInitRequest方法(代码太多,不贴了),可以看到是对用户信息的更新和APP版本的判断,连接成功后就将更新后的用户信息用Shared写入XML存储,接着跳转下一个Activity
forwardToNextActivity(hasNewVersion, version)
连接失败则直接赋值没有新版本跳转
forwardToNextActivity(false, null)
因为我们打开一个APP,如果此时没有网络,初始化数据连接不上总不能让APP直接结束吧,因为用户数据更新不是必须。这种后果就是在跳过闪屏Activity后再连接网络,可以跳过版本更新。目前很多APP都是这样
接着查看onCreate方法
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
enterTime = System.currentTimeMillis()
delayToForward()
}
其中System.currentTimeMillis()用于获取系统当前的毫秒数,接着看delayToForward代码
private fun delayToForward() {
Thread(Runnable {
GlobalUtil.sleep(MAX_WAIT_TIME.toLong())
forwardToNextActivity(false, null)
}).start()
}
这也是开头为什么放那段代码的原因,显然闪屏界面是需要停一会的,不停个几秒就会一闪而过,这里设置了闪屏界面停留的最久时间,接着查看forwardToNextActivity里面的代码
val currentTime = System.currentTimeMillis()
val timeSpent = currentTime - enterTime
if (timeSpent < MIN_WAIT_TIME) {
GlobalUtil.sleep(MIN_WAIT_TIME - timeSpent)
}
在onCreate方法时候就记录了enterTime,通过System.currentTimeMillis()记录onCreate到forwardToNextActivity这段时间,如果没有达到跳转的最少时间,则线程继续阻塞。
达到跳转最少时间后,切回UI线程
runOnUiThread {
if (GifFun.isLogin()) {
MainActivity.actionStart(this)
finish()
} else {
if (isActive) {
LoginActivity.actionStartWithTransition(this, logoView, hasNewVersion, version)
} else {
LoginActivity.actionStart(this, hasNewVersion, version)
finish()
}
}
}
接着进行判断,如果曾经登录过,直接跳转MainActivty,没有则跳转LoginActivity,当然,准确的来讲是OpenSourceLoginActivity,可以看LoginActivity代码
private val ACTION_LOGIN = "${
GifFun.getPackageName()}.ACTION_LOGIN"
fun actionStart(activity: Activity, hasNewVersion: Boolean, version: Version?) {
val intent = Intent(ACTION_LOGIN).apply {
putExtra(INTENT_HAS_NEW_VERSION, hasNewVersion)
putExtra(INTENT_VERSION, version)
}
activity.startActivity(intent)
}
接着看opensource模块下的AndroidManifest文件
:name=".OpenSourceLoginActivity"
……>
-filter>
:name="com.quxianggif.opensource.ACTION_LOGIN"/>
:name="android.intent.category.DEFAULT"/>
-filter>
……
>
就是隐式启动Activity
当然,判断是否曾经登录过的方法是GifFunApplication中初始化了initialize方法,而该方法里的refreshLoginState()方式是通过XML读取用户信息进行判断。
如果细心点会发现跳转Activity有些没finish
if (isActive) {
LoginActivity.actionStartWithTransition(this, logoView, hasNewVersion, version)
}
else {
LoginActivity.actionStart(this, hasNewVersion, version)
finish()
}
isActive是BaseActivity中用于判断Activity是否在前台,可以看BaseActivity代码
override fun onResume() {
super.onResume()
isActive = true
MobclickAgent.onResume(this)
}
override fun onPause() {
super.onPause()
isActive = false
MobclickAgent.onPause(this)
}
为什么这样?如果打开APP的同时我按下HOME键了呢?那这样就不需要附带动画跳转了,当然附带动画跳转会发现Activity没有finish。
由于此时闪屏Activity和登录Activity处于共享元素动画状态,需要等待动画加载完成后再结束闪屏Activity
可以看到OpenSourceLoginActivity下的代码
val event = FinishActivityEvent()
event.activityClass = OpenSourceSplashActivity::class.java
EventBus.getDefault().post(event)
并且在SplashActivity中可以看到接收事件
@Subscribe(threadMode = ThreadMode.MAIN)
override fun onMessageEvent(messageEvent: MessageEvent) {
if (messageEvent is FinishActivityEvent) {
if (javaClass == messageEvent.activityClass) {
if (!isFinishing) {
finish()
}
}
}
}
关于SplashActivity和OpenSourceLoginActivity之间动画跳转的解释可以等我更新下一篇博客