不推荐使用 Android-onRequestPermisonsResult()。是否有其他选择?

我试图实现从存储器进行写入和读取的请求权限。一切都很顺利,但是今天 Android 向我展示了 RequestPermisonsResult (...)方法已被弃用。在 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))

但是它们都显示 onRequestPermisonsResult (...)是不推荐的。

下面是我的 onRequestPermission (...)-方法:

  @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();
}
}
}

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

  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();
}

对于 onRequestPermisonsResult (...) ,有什么替代方案可以使用吗?

46280 次浏览

androidx.fragment.app.Fragment中不推荐使用 onRequestPermissionsResult()方法。

因此,可以使用 registerForActivityResult()方法而不是 onRequestPermissionsResult()方法。

您可以参考此 网址

以下是 Kotlin 代码,但你可以参考:

val requestPermissionLauncher = registerForActivityResult(
ActivityResultContracts.RequestPermission()
) { isGranted ->
if (isGranted) {
// PERMISSION GRANTED
} else {
// PERMISSION NOT GRANTED
}
}


// Ex. Launching ACCESS_FINE_LOCATION permission.
private fun startLocationPermissionRequest() {
requestPermissionLauncher(Manifest.permission.ACCESS_FINE_LOCATION)
}

我从下面的 URL 添加了 Java 代码。
如何在新的 ActivityResult API (1.3.0-alpha05)中获得权限请求?

private ActivityResultLauncher<String> requestPermissionLauncher = registerForActivityResult(
new ActivityResultContracts.RequestPermission(),
new ActivityResultCallback<Boolean>() {
@Override
public void onActivityResult(Boolean result) {
if (result) {
// PERMISSION GRANTED
} else {
// PERMISSION NOT GRANTED
}
}
}
);


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

您还可以请求多个权限:

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


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

您可以使用一些外部库进行权限处理,以减少一些样板代码。我用 德克斯特图书馆。如果您正在使用 RxJava2,Rx 许可也是一个很好的选择。

这对我有用:

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")
}
}

科特林中的一种简单方法

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
}
}

替代 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()
}
}
}

大多数答案都满足 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 ())。否则它不会工作,应用程序会崩溃。

错误:

Lang. IllegalStateException: 片段概要片段{ bf12414}(210ad5a1-3286-4586-a48f-deac1d8e3eef Id = 0x7f09008b)正在尝试注册 ForActivityResult 片段必须在调用 registerForActivityResult ()之前调用 创建(即初始化、 onAttach ()或 onCreate ())。

B)建议在真正需要的时候申请许可。在我的示例中,当用户使用 id locBtn单击 Button时,显示的是权限对话框,而不是显示创建活动/片段的时间。

请参阅官方文件: 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)
}
}

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

 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
}

在 pubspec.yamal 的 flutter 部分试试这个:

 plugin:
androidPackage: com.ly.permission
pluginClass: PermissionPlugin

对我有用。