浏览代码

feat: param方法添加URI参数

Jason 2 年之前
父节点
当前提交
2aecd377e3

+ 1 - 0
net/build.gradle

@@ -45,6 +45,7 @@ android {
 dependencies {
     implementation 'androidx.appcompat:appcompat:1.3.1'
     implementation 'androidx.startup:startup-runtime:1.0.0'
+    implementation 'androidx.documentfile:documentfile:1.0.1'
 
     compileOnly "com.squareup.okhttp3:okhttp:$okhttp_version"
 

+ 7 - 0
net/src/main/java/com/drake/net/request/BodyRequest.kt

@@ -18,7 +18,9 @@
 
 package com.drake.net.request
 
+import android.net.Uri
 import com.drake.net.interfaces.ProgressListener
+import com.drake.net.utils.fileName
 import com.drake.net.utils.toRequestBody
 import okhttp3.*
 import okhttp3.RequestBody.Companion.toRequestBody
@@ -94,6 +96,11 @@ open class BodyRequest : BaseRequest() {
         value ?: return
         partBody.addFormDataPart(name, null, value.toRequestBody())
     }
+    
+    fun param(name: String, value: Uri?) {
+        value ?: return
+        partBody.addFormDataPart(name, value.fileName(), value.toRequestBody())
+    }
 
     fun param(name: String, value: File?) {
         value ?: return

+ 40 - 0
net/src/main/java/com/drake/net/utils/Uri.kt

@@ -0,0 +1,40 @@
+package com.drake.net.utils
+
+import android.net.Uri
+import android.webkit.MimeTypeMap
+import androidx.documentfile.provider.DocumentFile
+import com.drake.net.NetConfig
+import okhttp3.MediaType
+import okhttp3.MediaType.Companion.toMediaTypeOrNull
+import okhttp3.RequestBody
+import okio.BufferedSink
+import okio.source
+import okio.use
+
+fun Uri.fileName(): String? {
+    return DocumentFile.fromSingleUri(NetConfig.app, this)?.name
+}
+
+fun Uri.mediaType(): MediaType? {
+    val fileName = DocumentFile.fromSingleUri(NetConfig.app, this)?.name
+    val fileExtension = MimeTypeMap.getFileExtensionFromUrl(fileName)
+    return MimeTypeMap.getSingleton().getMimeTypeFromExtension(fileExtension)?.toMediaTypeOrNull()
+}
+
+fun Uri.toRequestBody(): RequestBody {
+    val document = DocumentFile.fromSingleUri(NetConfig.app, this)
+    val length = document?.length() ?: 0
+    return object : RequestBody() {
+        override fun contentType(): MediaType? {
+            return mediaType()
+        }
+        
+        override fun contentLength() = length
+        
+        override fun writeTo(sink: BufferedSink) {
+            NetConfig.app.contentResolver.openInputStream(this@toRequestBody)?.source()?.use {
+                sink.writeAll(it)
+            }
+        }
+    }
+}

+ 6 - 0
sample/src/main/AndroidManifest.xml

@@ -18,6 +18,12 @@
     xmlns:tools="http://schemas.android.com/tools"
     package="com.drake.net.sample">
 
+    <queries>
+        <intent>
+            <action android:name="android.intent.action.PICK" />
+            <data android:mimeType="image/*" />
+        </intent>
+    </queries>
     <application
         android:name=".base.App"
         android:allowBackup="true"

+ 31 - 0
sample/src/main/java/com/drake/net/sample/contract/AlbumSelectContract.kt

@@ -0,0 +1,31 @@
+package com.drake.net.sample.contract
+
+import android.content.Context
+import android.content.Intent
+import android.net.Uri
+import android.provider.MediaStore
+import androidx.activity.result.contract.ActivityResultContract
+
+class AlbumSelectContract : ActivityResultContract<Unit, AlbumSelectContract.AlbumSelectResult>() {
+    
+    companion object {
+        fun canChoosePhoto(context: Context?): Boolean {
+            val intent = Intent(Intent.ACTION_PICK)
+            intent.type = "image/*"
+            return context?.packageManager?.queryIntentActivities(intent, 0)?.isNotEmpty() == true
+        }
+    }
+    
+    override fun createIntent(context: Context, input: Unit?): Intent {
+        val intent = Intent(Intent.ACTION_PICK)
+        intent.setDataAndType(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, "image/*")
+        return intent
+    }
+    
+    class AlbumSelectResult(val code: Int, val uri: Uri?)
+    
+    override fun parseResult(resultCode: Int, intent: Intent?): AlbumSelectResult {
+        println("AlbumSelectContract >>> selected = ${intent?.data}")
+        return AlbumSelectResult(resultCode, intent?.data)
+    }
+}

+ 39 - 8
sample/src/main/java/com/drake/net/sample/ui/fragment/UploadFileFragment.kt

@@ -16,13 +16,17 @@
 
 package com.drake.net.sample.ui.fragment
 
+import android.app.Activity
+import android.net.Uri
 import com.drake.engine.base.EngineFragment
 import com.drake.net.Post
 import com.drake.net.component.Progress
 import com.drake.net.interfaces.ProgressListener
 import com.drake.net.sample.R
+import com.drake.net.sample.contract.AlbumSelectContract
 import com.drake.net.sample.constants.Api
 import com.drake.net.sample.databinding.FragmentUploadFileBinding
+import com.drake.net.utils.TipUtils
 import com.drake.net.utils.scopeNetLife
 import okio.buffer
 import okio.sink
@@ -30,21 +34,48 @@ import okio.source
 import java.io.File
 
 
-class UploadFileFragment :
-    EngineFragment<FragmentUploadFileBinding>(R.layout.fragment_upload_file) {
+class UploadFileFragment : EngineFragment<FragmentUploadFileBinding>(R.layout.fragment_upload_file) {
+    private val albumSelectLauncher = registerForActivityResult(AlbumSelectContract()) {
+        when (it.code) {
+            Activity.RESULT_CANCELED -> TipUtils.toast("图片选择取消")
+            Activity.RESULT_OK -> uploadUri(it.uri)
+        }
+    }
 
     override fun initView() {
+        binding.btnFile.setOnClickListener {
+            uploadFile()
+        }
+        binding.btnUri.setOnClickListener {
+            albumSelectLauncher.launch(null)
+        }
+    }
+
+    private fun uploadFile() {
         scopeNetLife {
             Post<String>(Api.UPLOAD) {
-                param("file", assetsFile())
+                param("file", getAssetsFile())
+                addUploadListener(object : ProgressListener() {
+                    override fun onProgress(p: Progress) {
+                        binding.seek.post {
+                            binding.seek.progress = p.progress()
+                            binding.tvProgress.text = "上传进度: ${p.progress()}% 上传速度: ${p.speedSize()}     " + "\n\n文件大小: ${p.totalSize()}  已上传: ${p.currentSize()}  剩余大小: ${p.remainSize()}" + "\n\n已使用时间: ${p.useTime()}  剩余时间: ${p.remainTime()}"
+                        }
+                    }
+                })
+            }.await()
+        }
+    }
+
+    private fun uploadUri(uri: Uri?) {
+        scopeNetLife {
+            Post<String>("upload") {
+                param("file", uri)
                 addUploadListener(object : ProgressListener() {
                     override fun onProgress(p: Progress) {
                         binding.seek.post {
                             binding.seek.progress = p.progress()
-                            binding.tvProgress.text =
-                                "上传进度: ${p.progress()}% 上传速度: ${p.speedSize()}     " +
-                                        "\n\n文件大小: ${p.totalSize()}  已上传: ${p.currentSize()}  剩余大小: ${p.remainSize()}" +
-                                        "\n\n已使用时间: ${p.useTime()}  剩余时间: ${p.remainTime()}"
+                            binding.tvProgress.text = "上传进度: ${p.progress()}% 上传速度: ${p.speedSize()}     " + "\n\n文件大小: ${p.totalSize()}  已上传: ${p.currentSize()}  剩余大小: ${p.remainSize()}" + "\n\n已使用时间: ${p.useTime()}  剩余时间: ${p.remainTime()}"
                         }
                     }
                 })
@@ -52,7 +83,7 @@ class UploadFileFragment :
         }
     }
 
-    private fun assetsFile(): File {
+    private fun getAssetsFile(): File {
         val fileName = "upload_file.jpg"
         val inputStream = resources.assets.open(fileName)
         val file = File(requireContext().filesDir.path, fileName)

+ 18 - 15
sample/src/main/res/layout/fragment_upload_file.xml

@@ -18,12 +18,25 @@
     xmlns:app="http://schemas.android.com/apk/res-auto"
     xmlns:tools="http://schemas.android.com/tools">
 
-
-    <androidx.constraintlayout.widget.ConstraintLayout
+    <LinearLayout
         android:layout_width="match_parent"
         android:layout_height="match_parent"
+        android:gravity="center"
+        android:orientation="vertical"
         tools:context=".ui.fragment.UploadFileFragment">
 
+        <Button
+            android:id="@+id/btnUri"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="上传 Uri 文件" />
+
+        <Button
+            android:id="@+id/btnFile"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="上传 File 文件" />
+
         <SeekBar
             android:id="@+id/seek"
             android:layout_width="match_parent"
@@ -32,24 +45,14 @@
             android:gravity="center"
             android:text="等待下载完成"
             android:textSize="18dp"
-            android:textStyle="bold"
-            app:layout_constraintBottom_toBottomOf="parent"
-            app:layout_constraintLeft_toLeftOf="parent"
-            app:layout_constraintRight_toRightOf="parent"
-            app:layout_constraintTop_toTopOf="parent"
-            app:layout_constraintVertical_bias="0.5" />
+            android:textStyle="bold" />
 
         <TextView
             android:id="@+id/tvProgress"
-            android:layout_width="0dp"
+            android:layout_width="wrap_content"
             android:layout_height="wrap_content"
-            android:layout_marginHorizontal="16dp"
-            android:layout_marginTop="16dp"
             android:textSize="12dp"
-            app:layout_constraintLeft_toLeftOf="@id/seek"
-            app:layout_constraintRight_toRightOf="@id/seek"
-            app:layout_constraintTop_toBottomOf="@id/seek"
             tools:text="上传进度: 90%   上传速度: 20MB/s" />
 
-    </androidx.constraintlayout.widget.ConstraintLayout>
+    </LinearLayout>
 </layout>