Jetpack Compose-使用Retrofit2进行文件上传

前言

Retrofit是现在比较流行的网络请求框架,可以理解为okhttp的加强版,底层封装了Okhttp。

准确来说,Retrofit是一个RESTful的http网络请求框架的封装

因为网络请求工作本质上是由okhttp来完成,而Retrofit负责网络请求接口的封装。

https://square.github.io/retrofit/

MutiPart

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import com.xhkjedu.zxs_android.model.ResultVo
import okhttp3.MultipartBody
import okhttp3.RequestBody
import retrofit2.Response
import retrofit2.http.Multipart
import retrofit2.http.POST
import retrofit2.http.Part

interface ServiceFile {
@Multipart
@POST("/up/upfile")
suspend fun apiUploadFile(
@Part file: MultipartBody.Part,
@Part("savefolder") savefolder: RequestBody,
@Part("iscover") iscover: RequestBody,
@Part("isrename") isrename: RequestBody,
): Response<ResultVo<String>>
}

服务管理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
object ApiManager {
private lateinit var fileRetrofit: Retrofit
lateinit var fileService: ServiceFile

@SuppressLint("CustomX509TrustManager")
fun getUnsafeOkHttpClient(): OkHttpClient {
try {
// 创建一个信任所有证书的 TrustManager
val trustAllCerts = arrayOf<TrustManager>(

object : X509TrustManager {
override fun checkClientTrusted(
chain: Array<out java.security.cert.X509Certificate>?,
authType: String?
) {
}

override fun checkServerTrusted(
chain: Array<out java.security.cert.X509Certificate>?,
authType: String?
) {
}

override fun getAcceptedIssuers(): Array<java.security.cert.X509Certificate> =
arrayOf()
}
)

// 初始化 SSLContext
val sslContext = SSLContext.getInstance("TLS")
sslContext.init(null, trustAllCerts, SecureRandom())

// 创建一个允许所有主机名验证的 HostnameVerifier
val allHostsValid = HostnameVerifier { _, _ -> true }

// 创建 OkHttpClient 并配置 SSL 和主机名验证
return OkHttpClient.Builder()
.sslSocketFactory(sslContext.socketFactory, trustAllCerts[0] as X509TrustManager)
.hostnameVerifier(allHostsValid)
.build()
} catch (e: Exception) {
throw RuntimeException(e)
}
}


fun initFileService() {
if (!::fileRetrofit.isInitialized) {
val client = getUnsafeOkHttpClient().newBuilder()
.connectTimeout(60, TimeUnit.SECONDS)
.readTimeout(60, TimeUnit.SECONDS)
.writeTimeout(90, TimeUnit.SECONDS)
.addInterceptor(HeaderInterceptor())
.build();

fileRetrofit = Retrofit.Builder()
.baseUrl(CommonData.fileUploadUrl)
.client(client)
.addConverterFactory(GsonConverterFactory.create())
.build()
}
if (!::fileService.isInitialized) {
fileService = fileRetrofit.create(ServiceFile::class.java)
}
}

init {
initFileService()
}

}

调用示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
fun uploadPic(filePath: String) {
val file = File(filePath)
if (!file.exists()) {
return
}
// 创建 RequestBody,用于封装构建RequestBody
val requestFile = file.asRequestBody("multipart/form-data".toMediaTypeOrNull())

// 构建MultipartBody.Part,用于封装文件数据
val body = MultipartBody.Part.createFormData("file", file.name, requestFile)
val saveFolderBody = "test/001/".toRequestBody("text/plain".toMediaTypeOrNull())
val isCoverBody = "0".toString().toRequestBody("text/plain".toMediaTypeOrNull())
val isRenameBody = "1".toString().toRequestBody("text/plain".toMediaTypeOrNull())
mLaunch(suspend {
ApiManager.fileService.apiUploadFile(body, saveFolderBody, isCoverBody, isRenameBody)
}) { data ->
Log.i(TAG, "UserViewModel: " + Gson().toJson(data))
data.let {
if (it.code == 0) {

}
}
}
}

参数

1
2
3
4
5
6
7
8
9
10
11
12
val file = File(filePath)
if (!file.exists()) {
return
}
// 创建 RequestBody,用于封装构建RequestBody
val requestFile = file.asRequestBody("multipart/form-data".toMediaTypeOrNull())
// 构建MultipartBody.Part,用于封装文件数据
val body = MultipartBody.Part.createFormData("file", file.name, requestFile)
// 其他参数
val saveFolderBody = "test/001/".toRequestBody("text/plain".toMediaTypeOrNull())
val isCoverBody = "0".toString().toRequestBody("text/plain".toMediaTypeOrNull())
val isRenameBody = "1".toString().toRequestBody("text/plain".toMediaTypeOrNull())

Bitmap上传

我们获取的Bitmap要保存到本地才能上传

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
import android.content.Context
import android.graphics.Bitmap
import android.os.Environment
import java.io.File
import java.io.FileOutputStream
import java.io.IOException
import java.text.SimpleDateFormat
import java.util.Date
import java.util.Locale

object BitmapUtils {
/**
* 将 Bitmap 保存为临时 JPEG 文件
*/
fun saveBitmapToFile(bitmap: Bitmap, context: Context): File? {
val timeStamp = SimpleDateFormat("yyyyMMddHHmmssSSS", Locale.getDefault()).format(Date())
return try {
// 创建临时文件
val tempFile = File.createTempFile(
timeStamp,
".jpg",
context.getExternalFilesDir(Environment.DIRECTORY_PICTURES)
)

// 压缩并保存 Bitmap 到文件
FileOutputStream(tempFile).use { out ->
bitmap.compress(Bitmap.CompressFormat.JPEG, 80, out) // 质量 80%
}

tempFile
} catch (e: IOException) {
e.printStackTrace()
null
}
}
}