我试图从ViewModel异步获取所有可启动的已安装应用程序。
这是我的ViewModel类,看起来像:
class AppInstalledViewModel(application: Application) : AndroidViewModel(application) {
private var appInstalledLiveData: LiveData<ArrayList<AppInstalled>>? = null
fun getAppInstalledLiveData(): LiveData<ArrayList<AppInstalled>> {
if (appInstalledLiveData == null) {
appInstalledLiveData = liveData {
val appInstalled = ArrayList<AppInstalled>()
val pm: PackageManager =
getApplication<Application>().applicationContext.packageManager
val main = Intent(Intent.ACTION_MAIN, null).addCategory(Intent.CATEGORY_LAUNCHER)
// Get launchable installed apps
val launchAble = pm.queryIntentActivities(main, 0)
// Sort the installed app list
Collections.sort(launchAble, ResolveInfo.DisplayNameComparator(pm))
// Iterate over each launchable app and
// add it to AppInstalled ArrayList
for (l in launchAble) {
val activityInfo = l.activityInfo
activityInfo.run {
appInstalled.add(
AppInstalled(
loadLabel(pm).toString(),
applicationInfo.packageName,
loadIcon(pm)
)
)
}
}
emit(appInstalled)
}
}
return appInstalledLiveData as LiveData<ArrayList<AppInstalled>>
}
}
加载应用程序列表没有问题。 但是,似乎我的代码仍然没有异步运行,因为它仍然冻结了几秒钟,然后移动到应用程序安装列表activity。
这是我用来观察LiveData的代码:
appInstalledViewModel.getAppInstalledLiveData().observe(this, Observer { appInstalledItem ->
if (appInstalledItem.size > 0) {
appInstalledAdapter.appInstalled.addAll(appInstalledItem)
app_list_progressbar.visibility = View.GONE
}
})
我对在Android开发中使用Kotlin感到很困惑。 这是我第一次使用Kotlin开发应用程序。 我甚至不知道我上面写的代码在Kotlin风格的上下文中是不是一个好代码。
请帮帮我! 谢谢!
这是因为在main
Dispatcher中执行长时间运行的作业。 我强烈建议看看Coroutines Dispatchers。
因此,如果您将dispatcher更改为Dispatchers.default
,导致获取在后台线程中执行的已安装应用程序,因此UI将永远不会被冻结。
appInstalledLiveData = liveData(Dispatchers.Default) {
...
}
更多:
如果您想要获得更好的结构,最好不要通过调用函数访问LiveData
:
class AppInstalledViewModel(application: Application) : AndroidViewModel(application) {
private val reloadLiveData = MutableLiveData<Unit>()
val installedAppsLiveData: LiveData<ArrayList<AppInstalled>> =
reloadLiveData.switchMap {
liveData(Dispatchers.Default) {
emit(fetchInstalledApps())
}
}
fun reloadApps() {
reloadLiveData.postValue(Unit)
}
private fun fetchInstalledApps(): ArrayList<AppInstalled> {
val appInstalled = ArrayList<AppInstalled>()
val pm: PackageManager = getApplication<Application>().applicationContext.packageManager
val main = Intent(Intent.ACTION_MAIN, null).addCategory(Intent.CATEGORY_LAUNCHER)
// Get launchable installed apps
val launchAble = pm.queryIntentActivities(main, 0)
// Sort the installed app list
Collections.sort(launchAble, ResolveInfo.DisplayNameComparator(pm))
// Iterate over each launchable app and
// add it to AppInstalled ArrayList
for (l in launchAble) {
val activityInfo = l.activityInfo
activityInfo.run {
appInstalled.add(
AppInstalled(
loadLabel(pm).toString(),
applicationInfo.packageName,
loadIcon(pm)
)
)
}
}
return appInstalled
}
}
现在,在片段中:
appInstalledViewModel.installedAppsLiveData.observe(this, Observer { appInstalledItem ->
if (appInstalledItem.size > 0) {
appInstalledAdapter.appInstalled.addAll(appInstalledItem)
app_list_progressbar.visibility = View.GONE
}
})
appInstalledViewModel.reloadApps()
使用这种结构,如果您想要刷新加载的数据,只需调用AppInstalledViewModel.reloAdapps()
即可,然后应用程序列表将得到更新。