How can I make an activity go to background without calling its finish() method and return to the Parent activity that started this? I tried so much but I could not find a solution. So if you guys could help I would be very thankful.
The following will work if the Activity is running in a different task to its parent. To achieve this, see http://developer.android.com/guide/topics/manifest/activity-element.html#lmode.
public void onBackPressed () {
moveTaskToBack (true);
}
The current task will be hidden, but its state will remain untouched, and when it is reactivated it will appear just as it was when you left it.
If you have data you want to cache / store / process in the background, you can use an AsyncTask or a Thread.
When you are ready to cache / transition to parent, you would do something like the following in one of your child Activity methods (assuming you started child with startActivityForResult() )
Thread Approach:
Thread t1 = new Thread(new Runnable() {
#Override
public void run() {
// PUT YOUR CACHING CODE HERE
}
});
t1.start();
setResult( whatever );
finish();
You can also use a Handler if you need to communicate anything back from your new thread.
AsyncTask Approach:
new CacheDataTask().execute( data params );
set_result( whatever );
finish();
The AsyncTask is for situations in which you need to process something in a new thread, but be able to communicate back with the UI process.
Simply
protected void minimizeApp() {
Intent startMain = new Intent(Intent.ACTION_MAIN);
startMain.addCategory(Intent.CATEGORY_HOME);
startMain.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(startMain);
}
Moving the task backward is NOT going to insure that you will maintain any state, unless you do that manually by responding to the Activity lifecycle events.
You should just start the second Activity via Intent using startActivity(), or, if you need to receive a result back from the second Activity, use startActivityForResult(). This allows you to receive a callback when the user finishes the Activity and returns to your first Activity.
Starting an Activity and getting results: http://developer.android.com/reference/android/app/Activity.html#StartingActivities
Try:
Intent toNextActivity = new Intent(CurrentActivity.this,
NextActivity.class);
CurrentActivity.startActivity(toNextActivity);
If you use this way, the method onPause() from CurrentActivity will be called and if you have a static variable (like a MediaPlayer object) in CurrentActivity it will continue to exist (or play if it is playing)..
I'm using that in my application but I found a better way to do that with services.
Hope this will help you!
Related
startActivity(newActivity);
finish();
Assuming I'm calling it like above. Both calls are scheduled to happen on the UI thread after the end of the invoking method. However, is there a particular order in the scheduling? Is finish always scheduled before startActivity? or vice versa?
When calling finish() on an activity, the method onDestroy() is executed this method can do things like:
Dimiss any dialogs(search dialogs) that activity was managing.
Close any cursors the activity was managing.
And the activity is removed from the stack.
And calling startActivity(newActivity) creates and puts a new View on the Top.
Thus,if order is
startActivity(newActivity);
finish();
Then first newActivity is displayed and old one is detroyed.
But,if order is
finish();
startActivity(newActivity);
Then first the existing activity is destroyed and new one is created and displayed.
So, if we have lots of things to do in onDestroy()(like storing some datas) then calling startActivity() then finish() will be a good thing to do.Thus, the order depends on what we call first.
You should always Start Before You Finish
Hence the most desirable method call order would be,
startActivity(NewActivity);
finish();
Mark Murphy wrote an excellent article about this.
It will work in both the cases whether you write finish () before or after the start activity()
So basically the order of the scheduling depends on the order of the calls. If you call finish() first, it will be added into the queue followed by startActivity(). Same goes for the other way around. Depending on how your implementation goes, if you require a specific order in the scheduling, simply call the functions in the order that you want the scheduling to occur.
It should work is both cases.
I'm writing an application that has several activities. The main activity can receive data via Intent, then start another activity that process that data.
I have a problem when finished the second activity, since the main activity runs the onResume method (where check and intentions of the process), and the original intention is still alive. So App calls the second activity again.
My question is to eliminate the Intent data after calling second activity, and thus the return of second intention not to repeat the cycle.
Thank you very much
set a class variable to 0 and then make it 1 instead.
So you don't do the looping.
Can I eliminate the Intent data after calling second activity
yes.
As soon as you call second activity(Or the second activity is started), first activity onPause method will be called. You can override onPause method in Activity1 and do what ever you like to do.
Ex:
#Override
protected void onPause() {
super.onPause();
getIntent().removeExtra("YourMainActivityData");
}
Try add this code after u start second activity in onResume:
setIntent(new Intent());
this will replace the return intent when u call getIntent();
Hope it helps.
I can't remove Intent data, so I wrote an alternative method. I did set the intent-filter at the second activity, and this activity does all the work. When user wants to go back, I start first activity and finih second one.
Perhaps it's a good method, perhaps not is. But it runs OK for me.
Thank you very much!
There are some links in my app. It will start browsable intent like this:
Intent intent = new Intent();
intent.setAction(Intent.ACTION_VIEW);
intent.addCategory(Intent.CATEGORY_BROWSABLE);
intent.setData(Uri.parse(link));
startActivity(intent);
Then it will open a browser. At the same time, something is running in background and need to update UI. So I get this:java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState
I know the reason about this Exception. But how to fix it? It would be better that background task can keep running. However, pausing them is also acceptable.
If you are using AsyncTask you really dont need runOnUiThread() method. AsyncTask provides you with everything you need. It encapsulates two methods: preExecute() and postExecute() which run on the main thread, so you can update the UI components within these methods. Even if you need to update the UI progressively AsyncTask handles that in onProgressUpdate() method which again runs on main thread. This way your code is much cleaner then inserting:
getActivity().runOnUiThread(new Runnable() {
public void run() {
}
});
You can even cancel an ongoing task: asyncTask.cancel() for example onPause() method of your activity in order to avoid any unnecessary UI updates while the activity is not visible.
why would you want to do if the UI is not visible to user??
anyway,
for updating UI from background tasks try the runonUiThread
getActivity().runOnUiThread(new Runnable() {
public void run() {
//access UI here
}
});
http://android.okhelp.cz/java_android_code.php?s=runOnUiThread
In the callback used to update the UI, check if the activity is paused or stopped, and don't perform the UI update logic. You can use a flag isForeground which you set true in onResume() and false in onStop().
Alternatively, I found that you can avoid the exception if you use commitAllowingStateLoss when committing fragment transactions.
As I understand it, an activity being destroyed is not equivalently to an activity being finished.
Finished
The activity is removed from the back stack.
It can be triggered by the program (e.g. by calling finish()), or by the user pressing the back key (which implicitly calls finish()).
Finishing an activity will destroy it.
Destroyed
The Android OS may destroy an invisible activity to recover memory. The activity will be recreated when the user navigates back to it.
The activity is destroyed and recreated when the user rotates the screen.
Reference: Recreating an Activity
So how do I finish a destroyed activity? The finish() method requires an Activity object, but if the activity is destroyed, I have no Activity object - I am not supposed to be holding a reference to a destroyed activity, am I?
Case study:
I have an activity a, which starts b, which in turn starts c (using Activity.startActivity()), so now the back stack is:
a → b → c
In c, the user fills out a form and tap the Submit button. A network request is made to a remote server using AsyncTask. After the task is completed, I show a toast and finish the activity by calling c.finish(). Perfect.
Now consider this scenario:
While the async task is in progress, the user switches to another app. Then, the Android OS decided to destroy all 3 activities (a, b, c) due to memory constraints. Later, the async task is completed. Now how do I finish c?
What I have tried:
Call c.finish():
Can't, because c is destroyed.
Call b.finishActivity():
Can't, because b is destroyed.
Use Context.startActivity() with FLAG_ACTIVITY_CLEAR_TOP so as to raise b to the top, thus finishing c:
// appContext is an application context, not an activity context (which I don't have)
Intent intent = new Intent(appContext, B.class); // B is b's class.
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
appContext.startActivity(intent);
Failed, appContext.startActivity() throws an exception:
android.util.AndroidRuntimeException: Calling startActivity() from outside of an Activity context requires the FLAG_ACTIVITY_NEW_TASK flag. Is this really what you want?
Edit: Clarification: I need to wait until the async task finishes and decide whether to finish c based on server's response.
android.util.AndroidRuntimeException: Calling startActivity() from
outside of an Activity context requires the FLAG_ACTIVITY_NEW_TASK
flag. Is this really what you want?
This exception used to occur when you are starting an activity from
the background thread or service. You need to pass
FLAG_ACTIVITY_NEW_TASK flag whenever you need the "launcher"
type of behavior.
Just add mIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); to avoid this exception.
The way you are trying to kill the activity is not recommended, let the
android handle itself. There isn't any meaning to finish an activity
which is already destroyed.
Now, what you can do?
If you are facing problem in finishing activity when app is not in foreground, what you can do is to implement a security check which will finish the activity only when app is in foreground to go to back-stack activity or else just skip that step.
I think you are trying to kill the activity when app is in background. It seems a little bit difficult to do so, but you can make use of onUserLeaveHint to decide when app is going in the background in-order to finish the activity or you can finish the activity by adding finish(); in onStop(). Just make sure that asynctask's onPost() don't finish it again in-order to avoid the exception.
Have a look at android:clearTaskOnLaunch attribute and set it to true.
Google Doc says about this attribute is:
for example, that someone launches activity P from the home screen,
and from there goes to activity Q. The user next presses Home, and
then returns to activity P. Normally, the user would see activity Q,
since that is what they were last doing in P's task. However, if P set
this flag to "true", all of the activities on top of it (Q in this
case) were removed when the user pressed Home and the task went to the
background. So the user sees only P when returning to the task.
and i think this is the exact case which you want.
Hope this will give you some hint to achieve your desired task.
you can broadcast your action from the onPostExecute method in c and register a broadcast receiver to receive for that action in a and b. Then do finish in that receiver onRevice method
In c , AsyncTask,
void onPostExecute(Long result) {
----
Intent intent1 = new Intent("you custom action");
context.sendBroadcast(intent1);
}
In a and b
registerReceiver(new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
finish();
}
},new IntentFilter("you custom action"));
Personally, I'd use the notification bar to notify the user of the status of his query.
This way, I'd avoid the entire issue of having an unfinished activity. And I'd only keep the activity unfinished only if the user had not clicked on the submit button yet.
Regarding android manual onDestroy() called exactly before activity is destroyed, so you can call finish in it (even you can stop your bg thread before killing the activity completly).
We can assume that if activity was killed we don't interested in bg thread either, and for example if bg thread is to download image or etc that needs to be completed - so you have to use service instead of asynctask.
Can't finish a destroyed activity directly, so just finish() it in its onCreate() (suggested by #Labeeb P). Here's how:
If the activity is already destroyed when trying to finish it, save a boolean flag somewhere instead.
if(activity != null)
{
// Activity object still valid, so finish() now.
activity.finish();
}
else
{
// Activity is destroyed, so save a flag.
is_activity_pending_finish = true;
}
If the flag needs to stay even if the app is destroyed, use persistent storage, e.g. SharedPreferences (suggested by #Labeeb P).
In the activity's onCreate(), check the flag and call finish().
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
if(is_activity_pending_finish)
{
is_activity_pending_finish = false; // Clear the flag.
// This activity should have been finished, so finish it now.
finish();
return;
}
...
}
If there're multiple instances of the same Activity class, you may need something more than a boolean flag to identify the specific instance of activity to finish.
Calling finish() in onCreate() is actually a legimate operation, as it is mentioned in the doc:
... you might call finish() from within onCreate() to destroy the activity. In this case, the system immediately calls onDestroy() without calling any of the other lifecycle methods.
Other considerations:
It may not be a good idea to finish an activity while the app is in background, especially if it is the only activity. Make sure that you don't confuse the user.
For better user experience, if you finish an activity while the app is in background, you may want to inform the user. Consider using toasts (good for short notices) or notifications (good for long operations that the user may have forgotten)(suggested by #Stephan Branczyk and #dilix).
Of course, an activity being destroyed doesn't necessary mean that the app is in background (there might be another foreground activity). Still, the above solution (calling finish() in onCreate()) works.
When the system tries to destroy your Activity, it calls onSaveInstanceState. In here you can call finish(). That's it.
Warning: I've never tried this, so I don't know for sure if there are any issues with calling finish() from onSaveInstanceState. If you try this, please comment and let me know how it works out.
Sorry for answering this almost 10 years later.
In my understanding the premise of the question is wrong, mainly this part:
"While the async task is in progress, the user switches to another app. Then, the Android OS decided to destroy all 3 activities (a, b, c) due to memory constraints. Later, the async task is completed. Now how do I finish c?"
In my understanding if the operating system decides to destroy all three activities due to memory constraints, it won't destroy only them, but the whole process, and this should be including the AsyncTask in question. So, the async task won't be able to complete as well.
Resource: https://medium.com/androiddevelopers/who-lives-and-who-dies-process-priorities-on-android-cb151f39044f
mainly this line from the article: "Note that while we’ll talk about specific components (services, activities), Android only kills processes, not components."
In todays world, I guess that a WorkManager would be used for running work that needs to be guaranteed to run.
I have an activity. In this activity I want to start another activity using startActivityForResult(). I understand that my basic activity is started within a process with a main GUI thread.
But as far as I understand, startActivityForResult() is asynchronious which means that my new activity will be executed in a different thread.
I can't find information regarding the threads inside. If there is only one GUI thread, how does these functions work asynchroniously ?
But as far as I understand,
startActivityForResult() is
asynchronious which means that my new
activity will be executed in a
different thread.
startActivityForResult() is asynchronous. That does not mean that your new activity will be executed in a different thread. If the new activity is part of your own application, it runs on the main application thread, like all your other activities.
If there is only one GUI thread, how does these functions work asynchroniously ?
startActivityForResult(), like startActivity(), does not do anything immediately. Rather, it puts a message on a message queue, then returns. When you return control back to Android (e.g., your onClick() method ends), Android goes back to processing messages off of that queue. When it gets to your start-activity message, it starts up the new activity.
pass any info you want in the form of Extras in your Intent.
Intent i = new Intent(getApplicationContext(), YourClass.class);
i.putExtra("EXTRA_INFO", <your info here>);
startActivityForResult(i);
And in your new activity
protected void onCreate(Bundle savedInstanceState) {
if(getIntent().hasExtra("EXTRA_INFO"){
mString = getIntent().getStringExtra("EXTRA_INFO");
}
}