Android Handler Looper 深色主题行为
Android Handler Looper Dark Theme behavior
我在 Handler(Looper.getMainLooper()) 中遇到了有趣的行为。如果我的应用程序主题 (day/night) 设置为不同于 OS 设置,它会执行两次。例如,如果在设备设置中关闭深色模式并且我的应用程序 MainActivity 应用深色主题,那么 MainActivity 会启动两次。我没有找到任何关于为什么会发生的解释。
SplashActivity很简单
class SplashActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.splash_screen_layout)
Handler(Looper.getMainLooper()).postDelayed({
val intent = Intent(this, MainActivity::class.java)
startActivity(intent)
Log.i("SPLASH","Main activity started")
finish()
}, 2000)
}
}
Main Activity 有以下功能来检查应用程序设置中保存的主题并应用它:
函数
private fun checkDarkMode(){
when (MainSettings(this).darkMode) {
0 -> {
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM)
delegate.applyDayNight()
}
1 -> {
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO)
delegate.applyDayNight()
}
2 -> {
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES)
delegate.applyDayNight()
}
}
}
因此,如果在设备设置中关闭暗模式,那么处理程序代码将为 AppCompatDelegate.MODE_NIGHT_YES 执行两次,而对于其他人则按预期执行一次。
反之亦然,如果设备处于关闭状态,则代码会执行两次 AppCompatDelegate.MODE_NIGHT_NO。
正如我所说,我没有找到任何解释或解决方案,所以我所做的只是将处理程序定义为 val,并在 onPause 或 onDestroy 的 SplashActivity
中取消了它的所有内容
private val handler = Handler(Looper.getMainLooper())
override fun onPause() {
super.onPause()
handler.removeCallbacksAndMessages(null)
}
所以我的问题是为什么会发生这种情况,还有其他方法可以避免这种情况吗?
我会看一下 AppCompatDelegate
的源代码,它是 here(在第 201 行附近为它重新创建 activity 的部分做了很多工作)。
我无法为您的问题提供直接的解决方案,但另一种方法是仅继承 DayNight
主题之一(尽管您确实无法在下面的任何内容上使用夜间主题 Android 10,但在我看来这让事情变得容易多了)。
编辑:您可以在 Application
class 中执行您的 checkDarkMode
方法,这应该有望在创建任何活动之前设置正确的模式(从而避免它们被更改时再次创建)。
public class MyApplication extends Application {
public void onCreate() {
super.onCreate();
checkDarkMode()
}
我在 Handler(Looper.getMainLooper()) 中遇到了有趣的行为。如果我的应用程序主题 (day/night) 设置为不同于 OS 设置,它会执行两次。例如,如果在设备设置中关闭深色模式并且我的应用程序 MainActivity 应用深色主题,那么 MainActivity 会启动两次。我没有找到任何关于为什么会发生的解释。
SplashActivity很简单
class SplashActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.splash_screen_layout)
Handler(Looper.getMainLooper()).postDelayed({
val intent = Intent(this, MainActivity::class.java)
startActivity(intent)
Log.i("SPLASH","Main activity started")
finish()
}, 2000)
}
}
Main Activity 有以下功能来检查应用程序设置中保存的主题并应用它:
函数
private fun checkDarkMode(){
when (MainSettings(this).darkMode) {
0 -> {
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM)
delegate.applyDayNight()
}
1 -> {
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO)
delegate.applyDayNight()
}
2 -> {
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES)
delegate.applyDayNight()
}
}
}
因此,如果在设备设置中关闭暗模式,那么处理程序代码将为 AppCompatDelegate.MODE_NIGHT_YES 执行两次,而对于其他人则按预期执行一次。
反之亦然,如果设备处于关闭状态,则代码会执行两次 AppCompatDelegate.MODE_NIGHT_NO。
正如我所说,我没有找到任何解释或解决方案,所以我所做的只是将处理程序定义为 val,并在 onPause 或 onDestroy 的 SplashActivity
中取消了它的所有内容private val handler = Handler(Looper.getMainLooper())
override fun onPause() {
super.onPause()
handler.removeCallbacksAndMessages(null)
}
所以我的问题是为什么会发生这种情况,还有其他方法可以避免这种情况吗?
我会看一下 AppCompatDelegate
的源代码,它是 here(在第 201 行附近为它重新创建 activity 的部分做了很多工作)。
我无法为您的问题提供直接的解决方案,但另一种方法是仅继承 DayNight
主题之一(尽管您确实无法在下面的任何内容上使用夜间主题 Android 10,但在我看来这让事情变得容易多了)。
编辑:您可以在 Application
class 中执行您的 checkDarkMode
方法,这应该有望在创建任何活动之前设置正确的模式(从而避免它们被更改时再次创建)。
public class MyApplication extends Application {
public void onCreate() {
super.onCreate();
checkDarkMode()
}