在 kotlin 中使用 Mvvm 和 Retrofit 以及 Rxjava 实时数据的问题



我是 kotlin 的新手,我正在尝试使用 Rxjava 和 MVVM 架构中的实时数据进行改造。 我配置了改造,并在 ViewModel 中使用可观察和订阅来制作可观察变量以在活动绑定布局中使用。 我的视图中有一个按钮,当我单击它时,请求方法开始并订阅写入其自己的数据日志。但是我的变量一开始就为 null,几秒钟后,当改造完成其任务时,我的变量会获取数据,但日志值不会更新。

这是我的改造初始化类

class ApiService {
private val INSTANCE =
Retrofit.Builder()
.baseUrl("http://www.janbarar.ir/App/")
.addConverterFactory(GsonConverterFactory.create())
.build()
.create(IRetrofitMethods::class.java)

private fun <T> callBack(iDataTransfer: IDataTransfer<T>) =
object : Callback<T> {
override fun onResponse(call: Call<T>, response: Response<T>) {
val data = response.body()
if (data != null)
iDataTransfer.onSuccess(data)
else
try {
throw Exception("data is empty")
} catch (ex: Exception) {
iDataTransfer.onError(ex)
}
}
override fun onFailure(call: Call<T>, t: Throwable) {
iDataTransfer.onError(t)
}
}
fun getCategories(iDataTransfer: IDataTransfer<List<Category>>) =
INSTANCE.getCategories().enqueue(callBack(iDataTransfer))

这是一个用于改造的接口

@GET("GetCategories")
fun getCategories(): Call<List<Category>>

这是我的模型班。我认为问题就在这里。因为可观察量在改造完成其工作之前发送空数据。

fun getCategories(): Observable<ArrayList<Category>> {
val result = arrayListOf<Category>()
api.getCategories(object : IDataTransfer<List<Category>> {
override fun onSuccess(data: List<Category>) {
result.addAll(data)
}
override fun onError(throwable: Throwable) {
Log.e("Model", throwable.message!!)
}
})
return Observable.just(result)
}

这也是我的视图模型类

class ProductViewModel(private val model: ProductModel) : ViewModel() {
var isLoading = ObservableField(false)
var categoryList = MutableLiveData<ArrayList<Category>>()
private var compositeDisposable = CompositeDisposable()
fun getCategories() {
isLoading.set(true)
compositeDisposable +=
model.getCategories()
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe({
categoryList.value = it
}, {
Log.e("ViewModel", it.message.toString())
})
isLoading.set(false)
}

最后,这是我的活动

lateinit var binding: ActivityMainBinding
private val vm: ProductViewModel by viewModel()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = DataBindingUtil.setContentView(this, R.layout.activity_main)
binding.vm = vm
vm.categoryList.observe(this, Observer {
if (it != null)
Log.e("activity", it.toString())
})   
}

正如 ExpensiveBelly 在评论中提到的,Retrofit 为 RxJava 提供了一个调用适配器,因此您可以让您的 API 直接返回Observable<List<Category>>。 为此,您需要将 RxJava 调用适配器依赖项添加到应用模块的build.gradle

implementation 'com.squareup.retrofit2:adapter-rxjava2:(version)'

在构造Retrofit实例时添加调用适配器工厂:

private val INSTANCE =
Retrofit.Builder()
.baseUrl("http://www.janbarar.ir/App/")
.addCallAdapterFactory(RxJava2CallAdapterFactory.create()) // add this
.addConverterFactory(GsonConverterFactory.create())
.build()
.create(IRetrofitMethods::class.java)

然后让你的服务直接返回一个可观察量:

@GET("GetCategories")
fun getCategories(): Observable<List<Category>>

如果ApiService需要在应用程序的其余部分获得响应之前执行一些处理,则可以使用 RxJava 运算符,如map


了解为什么您的代码不起作用以及如何修复它将是说明性的。 当您调用api.getCategories(someCallback)时,将在将来的某个时候调用您的一个回调方法。 同时,model.getCategories()方法将立即返回。

当您订阅返回的Observable时,它会发出result变量,该变量当前为空列表。result最终会有一些数据,但你的代码根本不会被告知这一点。

您真正想做的是在类别列表可用时发出它。 从回调 API 获取Observable的标准方法是使用Observable.create

fun getCategories(): Observable<ArrayList<Category>> {
return Observable.create { emitter -> 
api.getCategories(object : IDataTransfer<List<Category>> {
override fun onSuccess(data: List<Category>) {
emitter.onNext(data)
emitter.onComplete()
}
override fun onError(throwable: Throwable) {
emitter.onError(throwable)
}
})
}
}

当然,如果可能的话,最好只使用RxJava2CallAdapterFactory,因为这项工作已经在那里完成。

相关内容

最新更新