目录

Activity Results 总结和封装

Activity Results 总结和封装

封装后的API很易用, 而且一看就知道是原理, 这还要总结啥, kotlin lambda yyds!

具体可以展开如下代码:

 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
import android.content.Intent
import android.graphics.Bitmap
import android.net.Uri
import androidx.activity.ComponentActivity
import androidx.activity.result.ActivityResult
import androidx.activity.result.ActivityResultCaller
import androidx.activity.result.contract.ActivityResultContracts
import androidx.core.os.bundleOf
import androidx.fragment.app.Fragment

/**
 * Author zsqw123
 * Create by damyjy
 * Date 2021/7/10 13:38
 */

fun ActivityResultCaller.takePhoto(targetUri: Uri, callback: (Boolean) -> Unit) =
    registerForActivityResult(ActivityResultContracts.TakePicture(), callback).launch(targetUri)

fun ActivityResultCaller.takePhoto(callback: (Bitmap) -> Unit) =
    registerForActivityResult(ActivityResultContracts.TakePicturePreview(), callback).launch(null)

fun ActivityResultCaller.requestPermissions(vararg permissions: String, callback: (Map<String, Boolean>) -> Unit) =
    registerForActivityResult(ActivityResultContracts.RequestMultiplePermissions(), callback).launch(permissions)

fun ActivityResultCaller.takeVideo(targetUri: Uri, callback: (Bitmap) -> Unit) =
    registerForActivityResult(ActivityResultContracts.TakeVideo(), callback).launch(targetUri)

fun ActivityResultCaller.pickContact(callback: (Uri) -> Unit) =
    registerForActivityResult(ActivityResultContracts.PickContact(), callback).launch(null)

fun ActivityResultCaller.getContent(mimeType: String, callback: (Uri) -> Unit) =
    registerForActivityResult(ActivityResultContracts.GetContent(), callback).launch(mimeType)

fun ActivityResultCaller.createDocument(defaultName: String, callback: (Uri) -> Unit) =
    registerForActivityResult(ActivityResultContracts.CreateDocument(), callback).launch(defaultName)

fun ActivityResultCaller.openDocuments(vararg mimeType: String, callback: (List<Uri>) -> Unit) =
    registerForActivityResult(ActivityResultContracts.OpenMultipleDocuments(), callback).launch(mimeType)

fun ActivityResultCaller.openDocument(vararg mimeType: String, callback: (Uri) -> Unit) =
    registerForActivityResult(ActivityResultContracts.OpenDocument(), callback).launch(mimeType)

fun ActivityResultCaller.openDocumentTree(defaultUri: Uri? = null, callback: (Uri) -> Unit) =
    registerForActivityResult(ActivityResultContracts.OpenDocumentTree(), callback).launch(defaultUri)

inline fun <reified C> ComponentActivity.startAndResult(vararg pairs: Pair<String, Any>, noinline callback: (ActivityResult) -> Unit) =
    registerForActivityResult(ActivityResultContracts.StartActivityForResult(), callback)
        .launch(Intent(this, C::class.java).apply { putExtras(bundleOf(*pairs)) })

inline fun <reified C> Fragment.startAndResult(vararg pairs: Pair<String, Any>, noinline callback: (ActivityResult) -> Unit) =
    registerForActivityResult(ActivityResultContracts.StartActivityForResult(), callback)
        .launch(Intent(context, C::class.java).apply { putExtras(bundleOf(*pairs)) })

什么? 你不知道如何获取一个文件的mimeType? 没关系, Java有自带方法的, 这里我做了包装

1
2
3
4
object typeMap {
    operator fun get(file: File): String = URLConnection.getFileNameMap().getContentTypeFor(file.name) ?: ""
    operator fun get(fileName: String): String = get(File(fileName))
}

使用起来极为舒适:

1
val mimeType = typeMap[name]

哦?

你以为真的这么简单就你用了吗?没错,这种API看起来简单直白,大多数人可能都会认为官方应该是这么用的,但实际上当你运行后会报错如下:

1
java.lang.IllegalStateException: LifecycleOwner com.zsqw123.learner.other.permission.storage.StorageAct@1c344622 is attempting to register while current state is RESUMED. LifecycleOwners must call register before they are STARTED.

实际上这玩意他要求在使用之前先把回调搞好, 然后再去获取并launch

!!!很气愤 但是就这样结束了吗? 我会屈服吗? 怎么可能! 直接将全部事件加入pending中, 调用的时候修改map中的函数类型调用即可

1
2
val ActivityResultCaller.pendingResults: SparseArray<(Any) -> Unit> by lazy { SparseArray() }
val ActivityResultCaller.pendingLaunches: SparseArray<ActivityResultLauncher<*>> by lazy { SparseArray() }

而相对应的我们在调用对应的触发事件的函数的同时, 从map里面取出来进行一下launch操作即可:

1
2
3
4
fun ActivityResultCaller.takePhoto(callback: (Bitmap) -> Unit) {
    pendingResults[1] = { callback(it as Bitmap) }
    pendingLaunches[1].launch(null)
}

完整代码: new-1-ActivityResults (github.com)