一、定义组件
定义一个Composable组件,当点击Composable组件中的按钮时候,就跳转到相册选择,然后选中图片上传。
import android.net.Uri
import android.util.Log
import androidx.activity.compose.rememberLauncherForActivityResult
import androidx.activity.result.contract.ActivityResultContracts
import androidx.compose.foundation.Image
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.material3.Button
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.tooling.preview.Preview
import coil.compose.rememberAsyncImagePainter
import com.google.gson.JsonObject
import com.xiangzhenming.taojin.network.ImageUploadNetwork
import okhttp3.MediaType.Companion.toMediaTypeOrNull
import okhttp3.MultipartBody
import okhttp3.RequestBody.Companion.toRequestBody
import retrofit2.Call
import retrofit2.Response
@Composable
fun UploadImageView() {
val context = LocalContext.current
val contentResolver = context.contentResolver
var imageUri by remember { mutableStateOf<Uri?>(null) }
val launcher = rememberLauncherForActivityResult(ActivityResultContracts.GetContent()) { uri: Uri? ->
if (uri != null) {
imageUri = uri
contentResolver.openInputStream(uri).use { inputStream ->
// 创建RequestBody对象
val requestBody = inputStream?.let {
it.readBytes().toRequestBody("image/jpeg".toMediaTypeOrNull())
}
// 创建MultipartBody.Part对象
val part = requestBody?.let {
MultipartBody.Part.createFormData(
"file", // API接口要求的参数名
uri.lastPathSegment ?: "${System.currentTimeMillis()}.jpg", // 文件名,默认使用URI的最后一段作为文件名
it
)
}
// 假设apiService是你的Retrofit服务实例
if (part != null) {
ImageUploadNetwork("").apiService.uploadImage(part)
.enqueue(object : retrofit2.Callback<JsonObject> {
override fun onResponse(call: Call<JsonObject>, response: Response<JsonObject>) {
Log.e("UploadImage", "onResponse: ${response.body().toString()}:")
if (response.isSuccessful) {
Log.e("UploadImage", "onResponse: success:")
} else {
Log.e("UploadImage", "onResponse: fail${response.code()}")
}
}
override fun onFailure(call: Call<JsonObject>, t: Throwable) {
Log.e("UploadImage", "onFailure: ${t.message}")
}
}
)
}
}
}
}
Column(
Modifier
.fillMaxSize()
.background(Color.White),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Center
)
{
Button(onClick = {
launcher.launch("image/*")
}) {
Text(text = "选择照片")
}
Image(painter = rememberAsyncImagePainter(model = imageUri), contentDescription = null)
}
}
上传接口
interface ImageUploadService {
companion object {
const val BASE_URL = "https://www.jishuge.cn/"
const val PREFIX_URL = "/upload/android"
}
@Multipart
@POST("${PREFIX_URL}/reward/upload/image")
fun uploadImage( @Part file: MultipartBody.Part): Call<JsonObject>
}
class ImageUploadNetwork {
val apiService: ImageUploadService by lazy {
initRetrofit()
}
private val gson: Gson = GsonBuilder().setLenient().create()
private fun initRetrofit(): ImageUploadService {
val okHttpClient = OkHttpClient.Builder()
.addInterceptor(LoggingInterceptor())
.connectTimeout(10, TimeUnit.SECONDS)
.readTimeout(20, TimeUnit.SECONDS)
.retryOnConnectionFailure(false)
.build()
val retrofit = Retrofit.Builder()
.addConverterFactory(GsonConverterFactory.create(gson))
.baseUrl(ImageUploadService.BASE_URL)
.client(okHttpClient)
.build()
return retrofit.create(ImageUploadService::class.java)
}
}
class LoggingInterceptor : Interceptor {
@Volatile
var level: Level = Level.BASIC // 设置默认的日志级别
enum class Level {
BASIC, // 只打印基本信息
HEADERS, // 打印基本信息以及请求/响应头信息
BODY // 打印所有信息(基本信息、请求/响应头及请求/响应体)
}
override fun intercept(chain: Interceptor.Chain): Response {
val request = chain.request()
when (level) {
Level.BASIC -> logBasic(request)
Level.HEADERS -> logHeaders(request)
Level.BODY -> logBodyAndHeaders(request, chain)
}
val response = chain.proceed(request)
when (level) {
Level.BASIC -> logBasic(response)
Level.HEADERS -> logHeaders(response)
Level.BODY -> logBodyAndHeaders(response)
}
return response
}
private fun logBasic(request: Request) {
Log.d("LoggingInterceptor", "Sending request ${request.url}")
}
private fun logHeaders(request: Request) {
Log.d("LoggingInterceptor", "Sending request ${request.url}")
Log.d("LoggingInterceptor", "Request Headers: ${request.headers}")
}
private fun logBodyAndHeaders(request: Request, chain: Interceptor.Chain) {
logHeaders(request)
val requestBody = request.body ?: return
val bodyString = requestBody.toString()
Log.d("LoggingInterceptor", "Request Body: $bodyString")
}
private fun logBasic(response: Response) {
Log.d("LoggingInterceptor", "Received response for ${response.request.url} with code ${response.code}")
}
private fun logHeaders(response: Response) {
Log.d("LoggingInterceptor", "Received response for ${response.request.url} with code ${response.code}")
Log.d("LoggingInterceptor", "Response Headers: ${response.headers}")
}
private fun logBodyAndHeaders(response: Response) {
logHeaders(response)
if (response.body != null) {
val bodyString = response.body?.string()
Log.d("LoggingInterceptor", "Response Body: $bodyString")
}
}
}
服务器端返回的值格式:
{
"code": 0,
"msg": "ok",
"data": "https://www.jishuge.cn/image/2024-03-13/b69935ce-912e-4d31-b1e5-a15a3da85f82-1710318431942.jpg",
"count": 0,
"version": "1.0.0",
"timestamp": 1710318433
}