Here's the scenario I'm struggling with:
The user starts my app and presses the Download button. The app starts a download on its own (with an AsyncTask, not using the System DownloadManager) and shows progress in the notifications. Now the user presses the back button, which finishes the activity. Except the AsyncTask and notification keep going, even with their "parent" activity finished.
Now the user goes back into the app by clicking on the notification. Because the last activity was finished and onDestroy() was called, a new activity gets created. The problem is this new activity has no idea that an AsyncTask from a previous instance of itself is still going, and so it shows the Download button again. Clicking this creates a duplicate AsyncTask and notification. Not good.
How can the new activity get a handle on this "lost" AsyncTask so that it can get information from it?
Ideas I'm not looking for:
Blocking/overwriting onBackPressed
Constantly sending info through SharedPreferences
Related
I have an android app that uses push. If the app receives a push message from the server it creates a push notification (with headline, message, icon) and presents it to the user.
normal case
The click on the notification opens up an Activity (not the launcher) and the activity opens a fragment that shows content based on the notification. No magic here and everything works as expected.
the special/bad case
If the device is inactive for at least 2h and you pick it up and click a notification that was pushed before, then it opens the Activity like in the normal case but no fragment comes up. Instead the launcher will be called.
While debugging this is time costly and frustrating I found out the following things. Maybe someone has an idea:
The Activity usually starts with an animation that I load from resources. I load and run it in onCreate(). If the Activity gets invoked by the push then the animation will be loaded but never runs. I bypassed this with a Handler that waits 2 seconds and checks if the animation listener was called. If not (bad case) then the handler calls the code to open the fragment.
opening the fragment caused a crash:
IllegalStateException: Cannot perform this after onSaveInstanceState. Similar like here Exception java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState So I replaced commitAllowingStateLoss(). Now there is no crash anymore but the fragment does not appear. Only Fragment.newInstance() will be called but no onCreate() or any other lifecycle method.
Question:
What crazy state is it that seems to break functions in my code after longer inactivity?
Device:
I'm currently testing with a Nexus 5 with Android 6.0.1
I found out that if my device is in this crazy sleep state that my activity gets startet twice if I then click on a push notification. At first the push triggers the activity with its data in the intent. Then, after it, the launcher activity gets invoked (with an empty intent) and starts the main screen.
I fixed it with like here -> Activity opened twice
To sum it up:
1) I changed my code so that all my deeplinks, push notifications, etc. will invoke the lauchner activity. The activity then decides what to do. That means we have a single entry point into the app. That makes everything easy and the code clearer.
(with this fix the same activity will be invoked twice. we have to do a little more to fix it)
2) I marked the activity in the manifest with android:launchMode="singleTask". This means that if there is an instance of the activity already, it will be reused and not created a second time.
3) The flag from 2) triggers a callback method. Instead of invoking the activity a second time, the system reuses the already running activity and calls the method onNewIntent(intent). That means if the activity is freshly started, then onCreate() will be called. If the activity is reused (because it was triggered by a push notification, deeplink, etc.) then onNewIntent(intent) will be called. In both, onCreate() and onNewIntent() I call a method to decide what screen/fragment/activity is next and handover the intent from getIntent(). Done.
The question is more conceptual than coding-related.
I have an app with Activity A and B.
I call an AsyncTask from Activity A, while the call is being made, I don't want to block the user showing the progressdialog, so my user can freely move around the application without getting bored of waiting.
Now, the query is AsyncTask or lets say a Service is being called from Activity A which is responsible for downloading some kind of data from the server. While the call is being made, the user has changed the Activity and Activity A has gone to background.
Now, while the user is freely moving around the application, he just wants to come back to Activity A to check the download status,(which is something lets say I set some data to my TextView).
Now the question is, once the download is over , while my Activity A is still in background, my UI should be updated while Activity is still in background. This way the user feels he gets the data before he switches to Activity A.
Is this possible, if so how?
Summarizing my question, can I update the UI of an Activity while it is still in background with the Asynctask or Service which the Activity invoked to fetch data from server.
One post suggested that ideally I need to update the **UI in onResume(). My question is, is this the only approach?
once the download is over , while my Activity A is still in background, my UI should be updated while Activity is still in background. This way the user feels he gets the data before he switches to Activity A.
It isn't possible. You see, the Activity has to pass through the onCreate() and onResume() callbacks for the UI to be changed.
Also, you should be using a bound Service to update the Activity when it returns to the foreground.
onResume() would be the best approach. You may save the changes in a SharedPreferenes or Pass the data using Intent and show the changes before the UI is visible.
Another approach would be running a service and checking if the activity is visible. If its visible immediately update the UI or wait until user visits the activity. To check if the activity is currently visible see here,
How to check if activity is in foreground or in visible background?
The first activity of my application is a splash screen, where some animation is displayed while some loading occurs in a background thread using AsyncTask.
Once the loading in the background is done, I want to start a new activity. What is the correct way to do that ?
Start a new activity directly from the onPostExecute method of the AsyncTask class.
Check if the current activity is displayed before starting the new activity :
If the current activity is display, start the new activity.
If the current activity is NOT display, use a flag (boolean) and check the flag during the onResume method in order to start the new activity there.
My main concern is :
If my application went to the background (due to an incoming phone call, a home key press, ...) and the background thread (AsyncTask) finished executing, and a new activity is started from the onPostExecute method while my application is still in the background : What happens ?
Will the new activity start directly as soon as my application is visible again ?
I faced a similar situation: my application went to background and after some time the app started an intent displaying another activity. However, the app's behavior now depends on the os that it's running:
on pre 4.4 devices the app silently opens the new activity and remains in background. When the user resumes the application, he is prompted with the second activity already.
on 4.4 devices (tested on 4.4.2 and 4.4.4) the app opens the second activity, but after 3-4 seconds, the app pops to foreground, interrumping the user.
Hope it helps anybody. I'm still looking solutions for the second case in order to prevent the app from popping to foreground.
From my experience i am answering your question
Question1
If you using AsyncTask you have to start new activity in OnPostExecute(). In my experience this is the correct way of doing it.
Question2
When ever your press the home key or receiving phone call. Your activity will go in to background until you exit the app by pressing back button(at that time your app is exited). So when you come back to your app your new activity will be visible if background process get finished. Otherwise you will see the start splash screen.
I think that it is dependent upon the OS of android. It has defined some built in priority model for each of the components.
Look at the answer given by commonsware.
change process priority in android
this gives brief idea about components priority.
I have an Android app. I have a main activity, that has a button. When the button is clicked, another activity comes to the foreground. The thing is, I want to run a background thread that polls updates from the server. However, I want it to run only when the app is in foreground (either the main activity or the second one), and to stop polling when the user clicks the Home button or clicks the Back button till it's going back from the main activity.
But how do I know if the app is still in the foreground? I can catch the onPause of the main activity, but it's called also when I'm launching the second activity.
So how do I know when the app is in background?
Thanks
You should make a Service for the work you are doing in the background.
For stopping it when you click the Home or Back button, just make a listener for them and stop the Service when either one is pressed.
Seems easiest to me that each activity polls. Is it super important that it can poll when it is between the two activities? Otherwise you will have problems about knowing who is in front or not.
You can have a singleton with reference counting.
You main activity should add the first reference on it's onResume and from now, upon calling for every new activity (startActivity for example) you should add a reference.
Each activity should decrease the reference counting on its onPause.
Another option is to use services: Services
I currently have a listview and when a user presses an item on the list it loads up a new activity which starts and binds to a service. When, i press back to go to the listview and I press the same item again, i am getting an unable to destroy activity error. any idea why?
Considering you didn't post any code for us to look at, I'm guessing that you never unbind your Service. You can find the same issue here.