从 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】:

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

我能够使用ContextCompatcheckSelfPermission,然后正如@NasaGeek 所说,调用android.support.v4.app.FragmentrequestPermissions 请求许可,然后在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&lt;Fragment&gt; 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&lt;String[]&gt; activityResultLauncher resultLauncher,当您需要权限时,只需调用resultLauncher.launch(stringArrayOfPermissions)。详细示例请查看第一行的链接。

【讨论】:

以上是关于从 v4.Fragment 请求运行时权限并让回调转到 Fragment?的主要内容,如果未能解决你的问题,请参考以下文章

片段中的请求权限

如何从 Support V4 Fragment 获取父活动?

使用请求进行异步调用并让回调在函数中工作[重复]

在一个ViewPager中同时使用v4 Fragment和native Fragment

如何从 Android Marshmallow 中的服务请求权限

从片段替换片段时,onRequestPermissionsResult 回调不起作用