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

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

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

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

【问题讨论】:

  • 我知道你的帖子已经过时了,你可能已经从这个问题上移开了。有几个库可以让你做到这一点。

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


【解决方案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),并在上下文所在的活动或片段中的相应方法中调用该方法。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2021-11-26
          • 1970-01-01
          • 2017-06-19
          • 1970-01-01
          • 1970-01-01
          • 2015-08-11
          • 2013-05-29
          • 2020-06-04
          相关资源
          最近更新 更多