从数据源搜索项目时,我有以下 UI 流程:
Outcome.loading(true)Outcome.success(results)Outcome.loading(false)现在的问题是当应用程序在后台时调用 #2 和 #3。恢复应用程序,LiveData 观察者只会收到 #3 而不是 #2 导致未填充 RecyclerView 的通知。
处理这种情况的正确方法是什么?
class SearchViewModel @Inject constructor(
private val dataSource: MusicInfoRepositoryInterface,
private val scheduler: Scheduler,
private val disposables: CompositeDisposable) : ViewModel() {
private val searchOutcome = MutableLiveData<Outcome<List<MusicInfo>>>()
val searchOutcomLiveData: LiveData<Outcome<List<MusicInfo>>>
get() = searchOutcome
fun search(searchText: String) {
Timber.d(".loadMusicInfos")
if(searchText.isBlank()) {
return
}
dataSource.search(searchText)
.observeOn(scheduler.mainThread())
.startWith(Outcome.loading(true))
.onErrorReturn { throwable -> Outcome.failure(throwable) }
.doOnTerminate { searchOutcome.value …Run Code Online (Sandbox Code Playgroud) 可能重复此
我正在用dagger2探索android注射api.所以,在我的示例应用程序中,我ViewModel直接注入了活动; 看看下面的代码片段.
class SampleApp : Application(), HasActivityInjector {
@Inject
lateinit var dispatchingAndroidInjector: DispatchingAndroidInjector<Activity>
override fun activityInjector(): AndroidInjector<Activity> =
dispatchingAndroidInjector
override fun onCreate() {
super.onCreate()
DaggerApplicationComponent.builder()
.application(this)
.build()
.inject(this)
}
}
Run Code Online (Sandbox Code Playgroud)
@Component(modules = [
AndroidInjectionModule::class,
ActivityBindingModule::class,
AppModule::class
/** Other modules **/
])
@Singleton
interface ApplicationComponent {
@Component.Builder
interface Builder {
@BindsInstance
fun application(application: Application): Builder
fun build(): ApplicationComponent
}
fun inject(sampleApp: SampleApp)
}
Run Code Online (Sandbox Code Playgroud)
@Module
public abstract class ActivityBindingModule {
@ContributesAndroidInjector(modules = MainModule.class)
public abstract MainActivity contributeMainActivityInjector();
} …Run Code Online (Sandbox Code Playgroud) android kotlin dagger-2 android-mvvm android-architecture-components
我正在使用MVVM体系结构来构建简单的订购应用程序。我在我的ProductsFragment中使用RecyclerView列出了所有可以订购的产品。我还在ViewModel中使用LiveData,在Fragment中可以观察到它,以检查对产品列表的任何更改。
在我的列表项中,我有3个按钮:1个按钮,用于将产品添加到购物篮中,另一个按钮,用于增加客户想要添加到购物篮中的数量,第三个按钮用于减少客户想要添加到购物篮中的数量。
在我的产品数据类中,每当客户单击增量或减量按钮时,数量都会在数据模型中更新。
我还使用数据绑定将产品绑定到recyclerview列表项布局和Click侦听器。我正在使用ListAdapter开箱即用地访问DiffUtil。
我遇到的问题是,当通知了observable时,我想使用ListAdapter的SubmitList方法,以便在RecyclerView中仅更新已更改的项目。但是,我注意到DiffUtil方法areContentsTheSame()始终返回true。因此,列表项未更新。我不想使用notifyDatasetChanged,因为这会阻塞UI线程。
我遇到的另一个问题是,当我向购物篮中添加产品时,会保留对该产品的引用,因此当我向购物篮中添加产品时,当我只想更新MutableLiveData时,MutableLiveData也将更新。将产品添加到购物篮时,如何停止对正在创建的LiveData的引用?
产品浏览模型
class ProductsViewModel : ViewModel() {
// LIVE DATA
private val _basket = MutableLiveData<Basket>()
val basket: LiveData<Basket>
get() = _basket
private val _products = MutableLiveData<List<Product>>()
val products: LiveData<List<Product>>
get() = _products
init {
_basket.value = Basket()
_products.value = dummyData
}
fun onIncrementProductQuantityButtonPressed(product: Product) {
//product.quantity += 1
//val newList = _products.value
//_products.value = newList
val newProduct = product.copy(quantity = product.quantity.plus(1))
_basket.value!!.updateProductInBasket(newProduct)
_basket.value = _basket.value
}
fun onDecrementProductQuantityButtonPressed(product: Product) {
if (product.quantity>1) {
//product.quantity = …Run Code Online (Sandbox Code Playgroud) android kotlin android-recyclerview android-mvvm android-livedata
我在我的应用程序中使用 MVVM 架构,我想从活动的视图模型类发出 API 请求。这里的问题是我没有得到最好的方法。由于 viewmodel 已经知道该活动的生命周期,所以不需要为 API 制作单独的 viewmodel 类?如果是这样,那么我应该从 viewmodel 类中触发正常的改造请求,或者在这种情况下最好的方法是什么?
我之前在没有 MVVM 的情况下所做的是:
class UserViewModel : ViewModel() {
private val cd = CompositeDisposable()
val status: MutableLiveData<Boolean>? = MutableLiveData<Boolean>()
val responseImages = MutableLiveData<ResponseImages>()
fun getImages(text: String) {
cd.add(
RetrofitHelper.apiInstance.getImages(Site.METHOD, Site.KEY, text)
.myApiSubscriber(status)
.subscribe({
responseImages.postValue(it)
}, {
it.printStackTrace()
})
)
}
private fun <T> Single<T>.myApiSubscriber(status: MutableLiveData<Boolean>?): Single<T> {
return this.doOnSubscribe {
status?.postValue(true)
// Utils.debugger("PROGRESS ", " doOnSubscribe")
}.doFinally {
status?.postValue(false)
// Utils.debugger("PROGRESS ", " doFinally")
}.subscribeOn(Schedulers.io())
}
override fun …Run Code Online (Sandbox Code Playgroud) 我正在Room使用ViewModel. 一切都运转良好。但要求是我想提供一些对ViewModel使用的依赖AndroidViewModelFactory。我能够创建ViewModelFactory实现ViewModelProvider.Factory. 我将一个普通字符串作为 ViewModel 的依赖项传递。工厂类的代码是
public class TestViewModelFactory implements ViewModelProvider.Factory{
private static final String DEFAULT_LIMIT = "4";
static Application application;
static String created="ViewModelFactorySuccess";
public static TestViewModelFactory createFactory(Activity activity) {
application = activity.getApplication();
if (application == null) {
throw new IllegalStateException("Not yet attached to Application");
}
return new TestViewModelFactory(application, created);
}
public TestViewModelFactory(Application application, String created) {
application=application;
created=created;
}
@NonNull
@Override
public <T extends ViewModel> T create(@NonNull Class<T> …Run Code Online (Sandbox Code Playgroud) 为了在 Android 应用程序中使用,我基本上是为&viewbinding创建基类,以删除每次编写膨胀代码的样板。ActivityFragment
活动:
BaseActivity和viewbinding:
abstract class BaseActivity<VB : ViewBinding> : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = getViewBinding()
}
abstract fun getViewBinding(): VB
}
Run Code Online (Sandbox Code Playgroud)
MainActivity:
class MainActivity : BaseActivity<ActivityMainBinding>() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(binding.root)
//we can directly use binding now and it works fine inside activity
//binding.view.doSomething()
}
override fun getViewBinding(): ActivityMainBinding = ActivityMainBinding.inflate(layoutInflater)
}
Run Code Online (Sandbox Code Playgroud)
片段:
BaseFragment:
abstract class BaseFragment<VB : ViewBinding> : …Run Code Online (Sandbox Code Playgroud) 我收到此错误:无法访问主线程上的数据库,因为它可能会长时间锁定 UI。当我在 ViewModel 中启动有趣的turnAllWordsOn() 时,就会发生这种情况(代码如下)。这个函数启动协程,我认为协程总是在后台线程上工作。那么为什么我会收到此错误?感谢任何帮助
在片段中:
override fun onOptionsItemSelected(item: MenuItem): Boolean {
return when (item.itemId) {
R.id.action_turn_all_words_on -> {
viewModel.turnAllWordsOn()
true
}
// othes items
}
Run Code Online (Sandbox Code Playgroud)
在视图模型中:
fun turnAllWordsOn() = viewModelScope.launch {
wordDao.turnAllWordsOn()
}
Run Code Online (Sandbox Code Playgroud)
在道中:
@Query("UPDATE word_table SET shown = 1")
fun turnAllWordsOn()
Run Code Online (Sandbox Code Playgroud) 我正在开发一个 Android Compose 项目,其中使用 Paging 3 和 LazyColumn 来显示从网络调用获取的项目列表。Paging 3 的默认行为是根据prefetchDistance用户滚动来加载页面,但在我的例子中,它会加载大约 15 个页面,每个页面在屏幕启动时包含 10 条记录。我尝试过将其设置prefetchDistace为 10,但不起作用。
这是我的代码: ViewModel
class ShowAllNotificationsViewModel @Inject constructor(private val pagingSource: NotificationPagingSource) :
BaseViewModel() {
private val _uiState =
MutableStateFlow<UIState<BaseResponseModel<NotificationResponseModel?>>>(UIState.StateLoading)
val uiState = _uiState.asStateFlow()
private val _isRefreshing = MutableStateFlow(false)
val isRefreshing = _isRefreshing.asStateFlow()
val items: Flow<PagingData<NotificationModel>> = Pager(
config = PagingConfig(
pageSize = 10,
prefetchDistance = 5,
enablePlaceholders = false,
),
pagingSourceFactory = { pagingSource }
)
.flow
.cachedIn(viewModelScope)
fun refreshData() {
pagingSource.invalidate() …Run Code Online (Sandbox Code Playgroud) android android-mvvm android-paging android-jetpack-compose android-paging-3
我已经用MVVM模式实现了DataBinding,这是我的ViewModel课程。
public class MainViewModel extends BaseObservable {
private String data, data1;
@Bindable
public String getData1() {
return data1;
}
public void setData1(String data1) {
this.data1 = data1;
}
@Bindable
public String getData() {
return data;
}
public void setData(String data) {
this.data = data;
notifyPropertyChanged(BR.data);
}
}
Run Code Online (Sandbox Code Playgroud)
现在的问题是,我可以看到BR.data有,但没能获得BR.data1,如何使用notifyPropertyChanged()的data1变量。
我曾尝试清理该项目,也尝试过重建它,但并没有帮助我。
这是我的build.gradle档案
android {
compileSdkVersion 23
buildToolsVersion "23.0.2"
dataBinding {
enabled = true
}
defaultConfig {
...
...
}
buildTypes …Run Code Online (Sandbox Code Playgroud) 所以我正在使用 Dagger 开发一些示例 MVVM 项目。我有一个视图模型工厂,如下所示:
class DaggerViewModelFactory @Inject constructor(private val viewModelsMap: Map<Class<out ViewModel>, @JvmSuppressWildcards Provider<ViewModel>>) :
ViewModelProvider.Factory {
override fun <T : ViewModel> create(modelClass: Class<T>): T {
val creator = viewModelsMap[modelClass] ?:
viewModelsMap.asIterable().firstOrNull {
modelClass.isAssignableFrom(it.key)
}?.value ?: throw IllegalArgumentException("unknown model class $modelClass")
return try {
creator.get() as T
} catch (e: Exception) {
throw RuntimeException(e)
}
}
}
Run Code Online (Sandbox Code Playgroud)
视图模型工厂模块
@Module
abstract class ViewModelFactoryModule {
@Binds
abstract fun bindViewModelFactory(viewModelFactory: DaggerViewModelFactory): ViewModelProvider.Factory
}
Run Code Online (Sandbox Code Playgroud)
我有一个 ViewModelModule:
@Module
abstract class MyViewModelModule {
@Binds
@IntoMap …Run Code Online (Sandbox Code Playgroud) android-mvvm ×10
android ×9
kotlin ×5
mvvm ×3
dagger-2 ×2
android-architecture-components ×1
android-room ×1
dagger ×1
data-binding ×1
rx-android ×1
rx-java2 ×1