双进程交互实现App自动重启

背景

你可能会好奇,有些手游(比如王者荣耀)是怎么实现资源更新后自动重启的?

这个体验确实不错,因为不需要用户手动点击桌面图标重启App,在一些数据恢复备份的场景中,很实用。比如,从云端拉取SQLite数据库db文件或一些prefs配置文件后,会直接覆盖到本地,但进程不重新启动的话,是不会生效的。

思路

基本思路其实很简单,利用Android应用对多进程的天然支持,来实现双进程互拉。

有的朋友一看见"双进程"、"互拉"这些词汇就会立马联想到保活,注意本文不是讲保活的哦。

为了方便讲解,我们定义主进程之外的另一个进程为 进程B。大致流程分这么几步:

  • 在主进程执行完一系列业务逻辑后,欲重启,先拉起进程B
  • 进程B启动后,主进程kill掉自己
  • 接着,进程B拉起主进程,然后再kill掉自己,此时主进程完成自动重启

实现

先在Manifest中声明进程B,为了良好的交互体验,需要实现一个Activity,进程名称自定义,比如此处叫"killer",是不是很贴切?

xml 复制代码
        <activity
            android:name=".KillerActivity"
            android:exported="false"
            android:launchMode="singleTask"
            android:process=":killer" />

关键实现来了:

kotlin 复制代码
class KillerActivity : FragmentActivity() {

    companion object {
        private const val EXTRA_MAIN_PID = "extra_main_pid"

        // 当主进程需要重启时,就直接调用此方法启动KillerActivity
        fun launch(activity: FragmentActivity) {
            activity.startActivity(
                Intent(activity, KillerActivity::class.java).apply {
                    putExtra(EXTRA_MAIN_PID, Process.myPid())
                }
            )
            activity.finish() // 主进程的Activity先关闭
            GlobalScope.launch {
                // 稍作延迟后,主进程kill掉自己
                delay(500L)
                killProcess()
            }
        }

        fun killProcess(pid: Int = Process.myPid()) {
            Process.killProcess(pid)
            exitProcess(0)
        }

        fun isMainProcessAlive(context: Context): Boolean = runCatching {
            (context.getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager)
                .runningAppProcesses.find { it.processName == context.packageName } != null
        }.getOrDefault(false)
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        lifecycleScope.launch {
            // 此处可以插入一些Loading的UI显示,比如ProgressDialog之类的
            // ...
            
            // 二次检查,防止主进程没杀掉
            doubleCheckMainProcess()
            // 稍作等待后,再次启动主进程的Activity
            startActivity(Intent(this, MainActivity::class.java).apply {
                addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK or Intent.FLAG_ACTIVITY_NEW_TASK)
            })
            
            // 进程B的KillerActivity先关闭,再kill掉自己
            finish()
            killProcess()
        }
    }

    private suspend fun doubleCheckMainProcess() {
        delay(1500L)
        if (isMainProcessAlive(this)) {
            val mainPid = intent.getIntExtra(EXTRA_MAIN_PID, 0)
            if (mainPid != 0) {
                killProcess(mainPid)
                delay(1500L)
            }
        }
    }
}

整个代码非常简单,只要搞清楚 killProcess 方法哪些时候是kill的哪个进程,就理解了。在任意一个需要重启当前进程(可以不只是主进程)的地方,调用:

kotlin 复制代码
KillerActivity.launch(this)  

即可。

相关推荐
yueqc129 分钟前
Kotlin 协程 Flow 操作符总结
kotlin·协程·flow
fanged2 小时前
天马G前端的使用
android·游戏
molong9316 小时前
Kotlin 内联函数、高阶函数、扩展函数
android·开发语言·kotlin
叶辞树8 小时前
Android framework调试和AMS等服务调试
android
慕伏白10 小时前
【慕伏白】Android Studio 无线调试配置
android·ide·android studio
低调小一10 小时前
Kuikly 小白拆解系列 · 第1篇|两棵树直调(Kotlin 构建与原生承载)
android·开发语言·kotlin
跟着珅聪学java10 小时前
spring boot 整合 activiti 教程
android·java·spring
川石课堂软件测试12 小时前
全链路Controller压测负载均衡
android·运维·开发语言·python·mysql·adb·负载均衡
2501_9159214312 小时前
iOS 26 电耗监测与优化,耗电问题实战 + 多工具 辅助策略
android·macos·ios·小程序·uni-app·cocoa·iphone
2501_9159214313 小时前
苹果软件混淆与 iOS 应用加固白皮书,IPA 文件加密、反编译防护与无源码混淆方案全解析
android·ios·小程序·https·uni-app·iphone·webview