apache设置了一个简单的字段, {"name":"this is new name"}
viewModel观察retrofit获取的数据,更新给textView
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)
}
})
}
}
}
方法灰色
直接引用也不行
需要详细更改代码参考学习,
定义数据模型 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)
}
})
}
}
}
定义仓库层的统一封装,我的数据只有一个参数,书本的比较多,这里不知道改的对不对,
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的逻辑
书上定义的suspend 修饰的挂起函数的调用需要在协程作用域中才可以调用。具体原因是kotlin 协程,suspend 修饰的函数,反编译之后会在函数最后一位增加一个continue 参数。普通函数无法调用suspend修饰的挂起函数
1.可以添加ViewModleScope 生命周期感知组件依赖。这样的话就可以
fun initData() {
viewModelScope.launch {
_xxxx.value = getAppData()
}
}
将 Kotlin 协程与生命周期感知型组件一起使用 | Android 开发者 | Android Developers
Kotlin的协程能够大大简化传统回调的写法。需要使用suspendCoroutine函数。但是要注意的是suspendCoroutine函数必须在协程作用域或者挂起函数中才能够调用。
在ViewModel中定义一个可观察的字段text,用于保存从网络请求获取到的数据。当数据改变时,通知观察者更新TextView
可以使用suspendCoroutine函数来实现
问题1、简单更改了下方式,小小代码示例:
#在这个示例代码中,await()函数使用了suspendCoroutine()函数来创建一个挂起函数,并将请求加入到线程池中执行。在enqueue()函数中,创建了一个Callback对象来处理请求的响应或失败情况,并通过continuation.resume()或continuation.resumeWithException()函数将结果返回给调用方。
class MainViewModel : ViewModel() {
val counter: LiveData<String>
get() = _counter
private val _counter = MutableLiveData<String>()
private 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)
}
})
}
}
}