开发者

Prevent Activity Stack from being Restored?

开发者 https://www.devze.com 2023-02-19 07:32 出处:网络
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

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 开发者_JS百科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


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...


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...


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);
    }
}


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);
  ...
}


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.

0

精彩评论

暂无评论...
验证码 换一张
取 消