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"
,它对我有用,我不知道它如何影响其他功能。
我已经开始研究 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"
,它对我有用,我不知道它如何影响其他功能。