从 v4.Fragment 请求运行时权限并让回调转到 Fragment?
Posted
技术标签:
【中文标题】从 v4.Fragment 请求运行时权限并让回调转到 Fragment?【英文标题】:Request runtime permissions from v4.Fragment and have callback go to Fragment? 【发布时间】:2015-12-29 16:36:28 【问题描述】:我遇到了一个导致冲突的奇怪问题。我不得不切换到原生 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 片段,但据我了解这不起作用。
【问题讨论】:
【参考方案1】:这种行为似乎出现在 v4 Fragment 支持类 requestPermissions in Fragment 中。 Activity/FragmentCompat 实现适用于希望在 11 到 23 之间的 API 级别上使用具有扩展功能的本机类。
【讨论】:
根据我的理解使用 Activity/FragmentCompat 的原因是,这意味着我不必检查用户是否在 Android 6.0 上,如果他们在旧版本的安卓。使用此代码,我将不得不为 API 23 上的那些和那些不是的代码添加代码,或者至少以不同的方式构建我的语句,因为 Android 不会处理它。我想那对我来说是不可用的? 嗯,很奇怪。我测试了它,它工作得很好。即使在旧版本的 Android 上,它也可以在没有请求许可的情况下无缝运行。也许我把事情搞混了,谢谢你的提示! +1 并将标记为答案。 这对我也很好。感谢您的指导...我想知道 requestPermission 方法如何在 v4 Fragment 中可用【参考方案2】:我最近遇到了同样的情况,当我需要检查支持片段中的权限并在那里获得回调时。
我能够使用ContextCompat
到checkSelfPermission
,然后正如@NasaGeek 所说,调用android.support.v4.app.Fragment
的requestPermissions
请求许可,然后在v4 片段中回电onRequestPermissionsResult
。
希望这会有所帮助。
谢谢。
【讨论】:
能否请您出示该代码...我遇到了同样的问题。【参考方案3】:v4.Fragment 运行良好。我对 v4.Fragment 的嵌套片段有疑问。请求权限,但在嵌套片段中从未调用回调 onRequestPermissionsResult()!
Issue opened
【讨论】:
我也有同样的问题,怎么办? @sonida 有一个解决该问题的方法:从父片段显式调用 childs onRequestPermissionsResult()。您可以在问题页面上找到代码。也请给问题加注星标。 @sonida 在下面查看我的答案【参考方案4】:目前最稳定的解决方案是手工完成。我自己只是通过通知父片段中的子片段来解决它。
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);
【讨论】:
【参考方案5】:将此添加到父活动对我有用:
@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<Fragment> fragments = getSupportFragmentManager().getFragments(); fragments.get(fragments.size() - 1).onRequestPermissionsResult(requestCode, permissions, grantResults);
现在只有最后一个可见的片段接收回调。【参考方案6】:
你可以使用这部分代码
requestPermissions(new String[]Manifest.permission.GET_ACCOUNTS, PERMISSION_REQUEST_CODE);
【讨论】:
【参考方案7】:如果您需要在fragment v4
中获取permissionResult,请确保使用
Fragment.requestPermission(String[], int);
而不是
AppCompat.requestPermission(Activity, String[], int)
查看this答案!
【讨论】:
【参考方案8】:只需使用 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);
【讨论】:
【参考方案9】:不知道是不是最近被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中,写我要处理结果的代码。
【讨论】:
【参考方案10】:在我的情况下,我已经请求片段的许可,并且还需要在片段中获取响应。
但是我的手机运行的是 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);
【讨论】:
【参考方案11】:检查 Fragment 的运行时权限(2021 方式)
我已经在另一个问题中回答了这个问题,这是链接:answer link.
简而言之,我们现在可以在片段中使用registerForActivityResult
。在片段的构造函数中(在onCreate 之前),初始化ActivityResultLauncher<String[]> activityResultLauncher resultLauncher
,当您需要权限时,只需调用resultLauncher.launch(stringArrayOfPermissions)
。详细示例请查看第一行的链接。
【讨论】:
以上是关于从 v4.Fragment 请求运行时权限并让回调转到 Fragment?的主要内容,如果未能解决你的问题,请参考以下文章
如何从 Support V4 Fragment 获取父活动?
在一个ViewPager中同时使用v4 Fragment和native Fragment