adsl9002 2023-06-18 15:08 采纳率: 46.2%
浏览 50
已结题

viewModel观察retrofit数据

apache设置了一个简单的字段, {"name":"this is new name"}
viewModel观察retrofit获取的数据,更新给textView

img


MainActivity.kt

class MainActivity : AppCompatActivity() {

    private lateinit var viewModel: MainViewModel

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        viewModel = ViewModelProvider(this)[MainViewModel::class.java]

        val textView: TextView = findViewById(R.id.textView)
        viewModel.counter.observe(this) { current ->
            textView.text = current
        }

        val btn: Button = findViewById(R.id.btn)
        btn.setOnClickListener {
            val intent = Intent(this, SecondActivity::class.java)
            startActivity(intent)
        }
}

MainViewModel.kt

import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.switchMap
import retrofit2.Call
import retrofit2.Callback
import retrofit2.Response

class MainViewModel : ViewModel() {
    val counter: LiveData<String>
        get() = _counter

    private val _counter = MutableLiveData<String>()
   
    init {
        val appService = ServiceCreator.create<AppService>()
        appService.getAppData().enqueue(object : Callback<App> {
            override fun onResponse(call: Call<App>, response: Response<App>) {
                val ponSe = response.body()
                if (ponSe != null) {
                    _counter.value = ponSe.name
                }
            }

            override fun onFailure(call: Call<App>, t: Throwable) {
                t.printStackTrace()
            }
        })
    }
}

问题①,使用协程简化回调,按书本方法不对,该如何正确使用.

class MainViewModel : ViewModel() {
    val counter: LiveData<String>
        get() = _counter

    private val _counter = MutableLiveData<String>()
    
    private suspend fun <T> Call<T>.await(): T {
        return suspendCoroutine { continuation ->
            enqueue(object : Callback<T> {
                override fun onResponse(call: Call<T>, response: Response<T>) {
                    val body = response.body()
                    if (body != null) continuation.resume(body)
                    else continuation.resumeWithException(
                        RuntimeException("response body is null")
                    )
                }

                override fun onFailure(call: Call<T>, t: Throwable) {
                    continuation.resumeWithException(t)
                }
            })
        }
    }
}

img


方法灰色

img


直接引用也不行

img


问题②,按书本的MVVM架构继续搭建,到了后两步按书大致意思修改但没写对,

需要详细更改代码参考学习,

定义数据模型 App.kt

class App (val name: String)

访问接口 AppService.kt

import retrofit2.Call
import retrofit2.http.GET

interface AppService {
    @GET("get_data.json")
    fun getAppData(): Call<App>
}

retrofit构建器 ServiceCreator.kt

import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory

object ServiceCreator {
    private const val BASE_URL = "http://10.0.2.2"

    private val retrofit = Retrofit.Builder()
        .baseUrl(BASE_URL)
        .addConverterFactory(GsonConverterFactory.create())
        .build()

    fun <T> create(serviceClass: Class<T>): T = retrofit.create(serviceClass)
    inline fun <reified T> create(): T = create(T::class.java)
}

定义统一的数据源访问入口,AppNetwork.kt

import retrofit2.Call
import retrofit2.Callback
import retrofit2.Response
import retrofit2.await
import kotlin.coroutines.resume
import kotlin.coroutines.resumeWithException
import kotlin.coroutines.suspendCoroutine

object AppNetwork {
    private val appService = ServiceCreator.create<AppService>()

    suspend fun searchApp() = appService.getAppData().await()

    private suspend fun <T> Call<T>.await(): T {
        return suspendCoroutine { continuation ->
            enqueue(object : Callback<T> {
                override fun onResponse(call: Call<T>, response: Response<T>) {
                    val body = response.body()
                    if (body != null) continuation.resume(body)
                    else continuation.resumeWithException(
                        RuntimeException("response body is null")
                    )
                }

                override fun onFailure(call: Call<T>, t: Throwable) {
                    continuation.resumeWithException(t)
                }
            })
        }
    }
}

定义仓库层的统一封装,我的数据只有一个参数,书本的比较多,这里不知道改的对不对,

img


Repository.kt

import androidx.lifecycle.liveData
import kotlinx.coroutines.Dispatchers

object Repository {
    fun searchApp(query: @JvmSuppressWildcards String) = liveData(Dispatchers.IO) {
        val result = try {
            val searchResponse = AppNetwork.searchApp()
            Result.success(searchResponse)
        } catch (e: Exception) {
            Result.failure<App>(e)
        }
        emit(result)
    }
}

书本viewModel的逻辑

img


MainViewModel.kt,这里的逻辑没写对

img


MativityAtivity也没正常引用

img

  • 写回答

5条回答 默认 最新

  • 灯塔@kuaidao 2023-06-18 20:02
    关注
    获得7.50元问题酬金

    书上定义的suspend 修饰的挂起函数的调用需要在协程作用域中才可以调用。具体原因是kotlin 协程,suspend 修饰的函数,反编译之后会在函数最后一位增加一个continue 参数。普通函数无法调用suspend修饰的挂起函数

    1.可以添加ViewModleScope 生命周期感知组件依赖。这样的话就可以

      fun initData() {
            viewModelScope.launch {
               
                _xxxx.value =  getAppData()
            }
        }
    
    

    将 Kotlin 协程与生命周期感知型组件一起使用  |  Android 开发者  |  Android Developers

    评论

报告相同问题?

问题事件

  • 系统已结题 6月26日
  • 创建了问题 6月18日

悬赏问题

  • ¥15 powerbuilder中的datawindow数据整合到新的DataWindow
  • ¥20 有人知道这种图怎么画吗?
  • ¥15 pyqt6如何引用qrc文件加载里面的的资源
  • ¥15 安卓JNI项目使用lua上的问题
  • ¥20 RL+GNN解决人员排班问题时梯度消失
  • ¥60 要数控稳压电源测试数据
  • ¥15 能帮我写下这个编程吗
  • ¥15 ikuai客户端l2tp协议链接报终止15信号和无法将p.p.p6转换为我的l2tp线路
  • ¥15 phython读取excel表格报错 ^7个 SyntaxError: invalid syntax 语句报错
  • ¥20 @microsoft/fetch-event-source 流式响应问题