imcys.com
遵从中二的召唤,来吧少年!

【Android】利用广播实现动态软件主题切换实现

前言

随着软件的开发,用户的需求也变得多样丰富,在最近的一条反馈里,我注意到了有个需要用户自己设置主题的需求,于是这段时间我就在研究主题的实现。

结果是,复杂的主题变动许多都是在绘制上改动的,这样可以不重启activity,但是代码侵入性很强,而且以我现在的技术也没办法实现。因此,我们采用了另一种方法,利用activty快速重启的方式,在基类的create中完成主题的设置。

实现

用户设置界面

我们在这里为用户提供一个可选的设置列表

如上图,这样用户就可以选择我们提供的主题了。

这里的代码比较简单,就不单独放出来了,我们看看接下来这块。

实现考虑

设想一下,我们切换壁纸后,需要重启当前的活动,还需要重启已经打开了的活动,这样,我们就得考虑在基类管理所有的activity,接到事件后重启并且恢复所有的活动。这样比较麻烦,我们换一种想法。

让每个activity都注册一个广播,当收到广播后,就结束这个活动。当活动重启时,先判断用户选择了什么主题,再进行设置。这样我们就可以很方便的实现这个主题切换了,只是这样的实现有一些痛点。

利用广播通知

我们上面既然已经想好了怎么实现,就开始动手试一试吧。

让我们先在基类定义一个重启当前的活动的函数,如下面所写的。

    open fun updateTheme() {
        //重启activity()
        recreate()
    }

接下来,让我们实现一个广播,这里就叫ThemeChangedBroadcast,让它继承掉BroadcastReceiver。

class ThemeChangedBroadcast : BroadcastReceiver() {
    /**
     * 这里主要是监听主题改变的,转发通知
     * @param context Context
     * @param intent Intent
     */

    override fun onReceive(context: Context, intent: Intent) {
        (context as AbsActivity).updateTheme()
    }
}

这里我们把context转换为了AbsActivity,啊哈,想必你已经知道,要用动态注册广播的方式了。这样我们就可以利用context实现重启当前的activity。

至此,当这里接收到广播后就会调用这个updateTheme函数,重启activity。

广播动态注册

我们得让每个活动都注册这个广播,因此我们还是在基类覆写下面的函数。

    override fun onResume() {
        super.onResume()
        //注册广播
        registerReceiver(
            //这块是主题广播
            mThemeChangedBroadcast,
            IntentFilter("com.imcys.bilibilias.app.THEME_CHANGED")
        )

    }

    override fun onDestroy() {
        super.onDestroy()
        //取消注册(防止泄露)
        unregisterReceiver(mThemeChangedBroadcast)
        // 移除当前活动
        removeActivity(this)
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setTheme()
    }

当启动时注册活动,关闭时取消注册,防止泄露,而这条广播的com.imcys.bilibilias.app.THEME_CHANGED。

而我们在onCreate中调用了另一个函数。

    //检查主题
    private fun setTheme() {
        val theme = PreferenceManager.getDefaultSharedPreferences(this).run {
            getString("app_theme", "System")
        }
        when (theme) {
            "System" -> {
                AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM)
            }
            "Light" -> {
                AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO)
            }
            "Dark" -> {
                AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES)
            }
            "Pink" -> {
                this.setTheme(R.style.Theme_BILIBILIAS)
            }
        }
    }

通过此方法我们可以设置暗夜模式或者亮色模式,以及其他的颜色,由此,我们的主题修改就大功告成了。

文末

此方法虽然解决了动态主题修改的问题,但是仍然存在一些不合理性,我们知道有许多的APP切换主题是不会重启活动的,也就是不会卡一下,更多的办法需要继续探索。以后有机会继续说。

随着软件的开发,用户的需求也变得多样丰富,在最近的一条反馈里,我注意到了有个需要用户自己设置主题的需求,于是这段时间我就在研究主题的实现。

萌新杰少

文章作者

I im CYS,一个热爱二次元的大专开发者

发表回复

textsms
account_circle
email

Captcha Code

萌新杰少の秘密基地

【Android】利用广播实现动态软件主题切换实现
随着软件的开发,用户的需求也变得多样丰富,在最近的一条反馈里,我注意到了有个需要用户自己设置主题的需求,于是这段时间我就在研究主题的实现。
扫描二维码继续阅读
2023-03-01