防止活动堆栈被恢复?

发布于 2024-10-26 11:12:05 字数 736 浏览 5 评论 0原文

当应用程序的进程被终止时,其活动堆栈将被保存。然后,当应用程序重新启动时,我的所有活动都会恢复并遇到空指针。我不想修改每个活动来适应此事件,而是宁愿让我的应用程序从基本活动开始,而不是尝试重新创建活动堆栈。

这可能吗?

我了解 Intent.FLAG_ACTIVITY_CLEAR_TOP,但据我了解,这只会在重新创建活动后将其杀死。

编辑: clearTaskOnLaunch 是我想要的吗?我已将其添加到我的默认活动中,但没有看到任何效果。但是,即使我只是最小化应用程序,这也会终止我的活动,不是吗?我宁愿只在整个进程重新启动时才清除堆栈。

编辑2:不,这不是我想要的 - 一位Android工程师对有关如何使用ClearTaskOnLaunch的一些问题给出了彻底的答复:http://groups.google.com/group/android-developers/browse_thread/thread/da024bcaf4e1960f/ab1e2b35c360cb65?pli=1

When an application's process is killed, its activity stack is saved. Then when the application is restarted, all my activities resume and run into null pointers. Rather than modify every activity to accommodate this event, I would rather just have my application start with the base activity and not try to re-create the activity stack.

Is this possible?

I know about Intent.FLAG_ACTIVITY_CLEAR_TOP, but as I understand that will only kill activities after they have been re-created.

EDIT: is clearTaskOnLaunch what I want? I've added it to my default activity, but am seeing no effect. But this will kill my activities even if I just minimize the application, wont it? I'd rather only clear the stack if the entire process is rebooting.

EDIT 2: No, it's not what I want- an Android engineer gave a thorough response to some questions on how to use ClearTaskOnLaunch: http://groups.google.com/group/android-developers/browse_thread/thread/da024bcaf4e1960f/ab1e2b35c360cb65?pli=1

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

怀念你的温柔 2024-11-02 11:12:05

我能找到的唯一解决方案是检查 onCreate() 的每个实例中的全局静态变量,如果该变量已重置为 null,则完成,表明任务已重新启动。我将所有活动关闭到我的根活动并重新开始。

很快我希望我的应用程序能够在 onPause() 中保存所需的值,但在那之前这是我知道处理丢失的初始化的唯一可靠方法......

The only solution I was able to find was to check a global static variable in every instance of onCreate() and finish if that variable had been reset to null, indicating the task had been restarted. I close all activities down to my root activity and start over.

Soon I hope to have my app at a point where it can save needed values in onPause(), but 'til then this is the only reliable way I know to work with lost initialization...

浅忆流年 2024-11-02 11:12:05

如果您正在使用spalshScreen或任何LauncherActivity,您可以创建一个全局静态布尔值并像这样使用它:

首先找到一种方法来存储这个静态变量(也许创建一个全局java文件),

public abstract class Global {
    ...
    public static boolean processKilled = true;
    ...
}

然后在您的laucherActivity(MainActivity或Splashscreen ...)添加这些行:

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

        Global.processKilled = false;
        ...//your code here
    }

事实上,如果您的应用程序进程死亡,它肯定不会通过您的 launcherActivity 的代码。因此静态布尔 processKilled 将保持为 true。即使确实如此,这也意味着您的应用程序当前正在重新启动,并且 processkiled 将正确设置为 true 并且所有变量正确实例化(无 NullPointerException)

通过创建您自己的 restartApp 方法,您将得到您想要的:(

在您添加的每个活动中这些行:)

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

        if (Global.processKilled){
            restartApp();
        }
        ...//your code here
    }

编辑

如果您不是全局变量狂热者,您可能想检查savedInstanceState是否为空...

If you're working with a spalshScreen or whatever LauncherActivity, you can create a Global static boolean and use it like this :

first find a way to store this static variable (maybe create a Global java file)

public abstract class Global {
    ...
    public static boolean processKilled = true;
    ...
}

then, in your laucherActivity (MainActivity or Splashscreen ...) add these lines :

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

        Global.processKilled = false;
        ...//your code here
    }

In fact, if your app process died it surely wont pass through the code of your launcherActivity. So the static boolean processKilled will remain true. Even if it does, that means your app is currently restarting and processkiled will be correclty set to true and all variables correclty instantiated (No NullPointerException)

By creating your own restartApp method you'll get what you want :

(in every activity you have add these lines :)

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

        if (Global.processKilled){
            restartApp();
        }
        ...//your code here
    }

EDIT

if you're not a global variable-aholic, you may want to check if savedInstanceState is or isn't null...

痴梦一场 2024-11-02 11:12:05

我使用这段代码:

public class NoRestoreActivity extends Activity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        // Shoul be always NULL when created the first time, just in case...
        if (savedInstanceState != null && savedInstanceState.getInt("SavedInstance") > 0) {
            // ----- Your prefferred way to kill an application ----
            try {                
                this.finishActivity(0);               
            } catch (Exception ee) {
            }
            try {
                android.os.Process.killProcess(android.os.Process.myPid());
                System.exit(10);
            } catch (Exception eeee) {
            }
            return;
        }
        super.onCreate(savedInstanceState);
    }

    @Override
    protected void onSaveInstanceState (Bundle outState){
        super.onSaveInstanceState(outState);
        outState.putInt("SavedInstance",1);
    }
}

I use this piece of code:

public class NoRestoreActivity extends Activity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        // Shoul be always NULL when created the first time, just in case...
        if (savedInstanceState != null && savedInstanceState.getInt("SavedInstance") > 0) {
            // ----- Your prefferred way to kill an application ----
            try {                
                this.finishActivity(0);               
            } catch (Exception ee) {
            }
            try {
                android.os.Process.killProcess(android.os.Process.myPid());
                System.exit(10);
            } catch (Exception eeee) {
            }
            return;
        }
        super.onCreate(savedInstanceState);
    }

    @Override
    protected void onSaveInstanceState (Bundle outState){
        super.onSaveInstanceState(outState);
        outState.putInt("SavedInstance",1);
    }
}
影子的影子 2024-11-02 11:12:05

上面依靠进程死亡来重置静态变量的解决方案是可行的,但由于它依赖于静态,所以有代码味道。这是一个具有非常相似属性的解决方案,但不依赖于进程死亡后重置的静态变量。相反,它依赖于这样一个事实:进程死亡后,任何保留的片段都将其实例变量设置回默认值。

/**
 * This retained fragment functions as a detector for when the activity is restoring it's state
 * after a process death.
 *
 * <p>The callback onRestoreInstanceState cannot be used here, since that callback is also invoked
 * during regular activity recreation due to configuration changes, and there's no way to tell
 * whether the state is being restored from a configuration change or from recreation after process
 * death.
 *
 * <p>This retained fragment can be used to disambiguate these two scenarios. When the fragment is
 * created, it's {@code wasProcessKilled} flag is set to {@code false}, which will be retained
 * across activity restarts from configuration changes. However, on process rebirth, the retained
 * fragment will still be retained, but the value of {@code wasProcessKilled} will be set back to
 * its default value of {@code true}.
 */
public class ProcessDeathDetectorFragment extends Fragment {

  public static final String TAG = "ProcessDeathDetectorFragmentTag";

  public static ProcessDeathDetectorFragment create() {
    ProcessDeathDetectorFragment frag = new ProcessDeathDetectorFragment();
    frag.wasProcessKilled = false;
    frag.setRetainInstance(true);
    return frag;
  }

  private boolean wasProcessKilled = true;

  public boolean wasProcessKilled() {
    return wasProcessKilled;
  }

  @VisibleForTesting
  public void clear() {
    wasProcessKilled = true;
  }
}




private void closeActivityIfRestoredAfterProcessDeath(Bundle bundle) {
  FragmentManager fragmentManager = getSupportFragmentManager();
  ProcessDeathDetectorFragment retainedFragment =
      (ProcessDeathDetectorFragment)
          fragmentManager.findFragmentByTag(ProcessDeathDetectorFragment.TAG);

  if (bundle != null && retainedFragment != null && retainedFragment.wasProcessKilled()) {
    // If the bundle is non-null, then this is a restore flow.
    // If we are in a restore flow AND the retained fragment's wasProcessKilled flag is set back
    // to its default value of true, then we are restoring
    // from process death, otherwise the flag would have the value of false that was set when it
    // was created for the first time.
    finish();
    return;
  }

  if (retainedFragment == null) {
    fragmentManager
        .beginTransaction()
        .add(ProcessDeathDetectorFragment.create(), ProcessDeathDetectorFragment.TAG)
        .commit();
  }
}

@Override
protected void onCreate(Bundle bundle) {
  super.onCreate(bundle);
  closeActivityIfRestoredAfterProcessDeath(bundle);
  ...
}

The solution above of relying on process death to reset a static variable works, but is a code smell due to it's reliance on static state. Here's a solution that has very similar properties, but doesn't rely on a static variable being reset after process death. Instead, it relies on the fact that after a process death any retained fragments will have their instance variables set back to default.

/**
 * This retained fragment functions as a detector for when the activity is restoring it's state
 * after a process death.
 *
 * <p>The callback onRestoreInstanceState cannot be used here, since that callback is also invoked
 * during regular activity recreation due to configuration changes, and there's no way to tell
 * whether the state is being restored from a configuration change or from recreation after process
 * death.
 *
 * <p>This retained fragment can be used to disambiguate these two scenarios. When the fragment is
 * created, it's {@code wasProcessKilled} flag is set to {@code false}, which will be retained
 * across activity restarts from configuration changes. However, on process rebirth, the retained
 * fragment will still be retained, but the value of {@code wasProcessKilled} will be set back to
 * its default value of {@code true}.
 */
public class ProcessDeathDetectorFragment extends Fragment {

  public static final String TAG = "ProcessDeathDetectorFragmentTag";

  public static ProcessDeathDetectorFragment create() {
    ProcessDeathDetectorFragment frag = new ProcessDeathDetectorFragment();
    frag.wasProcessKilled = false;
    frag.setRetainInstance(true);
    return frag;
  }

  private boolean wasProcessKilled = true;

  public boolean wasProcessKilled() {
    return wasProcessKilled;
  }

  @VisibleForTesting
  public void clear() {
    wasProcessKilled = true;
  }
}




private void closeActivityIfRestoredAfterProcessDeath(Bundle bundle) {
  FragmentManager fragmentManager = getSupportFragmentManager();
  ProcessDeathDetectorFragment retainedFragment =
      (ProcessDeathDetectorFragment)
          fragmentManager.findFragmentByTag(ProcessDeathDetectorFragment.TAG);

  if (bundle != null && retainedFragment != null && retainedFragment.wasProcessKilled()) {
    // If the bundle is non-null, then this is a restore flow.
    // If we are in a restore flow AND the retained fragment's wasProcessKilled flag is set back
    // to its default value of true, then we are restoring
    // from process death, otherwise the flag would have the value of false that was set when it
    // was created for the first time.
    finish();
    return;
  }

  if (retainedFragment == null) {
    fragmentManager
        .beginTransaction()
        .add(ProcessDeathDetectorFragment.create(), ProcessDeathDetectorFragment.TAG)
        .commit();
  }
}

@Override
protected void onCreate(Bundle bundle) {
  super.onCreate(bundle);
  closeActivityIfRestoredAfterProcessDeath(bundle);
  ...
}
皇甫轩 2024-11-02 11:12:05

这是在处理原生 Android 工具时应该考虑的问题,还是第三方任务杀手提出的问题?至少在模拟器上使用“强制停止”似乎会重置活动堆栈 - 这是我期望在应用程序终止时总是发生的事情。

Is this something one should take into account when dealing with native Android tools, or is this an issue brought up by third party task killers? At least on emulator using "force stop" seems to reset activity stack - which is something I've expected to happen always when application dies.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文