【问题标题】:Request runtime permissions from v4.Fragment and have callback go to Fragment?从 v4.Fragment 请求运行时权限并让回调转到 Fragment?
【发布时间】:2025-12-05 00:35:01
【问题描述】:

我遇到了一个导致冲突的奇怪问题。我不得不切换到原生 Fragments 来修复它,但存在一些错误。

我最初的问题:我有一个带有v4 Fragments. 的导航抽屉设置要在我调用ActivityCompat.requestPermissions(getActivity(), Manifest.permission.ACCESS_FINE_LOCATION, 1); 的片段中请求许可,提示显示得很好,但是当我接受或拒绝许可时,没有任何反应。永远不会调用回调 onRequestPermissionsResult()。相反,它在我的 Fragments 附加到的 Activity 中被调用。对我没用,我需要回调才能在 Fragment 中工作。

考虑到这一点,我被告知我需要使用 FragmentCompat,但这仅适用于 native Fragments (v13+),因此我将导航抽屉更改为使用原生 Fragments 而不是 v4 支持库 Fragments。 但是,因为我正在使用 AppCompatActivity,某些事情不起作用,例如 addToBackStack() 并返回到上一个片段。

长话短说,有谁知道我如何使用v4.Fragment 并且仍然在Fragment 中请求许可并让回调在Fragment 中?我觉得这是 Android 中的一个错误,尚未解决,但我不是 100%。

如果您需要查看我的代码,请告诉我,这只是您获得运行时权限所需的标准方法,我想使用 v4 片段,但据我了解这不起作用。

【问题讨论】:

    标签: java android android-fragments android-6.0-marshmallow


    【解决方案1】:

    将此添加到父活动对我有用:

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        List<Fragment> fragments = getSupportFragmentManager().getFragments();
        if (fragments != null) {
            for (Fragment fragment : fragments) {
                fragment.onRequestPermissionsResult(requestCode, permissions, grantResults);
            }
        }
    }
    

    来源:https://code.google.com/p/android/issues/detail?id=189121#c5

    【讨论】:

    • 干得好!将其发送给所有人并在那里检查编解码器。非常感谢!
    • 干得好。感谢您提供对现实世界有用的答案。
    • 完美解决方案。
    • 在某些情况下,片段可能为 null 但仍位于片段数组中,因此应添加检查以确保安全(或者,在 Kotlin 中,您可以使用 fragment?.onRequestPermissionsResult(...)
    • 我认为你不应该使用 for 循环。因为也许您有另一个片段在侦听相同的权限并且它不在堆栈顶部,并且您可能在其回调中显示弹出窗口或其他操作,因此虽然它在屏幕上不可见,但它将继续其进度。所以用户可能会对此感到困惑。我将此代码更改为此。 List&lt;Fragment&gt; fragments = getSupportFragmentManager().getFragments(); fragments.get(fragments.size() - 1).onRequestPermissionsResult(requestCode, permissions, grantResults); 现在只有最后一个可见的片段接收回调。
    【解决方案2】:

    如果您需要在fragment v4 中获取permissionResult,请确保使用

    Fragment.requestPermission(String[], int);
    

    而不是

    AppCompat.requestPermission(Activity, String[], int)
    

    查看this答案!

    【讨论】:

      【解决方案3】:

      这种行为似乎出现在 v4 Fragment 支持类 requestPermissions in Fragment 中。 Activity/FragmentCompat 实现适用于希望在 11 到 23 之间的 API 级别上使用具有扩展功能的本机类。

      【讨论】:

      • 根据我的理解使用 Activity/FragmentCompat 的原因是,这意味着我不必检查用户是否在 Android 6.0 上,如果他们在旧版本的安卓。使用此代码,我将不得不为 API 23 上的那些和那些不是的代码添加代码,或者至少以不同的方式构建我的语句,因为 Android 不会处理它。我想那对我来说是不可用的?
      • 嗯,很奇怪。我对其进行了测试,并且效果很好。即使在旧版本的 Android 上,它也可以在没有请求许可的情况下无缝运行。也许我把事情搞混了,谢谢你的提示! +1 并将标记为答案。
      • 这对我也很好。感谢您的指导...我想知道 requestPermission 方法如何在 v4 Fragment 中可用
      【解决方案4】:

      你可以使用这部分代码

      requestPermissions(new String[]{Manifest.permission.GET_ACCOUNTS}, PERMISSION_REQUEST_CODE);
      

      【讨论】:

        【解决方案5】:

        我最近遇到了同样的情况,当我需要检查支持片段内的权限并在那里获得回调时。

        我能够使用ContextCompatcheckSelfPermission,然后正如@NasaGeek 所说,调用android.support.v4.app.FragmentrequestPermissions 请求许可,然后在v4 片段中​​回电onRequestPermissionsResult

        希望这会有所帮助。

        谢谢。

        【讨论】:

        • 能否请您出示该代码...我遇到了同样的问题。
        【解决方案6】:

        v4.Fragment 运行良好。我对 v4.Fragment 的嵌套片段有疑问。请求权限,但在嵌套片段中从未调用回调 onRequestPermissionsResult()!

        Issue opened

        【讨论】:

        • 我也有同样的问题,怎么办?
        • @sonida 有一个解决该问题的方法:从父片段显式调用子 onRequestPermissionsResult()。您可以在问题页面上找到代码。也请给问题加注星标。
        • @sonida 在下面查看我的答案
        【解决方案7】:

        目前最稳定的解决方案是手工完成。我自己只是通过通知父片段中的子片段来解决它。

        if (fragment.getParentFragment() != null) {
                                    Fragment parentFragment = fragment.getParentFragment();
                                    try {
                                        ChildFragmentPermissionRegistry registry = (ChildFragmentPermissionRegistry) parentFragment;
                                        registry.registerPermissionListener((ChildFragmentPermissionCallback) fragment);
                                        parentFragment.requestPermissions(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.READ_EXTERNAL_STORAGE}, STORAGE_PERMISSION_REQUEST_CODE);
                                    } catch (ClassCastException e) {
                                        Log.e(PermissionVerifier.class.getSimpleName(), e.getMessage());
                                    }
                                } else {
                                    fragment.requestPermissions(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.READ_EXTERNAL_STORAGE}, STORAGE_PERMISSION_REQUEST_CODE);
                                }
        

        父fragment实现接口ChildFragmentPermissionRegistry并注册子fragment的地方,

        @Override
        public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
            super.onRequestPermissionsResult(requestCode, permissions, grantResults);
            if (callback != null) {
                callback.onRequestPermissionsResult(requestCode, permissions, grantResults);
                callback = null;
            }
        }
        

        子片段实现 ChildFragmentPermissionCallback

        接口是这样的:

        public interface ChildFragmentPermissionCallback {
            void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults);
        }
        
        public interface ChildFragmentPermissionRegistry {
            void registerPermissionListener(ChildFragmentPermissionCallback callback);
        }
        

        【讨论】:

          【解决方案8】:

          不知道是不是最近被google修复了,但是不做任何花招就可以达到预期的效果。

          最重要的是在activity中调用super.onRequestPermissionsResult(requestCode, permissions, grantResults);,这样如果从fragment请求它就会把结果传递给fragment。

          所以,我要做的是:

          1) 在片段中,使用v4 fragment.requestPermissions(permissions, requestCode)请求权限

          2) 在活动的 onRequestPermissionsResult 中,必须调用 super.onRequestPermissionsResult(requestCode, permissions, grantResults);

          3) 在fragment的onRequestPermissionsResult中,写我要处理结果的代码。

          【讨论】:

            【解决方案9】:

            在我的情况下,我已经请求了片段的许可,并且还需要在片段中获取响应。

            但是我的手机运行的是 android 8.1

            所以我需要再添加一个条件来检查这个

            所以最终有我的解决方案

            private void doOnWazeButtonClick()
            {
                int permissionStatus = PackageManager.PERMISSION_DENIED;
            
                if (getContext() != null)
                {
                    permissionStatus = ContextCompat.checkSelfPermission(getContext(), Manifest.permission.ACCESS_FINE_LOCATION);
                }
            
                if (permissionStatus == PackageManager.PERMISSION_GRANTED)
                {
                    showContentWaze();
                }
                else
                {
                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M)
                    {
                        Objects.requireNonNull(getActivity()).requestPermissions(new String[] {Manifest.permission.ACCESS_FINE_LOCATION}, REQUEST_CODE_PERMISSION_ACCESS_FINE_LOCATION);
                    }
                    else
                    {
                        requestPermissions(new String[] {Manifest.permission.ACCESS_FINE_LOCATION}, REQUEST_CODE_PERMISSION_ACCESS_FINE_LOCATION);
                    }
                }
            }
            

            【讨论】:

              【解决方案10】:

              检查 Fragment 的运行时权限(2021 方式)

              我已经在另一个问题中回答了这个问题,这是链接:answer link.

              简而言之,我们现在可以在片段中使用registerForActivityResult。在片段的构造函数中(在onCreate 之前),初始化ActivityResultLauncher&lt;String[]&gt; activityResultLauncher resultLauncher,当您需要权限时,只需调用resultLauncher.launch(stringArrayOfPermissions)。详细示例请查看第一行的链接。

              【讨论】:

                【解决方案11】:

                只需使用 requestPermission("your permission/s in string array",your request code) 就不需要使用Fragment.requestPermissons(String[],int );

                你的片段中的这个方法调用android.support.v4.app.Fragment class i.e的requestPermissions

                public final void requestPermissions(@NonNull String[] permissions, int requestCode) {
                        if (mHost == null) {
                            throw new IllegalStateException("Fragment " + this + " not attached to Activity");
                        }
                        mHost.onRequestPermissionsFromFragment(this, permissions, requestCode);
                    }
                

                【讨论】:

                  最近更新 更多