Activity接收傳值,請求權(quán)限

插播:
新的AppCompatActivity以及ComponentActivity,支持構(gòu)造函數(shù)中傳入layotuId了,不用再setContentView()了

//fragment
  implementation 'androidx.fragment:fragment-ktx:1.3.2'
//activity
  implementation 'androidx.activity:activity-ktx:1.3.0-alpha05'

位于 ComponentActivityFragment 中時,Activity Result API 會提供 registerForActivityResult() API,用于注冊結(jié)果回調(diào)。registerForActivityResult() 接受 ActivityResultContractActivityResultCallback 作為參數(shù),并返回 ActivityResultLauncher,供您用來啟動另一個 activity。

  • 跳轉(zhuǎn)頁面新的寫法
//跳轉(zhuǎn)手機默認Intent
class StartResultActivity : ComponentActivity(R.layout.activity_start_result) {
    private val TAG = "StartResultActivity"
//接受回傳結(jié)果
    val result = registerForActivityResult(ActivityResultContracts.GetContent()) {
        Log.d(TAG, "onCreate: ${it}")
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        text.setOnClickListener {
           //啟動跳轉(zhuǎn)
            result.launch("image/*")
        }

    }
}
//跳轉(zhuǎn)指定activity
 val result = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
        Log.d(TAG, "onCreate: ${it.data?.getStringExtra("value")}")
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        text.setOnClickListener {
            result.launch(Intent(this,ForResultMainActivity::class.java))
        }

    }

class ForResultMainActivity : AppCompatActivity(R.layout.activity_for_result_main) {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setResult(Activity.RESULT_OK,intent.putExtra("value","Angel"))
        finish()
    }
}

registerForActivityResult()是startActivityForResult()的替代,簡化了數(shù)據(jù)回調(diào)的寫法
最基本最簡單最常用的寫法

        //java寫法
        registerForActivityResult(new ActivityResultContracts.StartActivityForResult(), new ActivityResultCallback<ActivityResult>() {
            @Override
            public void onActivityResult(ActivityResult result) {
                Intent data = result.getData();
                int resultCode = result.getResultCode();
            }
        }).launch(new Intent(context,BActivity.class));
 
        //kotlin寫法
        registerForActivityResult(ActivityResultContracts.StartActivityForResult()
        ) { 
            val data = it.data
            val resultCode = it.resultCode
        }.launch(Intent(context,BActivity::class.java))

       //launch()方法,輸入Intent,ActivityResultCallback:獲取返回的數(shù)據(jù),
       //ActivityResultContracts.StartActivityForResult 是官方提供用來處理回調(diào)數(shù)據(jù)的ActivityResultContract類
       //跳轉(zhuǎn)到BActivity后,調(diào)用setResult()方法傳遞數(shù)據(jù),這部分和以前一樣
  

使用registerForActivityResult方法,可以簡化許多相關(guān)操作,舉幾個例子

調(diào)用聯(lián)系人列表,獲取聯(lián)系人

        registerForActivityResult(ActivityResultContracts.PickContact()){
            if(it != null){
                val cursor = contentResolver.query(it, null, null, null, null)
                cursor?.run {
                    if(cursor.moveToFirst()){
                        val name =
                            cursor.getString(cursor.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME))
                        LogUtils.e("聯(lián)系人姓名:$name")
                        if(cursor.getString(cursor.getColumnIndex(ContactsContract.Contacts.HAS_PHONE_NUMBER)) == "1"){
                            //該聯(lián)系人名下存在手機號,查詢方法自行實現(xiàn)
                        }
                    }
 
                }
            }
        }.launch(null)

調(diào)用相機拍照

        //需要WRITE_EXTERNAL_STORAGE權(quán)限
        val uri = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
            val values = ContentValues()
            values.put(MediaStore.MediaColumns.DISPLAY_NAME, "圖片名稱.jpg")
            values.put(MediaStore.MediaColumns.RELATIVE_PATH, Environment.DIRECTORY_PICTURES)
            contentResolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values)
        }else{
            FileProvider.getUriForFile(this,BuildConfig.authorities,File(externalCacheDir!!.absolutePath+"圖片名稱.jpg"))
        }    
        registerForActivityResult(ActivityResultContracts.TakePicture()){
            if(it)
                Glide.with(this).load(uri).into(binding.imageView)
        }.launch(uri)
 
 
        //或者可以用更簡單的方法
        registerForActivityResult(ActivityResultContracts.TakePicturePreview()){
            Glide.with(this).load(it).into(binding.imageView)
        }.launch(null)

調(diào)用文件選擇器選擇文件

調(diào)用文件選擇器,獲取指定類型的文件,可在launch()方法里使用mimetype指定調(diào)用文件類型,這里以調(diào)用文本文檔為例

        registerForActivityResult(ActivityResultContracts.GetContent()){
 
        }.launch("text/plain")

如果需要選擇多種文件類型,可以使用OpenDocument

        registerForActivityResult(ActivityResultContracts.OpenDocument()){
            Glide.with(this).load(it).into(binding.imageView)
        }.launch(arrayOf("image/*","text/plain"))

獲取敏感權(quán)限
使用registerForActivityResult獲取權(quán)限,也會變得非常簡單

獲取一個權(quán)限

            registerForActivityResult(ActivityResultContracts.RequestPermission()){
               if(it){
                   //用戶同意了該權(quán)限
               }else{
                   //用戶拒絕了該權(quán)限
               }
 
            }.launch(Manifest.permission.WRITE_EXTERNAL_STORAGE)

獲取多個權(quán)限

        registerForActivityResult(ActivityResultContracts.RequestMultiplePermissions()){it->
            //通過的權(quán)限
            val grantedList = it.filterValues { it }.mapNotNull { it.key }
            //是否所有權(quán)限都通過
            val allGranted = grantedList.size == it.size
            val list = (it - grantedList).map { it.key }
            //未通過的權(quán)限
            val deniedList = list.filter { ActivityCompat.shouldShowRequestPermissionRationale(this, it) }
            //拒絕并且點了“不再詢問”權(quán)限
            val alwaysDeniedList = list - deniedList
        }.launch(arrayOf("權(quán)限1","權(quán)限2","權(quán)限3"))

自定義ActivityResultContract<I,O>
ActivityResultContract<I,O> 官方提供的,通過輸入類型I構(gòu)建意圖并將回調(diào)數(shù)據(jù)轉(zhuǎn)換成輸入類型O的契約類,官方總共給我們提供了14個ActivityResultContract實現(xiàn)類(截自本文發(fā)布時間),通過ActivityResultContracts構(gòu)建,可以非常輕松地調(diào)用文件,聯(lián)系人,敏感權(quán)限等等,另外,我們也可以實現(xiàn)自己的ActivityResultContract來簡化意圖操作,這里寫一個裁剪圖片的ActivityResultContract為例

import android.content.ContentValues
import android.content.Context
import android.content.Intent
import android.net.Uri
import android.os.Build
import android.os.Environment
import android.provider.MediaStore
import android.webkit.MimeTypeMap
import androidx.activity.result.contract.ActivityResultContract
import java.io.File
 
class CropImage: ActivityResultContract<CropImageResult, Uri>(){
    var outUri:Uri? = null
    //構(gòu)建意圖
    override fun createIntent(context: Context, input: CropImageResult): Intent {
        //把CropImageResult轉(zhuǎn)換成裁剪圖片的意圖
        val intent = Intent("com.android.camera.action.CROP")
        val mimeType = context.contentResolver.getType(input.uri)
        val imageName:String = "${System.currentTimeMillis()}.${MimeTypeMap.getSingleton().getExtensionFromMimeType(mimeType)}"
        outUri = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q){
            val values = ContentValues()
            values.put(MediaStore.MediaColumns.DISPLAY_NAME,imageName)
            values.put(MediaStore.MediaColumns.MIME_TYPE,mimeType)
            values.put(MediaStore.MediaColumns.RELATIVE_PATH, Environment.DIRECTORY_DCIM)
            context.contentResolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,values)
        }else{
            Uri.fromFile(File(context.externalCacheDir!!.absolutePath, imageName))
        }
        context.grantUriPermission(context.getPackageName(),outUri, Intent.FLAG_GRANT_READ_URI_PERMISSION )
        intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
        intent.putExtra("noFaceDetection", true) //去除默認的人臉識別,否則和剪裁匡重疊
        intent.setDataAndType(input.uri, mimeType)
        intent.putExtra("crop", "true") // crop=true 有這句才能出來最后的裁剪頁面.
        intent.putExtra("output", outUri)
        intent.putExtra("outputFormat", "JPEG") // 返回格式
        intent.putExtra("return-data", true)
 
 
        if (input.outputX != 0 && input.outputY != 0) {
            intent.putExtra("outputX", input.outputX)
            intent.putExtra("outputY", input.outputY)
        }
        if(input.aspectX != 0 && input.aspectY != 0){
            if(input.aspectY == input.aspectX && Build.MANUFACTURER == "HUAWEI"){
                intent.putExtra("aspectX", 9999)
                intent.putExtra("aspectY", 9998)
            }else{
                intent.putExtra("aspectX", input.aspectX)
                intent.putExtra("aspectY", input.aspectY)
            }
        }
 
        return intent
    }
 
    //接收意圖并處理數(shù)據(jù)
    override fun parseResult(resultCode: Int, intent: Intent?): Uri {
        if(outUri != null)
            return outUri!!
        else
            return Uri.parse("")
    }
 
}
 
/**
 * uri:需要裁剪的圖片
 * aspect:長寬比例
 * output:圖片輸出長寬
 * uri 要裁剪的圖片
 * aspect 剪裁比例
 * output 輸入圖片長寬
 */
class CropImageResult(val uri: Uri,
                      val aspectX:Int = 0,
                      val aspectY:Int = 0,
                      @androidx.annotation.IntRange(from = 0 ,to = 1080)
                      val outputX:Int = 0,
                      @androidx.annotation.IntRange(from = 0 ,to = 1080)
                      val outputY:Int = 0)

使用:

    //裁剪圖片
    private fun crop(uri: Uri) {
        registerForActivityResult(CropImage()){
            Glide.with(this).load(it.toFile).into(binding.ivImage)
        }.launch(CropImageResult(uri,1,1))
    }

registerForActivityResult()方法的使用還沒做限制,新版本的ActivityResultLauncher必需在activity的onCreate()方法或fragment的onCreate()、onAttach()里先注冊,然后在需要調(diào)用的地方調(diào)用launch方法,以裁剪圖片為例,在activity方法里需要這樣寫:

class Activity1: ComponentActivity(){
    val cropImage:ActivityResultLauncher<CropRequest> =         
    registerForActivityResult(CropImage()) {
            //獲取到裁剪的圖片
        }
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        Button(this).setOnClickListener { 
            cropImage.launch(…)
        }
        
    }
}
 
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容