How to prevent app restart when using launcher aft

2019-02-10 15:08发布

问题:

My Android application is being restarted when using the launcher to launch it after I have used the app store to launch it (and visa versa). Is there any way to prevent this?

By restarted I mean that the activity stack is lost. This is important as our users are setting up and returning to an activity in the app intermittently over the course of an hour or so. After first install, they will likely have installed and opened the app from the app store, set themselves up and then backgrounded the app. Later they are likely to open the app from the launcher and lose all their state!

The problem is further compounded as we start a foreground service along with the set-up activity. Clicking the services notification should bring the user back to the set-up activity but, as with the launcher, if the user originally opened the app from the Play store, they again lose all their state!

Reproducing the problem

I've made a sample application here:

https://github.com/samskiter/LaunchTest

Note: it uses the BBC weather application package Id in order to allow you to quickly open from the app store (the "Open" button will be shown on the BBC weather application if this app is installed).

Steps are as follows:

  1. Uninstall the BBC weather app if you have it
  2. Install the LaunchTest app
  3. Close the LaunchTest app from recents
  4. Open the LaunchTest app from the BBC weather app page on the Play Store
  5. Click the button to navigate to the Second activity
  6. Background the application (press home)
  7. Open the LaunchTest application from the app launcher
  8. The state is lost! you are back at the First (root) activity

What I've tried

Using singleTask launch mode hasn't helped - it causes the app to be relaunched even if you use the launcher every time.

I've tried alwaysRetainTaskState - I don't really expect this to work as this only really affects things over about a 30 minute wait.

What I think is going on

There is no mechanism in the activity manager / intent system to open a running app in it's current state. Instead, I think the UID of the launching application is taken into account. If it is different then the Intent.FLAG_ACTIVITY_NEW_TASK flag is forced and so created a new task and dropping all my users' lovely state.

Inspecting Google Maps

Google maps has a very similar interaction model to our application: a setup UI, followed by an ongoing process the user is going through for a long period of time (navigation) with a paired, foreground service (the navigation service you can see in your notification bar). BUT GMaps doesn't suffer from this problem. I think this is because it uses only a single activity for all of it's interface and uses singleTask. So now, when you tap on the launcher after originally launching from the play store, the task can be reused.

In my opinion this exposes a hole in the android intent/activity management system. The whole point of the savedInstanceState/activity lifecycle is to prevent dropping state, but here we have a way to dump everything. My current best solution is to detect app restarts by the fact the service is running and try to get the user back to where they were, which is more than a little tricky.

If someone knows a way I can prevent my state being dropped on the floor when reopening from the app launcher after opening from the store, I would really appreciate it.

回答1:

This is more like a workaround to your problem, but it seems that there may be no real solution.

My first thought was - since the whole setup will take a while anyway - why don't you just save some kind of bookmark ('firstLaunch') to Preferences, post a (delayed?) notification and finish the app, so that the user has to open it again by tapping on the launcher icon. Only then you start the real setup, so you will not lose information due to the installer vs launcher problem.

But the problem seems to have been around for some time and the following SO-posts may help:

Re-launch of Activity on Home button, but…only the first time

After tap on app icon,launcher create a new instance of root activity again & again

Hope this helps!