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

viewModel加载网络图片

添加coil库,在MainActivity中加载图片,简单好用

img


然后我是想通过viewModel来更新图片的,但没法在viewModel中使用load(),请教正确的用法

img


MainViewModel.kt

package com.example.retrofittest

import android.content.res.Resources
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.switchMap

class MainViewModel : ViewModel() {

    val imageId: LiveData<Resources>
        get() = _imageId

    private val _imageId = MutableLiveData<Resources>()

  //  load()爆红了
    init {
        _imageId.value = load("http://pic-bucket.ws.126.net/photo/0010/2022-11-22/HMP3UMG2POUR0010NOS.png")
    }

}

如果没法像MainActivity中那样使用load()的话,那只能改用retrofit访问使用了.但是我在viewModel中不知道该怎么写具体的代码.

img


图片的数据模型 ImageResponse.kt, image: Resources用这个参数对了吗?

package com.example.retrofittest

import android.content.res.Resources

data class ImageResponse(val image: Resources)

访问接口 ImageService.kt

package com.example.retrofittest

import retrofit2.Call
import retrofit2.http.GET

interface ImageService {
    @GET("photo/0010/2022-11-22/HMP3UMG2POUR0010NOS.png")
    fun getImageData(): Call<ImageResponse>
}

retrofit构建器 ServiceCreator.kt

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

object ServiceCreator {
    private const val BASE_URL = "http://pic-bucket.ws.126.net/"

    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 kotlin.coroutines.resume
import kotlin.coroutines.resumeWithException
import kotlin.coroutines.suspendCoroutine

object AppNetwork {

    private val imageService = ServiceCreator.create<ImageService>()
    suspend fun imageApp() = imageService.getImageData().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)
                }
            })
        }
    }
}

仓库层的统一封装入口

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

// 定义仓库层的统一封装入口  Repository.kt
object Repository {

    fun imageApp() = liveData(Dispatchers.IO) {
        val result = try {
            val imagerResponse = AppNetwork.imageApp()
            val images = imagerResponse.image
            Result.success(images)
        } catch (e: Exception) {
            Result.failure<ImageResponse>(e)
        }
        emit(result)
    }
}
  • 写回答

2条回答 默认 最新

  • 泡沫o0 2023年度博客之星上海赛道TOP 1 2023-06-24 18:11
    关注

    在你的情况下,你应该在ViewModel中处理数据加载,然后在Activity或者Fragment中处理数据的显示。你不能在ViewModel中直接使用Coil的load()方法,因为这个方法是用来在View中加载图片的,而ViewModel不应该直接与View交互。

    你可以在ViewModel中使用Retrofit或者其他网络库来加载图片数据,然后将这个数据暴露给Activity或者Fragment。然后,在Activity或者Fragment中,你可以使用Coil的load()方法来加载这个数据。

    你的ImageResponse类应该包含一个表示图片URL的字符串字段,而不是一个Resources对象。你可以像下面这样修改你的ImageResponse类:

    data class ImageResponse(val imageUrl: String)
    

    然后,你可以在你的ViewModel中使用Retrofit来加载这个ImageResponse对象,然后将imageUrl字段暴露给Activity或者Fragment:

    class MainViewModel : ViewModel() {
     
        val imageUrl: LiveData<String>
            get() = _imageUrl
     
        private val _imageUrl = MutableLiveData<String>()
     
        init {
            // 使用Retrofit加载图片数据
            // 假设你已经在其他地方定义了一个Retrofit的实例和一个ImageService的实例
            val call = imageService.getImageData()
            call.enqueue(object : Callback<ImageResponse> {
                override fun onResponse(call: Call<ImageResponse>, response: Response<ImageResponse>) {
                    if (response.isSuccessful) {
                        val imageResponse = response.body()
                        if (imageResponse != null) {
                            _imageUrl.value = imageResponse.imageUrl
                        }
                    }
                }
     
                override fun onFailure(call: Call<ImageResponse>, t: Throwable) {
                    // 处理错误
                }
            })
        }
    }
    

    然后,在你的Activity或者Fragment中,你可以观察这个imageUrl字段,并使用Coil的load()方法来加载图片:

    viewModel.imageUrl.observe(this, Observer { imageUrl ->
        imageView.load(imageUrl)
    })
    

    这样,你就可以在ViewModel中处理数据加载,然后在Activity或者Fragment中处理数据的显示了。

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(1条)

报告相同问题?

问题事件

  • 已结题 (查看结题原因) 7月29日
  • 已采纳回答 7月29日
  • 创建了问题 6月24日

悬赏问题

  • ¥20 Java-Oj-桌布的计算
  • ¥15 请问如何在openpcdet上对KITTI数据集的测试集进行结果评估?
  • ¥15 powerbuilder中的datawindow数据整合到新的DataWindow
  • ¥20 有人知道这种图怎么画吗?
  • ¥15 pyqt6如何引用qrc文件加载里面的的资源
  • ¥15 安卓JNI项目使用lua上的问题
  • ¥20 RL+GNN解决人员排班问题时梯度消失
  • ¥60 要数控稳压电源测试数据
  • ¥15 能帮我写下这个编程吗
  • ¥15 ikuai客户端l2tp协议链接报终止15信号和无法将p.p.p6转换为我的l2tp线路