views:

364

answers:

2

In my Android app, I have a main activity that serves as an entry point to my application, which is configured in my manifest file like this :

<activity android:name=".Main"
              android:label="@string/app_name"
              android:screenOrientation="portrait"
              android:alwaysRetainTaskState="true"
              android:launchMode="singleTask">
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />
            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity>

So for a particular use case, lets say a user starts up the app from the home screen by clicking the icon inside the application launcher. After starting the app, the user navigates from the Main activity to activity A and then finally to activity B. At this point, the user decides to check their facebook, so they click the home button to put my app in the background, and launches the facebook app.

After checking their facebook, the user wants to return to my app, so they press the home key, and launch the application from the application launcher (just like they did the first time it was launched).

When a user returns to my app, I want the app to return to the last activity the user was at when the app was put into the background, which in this case is activity B. In the manifest file, I have set alwaysRetainTaskState=true to make sure the OS doesn't kill my app's activities.

Now to my question: how do I get the behavior I described above? Whenever I click my app's icon, it always starts at the Main activity, no matter what. I think this is because of the category.LAUNCHER attribute. I have tried android:launchMode=singleTask, but it hasn't made a difference; it always starts at Main.

If someone could clarify intent filters, launch modes, and tasks, that would be great!

+1  A: 

I solved this by adding the screenless DispatcherActivity and making it the default one (by using the very same intent filter). In its onCreate method you create and call the Intent based on some reasonable default (your Main activity for example) OR based on some saved token that identifies which Activity should be started. That token is saved/refreshed in onStop method of any Activity you want to call on restart. You can save this token to Preferences.

The rational here is that last activity that was visible will execute onStop method when interrupted.

Word of caution here: I did implement this pattern and it worked reasonably well. However it seems not play too well with history and finally I just gave up and yanked this code out. Nobody complained so far.

DroidIn.net
that's an intuitive solution. if you go back to my example, if i stored a token in activity B's onStop, and checked for this token in the DispatcherActivity and started activity B when the token is set, that would take you back to the last activity, but wouldn't you have to store a token for activities the user visited before B as well (activity A in my example)?
Surprisingly no. I think due to caching of information your activity B is not recreated from scratch and retains its history. So for example when you hit the back button it will know to go to the caller Activity. So one of the thing you need to do when you call the activity from dispatcher you also need to execute finish() so the Dispatcher will not be called again when you click back button
DroidIn.net
I got a feeling there's a better way to do this.. the application switcher menu (long press home key) handles it just fine.. i don't see why we can't duplicate that behavior in the application tray..
Sounds good. Plz share your findings if you succeed
DroidIn.net
+2  A: 

FYI singleTask is not what you want, since it starts a new task:

http://developer.android.com/guide/topics/manifest/activity-element.html#lmode

How are you launching Activity B? Any non-standard launch modes or Intent flags?

James
no i have no intent filters set for B, and i'm simply doing a startActivity(new Intent(this, B.class));