Multiple activity instances problem - android

In my application I have an activity class A that has a listview with a cursor adapter.
From A I can go to the activity B, by pressing a button. From B I can go back to A by pressing a button (not by pressing the BACK button). This means that a new instance of the A activity is created.
From this point, if I press the BACK key, the current A activity is destroyed and B is popped. And if I press BACk again the initial A activity is popped. I hope it is clear.
My problem is that when the second A activity is destroyed, the database connection is reseted, in a static manner. So in the end, when the initial A activity is displayed, the listview will be empty.
My question is: should I try to have a single instance for the A activities, or shoud I change the database connection (to link it with the activity instance)?
Thanks a lot
Gratzi

First Of All In class A which is carrying your ListView . on clicking any Listview call the startActivity method for the Class B Activity without calling any finish().
I hope which is you are already doing.
Now in the Second Activity The button (Not the Back Button) you are using for calling Activity A . in its clickListener for calling Activity A dont call the startActivity(intentForA) instead call the finish(); for ending the Activity B. this will resume the A activity which is paused..
I hope this will help

You will need to create 3 Activities rather than 2.
Have a MAIN activity that does not really display anything.
So You have Activity A that is your main activity that can handle the connection to the DB etc.
Then Activity B and C can be the A and B that you have used.
Activity A (Main activity) can have a static instance of itself so you can refernce it's
Variables etc -OR- you can pass data from one activity to the other using Intent.put, etc.
I prefer the global static instance way as I'm a little old school on Java.
Edit:
Forgot to mention, to handle the 'closing' of the app, either Activity B or C must also close Activity.
public class ActivityA extends Activity {
ActivityA act_a_instance;
public int some_integer = 22;
#Override
public void onCreate(Bundle savedInstanceState) {
act_a_instance = this;//Now you can reference this Activity outside
//Your creation stuff etc
}
}
public class ActivityB extends Activity {
#Override
public void onCreate(Bundle savedInstanceState) {
//Your creation stuff etc
//Reference stuff from ActivityA like so :
int temp_integer = ActivityA.act_a_instance.some_integer;
}
#Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.options_back:
startActivity(new Intent(this, ActivityC.class));
break;
}
}
#Override
protected void onStop() {
finish();
super.onStop();
}
}
public class ActivityB extends Activity {
#Override
public void onCreate(Bundle savedInstanceState) {
//Your creation stuff etc
}
#Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.options_back:
startActivity(new Intent(this, ActivityB.class));
break;
}
}
#Override
protected void onStop() {
finish();
super.onStop();
}
}

Use below code hope this will solve your problem
Intent i = new Intent(B.this, A.class);
i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(i);

Related

How to finish specific activities not all activities

In my android application suppose several activities are there
if using intent I go to other activities like this
[Activity A]->[activity B]->[Activity C]->[Activity-D]->[Activity N]
and now when am on activity N when I pressed button then I want to go to Activity B and want to destroy Activity C And Activity D but Activity A should not destroy. I also searched in various posts but I didn't get exactly the same solution.
Any help will be appriciated
In ActivityN, to return to ActivityB use this:
Intent intent = new Intent(this, ActivityB.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
startActivity(intent);
Using the flag CLEAR_TOP will finish all activities in the stack that are on top of ActivityB. In the example you gave, this will finish ActivityN, ActivityD and ActivityC. Using the flag SINGLE_TOP will make sure that this will return control to the existing instance of ActivityB (ie: it won't create a new instance of ActivityB).
In Your Activity C do like this
public static ActivityC instance = null;
public class ActivityC extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
instance = this;
}
}
And in your Activity D do like this
public static ActivityD instance = null;
public class ActivityD extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
instance = this;
}
}
Finally in your Activity N. Do Something like this
public class ActivityN extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Button yourButton= (Button) findViewById(R.id.yourButton);
yourButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
ActivityC.instance.finish();
Activityd.instance.finish();
finish();
}
});
}
}
Here's my approach.
From Activity A, don't just start the Activity B, call startActivityForResult() method. Do this for all subsequent calls.
Now, when you press the button from Activity N, set the result for a custom value and call the finish() method for Activity N. Now you should hit the onActivityResult method on your Activity D. Now you can check whether the result was you pressing the button. Depending on your result, keep on setting the result and subsequently calling finish() on each Activity.
This should technically work.
Try this code:
//Activity A
Intent i = new Intent(getApplicationContext,ActvityB.class);
startActivity(i);
//Activity B
Intent i = new Intent(getApplicationContext,ActvityC.class);
startActivity(i);
//Activity C
Intent i = new Intent(getApplicationContext,ActvityC.class);
startActivity(i);
finish();
// finish here actvity which you want to finish
//Try this second way:
In your first activity, declare one Activity object like this,
public static Activity fa;
onCreate()
{
fa = this;
}
now use that object in another Activity to finish first-activity like this,
onCreate()
{
FirstActivity.fa.finish();
}
EDIT : Use startActivityForResult() instead of startActivity()
So depending on the result you can change the behavour.
Say for example When you wanted to go to ActivityB just return some flag in the INTENT. When it will be caught in Activity D and C in onActivityResult(), finish them and you will be finally on B.
Flag Intent.FLAG_ACTIVITY_CLEAR_TOP may solve your problem:
http://developer.android.com/reference/android/content/Intent.html#FLAG_ACTIVITY_CLEAR_TOP
You can start ActivityC, ActivityD, ActivityN with the same request code passed to startForResult(requestCode)
And then at ActivityN, use finishActivity(int requestCode).
Documentation for finishActivity(int requestCode)
Force finish another activity that you had previously started with startActivityForResult.
Params:
requestCode – The request code of the activity that you had given to startActivityForResult().
If there are multiple activities started with this request code, they will all be finished.

Remove an activity from the stack

I have three activities ActivityA, ActivityB, ActivityC.
Suppose in ActivityA, there is some code like...
if(someCondition()){
gotoActivityB();
}
else{
gotoActivityC();
}
Now, If user goes to ActivityB, ActivityA should not be finished.
If he goes to ActivityC, it should be finished.
Adding noHistory in manifest file doesn't work.
Also, finish()in if condition doesn't work, As there are many activities after ActivityC in which ActivityA should be in background.
I don't want to call startActivity(context,ActivityA.class)in those activities onBackPressed() because, it will again execute code of onCreate() in ActivityA.
So, is there a way, where i can remove ActivityA from the stack when user presses back button in ActivityB?
may be something like this:?
ActivityB.this.finish();
ActivityA.finish(); //some code to finish ActivityA
Okay, here is one way you can accomplish your goal. You will need to pass around the Activity context to wherever you need it in order to call finish() on it. I used the Application class to do this. I only used two classes to do it for the sake of time, but it should work just fine for your purposes. Here is how I did it:
This is the first class. It is the Activity that we want to close from another Activity.
public class MainActivity extends Activity implements OnClickListener {
private Button button;
// application instance
private MainApplication mainApplication;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mainApplication = (MainApplication) getApplicationContext();
// set the Activity's context for later usage. Doing this determines which
// Activity can be closed from another Activity.
mainApplication.setActivityContext(this);
button = (Button) findViewById(R.id.button1);
button.setOnClickListener(this);
}
public void onClick(View v) {
switch (v.getId()) {
case R.id.button1:
Intent i = new Intent(this, SecondActivity.class);
startActivity(i);
break;
}
}
}
This is the Second Activity. Exiting out of it will also cause finish() to be called on the first class:
public class SecondActivity extends Activity {
private Activity activityContext;
private MainApplication mainApplication;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.second_activity_layout);
mainApplication = (MainApplication) getApplicationContext();
// get the Activity context you stored in the MainApplication class
// so you can call finish on it.
activityContext = mainApplication.getActivityContext();
}
#Override
protected void onPause() {
super.onPause();
// closes your defined Activity. If you press the back button you will find
// that you exit right out of the app as the other Activity gets popped off
// the stack.
activityContext.finish();
}
}
And the Application class:
public class MainApplication extends Application {
private Activity activityContext;
public Activity getActivityContext() {
return activityContext;
}
public void setActivityContext(Activity activityContext) {
this.activityContext = activityContext;
}
}
And of course make sure to declare your MainApplication class in the AndroidManifest:
<application
android:name=".MainApplication"
android:icon="#drawable/ic_launcher"
android:label="#string/app_name"
android:theme="#style/AppTheme" >
This is a sort of hacky way to do this. There may be better ways. But regardless, you have to pass around the context of the Activity that you want to call finish() on. Then you can close it from anywhere.
Hi you can finish your activity in current activity itself based on the condition. or use StartActivityforResult based on the result you can finish your activity.
hope this will help you.
You can try this in another way, like i do.
Create a static instance variable of the activity in the beginning.
private static Activity1 thisAct = null; // Activity1 is name of class
Now initialize this variable in onCreate() method
thisAct = this;
Create a static method which will finish this activity
public static void finishActivity()
{
thisAct.finish();
}
While going to Activity C, clear the FLAG :
Intent cIntent = new Intent(view.getContext(), cActivity.class).setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(cIntent);

Finishing an Activity in Android

When you press the back button while in an activity, by default, does the application not go back to the activity that called it? I am calling an activity in my application(call it Activity B), from Activity A, but when I hit the back button while in Activity B, I am taken back to the main page of the application.
So I guess in general, does pushing the back button on your phone take you to the calling activity?
Calling activity B from within an inner class of activity A:
class HeadlineButtonListener implements OnClickListener {
private Story story;
public HeadlineButtonListener(Story story) {
this.story = story;
}
#Override
public void onClick(View v) {
Intent myIntent = new Intent(HeadlineBoard.this, StoryView.class);
myIntent.putExtra(Constants.STORY_EXTRA, story);
HeadlineBoard.this.startActivity(myIntent);
finish();
}
}
You call finish() on first activity after firing the next activity, this will cause it to be removed from the activity stack, just remove the call to finish():
#Override
public void onClick(View v) {
Intent myIntent = new Intent(HeadlineBoard.this, StoryView.class);
myIntent.putExtra(Constants.STORY_EXTRA, story);
startActivity(myIntent);
}

Saving Activity State

I have two activities A, B . Now from A i call B by pressing a button (using startActivity()) , then press Back key to go back to A . Now when i press Button again to go to B , fresh activity is called (as expected).
Now can someone tell me how to show old previous state of B ?
I have read this article
Saving Android Activity state using Save Instance State , but couldn't help myself :(
public class B extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main1);
if(savedInstanceState!=null){
EditText editText=(EditText)findViewById(R.id.editText1);
editText.setText(savedInstanceState.getString("EditBox"));
}
}
#Override
protected void onSaveInstanceState(Bundle onSaveInstanceState) {
System.out.println("B.onSaveInstanceState()");
super.onSaveInstanceState(onSaveInstanceState);
onSaveInstanceState.putString("EditBox","Hello");
}
#Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
System.out.println("B.onRestoreInstanceState()");
super.onRestoreInstanceState(savedInstanceState);
EditText editText=(EditText)findViewById(R.id.editText1);
editText.setText(savedInstanceState.getString("EditBox"));
}}
My Class A
public class A extends Activity {
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Button button=(Button)findViewById(R.id.button1);
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent i=new Intent(StartActivityforresultActivity.this,B.class);
startActivity(i);
}
});
}
With what it sounds like you're trying to do you have two options:
1. Save the state of B when B's onDestroy or onBackPressed is called. You'll have to save this to memory or write it out using some sort of persistence (SharedPreferences, local file, etc). Then whenever B is started, check to see if that data exists and use it to load the state.
2. Override onBackPressed so that when it is pressed you aren't calling super.onBackPressed. Instead start an instance of activity A and set your intent's flags to be FLAG_ACTIVITY_REORDER_TO_FRONT before calling startActivity. So something like this:
Intent intent = new Intent(this, A.class);
intent.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
startActivity(intent);
Now when you hit back, it should find the instance of A that is in your activity stack and just bring it to the front. You may have to add the same flag whenever you start B as well.

Notification opens activity, press back button, prevent opening back stack activity?

This looks very similar to my previous question because it's some sort of follow up. I was not very happy with the only solution given; also, the solution was for a problem slightly different from this one. So let me try to explain the problem again...
A notification is created at boot (with a BroadcastReceiver).
My app main activity is opened and the home button is pressed (the activity will be sent to the back stack).
I pull down the status bar and press on the notification previously created at boot.
That will start some activity, different from the main one.
I press the back button and the main activity is displayed.
This is not very different from my previous question... The thing is, "main activity" was just an example. I could have opened the app main activity and then opened the about activity through a menu option and pressed the home button. The back stack would now be MainActivity » AboutActivity. Which means that when the back button is pressed while in "some activity" (started by pressing the notification), we would be brought to the top of the back stack, that is, the about activity.
What basically want is to prevent any other activity to be opened when I press the back button while in "some activity" (again, started by pressing the notification). I want to be brought exactly where I was, that could be the desktop or some other app's activity, but not my app's MainActivity nor AboutAcitivity cause that's not where I was, those were in the back stack, "sleeping" in the background.
I have come up with a solution, but I don't think it's very elegant and I was looking for something more, well, elegant... If you have any other suggestion, please, let me know.
Anyway, this is my proposed solution:
// I use this class for public static (or public static final) members and
// methods
public final class AppHelper {
public static final String KEY_RESUME_FROM_NOTIFICATION = "resumeFromNotification";
private static boolean sResumeFromNotification = false;
public static boolean getResumeFromNotification() {
return sResumeFromNotification;
}
public static void setResumeFromNotification(boolean resumeFromNotification) {
sResumeFromNotification = resumeFromNotification;
}
}
public class MainActivity extends ListActivity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
(...)
}
#Override
protected void onResume() {
super.onResume();
if(AppHelper.getResumeFromNotification()) {
AppHelper.setResumeFromNotification(false);
moveTaskToBack(true);
}
}
}
public class AboutActivity extends Activity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
(...)
}
#Override
protected void onResume() {
super.onResume();
if(AppHelper.getResumeFromNotification()) {
AppHelper.setResumeFromNotification(false);
moveTaskToBack(true);
}
}
}
public class SomeActivity extends Activity {
// This will be called when the notification is pressed and the activity is
// not opened yet
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
(...)
extractIntentExtras(intent);
}
// This will be called if the activity is already opened and the
// notification is pressed
#Override
protected void onNewIntent(Intent intent) {
extractIntentExtras(intent);
super.onNewIntent(intent);
}
private void extractIntentExtras(Intent intent) {
Bundle bundleExtras = intent.getExtras();
if(bundleExtras != null) {
// These intent extras are set on the Intent that starts this activity
// when the notification is pressed
AppHelper.setResumeFromNotification(bundleExtras.getBoolean(
AppHelper.KEY_RESUME_FROM_NOTIFICATION));
mRowId = bundleExtras.getLong(AgendaNotesAdapter.KEY_ROW_ID);
populateNoteUpdateFields();
}
}
}
I don't know, but this solution doesn't look very elegant to me (but it works as I expect it) and I'm looking for alternatives or for strong opinions on my proposed solution as an acceptable and good solution. Thoughts?
After doing some more reading perhaps this is the combination of flags you need:
Intent intent = new Intent(mContext, SomeActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
startActivity(intent);
I think that should force your SomeActivity class to be launched in a completely new task.
When launching the Activity from the notification, you can control how the Activity you are about to open is put on the back stack, and what task it's associated with with Intent flags. You can try something like:
Intent intent = new Intent(mContext, SomeActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
If that doesn't work, try setting a few of the other flags until you get the desired behavior.
Do you ever want your MainActivity to stay in history? If not then my simple, crude solution is to finish the MainActivity when it is paused.
(Call this in your MainActivity)
#Override
public void onPause() {
finish();
}
This will ensure that your MainActivity is removed from history when you navigate away from it, and will never appear when the back button is pressed.
This could be used for AboutActivity as well.

Categories

Resources