我不知道是用改造还是毕加索来得到这张照片
最好使用Picasso,否则如果使用Retrofit下载图片,则必须编写大量代码才能有效加载图片。
您会很高兴知道您可以同时使用 Retrofit 和 Picasso,具体取决于您从该 API 加载图像的选择。
在继续举例之前,我想澄清一件事,即您有一个误解,即您需要将上述 JSON 数据作为标头发送,但在使用 API 之后,我发现它需要JSON 作为请求正文。
示例
RemoteApi.kt
interface RemoteApi {
// Retrofit
@Streaming // Important
@POST("/api/DownloadFileForAndroid")
@Throws(Exception::class)
suspend fun getImage(@Body body: ImageRequest): ResponseBody?
companion object {
// Retrofit
fun create(): RemoteApi {
val retrofit = Retrofit.Builder()
.addConverterFactory(GsonConverterFactory.create())
.baseUrl("http://shop.atiafkar.ir")
.build()
return retrofit.create(RemoteApi::class.java)
}
// Picasso
fun getPicassoImageRequest(
builder : Picasso.Builder,
body: String,
url: String = "http://shop.atiafkar.ir/api/DownloadFileForAndroid"
) = builder.downloader(OkHttp3Downloader(getPicassoCallFactory(body)))
.build()
.load(url)
// Picasso
private fun getPicassoCallFactory(jsonBody : String): Call.Factory {
return Call.Factory { request ->
OkHttpClient().run {
RequestBody.create(MediaType.parse("application/json"), jsonBody).let {
newCall(request.newBuilder()
.post(it)
.addHeader("Content-Type", "application/json")
.build()
)
}
}
}
}
}
}
ImageRepository.kt
class ImageRepository(private val api: RemoteApi = RemoteApi.create()) {
companion object {
fun get() = ImageRepository()
}
// Retrofit
suspend fun downloadImage(body : ImageRequest = ImageRequest.default): Bitmap? {
return api.getImage(body)?.run {
withContext(Dispatchers.IO) {
bytes().let {
// to load bitmap efficiently follow the guideline provided by -
// https://developer.android.com/topic/performance/graphics/load-bitmap
// otherwise you may experience OutOfMemoryException
BitmapFactory.decodeByteArray(it, 0, it.size)
}
}
}
}
// Picasso
fun getPicassoImageLoader(
builder : Picasso.Builder,
body: ImageRequest = ImageRequest.default
) = RemoteApi.getPicassoImageRequest(builder, body.toJson())
}
ImageViewModel.kt
class ImageViewModel(private val repository: ImageRepository) : ViewModel() {
private val _progress = MutableLiveData<Boolean>()
val progress = _progress
// Retrofit
val liveImage = liveData {
_progress.value = true
emit(repository.downloadImage())
_progress.value = false
}
// Picasso
fun getPicassoImageLoader(builder: Picasso.Builder) = repository.getPicassoImageLoader(builder)
}
最后,
ImageActivity.kt
class ImageActivity : AppCompatActivity() {
private lateinit var dataBinding : ActivityImageBinding
private val imageViewModel by lazy { ViewModelProviders.of(this, ImageViewModelFactory()).get(ImageViewModel::class.java) }
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
dataBinding = DataBindingUtil.setContentView(this, R.layout.activity_image)
dataBinding.lifecycleOwner = this
dataBinding.viewModel = imageViewModel
// Retrofit
imageViewModel.liveImage.observe(this, Observer {
dataBinding.imageView.setImageBitmap(it)
})
// Picasso
imageViewModel.getPicassoImageLoader(Picasso.Builder(this)).into(dataBinding.imageView2)
}
}
ImageRequest.kt
data class ImageRequest(
@field:SerializedName("UserName")
val userName: String? = null,
@field:SerializedName("ContentId")
val contentId: String? = null,
@field:SerializedName("AndroidId")
val androidId: String? = null,
@field:SerializedName("Password")
val password: String? = null,
@field:SerializedName("frame")
val frame: String? = null
) {
companion object {
val default = ImageRequest(
"ApiService",
"704",
"15df3b3a90dc5688",
"BandarAndroid",
"1"
)
}
}
fun ImageRequest.toJson() : String {
return Gson().toJson(this, ImageRequest::class.java)
}