I have been developing this application for quite a while now and came up with this bug in the app. Initially when the application loads for the first time, it starts from the home activity. Then the user interaction will navigate application to activity1 which uses fragment1. The fragment1 has a button. If the user clicks on that button,the activity1 calls finish() and loads activity2 by calling startActivity().Also when the user clicks on the hardware back button from the fargment1, the application returns to the Home activity.
So the real issue here is that, when I am at activity2 and finish() the activity the application will show the Home activity. But i want to completely close the application on pressing back from the activity2.
The following is the code which starts the activity2 form the fragment1:
Intent intent = new Intent(context, Activity2.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(intent);
((Activity)context).finish();
I get that the Home activity has never been finish()-ed.
So how do I destroy the activity1 and home activity on navigating to the activity2, and make the activity2 only remaining activity in the application?
Thanks in advance.
Ok so this is what i did (according to #seema):
in the home activity i registered a broadcastreciever in OnCreate() method of the activity.
IntentFilter filter = new IntentFilter();
filter.addAction("com.example.CUSTOM_INTENT");
registerReceiver(receiver, filter);
BroadcastReceiver receiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
Log.d("==>","Broadcast Recieved.");
finish();
}
};
public void finish() {
super.finish();
};
then in the activity2 i send out the broadcast
Intent local = new Intent();
local.setAction("com.example.CUSTOM_INTENT");
sendBroadcast(local);
This worked out as I required it to be.
Thus any activity can be destroyed from any other activity.
First approach: use start activity for result instead of start activity and finish it in onActivityResult.
Second apparoach: Register a local broadcast in each required activity and in its receiver, finish it. From activtity2 send this broadcast. This will finiah all those activities in stack having that broadcast registered. I have used this approach for Logout implementation in many apps and it works well.
Related
I'm new in android development, and there is something about the life cycle activity that I don't understand, especially with the following example of application that i'm working on.
In my app, I have a Login activity and a Main activity.
In my Login activity, with successful attempt, there is a Intent that start the main activity, and finish() the login activity.
==> There, my login activity is destroyed, so this should not show up again.
Intent intent = new Intent(this, MainActivity.class);
intent.putExtra("authentResult", tokenDto);
startActivity(intent);
finish(); //destroy activity to not open it with back button`
In my Main activity, I have a disconnect button that create an Intent that start a (new ?) login activity.
==> Until there, everything's normal, and the login activity is displyed.
Intent loginActivity = new Intent(this, LoginActivity.class);
startActivity(loginActivity);
In the login activity, using the Back button should close the app.
To do that, I send an intent with special flag to the main activity to finish it (So the back button will not wake up the main activity), and then I finish the login activity. The onDestroy method is called and I see the login window close itself.
==> From here I expect the app to be closed. But a "new" login activity shows up, and i suspect that it would be the activity of the first point, so I'm a little lost there...
public void onBackPressed() {
Log.d(TAG, "BACK PRESSED - loginActivity");
//Finish MainActivity
Intent intent = new Intent(getApplicationContext(), MainActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
intent.putExtra("EXIT", true);
startActivity(intent);
finish(); // finish login activity
}
In the onCreate in the mainActivity, I begin with this :
if (getIntent().getBooleanExtra("EXIT", false)) {
finish();
}
Do anyone could explain to me what I'm missing, or show me a better way to close the app directly ?
Don't hesitate to telle me if something's not clear.
If you declare the Login activity as main activity in the Manifest, if you don't destroy it when you launch the second activity then i think the back button will do all you expect without any additional code, and if you press back key on the login activity it will go to phone home screen
On Android applications is the system that decides when to close/kill application.
My app issues notifications. By clicking the notification, the app needs to be launched or brought to the front. Here is the intent for the notification:
Intent launch_intent = new Intent("android.intent.action.MAIN");
launch_intent.setComponent(new ComponentName("com.example.helloworld","com.example.helloworld.MainActivity"));
launch_intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
launch_intent.addCategory(Intent.CATEGORY_LAUNCHER);
launch_intent.putExtra("some_data", "value");
And in my app I want to determine if it's launched or brought to the front by the notification click, so I use putExtra there. Then in MainActivity's onResume I check the intent data. This works fine is the app is launched by the notification click.
However, if the app is brought to the front by the notification click, in MainActivity's onResume there is no intent data.
I think the reason is: MainActivity is the root activity, and it's the splash screen. There could be any number of activities on top of it when the app is brought to the front. And when it's brought to the front, I want to keep its state.
What is the right way of doing this?
Override onNewIntent() in your activity and check the value there. If you want future calls to getIntent() to return this new intent, you can call setIntent() and pass the new intent.
Try in onNewIntent() method
#Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
String value = intent.getStringExtra("some_data");
}
I have two activities, A and B. I have a button in A,when pressed starts a new intent to B.
However whenever I press the back button while in B, than click the button again is restarts Activity.I do not want to do that,I want it to resume Activity B.
Actually I am doing some networking in Activity B and I want to save unless the user wants to refresh.
How can I do it? Thanks in advance
Use
#Override
public void onBackPressed(){
moveTaskToBack(true);
}
Hope, It must help you
You need to Overrider the
onBackPressed
method and start there the activity like this:
#Override
public void onBackPressed() {
Intent intent = new Intent(this, activityA.class);
startActivityForResult(intent, PICK_CONTACT_REQ);
}
This sounds like you need to rethink your architecture. You say:
Actually I am doing some networking in Activity B and I want to save
unless the user wants to refresh.
If this is the case, you probably don't want to do your networking in ActivityB. Maybe you should start a Service from ActivityB to do the networking. The service and the activity can communicate with each other so that the activity can keep the user up-to-date about the state of the networking. If the user presses BACK in ActivityB, it can finish (as usual) and return to ActivityA. In this case, the Service is still managing the networking. When the user again starts ActivityB (from ActivityA), the new instance of ActivityB can communicate with the service to see if there is any networking going on, and if so it can get the current status of that networking or start it or stop it or whatever.
I guess I'm too late but I had a similar problem.
I had two activities A,B and a next button in A.
Whenever I tried to do: A->press next button ->B->press back button->A->press next button->B, B screen got destroyed when I pressed the back button. So when I came back to B for the second time it was a newly created B (all the information I had put in was gone).
So it was like A->B->A->new B when I just wanted to go back to the original B! :(
So what I did was, in activity B, I overrode the onBackPressed() function so it doesn't destroy the activity. I also set the flag so that if there is a A activity already running, it would just pull it up to the front instead of creating a new A activity.
#Override
public void onBackPressed() {
Intent intent = new Intent(getApplicationContext(), ActivityA.class);
intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
startActivity(intent);
}
Then, for the onclicklistener function for the next button in activity A, I set the flags similarly.
public void onClickNextbutton(View v){
Intent intent = new Intent(getApplicationContext(), ActivityB.class);
intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
startActivity(intent);
}
I have a 'list' activity which starts an 'article' activity when clicked.
I also have push notifications which opens the 'article' activity directly.
I changed the back button behavior in the 'article' activity to start the 'list' activity, when coming from a notification so that the user will go back to the article list.
The problem is when the app is already opened in the background and I open a notification - it just brings it back to front.
What I want to achieve is open the right article when clicking a notification and going back to the 'list' activity, without having the possibility the the list activity will be open twice.
I tried to separate the 'article' task and create new task in the notification intent but then it would open separate 'list' activities when opening multiple notifications and clicking back.
What is the correct way to define the activities' tasks and intent flags to achieve my goal?
EDIT:
Manifest part:
<activity android:name="ListFeed" android:configChanges="orientation|screenLayout" android:launchMode="singleInstance" android:screenOrientation="unspecified"
android:taskAffinity="com.app.MyTask"></activity>
<activity android:name="Article" android:launchMode="standard" android:configChanges="orientation|screenLayout" android:screenOrientation="unspecified"
android:taskAffinity="com.app.MyTask"></activity>
Notification intent:
Intent notificationIntent = new Intent(context, Article.class);
PendingIntent contentIntent = PendingIntent.getActivity(context, notificationID, notificationIntent, PendingIntent.FLAG_ONE_SHOT);
Thanks!!
what i got from your question is that
1) you have listActivity A
2) ArticalActivity B.
i) And first you want to open Activity A whenever back from B, Correct? for that you can use dispatchKeyEvent, listen to Back button event and start activity A. or by using below code
#Override
public void onBackPressed() {
Intent intent = new Intent(this, MainActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(intent);
}
ii) you want to open only single instance of Activity A(list). for this you can basically use
launchMode in Activity A's Manifest declration as singleInstance.
android:launchMode="singleTask"
you can read docs for launch mode
let me know if i missed anything.
I see that you are playing around with launchModes and excludeFromRecents and this isn't a good thing. The standard behaviour of Android should do pretty much what you want.
To verify this I've created a simple 3-activity application that contains a MainActivity, a ListActivity and an ArticleActivity. I'm not using any non-standard launch modes and I'm not setting any Intent flags (except in onBackPressed() see below). The Main Activity creates and posts a notification to display a specific Article. The MainActivity starts the ListActivity. Each element of the ListActivity starts an Intent for the ArticleActivity and passes some information in EXTRAS so that the ArticleActivity knows which article to display.
In order to have the behaviour you described (ie: returning from the ArticleActivity to the ListActivity after starting the app from a notification, even if the app was not running), I've done what Ankit has suggested (ie: override onBackPressed() in ArticleActivity) like this:
#Override
public void onBackPressed() {
// Return to ListActivity
Intent intent = new Intent(this, ListActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
startActivity(intent);
// Finish this activity (in case the ListActivity wasn't already in the stack)
finish();
}
I used FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP because this will not recreate the ListActivity if it already exists in the activity stack (ie: it will go back to the same instance).
I had to add the finish() call, because if the app was not running in the background and the user started it from the notification, the ListActivity would be created and put on top of the ArticleActivity. Then when the user pressed "back" to leave the ListActivity, the ArticleActivity would be exposed underneath. Adding finish() here makes the ArticleActivity go away so that pressing "back" from the ListActivity goes back to wherever it came from.
If you want me to send you the code, just let me know.
There are a lot of topics on this post. But i couldn't find a solution to my problem.
Let me describe my activity stack first.
SplashScreen->A->Login->Home.
What i would like to achieve is , when i click on back button after logging in to Home, i should come out of the application and go to Home if i use my application again. For this i am assuming i should clear the activity stack before Home, after i login. I would also like to preserve the activity stack if the user hasn't logged in yet.
I want this to work on or after 2.1
What i have tried already.
using finish() in Login Activity , before calling startActivity on Home. This will redirect me to A , if i use back button on Home.
All variations of FLAG_ACTIVITY_NEW_TASK and FLAG_ACTIVITY_CLEAR_TOP . Nothing worked, when i use back button, i am redirected to login screen.
Any suggestions or simple solution to achieve this?
using finish() in Login Activity , before calling startActivity on Home. This will redirect me to A , if i use back button on Home.
ok so use finish on all the activities that you want them to be popped before calling startActivity
go to Home if i use my application again
Simply save your login parameters in SharedPreference and from A startActivity Home directly if login successful.
You can also try to make use of BroadcastReceiver aswell if you want to try that route.
In your "SplashScreen" and "A" activities, in the onCreate method you can create and register and IntentFilter and a BroadcastReceiver like so:
Assuming you have a global variable called broadcastReceiver
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction("ACTION_LOGIN");
this.broadcastReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
finish();
}
};
registerReceiver(broadcastReceiver, intentFilter);
Also don't forget to unregister your receiver in the onDestroy method (this is to prevent memory leaks in the program):
#Override
protected void onDestroy() {
unregisterReceiver(this.broadcastReceiver);
super.onDestroy();
}
Now in your "Login" activity, once the user has successfully logged in, you can broadcast a message to all the registered receivers, which will finish those activites in the back stack:
Intent broadcastIntent = new Intent();
broadcastIntent.setAction("ACTION_LOGIN");
sendBroadcast(broadcastIntent);
Your SplashScreen and A activities will now be finished.