onRequestPermissionsResult 未在对话框片段中调用

onRequestPermissionsResult not being called in dialog fragment

我已经开始研究 Android M 运行时权限。在这里,我面临的问题是,如果从 Dialog Fragment class 调用 requestPermissions,那么 onRequestPermissionsResult 不会在同一个 Dialog fragment class 中被调用。但是如果 requestPermissions 是从 Activity class 或 Fragment class 调用的,那么 onRequestPermissionsResult 方法会在同一个 class 中被调用。

这是我的示例代码:

public class ContactPickerDialog extends DialogFragment {
    private static final int READ_CONTACTS_REQUEST_CODE = 12;
    private Context mContext;

    private void loadContact() {
        if(hasPermission(mContext, Manifest.permission.READ_CONTACTS)){
            new ContactSyncTask().execute();
        } else {
            this.requestPermissions(new String[]{Manifest.permission.READ_CONTACTS}, READ_CONTACTS_REQUEST_CODE);
        }
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
        Logger.d("TAG", "dialog onRequestPermissionsResult");
        switch (requestCode) {
            case READ_CONTACTS_REQUEST_CODE:
                // Check Permissions Granted or not
                if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                    new ContactSyncTask().execute();
                } else {
                    // Permission Denied
                    Toast.makeText(getActivity(), "Read contact permission is denied", Toast.LENGTH_SHORT).show();
                }
            break;
            default:
                super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        }
    }

    private static boolean hasPermission(Context context, String permission){
        return ContextCompat.checkSelfPermission(context, permission) == PackageManager.PERMISSION_GRANTED;
    }

} 

在代码中,我调用了 Dialog Fragment class 的 requestPermissions 方法。所以我希望得到相同的结果 class.

感谢任何帮助。提前致谢!


编辑: 在这里,我添加了更多细节,以便对其他人更有帮助。 以前我使用 getChildFragmentManager() 来显示 DialogFragment。

ContactPickerDialog dialog = new ContactPickerDialog();
dialog.show(getChildFragmentManager(), "Contact Picker");

但是由于 @CommonWare 要求我使用 activity 来显示 DialogFragment。我进行了以下更改并且有效。

ContactPickerDialog dialog = new ContactPickerDialog();
dialog.show(getActivity().getSupportFragmentManager(), "Contact Picker");

似乎有 a bug in Android,其中嵌套片段不支持 onRequestPermissionsResult() 回调。对于 DialogFragment,解决方法似乎是让想要显示对话框的片段调用主机 activity 上的方法,而 activity 显示 DialogFragment 本身。

如果您在支持库的 Fragment 中,调用 requestPermissions() directly, and your Fragment's onRequestPermissionsResult() 将被回调。

如果您拨打 ActivityCompat.requestPermissions(), then it's the Activity's onRequestPermissionsResult() 将被回叫。

对我有帮助的一件事就是这个。 当您请求嵌套片段的许可时,请像这样使用 getParent

 fragment.getParentFragment().requestPermissions((new String[]
              {Manifest.permission.READ_CONTACTS}), requestCode);

然后覆盖父片段onRequestPermissionResult并检查相应的requestCode。

希望对你也有帮助。

如果嵌套片段有问题,可以请求父片段的许可

getParentFragment().requestPermissions(new String[]{permission}, requestCode);

然后将回调转发给子片段

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

编辑:

我建议使用新版本的支持库 23.3.0,因为 Google fixed issue with not calling onRequestPermissionsResult,但如果出于某些原因您需要使用旧版本,请参阅下面的原始答案。

原始答案:

我正在使用下一个解决方法(连同 easyPermissions 库):

基础片段:

@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
    /** child v4.fragments aren't receiving this due to bug. So forward to child fragments manually
     * https://code.google.com/p/android/issues/detail?id=189121
     */
    super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    List<Fragment> fragments = getChildFragmentManager().getFragments();
    if (fragments != null) {
        // it is possible that fragment might be null in FragmentManager
        for (Fragment fragment : fragments) {
            if (fragment != null) {
                fragment.onRequestPermissionsResult(requestCode, permissions, grantResults);
            }
        }
    }
}

基础活动:

@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
    Fragment fragment = getSupportFragmentManager().findFragmentById(getFragmentContainer())
    if (fragment != null) {
        fragment.onRequestPermissionsResult(requestCode&0xff, permissions, grantResults);
    }
}

用法:

public class SomeFragment extends BaseFragment implements EasyPermissions.PermissionCallbacks {
    private static final int PICK_CONTACT = 1;
    private static final int READ_CONTACTS_PERM = 2;

    // some code

    @AfterPermissionGranted(READ_CONTACTS_PERM)
    private void pickContactWithPermissionsCheck() {
        if (EasyPermissions.hasPermissions(getContext(), Manifest.permission.READ_CONTACTS)) {
            // Have permission
            pickContactForResult();
        } else {
            // Request one permission
            EasyPermissions.requestPermissions(this, getString(R.string.read_contacts_permission_explanation),
                    READ_CONTACTS_PERM, Manifest.permission.READ_CONTACTS);
        }
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);

        // FIXME problem with incorrect requestCode coming to callback for Nested fragments
        // More information here - https://code.google.com/p/android/issues/detail?id=189121
        if (isVisible() && Arrays.asList(permissions).contains(Manifest.permission.READ_CONTACTS)) {
            requestCode = READ_CONTACTS_PERM;
        }

        // EasyPermissions handles the request result.
        EasyPermissions.onRequestPermissionsResult(requestCode, permissions, grantResults, this);
    }
}

issue seems to be fixed in Android Support Library 23.3.0及以上版本。

If you’re using Support v4 Fragments, nested fragments will now receive callbacks to onRequestPermissionsResult().

编辑:@AndrewS,这是更新的方法。

在您的 build.gradle(app) 文件中,更改以下行以使用最新版本的最新支持库 24.0.0:

dependencies {
    compile 'com.android.support:appcompat-v7:24.0.0'
}

我在没有嵌套片段的情况下遇到了这个问题,其中 activity 显示了对话框片段,结果没有通过。

添加
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
Activity 的 onRequestPermissionsResult() 解决了这个问题。

我是这样搞定的

public class DialogFragmentSMS extends DialogFragment implements View.OnClickListener {

public static DialogFragmentSMS frag;
private static View view;
private static ViewGroup parent;
private EditText editTextMensagem;
private String celular;

private final static int SMS_REQUEST = 20;

public DialogFragmentSMS() {

}
public static DialogFragmentSMS newInstance(String celular)
{

    Bundle args = new Bundle();
    args.putString("celular", celular);
    frag = new DialogFragmentSMS();
    frag.setArguments(args);
    return frag;
}

@Override
public void onCreate(Bundle saveInstaceState)
{
    super.onCreate(saveInstaceState);
}

    @Override
public void onClick(View v) {
    if (!PermissaoUtils.hasPermission(getActivity(), Manifest.permission.SEND_SMS)) {
        //PermissaoUtils.requestPermissions(getActivity(), new String[]{Manifest.permission.SEND_SMS}, SMS_REQUEST);
        frag.requestPermissions(new String[]{Manifest.permission.SEND_SMS}, SMS_REQUEST);
    }else{
        if (validaCampos()) {
            SmsManager smsManager = SmsManager.getDefault();
            smsManager.sendTextMessage("0" + celular, null, editTextMensagem.getText().toString(), null, null);
            Toast.makeText(getActivity(), R.string.sms_enviado, Toast.LENGTH_SHORT).show();
            getDialog().getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN);
            frag.dismiss();
        }
    }
}

我的Class权限

public class PermissaoUtils
{
    public static boolean useRunTimePermissions() {
        return Build.VERSION.SDK_INT > Build.VERSION_CODES.LOLLIPOP_MR1;
    }

    public static boolean hasPermission(Activity activity, String permission) {
        if (useRunTimePermissions()) {
            return activity.checkSelfPermission(permission) == PackageManager.PERMISSION_GRANTED;
        }
        return true;
    }

    public static void requestPermissions(Activity activity, String[] permission, int requestCode) {
        if (useRunTimePermissions()) {
            activity.requestPermissions(permission, requestCode);
        }
    }
}

如果您查看片段的 requestPermissions 方法的文档,您会发现您仍然需要在清单中声明权限:

如果不是这种情况,片段自己的 onRequestPermissionsResult 将不会被调用。

相反,activity 的 onRequestPermissionsResult 被调用但不会有任何效果。

因此,应按如下方式从片段中授予权限:

1.在清单中声明权限

<uses-permission android:name="android.permission.CAMERA"/>

在应用程序标签前输入。

2。检查您的片段中的权限

if (ActivityCompat.checkSelfPermission(context, permission) 
        != PackageManager.PERMISSION_GRANTED) {

    requestPermissions(
        arrayOf(Manifest.permission.CAMERA), 
        REQUEST_CODE_CAMERA_PERMISSION)
}

3。在您的片段中等待许可结果

override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
    when (requestCode) {
        REQUEST_CODE_CAMERA_PERMISSION -> { 

        val granted = grantResults.isNotEmpty()
            && permissions.isNotEmpty()
            && grantResults[0] == PackageManager.PERMISSION_GRANTED
            && !ActivityCompat.shouldShowRequestPermissionRationale(activity, permissions[0])    

        when (granted) {
            true -> openCamera()
            else -> proceedWithoutPermission()
        }
    }
}

4.确保您没有覆盖 activity 的 onRequestPermissionsResult

覆盖 activity 的 onRequestPermissionsResult 将导致片段的不反应。

除了 Nino Handler 的回答的结尾部分之外,对于仍然对此有疑问的任何人,请确保如果您在对话片段的父级 activity/fragment 中重写 onRequestPermissionsResult,您调用 super.onRequestPermissionsResult那里。

我在对话框片段的父级 activity 中重写了 onRequestPermissionsResult,但忽略了在那里调用 super 方法。一旦我将其更改为调用 super 方法,它就会正确地委托给对话框片段中的 onRequestPermissionsResult。

我在 Android 清单中添加了 android:noHistory="true" android:excludeFromRecents="true",它对我有用,我不知道它如何影响其他功能。