【问题标题】:Android - onRequestPermissionsResult() is deprecated. Are there any alternatives?Android - onRequestPermissionsResult() 已弃用。有没有其他选择?
【发布时间】:2021-06-07 15:08:11
【问题描述】:

我尝试实现从存储中写入和读取的请求权限。一切正常,但今天 Android 向我展示了 onRequestPermissionsResult(...) 方法已被弃用。 StackOverflow 中有很多关于这个主题的问题,但不幸的是,它们已经过时了。

我在片段中调用了以下方法。

建议只是调用:

requestPermissions(new String[] {Manifest.permission.WRITE_EXTERNAL_STORAGE},
StorageKeys.STORAGE_PERMISSION_CODE)

而不是我的方法:

ActivityCompat.requestPermissions(getActivity(),
new String[] {Manifest.permission.WRITE_EXTERNAL_STORAGE},
StorageKeys.STORAGE_PERMISSION_CODE))

但它们都表明 onRequestPermissionsResult(...) 已被弃用。

这是我的 onRequestPermissionsResult(...) 方法:

  @Override
  public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
                                         @NonNull int[] grantResults) {

    if (requestCode == StorageKeys.STORAGE_PERMISSION_CODE) {

      if (grantResults.length > 0
          && grantResults[0] == PackageManager.PERMISSION_GRANTED) {

        exportBibTex.createBibFile();
        exportBibTex.writeBibFile(exportBibTex
            .getBibDataLibrary(libraryModel, bookDao, noteDao));

        Toast.makeText(getContext(),
            getString(R.string.exported_file_stored_in) + '\n'
                + File.separator + StorageKeys.DOWNLOAD_FOLDER + File.separator + fileName
                + StorageKeys.BIB_FILE_TYPE, Toast.LENGTH_LONG).show();

      } else {
        Toast.makeText(getContext(), R.string.storage_permission_denied,
            Toast.LENGTH_SHORT).show();
      }
    }
  }

这是一个简单的警报对话框,我在其中调用 onRequestPermissionsResult(...):

  private void showRequestPermissionDialog() {
    AlertDialog.Builder reqAlertDialog = new AlertDialog.Builder(getContext());
    reqAlertDialog.setTitle(R.string.storage_permission_needed);
    reqAlertDialog.setMessage(R.string.storage_permission_alert_msg);

    reqAlertDialog.setPositiveButton(R.string.ok,
        (dialog, which) -> ActivityCompat.requestPermissions(getActivity(),
            new String[] {Manifest.permission.WRITE_EXTERNAL_STORAGE},
            StorageKeys.STORAGE_PERMISSION_CODE));
    reqAlertDialog.setNegativeButton(R.string.cancel,
        (dialog, which) -> dialog.dismiss());

    reqAlertDialog.create().show();
  }

我可以使用 onRequestPermissionsResult(...) 的替代方法吗?

【问题讨论】:

  • onRequestPermissionsResult()androidx.appcompat.app.AppCompatActivity 中没有被弃用。你使用了哪个 Activity 类?
  • 我在片段中使用它。 Android Studio 的解释是:“Overrides deprecated method in 'androidx.fragment.app.Fragment'”
  • 我发布了答案并宣传了您的问题。所以你可以检查我的答案。
  • 你应该看看这个官方指南:youtu.be/oP-zXjkT0C0onActivityResult()onRequestPermissionResult() 现在都已弃用。
  • requestPermissions 方法已弃用。

标签: java android permissions request deprecated


【解决方案1】:

onRequestPermissionsResult() 方法在 androidx.fragment.app.Fragment 中已弃用。

所以你使用registerForActivityResult() 方法而不是onRequestPermissionsResult()

你可以参考这个URL

以下是 kotlin 代码。不过你可以参考一下。

val permReqLuncher = registerForActivityResult(ActivityResultContracts.RequestPermission()){
  if (it) {
     // Good pass
  } else {
     // Failed pass
  }
}

我从以下 URL 添加了 java 代码。
How to get a permission request in new ActivityResult API (1.3.0-alpha05)?

private ActivityResultLauncher<String> mPermissionResult = registerForActivityResult(
        new ActivityResultContracts.RequestPermission(),
        new ActivityResultCallback<Boolean>() {
            @Override
            public void onActivityResult(Boolean result) {
                if(result) {
                    Log.e(TAG, "onActivityResult: PERMISSION GRANTED");
                } else {
                    Log.e(TAG, "onActivityResult: PERMISSION DENIED");
                }
            }
        });



        // Launch the permission window -- this is in onCreateView()
    floatingActionButton.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
         mPermissionResult.launch(Manifest.permission.ACCESS_BACKGROUND_LOCATION);

        }
    });

您可以请求多个权限。

    val requestMultiplePermissions = registerForActivityResult(ActivityResultContracts.RequestMultiplePermissions()) { permissions ->
        permissions.entries.forEach {
            Log.e("DEBUG", "${it.key} = ${it.value}")
        }
    }

    requestMultiplePermissions.launch(
        arrayOf(
            Manifest.permission.READ_CONTACTS,
            Manifest.permission.ACCESS_FINE_LOCATION
       )
    )

【讨论】:

  • 谢谢,我可以使用 ActivityResultLauncher(..) 获得多个权限吗?例如 requestPermissionLauncher.launch(Manifest.permission.WRITE_EXTERNAL_STORAGE); requestPermissionLauncher.launch(Manifest.permission.READ_EXTERNAL_STORAGE);
  • 是的,您可以使用它。但是您需要更改我的代码的某些部分。我更新了我的帖子。
  • 所以调用registerForActivityResult()方法时需要使用ActivityResultContracts.RequestMultiplePermissions()
  • 这在the documentation中也特别提到。
【解决方案2】:

Kotlin中的简单方法

import android.Manifest
import android.content.Context
import android.content.pm.PackageManager
import android.os.Build
import androidx.activity.result.contract.ActivityResultContracts
import androidx.core.app.ActivityCompat
import androidx.fragment.app.Fragment

class MyFragment : Fragment() {

companion object {
    val TAG: String = MyFragment::class.java.simpleName
    var PERMISSIONS = arrayOf(
        Manifest.permission.CAMERA,
        Manifest.permission.READ_EXTERNAL_STORAGE,
        Manifest.permission.WRITE_EXTERNAL_STORAGE
    )
}

private val permReqLauncher =
    registerForActivityResult(ActivityResultContracts.RequestMultiplePermissions()) { permissions ->
        val granted = permissions.entries.all {
            it.value == true
        }
        if (granted) {
            displayCameraFragment()
        }
    }

private fun takePhoto() {
    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
        displayCameraFragment()
    }
    activity?.let {
        if (hasPermissions(activity as Context, PERMISSIONS)) {
            displayCameraFragment()
        } else {
            permReqLauncher.launch(
                PERMISSIONS
            )
        }
    }
}

// util method
private fun hasPermissions(context: Context, permissions: Array<String>): Boolean = permissions.all {
    ActivityCompat.checkSelfPermission(context, it) == PackageManager.PERMISSION_GRANTED
}

private fun displayCameraFragment() {
    // open camera fragment
}
}

【讨论】:

    【解决方案3】:

    替代 registerForActivityResult

    使用示例:

     private fun permissionSetup() {
        val permission = ContextCompat.checkSelfPermission(
            requireContext(), Manifest.permission.READ_CONTACTS)
    
        if (permission != PackageManager.PERMISSION_GRANTED) {
            permissionsResultCallback.launch(Manifest.permission.READ_CONTACTS)
        } else {
            println("Permission isGranted")
        }
    }
    
    private val permissionsResultCallback = registerForActivityResult(
        ActivityResultContracts.RequestPermission()){
        when (it) {
            true -> { println("Permission has been granted by user") }
            false -> {
                Toast.makeText(requireContext(), "Permission denied", Toast.LENGTH_SHORT).show()
                dialog.dismiss()
            }
        }
    }
    

    【讨论】:

      【解决方案4】:

      这对我有用 - (kotlin):

      private fun checkPermissions() {
          if (mContext?.let {
              ContextCompat.checkSelfPermission(
                  it,
                  READ_EXTERNAL_STORAGE
              )
          } != PackageManager.PERMISSION_GRANTED) {
          Log.d(TAG, "Request Permissions")
          requestMultiplePermissions.launch(
              arrayOf(READ_EXTERNAL_STORAGE, WRITE_EXTERNAL_STORAGE))
       } else {
              Log.d(TAG, "Permission Already Granted")
          }
      }
      
      private val requestMultiplePermissions =
          registerForActivityResult(ActivityResultContracts.RequestMultiplePermissions()) { permissions ->
              permissions.entries.forEach {
                  Log.d(TAG, "${it.key} = ${it.value}")
              }
              if (permissions[READ_EXTERNAL_STORAGE] == true && permissions[WRITE_EXTERNAL_STORAGE] == true) {
                  Log.d(TAG, "Permission granted")
              } else {
                  Log.d(TAG, "Permission not granted")
              }
          }
      

      【讨论】:

        【解决方案5】:

        大多数答案都解决了 OP 要求。但是我发现缺少的东西很少,所以我想提供一个完整的例子(在 Koltin 中)

        class ProfileFragment : Fragment(){
        
        private lateinit var permissionRequest : ActivityResultLauncher<Array<String>>
        
        companion object {
              
            val LOCATION_PERMISSIONS = arrayOf(
                    Manifest.permission.ACCESS_FINE_LOCATION,
                    Manifest.permission.ACCESS_COARSE_LOCATION
                )
            }
        
            private fun getGpsLocation() {
                if(activity != null){
                    permissionRequest.launch(LOCATION_PERMISSIONS)
                }
            }
        
            override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
                super.onViewCreated(view, savedInstanceState)
        
                binding.locBtn.setOnClickListener { getGpsLocation() }
            }
        
        
            override fun onCreate(savedInstanceState: Bundle?) {
                super.onCreate(savedInstanceState)
                registerPermissionRequest()
            }
                
            override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
        
                binding = DataBindingUtil.inflate(inflater, R.layout.fragment_profile, container, false)
               
                return binding.root
            }
            
            private fun registerPermissionRequest(){
                    var permissionCount = 0
                    permissionRequest = registerForActivityResult(ActivityResultContracts.RequestMultiplePermissions()) { permissions ->
                        permissions.entries.forEach {
                            if(it.value){
                                permissionCount++
                            }
            
                        }
            
                        if(permissionCount == 2){
                            getMyLocation()
                        }
                    }
                }
            }
        

        缺少的东西是

        A)片段必须在创建之前调用 registerForActivityResult()(即初始化、onAttach() 或 onCreate())。否则它将无法工作并且应用程序会崩溃。

        错误:

        java.lang.IllegalStateException: 片段 ProfileFragment{bf12414} (210ad5a1-3286-4586-a48f-deac1d8e3eef id=0x7f09008b) 正在尝试 registerForActivityResult 在被 创建的。片段必须在它们之前调用 registerForActivityResult() 被创建(即初始化、onAttach() 或 onCreate())。

        B) 建议在真正需要时请求许可。在我的示例中,当用户单击 ID 为 locBtnButton 时,将显示权限对话框,而不是显示何时创建活动/片段。

        【讨论】:

        • 在您的情况下,您在onCreateView 中调用registerForActivityResult。根据我的经验,在onCreateonAttach 中创建permissionRequest 变量或作为初始化的局部变量通常就足够了。在onCreate 中,我们应该检查调用顺序。最好在其他运算符之前创建变量,因为有时它可能被调用得太早。
        • @CoolMind,我完全同意你的看法。我确实在描述中提到了相同的内容。我现在已经纠正了。谢谢。
        【解决方案6】:

        请参考官方文档:https://developer.android.com/training/permissions/requesting

        查看以下内容,可在文档中找到。

        // Register the permissions callback, which handles the user's response to the
        // system permissions dialog. Save the return value, an instance of
        // ActivityResultLauncher. You can use either a val, as shown in this snippet,
        // or a lateinit var in your onAttach() or onCreate() method.
        val requestPermissionLauncher =
            registerForActivityResult(RequestPermission()
            ) { isGranted: Boolean ->
                if (isGranted) {
                    // Permission is granted. Continue the action or workflow in your
                    // app.
                } else {
                    // Explain to the user that the feature is unavailable because the
                    // features requires a permission that the user has denied. At the
                    // same time, respect the user's decision. Don't link to system
                    // settings in an effort to convince the user to change their
                    // decision.
                }
            }
        

        之后,启动请求

        when {
            ContextCompat.checkSelfPermission(
                    CONTEXT,
                    Manifest.permission.REQUESTED_PERMISSION
                    ) == PackageManager.PERMISSION_GRANTED -> {
                // You can use the API that requires the permission.
            }
            //Is not needed for it to work, but is a good practice as it plays a role
            //in letting user know why the permission is needed.
            shouldShowRequestPermissionRationale(...) -> {
                // In an educational UI, explain to the user why your app requires this
                // permission for a specific feature to behave as expected. In this UI,
                // include a "cancel" or "no thanks" button that allows the user to
                // continue using your app without granting the permission.
                showInContextUI(...)
            }
            else -> {
                // You can directly ask for the permission.
                // The registered ActivityResultCallback gets the result of this request.
                requestPermissionLauncher.launch(
                        Manifest.permission.REQUESTED_PERMISSION)
            }
        }
        

        【讨论】:

          【解决方案7】:

          您可以使用一些外部库进行权限处理以减少一些样板代码。我使用Dexter library。如果您使用 RxJava2,Rx Permissions 也是不错的选择。

          【讨论】:

            【解决方案8】:

            在您的活动或片段中注册权限回调。处理用户权限 示例-存储权限

             private final ActivityResultLauncher<String> requestPermissionLauncher = registerForActivityResult(
                    new ActivityResultContracts.RequestPermission(),
                    result -> {
                        if (result) {
                              //Permission granted
             
                        } else {
                           //permission denied
                            if (ActivityCompat.shouldShowRequestPermissionRationale(activity, WRITE_EXTERNAL_STORAGE)) {
                                //show permission snackbar
                            } else {
                               //display error dialog
                            }
                        }
            
                    });
            

            请求权限。注册的ActivityResultCallback得到这个请求的结果。

            if (checkSelfPermission(activity, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PermissionChecker.PERMISSION_GRANTED) {
                                requestPermissionLauncher.launch(Manifest.permission.WRITE_EXTERNAL_STORAGE);
                            } else {
                                //Permission already granted 
                            }
            

            【讨论】:

              猜你喜欢
              • 2023-02-26
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2023-03-21
              • 2018-09-26
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多