如何处理Activity和Fragment之外的权限请求?

时间:2016-04-07 18:42:39

标签: android android-custom-view android-permissions android-6.0-marshmallow android-external-storage

我正在开发一个需要访问外部存储的自定义复合视图。如何在不涉及外部各方(即活动或片段)的情况下实施权限处理?

我知道我可以使用View的上下文请求权限,但是如何在View中处理onRequestPermissionsResult()?它甚至可能吗?

如果不可能,处理这样的事情最优雅的解决方案是什么?

4 个答案:

答案 0 :(得分:6)

  

我正在开发一个需要访问外部存储的自定义复合视图

恕我直言,这是一个架构错误。 View用于向用户显示内容,有时用于收集低级输入事件并将其转换为更高阶的构造(例如,点击,滑动)。 View不应与文件,数据库等有任何连接。请参阅MVC,MVP,MVVM和类似的GUI架构模式。

不遵守此规则的

WebView会导致问题(例如,在主应用程序线程上执行磁盘I / O)。

  

如何在不涉及外部各方的情况下实施权限处理,即活动或片段?

你做不到。活动或片段负责请求许可,大概是在您的视图需要此数据之前。

  

处理这样的事情最优雅的解决方案是什么?

将此View的数据访问部分提取到由活动或片段管理的其他内容中,其中可以管理与该数据访问相关联的线程,权限和其他工作。

答案 1 :(得分:0)

没有活动实例,就无法使用权​​限,但可以使代码更漂亮。如果要发送请求并在一个地方处理,则可以使用以下示例。

只需创建类似于BaseActivity的代码并将其放在其中

public class PermActivity extends Activity {

    interface OnPermissionCallback{
        void requestResult(String[] permissions, int[] grantResults);
    }

    private SparseArray<OnPermissionCallback> permissionCallback = new SparseArray<>();

    @Override
    public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
        permissionCallback.get(requestCode).requestResult(permissions, grantResults);
    }

    public void addPermissionCallback(int requestCode, OnPermissionCallback  callback){
        permissionCallback.put(requestCode, callback);
    }
}

现在在我们的客户代码中,我们可以做类似的事情

class SomeClasThatWorksWithPerms{

    private PermActivity activity;

    public SomeClasWorksWithPerms(PermActivity activity) {
        this.activity = activity;
    }

    void foo(){
        if (ContextCompat.checkSelfPermission(activity, WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED){
            // do something
        }else {
            activity.addPermissionCallback(0, (perms, grantResults) -> {
                if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                    foo(); // try one more
                }
            });
            activity.requestPermissions(new String[]{WRITE_EXTERNAL_STORAGE}, 0);
        }
    }
}

我在请求代码中使用了spareArray和索引,但是您可以使用另一种存储回调的方式。

这是一个非常简单的示例,您可以在那里看到更严重的内容 https://github.com/mrizyver/Fl_Launcher/blob/master/app/src/main/java/com/izyver/fllauncher/presentation/activity/FlActivity.kt-如您所见,这是活动 https://github.com/mrizyver/Fl_Launcher/blob/master/app/src/main/java/com/izyver/fllauncher/presentation/loaders/WallpaperLoader.kt-具有权限的客户代码

答案 2 :(得分:0)

让我们假设您需要在用户单击“确定”或其他按钮时从对话框片段调用 requestPermissionLauncher。这是在 MainActivity 中找到的 requestPermissionLauncher,或者您可以将它放在调用对话框片段的任何其他活动中。

public ActivityResultLauncher<String> requestPermissionLauncher =
        registerForActivityResult(new ActivityResultContracts.RequestPermission(), isGranted -> {
            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.
               
            }
        });

这里是代码源,如果你想参考https://developer.android.com/training/permissions/requesting

然后在您的对话框片段中使用以下代码调用实例 requestPermissionLauncher

((MainActivity)getContext()).requestPermissionLauncher.launch(Manifest.permission.[*your permission goes here*]);

答案 3 :(得分:-2)

只有在活动和碎片中才有可能。

您可以在视图中复制public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults),并在上下文所在的活动或片段中的相应方法中调用该方法。