Skip to content

Commit 265b3d9

Browse files
committed
perf: app info list
1 parent 0f03bcd commit 265b3d9

File tree

7 files changed

+45
-48
lines changed

7 files changed

+45
-48
lines changed

app/src/main/kotlin/li/songe/gkd/MainActivity.kt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -125,9 +125,11 @@ class MainActivity : ComponentActivity() {
125125
activityVisibleFlow.update { it + 1 }
126126
}
127127

128+
var isFirstResume = true
128129
override fun onResume() {
129130
super.onResume()
130-
if (startTime - app.startTime < 2000) {
131+
if (isFirstResume && startTime - app.startTime < 2000) {
132+
isFirstResume = false
131133
return
132134
}
133135
syncFixState()

app/src/main/kotlin/li/songe/gkd/permission/PermissionState.kt

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -255,17 +255,17 @@ fun startQueryPkgSettingActivity(context: Activity) {
255255
}
256256

257257
fun updatePermissionState() {
258+
val stateChanged = canQueryPkgState.stateFlow.value != canQueryPkgState.updateAndGet()
259+
if (!updateAppMutex.mutex.isLocked && (stateChanged || mayQueryPkgNoAccessFlow.value)) {
260+
appScope.launchTry(Dispatchers.IO) {
261+
initOrResetAppInfoCache()
262+
}
263+
}
258264
arrayOf(
259265
notificationState,
260266
canDrawOverlaysState,
261267
canWriteExternalStorage,
262268
writeSecureSettingsState,
263269
shizukuOkState,
264270
).forEach { it.updateAndGet() }
265-
val stateChanged = canQueryPkgState.stateFlow.value != canQueryPkgState.updateAndGet()
266-
if (!updateAppMutex.mutex.isLocked && (stateChanged || mayQueryPkgNoAccessFlow.value)) {
267-
appScope.launchTry(Dispatchers.IO) {
268-
initOrResetAppInfoCache()
269-
}
270-
}
271271
}

app/src/main/kotlin/li/songe/gkd/ui/AppConfigPage.kt

Lines changed: 5 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,6 @@ import com.ramcosta.composedestinations.utils.toDestinationsNavigator
5353
import kotlinx.coroutines.delay
5454
import kotlinx.coroutines.flow.update
5555
import li.songe.gkd.data.RawSubscription
56-
import li.songe.gkd.data.Value
5756
import li.songe.gkd.ui.component.AnimationFloatingActionButton
5857
import li.songe.gkd.ui.component.AppNameText
5958
import li.songe.gkd.ui.component.BatchActionButtonGroup
@@ -77,6 +76,7 @@ import li.songe.gkd.util.launchAsFn
7776
import li.songe.gkd.util.storeFlow
7877
import li.songe.gkd.util.switchItem
7978
import li.songe.gkd.util.throttle
79+
import java.util.Objects
8080

8181
@Destination<RootGraph>(style = ProfileTransitions::class)
8282
@Composable
@@ -87,16 +87,10 @@ fun AppConfigPage(appId: String) {
8787
val ruleSortType by vm.ruleSortTypeFlow.collectAsState()
8888
val groupSize by vm.groupSizeFlow.collectAsState()
8989
val firstLoading by vm.linkLoad.firstLoadingFlow.collectAsState()
90-
val scrollBehavior = TopAppBarDefaults.enterAlwaysScrollBehavior()
91-
val listState = key(groupSize > 0) { rememberLazyListState() }
92-
val isFirstVisit = remember { Value(true) }
93-
LaunchedEffect(ruleSortType.value) {
94-
if (isFirstVisit.value) {
95-
isFirstVisit.value = false
96-
} else {
97-
listState.scrollToItem(0)
98-
}
99-
}
90+
val resetKey = Objects.hash(groupSize > 0, ruleSortType.value)
91+
val scrollBehavior = key(resetKey) { TopAppBarDefaults.enterAlwaysScrollBehavior() }
92+
val listState = key(resetKey) { rememberLazyListState() }
93+
10094
val isSelectedMode = vm.isSelectedModeFlow.collectAsState().value
10195
val selectedDataSet = vm.selectedDataSetFlow.collectAsState().value
10296
LaunchedEffect(key1 = isSelectedMode) {

app/src/main/kotlin/li/songe/gkd/ui/GlobalGroupExcludePage.kt

Lines changed: 3 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -113,18 +113,9 @@ fun GlobalGroupExcludePage(subsItemId: Long, groupKey: Int) {
113113
vm.searchStrFlow.value = ""
114114
}
115115
})
116-
val scrollBehavior = TopAppBarDefaults.enterAlwaysScrollBehavior()
117-
val listState = rememberLazyListState()
118-
var isFirstVisit by remember { mutableStateOf(true) }
119-
LaunchedEffect(
120-
key1 = showAppInfos.mapHashCode { it.id },
121-
) {
122-
if (isFirstVisit) {
123-
isFirstVisit = false
124-
} else {
125-
listState.scrollToItem(0)
126-
}
127-
}
116+
val resetKey = showAppInfos.mapHashCode { it.id }
117+
val scrollBehavior = key(resetKey) { TopAppBarDefaults.enterAlwaysScrollBehavior() }
118+
val listState = key(resetKey) { rememberLazyListState() }
128119
var expanded by remember { mutableStateOf(false) }
129120
val softwareKeyboardController = LocalSoftwareKeyboardController.current
130121
Scaffold(modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection), topBar = {

app/src/main/kotlin/li/songe/gkd/ui/SubsAppListPage.kt

Lines changed: 5 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ import androidx.compose.runtime.Composable
2929
import androidx.compose.runtime.LaunchedEffect
3030
import androidx.compose.runtime.collectAsState
3131
import androidx.compose.runtime.getValue
32+
import androidx.compose.runtime.key
3233
import androidx.compose.runtime.mutableStateOf
3334
import androidx.compose.runtime.remember
3435
import androidx.compose.runtime.saveable.rememberSaveable
@@ -95,21 +96,13 @@ fun SubsAppListPage(
9596
vm.searchStrFlow.value = ""
9697
}
9798
})
98-
val scrollBehavior = TopAppBarDefaults.enterAlwaysScrollBehavior()
99+
val resetKey = appAndConfigs.mapHashCode { it.first.id }
100+
val scrollBehavior = key(resetKey) { TopAppBarDefaults.enterAlwaysScrollBehavior() }
101+
val listState = key(resetKey) { rememberLazyListState() }
99102
var expanded by remember { mutableStateOf(false) }
100103
val showUninstallApp by vm.showUninstallAppFlow.collectAsState()
101104
val sortType by vm.sortTypeFlow.collectAsState()
102-
val listState = rememberLazyListState()
103-
var isFirstVisit by remember { mutableStateOf(true) }
104-
LaunchedEffect(
105-
key1 = appAndConfigs.mapHashCode { it.first.id }
106-
) {
107-
if (isFirstVisit) {
108-
isFirstVisit = false
109-
} else {
110-
listState.scrollToItem(0)
111-
}
112-
}
105+
113106
val softwareKeyboardController = LocalSoftwareKeyboardController.current
114107
Scaffold(
115108
modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection),

app/src/main/kotlin/li/songe/gkd/ui/home/AppListPage.kt

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -93,8 +93,9 @@ fun useAppListPage(): ScaffoldExt {
9393
null
9494
}
9595
val showSearchBar by vm.showSearchBarFlow.collectAsState()
96-
val listState = key(orderedAppInfos.mapHashCode { it.id }) { rememberLazyListState() }
97-
val scrollBehavior = TopAppBarDefaults.enterAlwaysScrollBehavior()
96+
val resetKey = orderedAppInfos.mapHashCode { it.id }
97+
val scrollBehavior = key(resetKey) { TopAppBarDefaults.enterAlwaysScrollBehavior() }
98+
val listState = key(resetKey) { rememberLazyListState() }
9899
return ScaffoldExt(
99100
navItem = appListNav,
100101
modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection),

app/src/main/kotlin/li/songe/gkd/util/AppInfoState.kt

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import li.songe.gkd.app
2222
import li.songe.gkd.appScope
2323
import li.songe.gkd.data.AppInfo
2424
import li.songe.gkd.data.toAppInfo
25+
import li.songe.gkd.permission.canQueryPkgState
2526

2627
val userAppInfoMapFlow = MutableStateFlow(emptyMap<String, AppInfo>())
2728
val allPackageInfoMapFlow = MutableStateFlow(emptyMap<Int, List<PackageInfo>>())
@@ -47,13 +48,15 @@ val orderedAppInfosFlow by lazy {
4748
}
4849
}
4950

51+
private fun Map<String, AppInfo>.getMayQueryPkgNoAccess(): Boolean {
52+
return values.count { a -> !a.isSystem && !a.hidden && a.id != META.appId } < MINIMUM_NORMAL_APP_SIZE
53+
}
54+
5055
// https://github.com/orgs/gkd-kit/discussions/761
5156
// 某些设备在应用更新后出现权限错乱/缓存错乱
5257
private const val MINIMUM_NORMAL_APP_SIZE = 8
5358
val mayQueryPkgNoAccessFlow by lazy {
54-
userAppInfoMapFlow.map(appScope) { c ->
55-
c.values.count { a -> !a.isSystem && !a.hidden && a.id != META.appId } < MINIMUM_NORMAL_APP_SIZE
56-
}
59+
userAppInfoMapFlow.map(appScope) { it.getMayQueryPkgNoAccess() }
5760
}
5861

5962
private val willUpdateAppIds by lazy { MutableStateFlow(emptySet<String>()) }
@@ -131,14 +134,27 @@ suspend fun initOrResetAppInfoCache() = updateAppMutex.withLock {
131134
}
132135
}
133136
}
137+
if (!canQueryPkgState.updateAndGet() || appMap.getMayQueryPkgNoAccess()) {
138+
withContext(Dispatchers.IO) {
139+
app.packageManager.queryIntentActivities(
140+
Intent(Intent.ACTION_MAIN),
141+
0
142+
).map { it.activityInfo.packageName }.toSet().forEach { appId ->
143+
if (!appMap.contains(appId)) {
144+
getAppInfo(appId)?.let {
145+
appMap[appId] = it
146+
}
147+
}
148+
}
149+
}
150+
}
134151
userAppInfoMapFlow.value = appMap
135152
LogUtils.d("initOrResetAppInfoCache end ${oldAppIds.size}->${appMap.size}")
136153
}
137154

138155
fun initAppState() {
139156
packageReceiver
140157
appScope.launchTry(Dispatchers.IO) {
141-
initOrResetAppInfoCache()
142158
willUpdateAppIds.debounce(1000)
143159
.filter { it.isNotEmpty() }
144160
.collect { updateAppInfo(it) }

0 commit comments

Comments
 (0)