安卓 - 有时会启动错误的活动页面

5
我有一个Android应用程序,其中包含许多活动。有时会启动错误的活动。
通常情况下,Application子类启动,然后启动活动(StartAct...android:name =“android.intent.action.MAIN”,android:name =“android.intent.category.LAUNCHER”)执行一些操作,然后启动InitializeActivity。这个活动也会执行一些工作,然后启动我的主显示活动(MainAct)。前两个活动都会进行一些必要的初始化,包括在启动MainAct之前设置静态“isInitialized”标志。
使用特定意图(...activity.class指定)通过startActivity()启动活动,并在startActivity()之后调用finish()。
然而,以下情况有时会发生,我不知道为什么......
简而言之,应用程序被杀死,当按下图标启动它时,它直接跳转到第三个(MainAct)活动。这导致应用程序检测到错误(isInitialized标志为false)并停止:
- 用图标正常启动应用程序: - ...Application子类启动,还启动一些工作线程 - ...StartActivity运行,然后启动InitializeActivity并完成 - ...InitializeActivity运行,然后设置isInitialized并启动MainAct并完成 - ...MainAct启动,运行正常 - ...按下Home按钮,运行Angry Birds - ...MainAct记录onPause,然后onStop。 - ...由Application子类拥有的工作线程继续定期执行操作并记录。 - 25分钟后,整个应用程序突然被杀死。这个观察是基于日志活动的结束, - 时间过去了 - 按下Home按钮 - 按下应用程序的Launcher ICON - Application子类onCreate被调用并返回 - *MainAct.onCreate被调用!(没有StartAct,没有InitializeActivity)*
我错过了什么?
注意:初始化标志是由于此问题添加的。它在代码中唯一启动主要活动的地方设置,并且仅在主要活动的onCreate中进行检查。
[按要求] 清单文件(略有删节)。请注意,此处的服务当前未使用。
<manifest
  xmlns:android="http://schemas.android.com/apk/res/android"
  package="xxx.yyy.zzz"
  android:versionCode="1" android:versionName="1.0.1">
  <application
    android:icon="@drawable/icon_nondistr"
    android:label="@string/app_name"
    android:name=".app.MainApp"
    android:debuggable="true">
    <activity
      android:label="@string/app_name"
      android:name=".app.StartAct" android:theme="@android:style/Theme.NoTitleBar">
      <intent-filter>
        <action
          android:name="android.intent.action.MAIN" />
        <category
          android:name="android.intent.category.LAUNCHER" />
      </intent-filter>
    </activity>
    <activity
      android:label="Html"
      android:name=".app.HtmlDisplayAct"/>
    <activity
      android:label="Init"
      android:configChanges="orientation"
      android:name=".app.InitializeActivity" android:theme="@android:style/Theme.NoTitleBar"/>
    <activity
      android:label="MyPrefs"
      android:name=".app.PrefsAct" />
    <activity
      android:label="@string/app_name"
      android:theme="@android:style/Theme.NoTitleBar"
      android:name=".app.MainAct">
    </activity>
    <service
      android:name=".app.svcs.DataGetterService" />
  </application>
  <uses-sdk android:minSdkVersion="4"/>
  <uses-permission
    android:name="android.permission.INTERNET" />
  <uses-permission
    android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
  <uses-permission
    android:name="android.permission.ACCESS_NETWORK_STATE" />
  <uses-permission
    android:name="com.android.vending.CHECK_LICENSE" />
  <uses-feature
    android:name="android.hardware.location.network"
    android:required="false" />
</manifest>

你能展示一下你的清单文件吗?似乎问题出在那里。 - Dinash
这是一个非常古老的帖子,但我很高兴你发了出来,也很高兴我找到了它。否则我可能不会相信我真的经历了Android对我的应用程序所做的事情。不幸的是,唯一的答案相当棘手 - 我必须向大约20个Activity类添加笨拙的代码来捕获所有可能的情况。你有没有找到更好的解决方案? - RenniePet
2个回答

2
当应用程序因低内存而被杀死时,这一事实应对用户透明。这就是为什么当应用程序被杀死时,Android会记住该应用程序中运行的最后一个活动,并在用户返回应用程序时直接创建此活动的原因。
也许您可以在您的Application(或MainAct)的onCreate()方法中做一些事情,以确保一切都得到适当的初始化。
顺便说一句,除非您真的需要,否则您不应该让工作线程在用户不使用您的应用程序时执行某些工作。根据您所做的内容,这可能会快速耗尽电池,或使用户认为它可能会快速耗尽电池(这更糟糕,因为用户将卸载您的应用程序!)
您还可以在用户退出应用程序时结束每个活动。

部分功能是在后台执行定期工作,因此我确实需要工作线程(可以在服务中,但它们不在那里)。虽然我可以让onCreate()确保初始化,但这并不容易(在初始化期间,我有一个不同的活动,所以我可以显示有关初始化的内容)。我在文档中找不到Android是否具有此行为,否则我就不会问了。您确定吗?请注意,对用户来说这并不透明-用户必须再次点击活动图标才能重新启动它。只是备份堆栈不会启动应用程序。谢谢。 - Mesocyclone
如果您将工作线程放在服务中,您的应用程序可能不会被杀死,也就不会出现这个问题。我不完全确定我所说的是否正确,但文档中说:“如果活动已暂停或停止,系统可以通过要求其完成或仅仅终止其进程来将该活动从内存中删除。当它再次显示给用户时,必须完全重新启动并恢复到其先前的状态。”在这里,不确定它的意思是什么。 - Guillaume Brunerie
另一个想法,不知道是否可行,是将MainAct声明为主要活动(其图标显示在启动器中),并使应用程序的onCreate()运行StartActivity(您可能需要在MainAct中等待初始化完成)。 - Guillaume Brunerie
我之前考虑过你的建议,我认为它可能是正确的解决方案。Android 似乎认为第一个 Activity 和最近的 Activity 在某种程度上都是特殊的,因此将它们设置为相同的确实是有意义的。目前,我只是检测条件并让 MainActivity 启动 StartActivity 然后 finish(),这样以一种不太优雅的方式解决了问题。我希望其他人也能提出自己的想法,但我会把这个标记为答案。谢谢! - Mesocyclone
我也遇到了这个问题,但这是一个非常非常丑陋的解决方案。我不知道为什么Android会决定启动一个活动,明知它和静态引用之间存在联系,就像在你的情况下一样,在启动时填充项目。 - Kevin Parker

1
这真的是一种“雪上加霜”的情况 - 首先,Android杀死了我的出色应用程序,然后当用户重新启动我的应用程序时,Android试图通过启动错误的活动来“有帮助地”解决问题,导致我的应用程序崩溃。叹气。

这是我非常拙劣的解决方案,以抵消Android的有益性。我的应用程序要求StartActivity必须是第一个活动,因此对于所有其他活动,我在onCreate()方法中添加一行。例如:

public class HelpActivity extends AppCompatActivity {

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

      if (StaticMethods.switchToStartActivityIfNecessary(this))  return;  // <- this is the magic line

      ...

   }

  ...

}

为了使这个工作正常,我在我的应用程序类中添加了一个开关变量:
public class OutBackClientApplication extends Application {

   ...

   // Switch to indicate if StartActivity has been started.
   // Values: -1 = StartActity has never been started or this is first invocation.
   //         0 = normal situation, StartActivity has been run at least once.
   private int _startActivityStatus = -1;

   public int getStartActivityStatus() { return _startActivityStatus; }

   public void setStartActivityStatus(int startActivityStatus) {
      _startActivityStatus = startActivityStatus;
   }

   ...

}

我有一个名为StaticMethods的类,其中包括以下方法:

public class StaticMethods {

   /**
    * Method to test for the problematic situation where Android has previously killed this app, and
    * then when the user restarts the app Android tries to be helpful by restarting the activity
    * that was in the foreground when it killed the app, instead of starting the activity specified
    * in the manifest as the launch activity. See here:
    * https://dev59.com/sVnUa4cB1Zd3GeqPYC03
    *
    * The following line should be added to the onCreate() method of every Activity, except for
    * StartActivity, of course:
    *
    *    if (StaticMethods.switchToStartActivityIfNecessary(this))  return;
    */
   public static boolean switchToStartActivityIfNecessary(Activity currentActivity) {

      OutBackClientApplication outBackClientApplication =
                                        (OutBackClientApplication) currentActivity.getApplication();

      if (outBackClientApplication.getStartActivityStatus() == -1) {
         currentActivity.startActivity(new Intent(currentActivity, StartActivity.class));
         currentActivity.finish();
         return true;
      }
      return false;
   }

}

最后,当StartActivity启动时,它需要重置开关:
 public class StartActivity extends AppCompatActivity {

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

      ((OutBackClientApplication) getApplication()).setStartActivityStatus(0);

      ...

   }

   ...

}

所有这些,只是为了抵消Android的“好心帮助”...

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