0

Long story short, I am developing a multi-activity app for the Amazon Kindle. Kindle has a somewhat exotic launcher that does not support (correctly) more than one LAUNCHER activity in the manifest, so if you are on a child activity, go to home screen, then press the app icon again, the child activity is killed and the main activity is re-launched.

I have 2 activities: ACTIVITY_PLAY and ACTIVITY_DESIGNER. Typical session starts in ACTIVITY_PLAY, then the user might go to ACTIVITY_DESIGNER to do some work. This activity is instantiated by ACTIVITY_PLAY. If he/she leaves the app for a moment (ie. check mail) then attempting to return will cause PLAY_MODE to be started.

To solve this, I've created a "Launcher" activity (see source below), that is now the only application entry point. This activity decides wether to launch ACTIVITY_PLAY or ACTIVITY_DESIGN depending on a static value that I change from those activities' "onResume": The latest onResume received is the last activity the user was working on.

My problem is, now when I select the app icon in the launcher, it launches the correct activity BUT restarts it, even though all involved activities have android:launchmode = singleTask. Also all involved activities have the same android:taskAffinity.

Any ideas? Is it correct to declare the 3 activities (Launcher/Play/Design) with the same taskAffinity? Shouldn't this work?

public class Launcher extends Activity {

    private static final String TAG = "Launcher";
    public static final int ACTIVITY_PLAY=1, ACTIVITY_DESIGN=2, ACTIVITY_QUIT=3;

    private static int msFocused=FUNQ_PLAY;

    private void launch() {

        Bundle bundle=getIntent().getExtras();

        switch (msFocused) {
        case ACTIVITY_DESIGN:
            Log.v(TAG, "*** Launcher launch DESIGNER");
            Misc.runActivity(this, DesignActivity.class, bundle);
            break;
        case ACTIVITY_QUIT: // special code to quit instead of launching anything
            finish();
            setFocused(ACTIVITY_PLAY); // so next button press will launch play mode if the app is still alive
            break;
        case ACTIVITY_PLAY:
        default:
            Log.v(TAG, "*** Launcher launch PLAYER");
            Misc.runActivity(this, PlayActivity.class, bundle);
            break;
        }
    }

    @Override
    protected void onResume() {
        super.onResume();
        launch();
    }

    // called from the child activities' onResume.
    public static void setFocused(int activityCode) {
        Log.i(TAG, "*** CURRENTLY FOCUSED IS "+activityCode);
        msFocused=activityCode;
    }

}
rupps
  • 9,712
  • 4
  • 55
  • 95

2 Answers2

1

I managed to solve it, hope it is useful to somebody.

Launcher: taskAffinity=".launcher" launchMode="normal"
Master Activity: taskAffinity=".workflow" launchMode="singleTop"
Child Activity: taskAffinity=".workflow" launchMode="singleTop"

Detaching the launcher from the workflow task, and normal launchMode seems to do the trick for the Kindle. The singleTop thing is specific for my apps, maybe not related to the problem, but I initially used singleTop in the launcher too, and that apparently led to the side-effect of my question.

rupps
  • 9,712
  • 4
  • 55
  • 95
0

You can use SharedPreferences to save last state then check the SharedPreferences to decide which activity to start. I will add an example code in a minute.

Edit: Here is the example code:

in your launcher activities onCreateView function do something like this:

SharedPreferences reader = pActivity.getSharedPreferences( "PutDesiredPrefNameHere", Context.MODE_PRIVATE);

int lastState = reader.getInt( "LAST_STATE", 0 ); //if there is no last state saved it will return second parameter. 0 in this situation.

switch( lastState ){

     case 0:
            Intent i=new Intent( this, PlayModeActivity.class);
        startActivity(i);

        //Remove launcher activity
        finish();
            break;

     case 1:
            Intent i=new Intent( this, EditModeActivity.class);
        startActivity(i);

        //Remove launcher activity
        finish();
            break;

}

and in your PlayModeActivity's onCreateView method call this:

  SharedPreferences.Editor writer = pActivity.getSharedPreferences( "PutDesiredPrefNameHere" , Context.MODE_PRIVATE).edit();   //Don't forget pref names must be same

  write.putInt( "LAST_STATE" ,0 );
  write.comit();

and in your EditModeActivity's onCreateView method call this:

  SharedPreferences.Editor writer = pActivity.getSharedPreferences( "PutDesiredPrefNameHere" , Context.MODE_PRIVATE).edit();   //Don't forget pref names must be same

  write.putInt( "LAST_STATE" ,0 );
  write.comit();

Here is a link about SharedPreferences:

http://www.tutorialspoint.com/android/android_shared_preferences.htm

Arda Kara
  • 501
  • 6
  • 24
  • I already solved the problem to decide which one to launch. My problem is, that activity is RESTARTED instead of resumed! – rupps Aug 12 '14 at 17:47
  • Sorry for the misunderstanding I will try to find a solution for you. – Arda Kara Aug 12 '14 at 18:02
  • http://stackoverflow.com/questions/9541991/can-i-keep-android-app-alive-in-background you can try answers suggested here or you can create a saved instance and save it using ObjectOutputStream and reload with an ObjectInputStream when needed. You can checke this link to learn how to save state: http://stackoverflow.com/questions/151777/saving-activity-state-in-android – Arda Kara Aug 12 '14 at 18:12
  • thanks for the research, but unfortunately it's not very related, I guess it has more to do with TaskAffinities and LaunchModes, as the app is certainly alive, only it gets restarted discarding its previous state :( – rupps Aug 12 '14 at 18:15
  • I made an edit and added a link to save state. If you want I can explain the idea a little bit more – Arda Kara Aug 12 '14 at 18:16
  • Thanks, but it's not the route I'm looking for! I already save the state. I'm looking to avoid a restart, not workaround over it, my app's pretty heavy and I lose a lot of stuff just to recreate it. – rupps Aug 12 '14 at 18:22
  • Making it as a sevice is a good advice but it can still be restarted. I don't think if there is a way to prevent you app from being killed by android if it is pretty heavy. You can check Tseng's reply here: http://forum.unity3d.com/threads/android-apps-crashing-on-resume.127794/ – Arda Kara Aug 12 '14 at 18:46
  • Hi! I managed to solve it, the problem was the launcher had incorectly setup launchMode="singleTop". I need that setting for the activities. So putting Play and Design activity in the same affinity group, and the launcher outside of it, and without singleTop finally makes it! Thanks for your dedication though! – rupps Aug 12 '14 at 21:21
  • If I helped you can give an up vote and don't forget to answer your question to share your solution with others. Happy to hear you solved it :) Edit: I have just saw you answered sorry. – Arda Kara Aug 12 '14 at 21:40