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

Posted

技术标签:

【中文标题】如何处理 Activity 和 Fragment 之外的权限请求?【英文标题】:How to handle permission requests outside Activity and Fragment? 【发布时间】:2016-07-28 20:00:31 【问题描述】:

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

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

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

【问题讨论】:

我知道你的帖子已经过时了,你可能已经从这个问题上移开了。有几个库可以让你做到这一点。 【参考方案1】:

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

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

WebView 不遵守这一点,结果会导致问题(例如,在主应用程序线程上进行磁盘 I/O)。

如何在不涉及外部方(即 Activity 或 Fragment)的情况下实现权限处理?

你不能。请求权限是 Activity 或 Fragment 的责任,大概在您的视图需要这些数据之前。

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

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

【讨论】:

【参考方案2】:

如果没有 Activity 的实例,您将无法使用权​​限,但您可以让您的代码更漂亮。如果你想发送一个请求并在一个地方处理它,那么你可以使用下面的例子。

只需创建一个看起来像 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);
        
    

我已经通过请求代码使用了备用数组和索引,但您可以使用另一种存储回调的方式。

这是一个非常简单的例子,你可以在那里看到更严重的东西 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 - 使用权限的客户端代码

【讨论】:

【参考方案3】:

假设您需要在用户单击“确定”或其他按钮时从对话框片段中调用 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*]);

【讨论】:

【参考方案4】:

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

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

【讨论】:

以上是关于如何处理 Activity 和 Fragment 之外的权限请求?的主要内容,如果未能解决你的问题,请参考以下文章

离开 Activity 时 Android 如何处理后台线程?

android软键盘弹出时如何处理页面布局

片段如何处理触摸?

如何处理 Freemarker 字符串模板?

如何处理片段上的触摸事件?

如何处理Android导航栏菜单键上的长按?