当用户在运行时权限对话框上单击拒绝时显示 DialogFragment

Posted

技术标签:

【中文标题】当用户在运行时权限对话框上单击拒绝时显示 DialogFragment【英文标题】:Show DialogFragment when user clicks deny on Runtime permissions dialog 【发布时间】:2016-01-15 21:12:43 【问题描述】:

我试图在用户在 android 6 的“允许/拒绝权限”对话框上单击“拒绝”后立即显示一个 DialogFragment 但我却收到此错误:

    Caused by: java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState
  at android.support.v4.app.FragmentManagerImpl.checkStateLoss(FragmentManager.java:1448)
  at android.support.v4.app.FragmentManagerImpl.enqueueAction(FragmentManager.java:1466)
  at android.support.v4.app.BackStackRecord.commitInternal(BackStackRecord.java:634)
  at android.support.v4.app.BackStackRecord.commit(BackStackRecord.java:613)
  at android.support.v4.app.DialogFragment.show(DialogFragment.java:139)
  at android.support.v4.app.FragmentActivity.onRequestPermissionsResult(FragmentActivity.java:802)
  at android.app.Activity.dispatchRequestPermissionsResult(Activity.java:6553)
  at android.app.Activity.dispatchActivityResult(Activity.java:6432)
  at android.app.ActivityThread.deliverResults(ActivityThread.java:3695)
  at android.app.ActivityThread.handleSendResult(ActivityThread.java:3742) 
  at android.app.ActivityThread.-wrap16(ActivityThread.java) 
  at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1393) 
  at android.os.Handler.dispatchMessage(Handler.java:102) 
  at android.os.Looper.loop(Looper.java:148) 
  at android.app.ActivityThread.main(ActivityThread.java:5417) 
  at java.lang.reflect.Method.invoke(Native Method) 
  at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726) 
  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616) 

我的对话代码很标准

  protected void showDialog(DialogFragment diag)
    
        if (diag != null && !diag.isAdded())
            diag.show(getSupportFragmentManager(), "dialog");
    

如何解决这个问题?

【问题讨论】:

【参考方案1】:

所以,有几个解决方案,没有一个特别漂亮。这意味着您的 Activity 的 FragmentManager 尚未处于以安全方式提交 FragmentTransactions 的有效状态(尽管在这种特殊情况下,它应该始终如此。)

1) 使用.commitAllowingStateLoss() 而不是.show()

这是最简单的解决方法,尽管我不完全清楚不使用 .show() 方法会产生什么差异,该方法在内部设置了一些标志。似乎工作正常。

getSupportFragmentManager()
        .beginTransaction()
        .add(diag, "dialog")
        .commitAllowingStateLoss();

1) 将.show() 作为Runnable 发布到Handler

// Initialize a Handler ahead of time and keep it around
private Handler mHandler = new Handler();

...

// after getting denied:
mHandler.post(new Runnable() 
    @Override
    public void run() 
        // Show your dialog
    


...

@Override
protected void onStop() 
    super.onStop();

    // Clear out the Runnable for an unlikely edge case where your
    // Activity goes to stopped state before the Runnable executes
    mHandler.removeCallbacksAndMessages(null);

2) 设置标志并在 onResume() 中显示对话框

private boolean mPermissionDenied;

@Override
public void onRequestPermissionsResult(...) 
    // If denied...
    mPermissionDenied = true;   


@Override
protected void onResume() 
    super.onResume();

    if (mPermissionDenied) 
        mPermissionDenied = false;
        // Show your dialog
    

【讨论】:

第一个最简单的解决方案对我不起作用。但是另外两个确实加上了我刚刚发现的一个新的。我会为此发布一个答案。并接受你的正确。谢谢!【参考方案2】:

我还想添加一些我刚刚发现的东西。如果我用getSupportFragmentManager().beginTransaction() 在现有代码上切换getSupportFragmentManager(),它工作正常。代码如下

   protected void showDialog(final DialogFragment diag)
    
        cancelDialog();
        if (diag != null && !diag.isAdded())
            diag.show(getSupportFragmentManager().beginTransaction(), "dialog");
    

不知道为什么我想这样做。

【讨论】:

这太奇怪了。查看这两种方法的来源,我无法想象为什么会有任何不同。不过,很高兴你有一个可行的解决方案。 :) 我在 *** 上浏览时实际上在另一个类似问题中看到了该解决方法(我没有链接)。所以我想它只是有效! 您在测试什么手机?刚刚在 Nexus 6 上尝试过,它对我来说无论哪种方式都崩溃了。 并且使用我上面提到的第一个解决方案确实对我有用。我想知道这是否与您似乎在重用对话框有关。也许它处于某种意想不到的状态?我建议只显示对话框的一个新实例。 也许你是对的 ^^ 遗憾的是我正在安卓模拟器上尝试这个。我没有安卓 6 设备。我认为我当前的代码结构使事情变得怪异。我刚刚尝试对我的代码进行一些更改,您的第一个解决方案也有效【参考方案3】:

用户点击拒绝后显示对话框并不是指南所说的。您应该仅在第二次请求之前显示许可理性。您可以在这里寻找自动管理:Permission library

【讨论】:

谢谢,我会考虑的

以上是关于当用户在运行时权限对话框上单击拒绝时显示 DialogFragment的主要内容,如果未能解决你的问题,请参考以下文章

文件选择器对话框只能在用户激活问题时显示

Activity 在调用运行时权限时变黑

Android - 仅在 AsyncTask 未完成时单击按钮时显示进度对话框

单击按钮时显示 jquery 数据表模式对话框不起作用

在操作按钮单击时显示 selectInput 和 sliderInput 值

如何在 CRM 的子网格形式中单击按钮时显示查找窗口?