【问题标题】:Unable to get callback from LiveData through retrofit call via CustomCallAdapterFactory kotlin无法通过 CustomCallAdapterFactory kotlin 通过改造调用从 LiveData 获取回调
【发布时间】:2020-01-10 11:49:03
【问题描述】:

我是 MVVVM 的新手,我按照 Google 的 GihubBrowser 示例实施改造将 LiveData 回调,但我无法使用此实施对 rerofit 请求进行排队。请帮助我做错了什么:

存储库

class LoginRepository(var application: Application) {


    var result = MutableLiveData<Resource<GenericResponse>>()


    fun iniateOTPprocess()  {

        result = object : NetworkBoundResource<GenericResponse, GenericResponse>() {

            override fun createCall() = RetroUtils.getApiManager().listRepos()

            override fun processResponse(response: ApiSuccessResponse<GenericResponse>)
                    : GenericResponse {
                val body = response.body
                return body
            }
        }.asLiveData()
    }


    fun getData(): MutableLiveData<Resource<GenericResponse>> {
        return result
    }
}

视图模型

class LoginViewModel2(application: Application) : AndroidViewModel(application) {


    lateinit var username: MutableLiveData<String>
    lateinit var password: MutableLiveData<String>
    var repository: LoginRepository = LoginRepository(application)
    var data = MediatorLiveData<Resource<GenericResponse>>()


    init {
        data.addSource(repository.getData(), Observer {
            data.postValue(it)
        })
    }


    fun onLoginBtnCLicked() {
        initiateOTP()
    }


    private fun initiateOTP() {
        repository.iniateOTPprocess()
    }


    fun getResponse() : MutableLiveData<Resource<GenericResponse>>{
        return data
    }


}   

下面提到的是适配器

class LiveDataCallAdapter<R>(private val responseType: Type) :
    CallAdapter<R, LiveData<ApiResponse<R>>> {

    override fun responseType() = responseType

    override fun adapt(call: Call<R>): LiveData<ApiResponse<R>> {
        return object : LiveData<ApiResponse<R>>() {
            private var started = AtomicBoolean(false)
            override fun onActive() {
                super.onActive()
                if (started.compareAndSet(false, true)) {
                    call.enqueue(object : Callback<R> {
                        override fun onResponse(call: Call<R>, response: Response<R>) {
                            postValue(ApiResponse.create(response))
                        }

                        override fun onFailure(call: Call<R>, throwable: Throwable) {
                            postValue(ApiResponse.create(throwable))
                        }
                    })
                }
            }
        }
    }
}

活动

  class LoginActivity2 : AppCompatActivity() {


lateinit var binding: LoginViewBinding;
lateinit var vModel: LoginViewModel2;


override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    binding = DataBindingUtil.setContentView(this, R.layout.login_view)
    binding.setLifecycleOwner(this)
    vModel = ViewModelProviders.of(this).get(LoginViewModel2::class.java)
    binding.loginViewModel = vModel



    vModel.getResponse().observe(this, Observer { t ->

        Log.e("data", t?.data.toString() ?: "Data is null")


    })

}


}

请注意这不是重复的

Retrofit LiveDataCallAdapter doesn't call function adapt (call)

如果我直接在 viewmodel 中直接观察 initialOTP() 方法,我可以使这段代码工作,但这样 API 将被命中,甚至无需点击我不想要的按钮。

请提出最佳方法。提前致谢。

【问题讨论】:

    标签: android kotlin mvvm retrofit2 android-livedata


    【解决方案1】:

    每次调用iniateOTPprocess() 都会创建一个新的result,因此观察旧的没有用。试试这个:

    存储库

    class LoginRepository(var application: Application) {
    
        // remove this
        // var result = MutableLiveData<Resource<GenericResponse>>()
    
        fun initiateOtpProcess(): LiveData<Resource<GenericResponse>> {
    
            return object : NetworkBoundResource<GenericResponse, GenericResponse>() {
    
                override fun createCall() = RetroUtils.getApiManager().listRepos()
    
                override fun processResponse(response: ApiSuccessResponse<GenericResponse>)
                        : GenericResponse {
                    val body = response.body
                    return body
                }
            }.asLiveData()
        }
    
        // remove this as well
        // fun getData(): MutableLiveData<Resource<GenericResponse>>
    }
    

    在之前的Repository 设计中,initiateOTPprocessgetData 必须按顺序调用。相反,让initiateOtpProcess 返回一个LiveData

    视图模型

    class LoginViewModel2(application: Application) : AndroidViewModel(application) {
    
        lateinit var username: MutableLiveData<String>
        lateinit var password: MutableLiveData<String>
        val repository: LoginRepository = LoginRepository(application)
        val data = MediatorLiveData<Resource<GenericResponse>>()
    
        var currentOtpSource: LiveData<Resource<GenericResponse>>()
    
    
        // init {
        //    data.addSource(repository.getData(), Observer {
        //        data.postValue(it)
        //    })
        //}
    
    
        fun onLoginBtnCLicked() {
            initiateOTP()
        }
    
    
        private fun initiateOTP() {
            currentOtpSource?.let {
                // remove previous source if any
                data.removeSource(it)
            }
    
            newSource = repository.iniateOTPprocess()
            currentOtpSource = newSource
    
            data.addSource(newSource, Observer {
                data.setValue(it)
            })
        }
    
    
        fun getResponse() : LiveData<Resource<GenericResponse>>{
            return data
        }
    }
    

    【讨论】:

    • 虽然我没有运行这段代码,但我理解的是currentOTPsource的作用是保持对数据源的引用,以便在需要时可以从数据livedata中删除。
    • @HarrySharma 请发布您的片段/活动代码,您调用getResponse()onLoginBtnClicked() 的部分。
    • 我也加了。
    • 尝试登录并查看是哪个部分导致了问题。你得到一个空数据,还是你根本没有得到任何事件?请描述哪个部分不起作用。
    • 我总是得到空数据。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-09-15
    • 2019-02-04
    • 2021-10-15
    • 1970-01-01
    相关资源
    最近更新 更多