从 v4.Fragment 请求运行时权限并将回调转到 Fragment?

Request runtime permissions from v4.Fragment and have callback go to Fragment?

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

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

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

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

如果您需要查看我的代码,请告诉我,它只是您需要运行时权限的标准方法,我想使用 v4 片段,尽管根据我的理解这不起作用。

此行为似乎存在于 v4 片段支持中 class requestPermissions in Fragment。 Activity/FragmentCompat 实现适用于希望在 11 到 23 级 API 级别上使用具有扩展功能的本机 classes 的人。

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

我能够使用 ContextCompatcheckSelfPermission,然后正如@NasaGeek 所说,我打电话给 android.support.v4.app.FragmentrequestPermissions 来请求许可,然后得到回电到 v4 片段中​​的 onRequestPermissionsResult

希望这对您有所帮助。

谢谢。

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

Issue opened

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

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

其中父片段实现接口 ChildFragmentPermissionRegistry 并注册子片段,

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

将此添加到父 activity 对我有用:

@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

您可以使用这部分代码

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

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

Fragment.requestPermission(String[], int);

而不是

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

查看 答案!

只需使用requestPermission("your permission/s in string array",你的请求代码)根本不需要使用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);
    }

不知道最近有没有被google修复,不过不用任何技巧也能达到预期的效果

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

所以,我做的是:

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

请求许可

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

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

在我的例子中,我已经请求了片段的许可,并且还需要在片段中获得响应。

但是我的 phone 运行 在 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);
        }
    }
}

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

我已经在另一个问题中回答了这个问题,这里是link:

简而言之,我们现在可以在片段中使用registerForActivityResult。在片段的构造函数中(在 onCreate 之前),您初始化 ActivityResultLauncher<String[]> activityResultLauncher resultLauncher,当您需要许可时,只需调用 resultLauncher.launch(stringArrayOfPermissions)。请检查第一行的 link 以获得详细示例。