GifFun源码学习(2):SplashActivity的分析

前言:闪屏界面在许多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之间动画跳转的解释可以等我更新下一篇博客

你可能感兴趣的:(Android)