从 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 的人。
我最近遇到了同样的情况,当时我需要在支持片段中检查权限并在那里获得回调。
我能够使用 ContextCompat
到 checkSelfPermission
,然后正如@NasaGeek 所说,我打电话给 android.support.v4.app.Fragment
的 requestPermissions
来请求许可,然后得到回电到 v4 片段中的 onRequestPermissionsResult
。
希望这对您有所帮助。
谢谢。
v4.Fragment 效果很好。我对 v4.Fragment 的嵌套片段有疑问。已请求权限,但从未在嵌套片段中调用回调 onRequestPermissionsResult()!
目前最稳定的解决方案是手工完成。我自己只是通过从父片段通知子片段来解决它。
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 以获得详细示例。
我遇到了一个导致冲突的奇怪问题。我不得不切换到本机 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 的人。
我最近遇到了同样的情况,当时我需要在支持片段中检查权限并在那里获得回调。
我能够使用 ContextCompat
到 checkSelfPermission
,然后正如@NasaGeek 所说,我打电话给 android.support.v4.app.Fragment
的 requestPermissions
来请求许可,然后得到回电到 v4 片段中的 onRequestPermissionsResult
。
希望这对您有所帮助。
谢谢。
v4.Fragment 效果很好。我对 v4.Fragment 的嵌套片段有疑问。已请求权限,但从未在嵌套片段中调用回调 onRequestPermissionsResult()!
目前最稳定的解决方案是手工完成。我自己只是通过从父片段通知子片段来解决它。
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
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 以获得详细示例。