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

问题描述 投票:0回答:1

我是kotlin的新手,我试图在MVVM架构中使用Rxjava和实时数据的retrofit.我配置了retrofit,并在ViewModel中使用observable和subscribe来制作observable变量以用于活动绑定布局.我在我的视图中有一个按钮,当我点击它时,请求方法开始和subscribe写下它自己的数据日志.但我的变量一开始是空的,几秒钟后,当retrofit完成它的任务时,我的变量得到了数据,但日志值没有更新.

这是我的retrofit初始化类

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>>

这是我的模型类。我想问题出在这里,因为在retrofit完成工作之前,observable会发送null数据,而这也是我的ViewModel类。

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)
    }

这也是我的ViewModel类

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())
        })   
    }
kotlin mvvm observable retrofit2 rx-java2
1个回答
0
投票

正如ExpensiveBelly在评论中提到的那样,Retrofit为RxJava提供了一个调用适配器,所以你可以让你的API回到 Observable<List<Category>> 直接调用。 要做到这一点,您需要将 RxJava 调用适配器依赖性添加到您的应用程序模块的 build.gradle:

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

在构建你的 Retrofit 实例,然后直接让你的服务返回一个Observable:。

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

然后让你的服务直接返回一个Observable。

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

If ApiService 需要在应用程序的其余部分获得响应之前进行一些处理,您可以使用 RxJava 操作符,如 map.


这将说明为什么你的代码不能工作以及如何修复它。 当你调用 api.getCategories(someCallback),你的一个回调方法将在未来的某个时刻被调用。 在这段时间里,你的 model.getCategories() 方法将立即返回。

当你订阅返回的 Observable,它发出了 result 变量,目前是一个空列表。 result 最终会有一些数据在其中,但你的代码根本不会被告知这些。

你真正想做的是在类别列表可用时发出它。 标准的方法是获取一个 Observable 从回调API是用 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 如果可能的话,因为这项工作已经在那里进行了。

© www.soinside.com 2019 - 2024. All rights reserved.