[英]How to start Kotlin Coroutine in ViewModel with LiveData
I was trying to get all launchable installed apps asynchronously from ViewModel
.我试图从
ViewModel
异步获取所有可启动的已安装应用程序。
This is my ViewModel
class looks like:这是我的
ViewModel
class 看起来像:
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>>
}
}
There is no problem with loading the app list.加载应用列表没有问题。 But, it seems that my code still not run asynchronously because it still freezes for a very few seconds before moving to the app installed list activity.
但是,我的代码似乎仍然没有异步运行,因为它在移动到应用程序安装列表活动之前仍然冻结了几秒钟。
And this is the code I use to observe the LiveData
:这是我用来观察
LiveData
的代码:
appInstalledViewModel.getAppInstalledLiveData().observe(this, Observer { appInstalledItem ->
if (appInstalledItem.size > 0) {
appInstalledAdapter.appInstalled.addAll(appInstalledItem)
app_list_progressbar.visibility = View.GONE
}
})
I'm so confusing trying to use Kotlin on Android Development.尝试在 Android 开发中使用 Kotlin 让我很困惑。 This is my first time developing an app using Kotlin.
这是我第一次使用 Kotlin 开发应用程序。 I don't even know if the code I wrote above is a good code in the context of Kotlin's style.
我什至不知道我上面写的代码在 Kotlin 风格的上下文中是否是一个好的代码。
Please help me!请帮我! Thank you!
谢谢!
It is because of executing the long-running job in Main
dispatcher.这是因为在
Main
调度程序中执行了长时间运行的作业。 I highly recommend taking a look at Coroutines Dispatchers .我强烈推荐看看Coroutines Dispatchers 。
So, if you change the dispatcher to Dispatchers.Default
, leading to fetch installed apps executing in a background thread, consequently, the UI will never be frozen.因此,如果您将调度程序更改为
Dispatchers.Default
,导致获取已安装的应用程序在后台线程中执行,因此,UI 将永远不会被冻结。
appInstalledLiveData = liveData(Dispatchers.Default) {
...
}
More:更多的:
If you want to achieve a better structure, it could be even better not accessing the LiveData
by calling a function:如果您想获得更好的结构,最好不要通过调用 function 来访问
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
}
}
Now, in the fragment:现在,在片段中:
appInstalledViewModel.installedAppsLiveData.observe(this, Observer { appInstalledItem ->
if (appInstalledItem.size > 0) {
appInstalledAdapter.appInstalled.addAll(appInstalledItem)
app_list_progressbar.visibility = View.GONE
}
})
appInstalledViewModel.reloadApps()
Using this structure, if you want to refresh the loaded data, it's just enough to call appInstalledViewModel.reloadApps()
, then the list of apps gets updated.使用这种结构,如果要刷新加载的数据,只需调用
appInstalledViewModel.reloadApps()
,然后更新应用列表。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.