I have two activites. Activity A and Activity B.
Activity A is a singleTask activity. Activity B has no extra configuration. So it is a normal activity.
When Activity A launches the activity B then if user presses to the home button then comes back immediately (so my app is not killed by android yet.) My app is showing activity A. But it should show the activity B because the user pressed to home button when active activity is B.
If i remove the singleTask property from Activity A. It is working as expected. But i have to use singleTask activity for some other reason.
How can i resolve this problem?
As you have constraint to use singleTask launch mode, you can do following :
When user press Home, app or Activity B goes in background (stopped state)
Then when you open app, it'll show Activity A because of singleTask launch mode
In Activity A, override onNewIntent() method. This will get called from android os. You can fire Activity B's intent from this method. So, system will open Activity A when coming from background to your app, but from this method, Activity B would be shown.
I've edited my answer to handle below scenario :
If we're on ActivityA, we press Home button and we come back, ActivityA should be shown, not ActivityB. To do this, I used boolean shouldOpenB
in Activity A :
static boolean shouldOpenB = false;
// set shouldOpenB to true when you are opening ActivityB from your code with Intent
// reset shouldOpenB to false in onStart() of AcrivityA
protected void onNewIntent (Intent intent) {
if(shouldOpenB) {
Intent openIntentB = new Intent(this, ActivityB.class);
startActivity(openIntentB);
}
}
Note : The animation of Activity A -> Activity B would be visible to user for fraction of time. If you agree to change to singleTop, we can remove this animation also.
Related
here is the brief of my activities actions :
Activity A is a launcher that call activity B with intent flag Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK.
When Activity A launch activity B, ondestroy is called in activity A, as expected.
When I press back button in activity B, ondestroy is called in activity B and it bring me to the hope launcher.
There are no alive activity at this moment, but the application is still visible and the task manager. When I click on it, it brings me to the activity A (maybe because it is the action MAIN in the manifest).
The behaviour I try to get is that when i press back button in activity B, it brings me to the home screen and I can return to is, as if it is root activity.
Can anyone help me for this ?
Thanks you !
If you click on the Back button in activity B, you will be able to navigate to the Home screen and return to the root activity(A) from the following sources.
why you used Intent.FLAG_ACTIVITY_CLEAR_TASK?
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
((Button)findViewById(R.id.btn_send)).setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
//Case 1.
//startActivity(new Intent(A.this, B.class).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
//Case 2.
startActivity(new Intent(A.this, B.class).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP));
}
});
}
FLAG_ACTIVITY_CLEAR_TASK
added in API level 11
int FLAG_ACTIVITY_CLEAR_TASK
If set in an Intent passed to Context.startActivity(), this flag will cause any existing task that would be associated with the activity to be cleared before the activity is started. That is, the activity becomes the new root of an otherwise empty task, and any old activities are finished. This can only be used in conjunction with FLAG_ACTIVITY_NEW_TASK.
Constant Value: 32768 (0x00008000)
Google Developer
You have to remove the flag FLAG_ACTIVITY_CLEAR_TASK, because as the android developer site here, the behavior will destroy your Activity A,
You need to remove that flag and then your activity will remain in the stack, and you will be able to back to activity A
I have activity A->B in the stack, and to launch activity C, I call
Intent starter = new Intent(context, MainActivity.class);
starter.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
context.startActivity(starter);
This all works fine, Activity A and B both have OnDestroy called. If I press the hardware 'back' button now, the activity appropriately finishes and is hidden. The problem is now however, if I return to the application through the application by clicking the hardware recent apps button, it will return to Activity A. Activity was destroyed and not in the stack. In the manifest, none of activities have had a android:launchMode set, so they are on default.
The only other possible piece of relevant information is that there is an Activity X that is a launcher Activity that is android:launchMode="singleInstance" and it launches activity A, that being said, it gets destroyed and it shouldn't be in that activity stack anyways.
While pressing back button While in Activity C may called onDestroy() of actvity C.
please insert logs to see whether it is called or not. This is the only reason why your activity A launch again.
please refer Android Back button calls ondestroy?
please let me know if these not work for you.
The hardware back-button can be overwritten by the follwing code :
#Override
public void onBackPressed() {
//put Intent to go back here
}
You could just overwrite it with your code written above
[UPDATE BELOW]
I have application with multiple activities. I have issues in handling the activity started from the click of notification item.
Below is the app structure:
For normal flow/working, user start the application and Activity A being the launch Activity, it starts. User could navigate to activity B from activity A (i.e. A -> B)
On click of back button on B, activity A is displayed.
However, the issue is with starting activity from the click of notification. Below is the flow:
User clicks on the notification
Activity B is started
On click of back button on activity B, it doesn't start activity A (which is understand) but it doesn't kill the activity B either (moves activity B to background). What I want is, if the activity B is started by the notification click, then back press on B should either takes user to Activity A or kill activity B.
Any pointers in this regard would be appreciated.
[UPDATE]:
Strange but, this is what is happening now.
1. Overridden the onBackPressed event in activity B.
2. In this method, finish() is called.
If the application is already running and on click of notification, activity B is displayed and then on back press, the activity B is finished. However, if the application is not running, notification click starts the activity B and on back press, it does call the backpress event and finish() method but the activity doesn't finish and goes in the background. This is really weird. Or may be I am missing some details :((
Thanks
Shrey
Override in onBackPressed().
#Override
public void onBackPressed()
{
finish();
super.onBackPressed();
}
But, user can directly got to activity B, if he/she start's your app from recent apps. To avoid this, add below to your ActivityB in Manifest. If you are navigating to ActivityC from here, pressing back in ActivityC will not return to ActivtyB so override onBackPressed() and relaunch ActivityB via Intent.
<activity
android:name="ActivityB"
android:clearTaskOnLaunch="true"
android:excludeFromRecents="true"
android:finishOnTaskLaunch="true"
android:noHistory="true"/>
follow this flow:-
1- check isLauchFrom in oncreate() of Activity A.
2- If isLaunchFrom Notification then navigate on Activity B.using startActivityFor Result.
hope this will help you ,If any Confusion send comment.
#Override
public void onBackPressed() {
Intent returnIntent = new Intent(B.this,A.class);
B.this.finish();
startActivity(returnIntent);
}
Try like this
I have an Activity A which starts an Activity B (Dialog Theme), where Activity A is then visible in the background and B in the foreground.
However, when pushing the home button and then returning to the app again, A is not visible any more - only B. onResume() of B is called, but not of A, which maybe is how it should be...
onDestroy() in A is not being called as I can see. What could be the reason for this behaviour?
A is defined as singleInstance MAIN/LAUNCHER Activity and starting B through SettingsActivity.show:
public static void show(final Context context, final boolean inRegisterFlow) {
final Intent intent = new Intent(context, SettingsActivity.class);
context.startActivity(intent);
}
The problem is your use of launchMode="singleInstance'. If ActivityA is defined with launchMode="singleInstance", then when ActivityA launches ActivityB, ActivityB ends up in a different task. When the user presses the BACK button, both tasks (the one containing ActivityA and the one containing ActivityB) end up in the background. When the user brings the task containing ActivityB to the foreground, the other task (containing ActivityA) is still in the background.
Your architecture sounds broken. Why are you launching a Dialog-themed Activity if you want it to behave like a Dialog? Why don't you just show a Dialog in ActivityA? Why are you using launchMode="singleInstance"? In general, this is wrong (unless you are developing a HOME-screen replacement) and it usually created more problems than it solves because most developers don't really understand how it works.
Also, onResume() is called on ActivityB because it is resumed (ie: it is in the foreground). onResume() isn't called on ActivityA because that activity isn't in the foreground. Only 1 activity is ever in "resumed state". All other activities are "paused".
Maybe a quick fix apply here, add A.onResume() to be onResume() implementation, that is because when you come back A doesn't resume since its in background.
But that's just a bad approach
Is there any way to tell whether an Activity is being resumed (i.e. onResume is called) from the home screen/launcher?
For example, if I have an Application with two activities, A and B.
Scenario 1:
Some user action on Activity A will invoke Activity B, bringing it into the foreground - moving Activity A into the background. As Activity A moves into the background, it goes through onPause() and onStop(). The user (now on Activity B) either finishes the Activity or hits the "back" button, bringing Activity A back to the foreground, causing an onRestart(), onStart(), onResume() sequence.
Scenario 2:
If the user hits the "home" button while Activity A is in the foreground and then re-invokes the Application from the launcher, it goes through the same lifecycle as in Scenario 1. I.e. User hits the "home" button. Activity goes through onPause() and onStop(). User launches the application again, causing Activity A go come back into the foreground, again going through the same onRestart(), onStart(), onResume() sequence as in Scenario 1.
As far as I can tell, the Activity has no way of knowing how it was resumed, it just knows it is being brought back into view. In fact, I have a feeling that there isn't really as much of a concept of an "Application" in Android - in the sense of something that has a single entry and exit point.
in Scenario 2, your activity will get an onNewIntent call, with the launcher intent passed to it.
You could capture the back button press on Activity B and pass an extra value to Activity A. If there is an extra value then the activity was resumed from pressing back on Activity B, if there is no extra value then the Activity was resumed from being hidden.
Could Acitivity A use startActivityForResult() to start Activity B and use onActivityResult() to detect that Activity B finished?
So the straightforward answer to the initial question is probably: no. Launching an activity from the home screen through an icon, or resuming it from the recents screen can not be observed from the intent it is (re)started/resumed with.
Depending on what you are trying to achieve there are some approaches though:
what #superfell suggested:
Check for whether the onNewIntent-method is called on your activity to decide if it was restarted from the launcher. As a precondition you need to set your activity to singleTask/singleTop launchMode in your Manifest:
android:launchMode="singleTask"
depending on what you're trying to achieve, this might be enough! But additionally you might have to deal with what happens when the user presses the back button. Default behavior is to finish & destroy your activity. Thus a brand new copy of it would be launched when it gets selected from the recents screen. Though onNewIntent would not be called, everything would be rebuilt from scratch. If you need to prevent this you can use:
override fun onBackPressed() {
moveTaskToBack(true)
}
finally when you navigate "back" from an activity you launched yourself onNewIntent will also not be called. If you further need to distinguish why your activity is resumed, you might want to start the 2nd activity with startActivityForResult so the onActivityResult is called when you get resumed.
Launcher activity & Intent extra
A completely different approach would be to have a "launcher" activity in your manifest that directly calls your "main" activity and finishes itself. When calling your main activity you can put an intent extra that allows your main activity to distinguish if it was just launched for the first time, or not. As the extra would be present on further onResumes, make sure to overwrite it the first time you "consume" it:
override fun onResume() {
super.onResume()
val firstLaunch = intent.getBooleanExtra(FIRST_LAUNCH, false)
intent.putExtra(FIRST_LAUNCH, false)
if (firstLaunch) {
// do something
}
}
and when starting from your "launcher" activity:
intent.putExtra(FIRST_LAUNCH, true)
startActivity(intent)