manager: Fixed flickering on activity refresh using a clever method.
- Add Activity lifecycle callback and method to refresh current Activity
This commit is contained in:
@@ -1,11 +1,14 @@
|
|||||||
package com.sukisu.ultra
|
package com.sukisu.ultra
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
|
import android.app.Activity
|
||||||
|
import android.app.ActivityOptions
|
||||||
import android.app.Application
|
import android.app.Application
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.res.Configuration
|
import android.content.res.Configuration
|
||||||
import android.content.res.Resources
|
import android.content.res.Resources
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
|
import android.os.Bundle
|
||||||
import coil.Coil
|
import coil.Coil
|
||||||
import coil.ImageLoader
|
import coil.ImageLoader
|
||||||
import com.dergoogler.mmrl.platform.Platform
|
import com.dergoogler.mmrl.platform.Platform
|
||||||
@@ -14,9 +17,31 @@ import me.zhanghai.android.appiconloader.coil.AppIconKeyer
|
|||||||
import java.io.File
|
import java.io.File
|
||||||
import java.util.Locale
|
import java.util.Locale
|
||||||
|
|
||||||
|
@SuppressLint("StaticFieldLeak")
|
||||||
lateinit var ksuApp: KernelSUApplication
|
lateinit var ksuApp: KernelSUApplication
|
||||||
|
|
||||||
class KernelSUApplication : Application() {
|
class KernelSUApplication : Application() {
|
||||||
|
private var currentActivity: Activity? = null
|
||||||
|
|
||||||
|
private val activityLifecycleCallbacks = object : ActivityLifecycleCallbacks {
|
||||||
|
override fun onActivityCreated(activity: Activity, savedInstanceState: Bundle?) {
|
||||||
|
currentActivity = activity
|
||||||
|
}
|
||||||
|
override fun onActivityStarted(activity: Activity) {
|
||||||
|
currentActivity = activity
|
||||||
|
}
|
||||||
|
override fun onActivityResumed(activity: Activity) {
|
||||||
|
currentActivity = activity
|
||||||
|
}
|
||||||
|
override fun onActivityPaused(activity: Activity) {}
|
||||||
|
override fun onActivityStopped(activity: Activity) {}
|
||||||
|
override fun onActivitySaveInstanceState(activity: Activity, outState: Bundle) {}
|
||||||
|
override fun onActivityDestroyed(activity: Activity) {
|
||||||
|
if (currentActivity == activity) {
|
||||||
|
currentActivity = null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun attachBaseContext(base: Context) {
|
override fun attachBaseContext(base: Context) {
|
||||||
val prefs = base.getSharedPreferences("settings", MODE_PRIVATE)
|
val prefs = base.getSharedPreferences("settings", MODE_PRIVATE)
|
||||||
@@ -62,6 +87,9 @@ class KernelSUApplication : Application() {
|
|||||||
super.onCreate()
|
super.onCreate()
|
||||||
ksuApp = this
|
ksuApp = this
|
||||||
|
|
||||||
|
// 注册Activity生命周期回调
|
||||||
|
registerActivityLifecycleCallbacks(activityLifecycleCallbacks)
|
||||||
|
|
||||||
Platform.setHiddenApiExemptions()
|
Platform.setHiddenApiExemptions()
|
||||||
|
|
||||||
val context = this
|
val context = this
|
||||||
@@ -107,4 +135,17 @@ class KernelSUApplication : Application() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
// 添加刷新当前Activity的方法
|
||||||
|
fun refreshCurrentActivity() {
|
||||||
|
currentActivity?.let { activity ->
|
||||||
|
val intent = activity.intent
|
||||||
|
activity.finish()
|
||||||
|
|
||||||
|
val options = ActivityOptions.makeCustomAnimation(
|
||||||
|
activity, android.R.anim.fade_in, android.R.anim.fade_out
|
||||||
|
)
|
||||||
|
activity.startActivity(intent, options.toBundle())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -44,127 +44,170 @@ class MainActivity : ComponentActivity() {
|
|||||||
|
|
||||||
private lateinit var themeChangeObserver: ThemeChangeContentObserver
|
private lateinit var themeChangeObserver: ThemeChangeContentObserver
|
||||||
|
|
||||||
|
// 添加标记避免重复初始化
|
||||||
|
private var isInitialized = false
|
||||||
|
|
||||||
override fun attachBaseContext(newBase: Context) {
|
override fun attachBaseContext(newBase: Context) {
|
||||||
val context = LocaleUtils.applyLocale(newBase)
|
val context = LocaleUtils.applyLocale(newBase)
|
||||||
super.attachBaseContext(context)
|
super.attachBaseContext(context)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
// 确保应用正确的语言设置
|
try {
|
||||||
LocaleUtils.applyLanguageSetting(this)
|
// 确保应用正确的语言设置
|
||||||
|
LocaleUtils.applyLanguageSetting(this)
|
||||||
|
|
||||||
// 应用自定义 DPI
|
// 应用自定义 DPI
|
||||||
DisplayUtils.applyCustomDpi(this)
|
DisplayUtils.applyCustomDpi(this)
|
||||||
|
|
||||||
// Enable edge to edge
|
// Enable edge to edge
|
||||||
enableEdgeToEdge()
|
enableEdgeToEdge()
|
||||||
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
||||||
window.isNavigationBarContrastEnforced = false
|
window.isNavigationBarContrastEnforced = false
|
||||||
|
}
|
||||||
|
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
|
||||||
|
// 使用标记控制初始化流程
|
||||||
|
if (!isInitialized) {
|
||||||
|
initializeViewModels()
|
||||||
|
initializeData()
|
||||||
|
isInitialized = true
|
||||||
|
}
|
||||||
|
|
||||||
|
setContent {
|
||||||
|
KernelSUTheme {
|
||||||
|
val navController = rememberNavController()
|
||||||
|
val snackBarHostState = remember { SnackbarHostState() }
|
||||||
|
val currentDestination = navController.currentBackStackEntryAsState().value?.destination
|
||||||
|
|
||||||
|
val showBottomBar = when (currentDestination?.route) {
|
||||||
|
ExecuteModuleActionScreenDestination.route -> false
|
||||||
|
else -> true
|
||||||
|
}
|
||||||
|
|
||||||
|
LaunchedEffect(Unit) {
|
||||||
|
initPlatform()
|
||||||
|
}
|
||||||
|
|
||||||
|
CompositionLocalProvider(
|
||||||
|
LocalSnackbarHost provides snackBarHostState
|
||||||
|
) {
|
||||||
|
Scaffold(
|
||||||
|
bottomBar = {
|
||||||
|
AnimatedBottomBar.AnimatedBottomBarWrapper(
|
||||||
|
showBottomBar = showBottomBar,
|
||||||
|
content = { BottomBar(navController) }
|
||||||
|
)
|
||||||
|
},
|
||||||
|
contentWindowInsets = WindowInsets(0, 0, 0, 0)
|
||||||
|
) { innerPadding ->
|
||||||
|
DestinationsNavHost(
|
||||||
|
modifier = Modifier.padding(innerPadding),
|
||||||
|
navGraph = NavGraphs.root as NavHostGraphSpec,
|
||||||
|
navController = navController,
|
||||||
|
defaultTransitions = NavigationUtils.defaultTransitions()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (e: Exception) {
|
||||||
|
e.printStackTrace()
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
super.onCreate(savedInstanceState)
|
private fun initializeViewModels() {
|
||||||
|
|
||||||
// 初始化 SuperUserViewModel
|
|
||||||
superUserViewModel = SuperUserViewModel()
|
superUserViewModel = SuperUserViewModel()
|
||||||
|
|
||||||
lifecycleScope.launch {
|
|
||||||
superUserViewModel.fetchAppList()
|
|
||||||
}
|
|
||||||
|
|
||||||
// 初始化 HomeViewModel
|
|
||||||
homeViewModel = HomeViewModel()
|
homeViewModel = HomeViewModel()
|
||||||
|
|
||||||
// 预加载数据
|
// 设置主题变化监听器
|
||||||
|
themeChangeObserver = ThemeUtils.registerThemeChangeObserver(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun initializeData() {
|
||||||
lifecycleScope.launch {
|
lifecycleScope.launch {
|
||||||
homeViewModel.initializeData()
|
try {
|
||||||
|
superUserViewModel.fetchAppList()
|
||||||
|
} catch (e: Exception) {
|
||||||
|
e.printStackTrace()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
lifecycleScope.launch {
|
||||||
|
try {
|
||||||
|
homeViewModel.initializeData()
|
||||||
|
} catch (e: Exception) {
|
||||||
|
e.printStackTrace()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 数据刷新协程
|
// 数据刷新协程
|
||||||
DataRefreshUtils.startDataRefreshCoroutine(lifecycleScope)
|
DataRefreshUtils.startDataRefreshCoroutine(lifecycleScope)
|
||||||
|
|
||||||
DataRefreshUtils.startSettingsMonitorCoroutine(lifecycleScope, this, settingsStateFlow)
|
DataRefreshUtils.startSettingsMonitorCoroutine(lifecycleScope, this, settingsStateFlow)
|
||||||
|
|
||||||
// 初始化主题相关设置
|
// 初始化主题相关设置
|
||||||
ThemeUtils.initializeThemeSettings(this, settingsStateFlow)
|
ThemeUtils.initializeThemeSettings(this, settingsStateFlow)
|
||||||
|
|
||||||
// 设置主题变化监听器
|
|
||||||
themeChangeObserver = ThemeUtils.registerThemeChangeObserver(this)
|
|
||||||
|
|
||||||
val isManager = AppData.isManager(ksuApp.packageName)
|
val isManager = AppData.isManager(ksuApp.packageName)
|
||||||
if (isManager) {
|
if (isManager) {
|
||||||
install()
|
install()
|
||||||
UltraToolInstall.tryToInstall()
|
UltraToolInstall.tryToInstall()
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
setContent {
|
override fun onResume() {
|
||||||
KernelSUTheme {
|
try {
|
||||||
val navController = rememberNavController()
|
super.onResume()
|
||||||
val snackBarHostState = remember { SnackbarHostState() }
|
LocaleUtils.applyLanguageSetting(this)
|
||||||
val currentDestination = navController.currentBackStackEntryAsState().value?.destination
|
ThemeUtils.onActivityResume()
|
||||||
|
|
||||||
val showBottomBar = when (currentDestination?.route) {
|
// 仅在需要时刷新数据
|
||||||
ExecuteModuleActionScreenDestination.route -> false // Hide for ExecuteModuleActionScreen
|
if (isInitialized) {
|
||||||
else -> true
|
refreshData()
|
||||||
}
|
}
|
||||||
|
} catch (e: Exception) {
|
||||||
|
e.printStackTrace()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// pre-init platform to faster start WebUI X activities
|
private fun refreshData() {
|
||||||
LaunchedEffect(Unit) {
|
lifecycleScope.launch {
|
||||||
initPlatform()
|
try {
|
||||||
}
|
superUserViewModel.fetchAppList()
|
||||||
|
homeViewModel.initializeData()
|
||||||
CompositionLocalProvider(
|
DataRefreshUtils.refreshData(lifecycleScope)
|
||||||
LocalSnackbarHost provides snackBarHostState
|
} catch (e: Exception) {
|
||||||
) {
|
e.printStackTrace()
|
||||||
Scaffold(
|
|
||||||
bottomBar = {
|
|
||||||
AnimatedBottomBar.AnimatedBottomBarWrapper(
|
|
||||||
showBottomBar = showBottomBar,
|
|
||||||
content = { BottomBar(navController) }
|
|
||||||
)
|
|
||||||
},
|
|
||||||
contentWindowInsets = WindowInsets(0, 0, 0, 0)
|
|
||||||
) { innerPadding ->
|
|
||||||
DestinationsNavHost(
|
|
||||||
modifier = Modifier.padding(innerPadding),
|
|
||||||
navGraph = NavGraphs.root as NavHostGraphSpec,
|
|
||||||
navController = navController,
|
|
||||||
defaultTransitions = NavigationUtils.defaultTransitions()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onPause() {
|
override fun onPause() {
|
||||||
super.onPause()
|
try {
|
||||||
ThemeUtils.onActivityPause(this)
|
super.onPause()
|
||||||
}
|
ThemeUtils.onActivityPause(this)
|
||||||
|
} catch (e: Exception) {
|
||||||
override fun onResume() {
|
e.printStackTrace()
|
||||||
super.onResume()
|
|
||||||
LocaleUtils.applyLanguageSetting(this)
|
|
||||||
ThemeUtils.onActivityResume()
|
|
||||||
|
|
||||||
lifecycleScope.launch {
|
|
||||||
superUserViewModel.fetchAppList()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
lifecycleScope.launch {
|
|
||||||
homeViewModel.initializeData()
|
|
||||||
}
|
|
||||||
|
|
||||||
DataRefreshUtils.refreshData(lifecycleScope)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onDestroy() {
|
override fun onDestroy() {
|
||||||
ThemeUtils.unregisterThemeChangeObserver(this, themeChangeObserver)
|
try {
|
||||||
super.onDestroy()
|
ThemeUtils.unregisterThemeChangeObserver(this, themeChangeObserver)
|
||||||
|
super.onDestroy()
|
||||||
|
} catch (e: Exception) {
|
||||||
|
e.printStackTrace()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onConfigurationChanged(newConfig: Configuration) {
|
override fun onConfigurationChanged(newConfig: Configuration) {
|
||||||
super.onConfigurationChanged(newConfig)
|
try {
|
||||||
LocaleUtils.applyLanguageSetting(this)
|
super.onConfigurationChanged(newConfig)
|
||||||
|
LocaleUtils.applyLanguageSetting(this)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
e.printStackTrace()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -90,6 +90,7 @@ import androidx.compose.material3.TextButton
|
|||||||
import androidx.compose.runtime.saveable.rememberSaveable
|
import androidx.compose.runtime.saveable.rememberSaveable
|
||||||
import androidx.compose.ui.unit.sp
|
import androidx.compose.ui.unit.sp
|
||||||
import com.ramcosta.composedestinations.navigation.DestinationsNavigator
|
import com.ramcosta.composedestinations.navigation.DestinationsNavigator
|
||||||
|
import com.sukisu.ultra.ksuApp
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author ShirkNeko
|
* @author ShirkNeko
|
||||||
@@ -388,14 +389,7 @@ fun MoreSettingsScreen(
|
|||||||
@Suppress("DEPRECATION")
|
@Suppress("DEPRECATION")
|
||||||
context.resources.updateConfiguration(config, context.resources.displayMetrics)
|
context.resources.updateConfiguration(config, context.resources.displayMetrics)
|
||||||
}
|
}
|
||||||
|
ksuApp.refreshCurrentActivity()
|
||||||
val intent = Intent(context, MainActivity::class.java)
|
|
||||||
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK or Intent.FLAG_ACTIVITY_NEW_TASK)
|
|
||||||
context.startActivity(intent)
|
|
||||||
|
|
||||||
if (context is Activity) {
|
|
||||||
context.finish()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user