安卓6.0权限 => 取消权限并返回应用时崩溃

20

我希望在我的应用程序中使用Android 6的权限,但我遇到了一个奇怪的问题。也许你能帮助我。

如果您使用“危险”权限启动应用程序,则这些权限将出现在您的Android设备的“应用程序权限”中。完美!

但是,如果您将应用程序保留在后台,转到“应用程序权限”菜单,禁用(可以启用,然后禁用)某个权限,然后返回到您的应用程序中,Android永远不会进入onStart(片段或活动)?!而且再也不会进入那里。

如果您不触摸权限或启用权限,它将进入onStart和其他内容。

这很有问题,例如,如果您的应用程序使用监听器,您无法重新启动它并可能会崩溃...

您知道当您禁用权限时,Android会执行哪个方法吗?

我尝试过 onCreate onStart onResume onRestart onRestoreInstanceState onActionModeStarted onRestoreInstanceState onPostResume onContentChanged

...但是没有用... :/


4
“android 永远不会进入 onStart(片段或活动)?!而且永远不会再次进入。”-- 如果用户从设置中撤销了权限,Android 将终止您的进程。如果在后台时 Android 因任何其他原因终止您的进程,您需要采取相同的处理方式。 - CommonsWare
谢谢您的回答!我会继续调查。当我创建我的活动时,我显示1个片段。如果我更改权限并返回应用程序,则会出现2个片段(更改权限之前和之后的片段)。您有任何想法为什么旧片段被保留吗? - acs-team
你有没有想过为什么旧的片段被保留?因为你的任务仍未完成,所以Android会重新创建活动并尽可能地恢复其状态,包括重新创建任何现有的片段。如果您经历配置更改(例如,旋转屏幕),则会获得相同的结果,因为默认情况下将销毁并重新创建您的活动。在添加片段之前,请检查该片段是否存在。 - CommonsWare
非常感谢!!!现在好多了! :p - acs-team
1
我们也遇到了同样的问题。已经修复了吗? - Suresh
我的解决方案如下!!! - acs-team
2个回答

8

以下是我的解决方案:

在我的主活动中,我使用了一些片段。

正如您所知,当用户禁用权限时,活动会被重新创建 => 经历onCreate等环节...

在我的mainActivity的onCreate(...)中,我移除了所有已加载的片段,并将我的应用程序恢复到第一次运行时的状态。

就像这样:

    // Clean fragments (only if the app is recreated (When user disable permission))
    FragmentManager fragmentManager = getSupportFragmentManager();
    if (fragmentManager.getBackStackEntryCount() > 0) {
        fragmentManager.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
    }

    // Remove previous fragments (case of the app was restarted after changed permission on android 6 and higher)
    List<Fragment> fragmentList = fragmentManager.getFragments();
    if (fragmentList != null) {
        for (Fragment fragment : fragmentList) {
            if (fragment != null) {
                fragmentManager.beginTransaction().remove(fragment).commit();
            }
        }
    }

注意!:我遇到了 appcompat 和 design 库的 23.2.0 版本的 crash。这个 crash 会在应用程序重新创建时出现!

请查看此链接获取更多信息。


1
我们何时知道活动被重新创建?出现崩溃“片段不再存在”。 - Santosh
@Santosh,你可以像上面写的那样检查片段管理器是否有任何片段,或者使用我的解决方案,在应用程序类中保存初始化状态。在重新启动的情况下,你的应用程序通常会从启动活动闪屏开始,启动活动将被跳过,直接显示最后一个活动。 - eugstman

8
如已指出,正确的Android会重新启动您的应用程序。这与您的应用程序在后台时,系统由于使用更多内存而杀死应用程序的行为相同。 当您返回到应用程序时,最后一个活动包括片段将被重新创建。
通常使用启动屏幕(闪屏)来初始化应用程序。 一旦应用程序初始化完成(例如服务、视图模型已准备就绪),启动活动就会切换到主活动。
许多应用程序在重新创建应用程序(例如撤销权限)时发生崩溃,因为应用程序未初始化,使用的服务或视图模型为空。 我认为没有办法避免在应用程序重新启动后重新创建最后一个活动。
您可以做的是检查应用程序是否已初始化,否则切换到启动活动并初始化应用程序。 请注意,您必须在活动和片段中处理未初始化的应用程序。
Xamarin示例代码:
if (!((MyApplication)ApplicationContext).IsInitialized)
{
    Intent intent = new Intent(Application.Context,typeof(StartupActivity));
    intent.SetFlags(ActivityFlags.NewTask);
    StartActivity(intent);
    Finish();
}

一旦调用base.onCreate,片段就会被创建,因此即使acs-team提供的“解决方法”也无法避免最后一个片段的重建。

如果活动有一个片段,则上述提供的示例代码的生命周期将如下所示:

  • 撤销权限应用程序被杀死
  • 重新启动应用程序
  • 应用程序OnCreate
  • LastActivity.OnCreate
  • LastFragment.OnAttach
  • LastFragment.OnCreate
  • LastFragment.OnCreateView
  • LastFragment.OnViewCreated
  • LastFragment.OnDestroy
  • LastFragment.OnDettach
  • LastActivity.OnDestroy
  • StartupActivity.OnCreate

顺便说一句,您也可以通过adb shell测试应用程序重启:

打开您的应用程序,然后转到Android主屏幕,以便您的应用程序在后台运行

adb shell "ps | grep <com.yourpackage>" // get the app process id
adb shell run-as <com.yourpackage> kill <app-process-id>    // kill the app

通过图标或最近任务重新启动您的应用程序。


你能同时发布Java示例代码吗?在Java中似乎不存在IsInitialized方法。 - Cody
1
@Cody 这是一个标志,你在初始化所有必需的服务后在应用程序中设置。它在 Xamarin 和 Java 中不可用,你必须自己完成。 - eugstman
@eugstman 我在用户撤销任何权限时遇到问题。在这种情况下,应用程序会立即崩溃,并且应用程序中不会调用任何生命周期事件。是否有任何方法来处理这种情况? - Jan Nepraš
@JanNepraš,您的应用程序被杀死并重新启动,打开上一个活动。在撤销权限后立即检查logcat,您应该会在那里找到异常。此外,您也不应该进行调试,否则重启可能会失败。 - eugstman
你如何检测权限从设置中被移除的事件?@eugstman - Mansuu....
@Mansuu.... 你没有接收到任何事件,但你的应用程序已经重新启动。当你需要它们时,应该检查并请求所需的权限,例如:if (ContextCompat.CheckSelfPermission(this, Manifest.Permission.Camera) == (int)Permission.Granted) { } - eugstman

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接