我正在开发一个 Android 应用程序,用户可以从设备的图库中选择多张照片并将其上传到后端服务器。为了实现这一目标,我使用
PickMultipleVisualMedia()
来获取所选图像的 URI,然后将它们传递给工作人员进行上传。
这是我实现照片选择器和工作人员的方法:
照片选择器实现:
private fun launchNewPhotoPicker(){
newPicker.launch(PickVisualMediaRequest(ActivityResultContracts.PickVisualMedia.ImageOnly))
}
val newPicker = registerForActivityResult(ActivityResultContracts.PickMultipleVisualMedia(5)) { uris ->
if (uris != null) {
Log.d("PhotoPicker", "Selected URIs: ${uris}")
runUploadImageWorker(uris)
} else {
Log.d("PhotoPicker", "No media selected")
}
}
private fun runUploadImageWorker(uris: List<Uri>) {
val strUris = uris.map { it.toString() }.toTypedArray()
val data = Data.Builder()
.putStringArray("uris", strUris)
.build()
val uploadImageRequest = OneTimeWorkRequestBuilder<UploadImageWorker>()
.setInputData(data)
.build()
WorkManager.getInstance(requireContext()).enqueue(uploadImageRequest)
}
工人实施:
class UploadImageWorker(appContext: Context, workerParams: WorkerParameters) :
Worker(appContext, workerParams) {
override fun doWork(): Result {
val uris = inputData.getStringArray("uris") ?: return Result.failure()
val client = okhttp3.OkHttpClient()
for (uriString in uris) {
val uri = Uri.parse(uriString)
val inputStream = applicationContext.contentResolver.openInputStream(uri)
val requestBody = inputStream?.readBytes()?.toRequestBody("image/*".toMediaTypeOrNull())
val body = requestBody?.let {
MultipartBody.Part.createFormData("picture", UUID.randomUUID().toString(), it)
} ?: return Result.failure()
val multipartBody = MultipartBody.Builder()
.setType(MultipartBody.FORM)
.addPart(body)
.build()
val request = okhttp3.Request.Builder()
.url("https://mywonderfullfakeurl.com/api/pictures")
.post(multipartBody)
.build()
val response = client.newCall(request).execute()
if (!response.isSuccessful) {
val errorBody = response.body?.string() ?: "Unknown error"
Log.d("error", errorBody)
return Result.failure()
}
}
return Result.success()
}
}
但是,我注意到上传到后端服务器的图像缺少 EXIF 数据。使用 Kotlin 从 Android 应用上传图像时,如何确保保留 EXIF 数据?
从图像文件中读取 EXIF 数据并将其添加到多部分请求中。
import android.media.ExifInterface
import okhttp3.*
import okhttp3.MediaType.Companion.toMediaTypeOrNull
import okhttp3.RequestBody.Companion.toRequestBody
import java.io.File
import java.util.*
val uris = inputData.getStringArray("uris") ?: return Result.failure()
val client = OkHttpClient()
for (uriString in uris) {
val uri = Uri.parse(uriString)
val inputStream = applicationContext.contentResolver.openInputStream(uri)
val requestBody = inputStream?.readBytes()?.toRequestBody("image/*".toMediaTypeOrNull())
val body = requestBody?.let {
MultipartBody.Part.createFormData("picture", UUID.randomUUID().toString(), it)
} ?: return Result.failure()
val multipartBodyBuilder = MultipartBody.Builder()
.setType(MultipartBody.FORM)
.addPart(body)
// This part is important
val exifInterface = ExifInterface(uri.path!!)
val attributes = exifInterface.attributes
for ((tag, value) in attributes) {
multipartBodyBuilder.addFormDataPart("exif_$tag", value)
}
val multipartBody = multipartBodyBuilder.build()
val request = Request.Builder()
.url("https://mywonderfullfakeurl.com/api/pictures")
.post(multipartBody)
.build()
val response = client.newCall(request).execute()
if (!response.isSuccessful) {
val errorBody = response.body?.string() ?: "Unknown error"
Log.d("error", errorBody)
return Result.failure()
}
}