Search code examples
javaandroidfiltermanifestandroid-intent

Retaining android app state using alwaysRetainTaskState and lauchMode


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!


Solution

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