My App has two activities. Let's just call them "A" and "B" (B is a very heavyweight game). The way it's supposed to work is that "A" launches, validates the OBB package, mounts it and then launches "B" and passes some data to "B" and then "A" calls finish on itself since it's done.
It's important that "A" is the only thing that can launch/create "B".
What's happening is that when "B" gets terminated by the OS because of memory pressure, and then sometime later the user task switches back to it via the "recents", Android tries to create a new "B" activity.
In that situation, I want it to start a new "A" activity which will then create "B". Can someone tell me what I should look into to do this?
It's important that the user be able to switch between apps, take a phone call etc. and return to the already created/running "B" activity if it's still there and hasn't been terminated. If it HAS been terminated, tapping on it needs to launch activity "A" so that the OBB can be verified and remounted etc.
NOTE: I've had to simplify and gloss over some complex things to make the question short but let's assume that the preparation that "A" does cannot be moved to "B". I know that looks like a sane work around at this simplified level...but sadly it's not.
Pass some data in an Intent when opening Activity B from A, then every time Activity B is created check if that data is there, otherwise create an Intent to Activity A and terminate Activity B.
Activity A:
Intent i = new Intent(activity, ActivityB.class);
// Pass your data or otherwise a boolean like so
i.putExtra("validIntent", true);
startActivity(i);
finish();
Activity B:
Bundle loginBundle = getIntent().getExtras();
boolean continueActivity = false;
if (loginBundle =! null) {
if (loginBundle.getBoolean("validIntent");) {
continueActivity = true;
}
}
if (!continueActivity) {
startActivity(new Intent(this, ActivityA.class));
finish();
}
To preserve the data/boolean while paused, you could use saveInstanceState.
Related
In my android activity B, I read values bundled in the intent like this
Bundle bundle = getIntent().getExtras();
Boolean mine = bundle.getString("mine").equals("1");
int pagenum = bundle.getInt("page");
When I start B from another activity A, I give in mine=0,pagenum=0.
And I can read that fine in B.
But then in B, I want to reload the activity, by finishing itself and opening another B. I also need to pass in the new data like this:
private void refresh(Boolean mine, int newpage) {
finish();
Intent myIntent = new Intent(this, AllThreadsScreen.class);
myIntent.putExtra("mine", mine ? "1" : "0");
myIntent.putExtra("page", Integer.toString(newpage, 10));
startActivity(myIntent);
}
When I call this, I make sure that newpage has a value of 1. However the problem is that, after starting the activity, when I read the page value from the bundle, it becomes 0 again...
Does anyone know whats wrong?
Thanks.
You are not "restarting" the Activity. If you call finish() and the lines after still work, then it ins't really finished, is it?
What is happening is the Activity may begin the process of finishing, but then receives a new Intent. Android doesn't actually destroy it.
Also, you don't need to finish the Activity anyway. just use onNewIntent (a little known, little used Activity method).
How to capture the new Intent in onNewIntent()?
I read many threads about this subject, but I couldn't find anything that fits my needs.
I have an application with 3 activities (I'll call them screens here, more intuitive): A (MainActivity), B and C.
Screen A starts another process, retrieves some information from that process and sets the layout according to the answer. Then it gives you the opportunity to do something (write a text). This is done on OnCreate().
Screen B is not very interesting (presents the text and allows you to edit it).
Screen C has a single button which exits the application (basically starts the home activity). C also closes the process we started on A (after communicating some info to it).
So far so good.
The problem is that when I restart my app, I see screen C again. This is not good for me, because I want the user to be able to edit the text, without having to go back to the first or second screen (not because it's so difficult, but because I need him to see the new info presented on screen A before he does anything. And this can't be done after C, because after C he's done, unless he decides to start the app again).
This means that when I get to screen C and press the button, my app is completed and there's nothing left for me to do there (but start over fresh). But if my app was suspended on screen B, there's no need to start fresh - I can just go back to it and continue from there (regular Android behavior).
So I set android:clearTaskOnLaunch="true"but now I have two problems:
1. It now starts fresh again (sort of, see #2) even if the app was suspended on B, which is not what I need.
2. It's not really starting fresh.... Yes, I see screen A. But all the things I did on OnCreate() are not done again, which means my other process is not up and running, and then my app crashes because I have no one to talk to.....
Is there any solution to such cases?
I need to start fresh (but really fresh, with all the things I did on OnCreate() done again) only after previous run of the application was completed (we pressed the single button on screen C and got back to the home screen).
In any other case of suspension (in A, B, and even C if we didn't press the button yet) I want the normal Android behavior (i.e. go back to the same screen).
Any help will be much appreciated.
To solve this you can take advantage of the Android Activity Lifecycle: http://developer.android.com/training/basics/activity-lifecycle/stopping.html
Simply call finish() in Activity B and C in onStop() or onPause() appropriately to wipe away those activities (or "screens" as you say) when the app is closed. Activity A should reopen holding the last state when you open your app back up.
If you're looking to wipe out the last state in Activity A as well, then add a finish() call to it as well where appropriate (probably onStop or onPause again per your use case)
Good luck!
I had a similar app before, a survey app, and had the same situation. A->B->C and once you finish C you go straight to A and can't go back but you can go back from B->A. Here what I did:
1) Add this to A Activity when you start B Activity:
Intent start;
start = new Intent(MainActivity.this, RecordName.class);
startActivityForResult(start, 2);
and this method in your A activity:
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == 2) {
if(resultCode == RESULT_OK){
//String result=data.getStringExtra("result");
finish();
}
}
2) In B Activity add this when you start C Activity:
Intent start;
start = new Intent(B.this, C.class);
startActivityForResult(start,1);
and this again in your B activity:
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == 1) {
if(resultCode == RESULT_OK){
//String result=data.getStringExtra("result");
finish();
}
}
3) In your C activity add this to your press method:
Intent start;
start = new Intent(C.this,A.class);
// pass any data back to A activity
start.putExtra("Key", String);
startActivity(start);
// to close previous activities
Intent returnIntent = new Intent();
//returnIntent.putExtra("result","finish");
setResult(RESULT_OK,returnIntent);
// close current activity
finish();
I hope this helps
I am puzzled over this behavior I am experiencing in an application I am developing...
Short:
Intent data is not clearing out when the user presses the back button to leave the application and then presses the recent button to re-enter the application. (Every other case, the intent data is cleared out)
Long:
I have an application with a splash screen that is used to collect data that is passed in from a URI scheme. I then setup an intent to forward the data to the main activity. The main activity has fragments and is based off the master/detail template.
The intent data is cleared out in all cases, such as pressing the home button and then going back to the application, pressing the recent apps button and then going back to the application, etc. The only case where the intent data is not cleared out is when the user presses the back button and then the recent apps button to get back into the application.
Relevant snippets of code that involve the intents:
// Splash Screen Activity
#Override
protected void onPostExecute(Void result) {
// Data is done downloading, pass notice and app ids to next activity
Intent intent = new Intent(getBaseContext(), ListActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK);
intent.putExtra("id1", id1);
intent.putExtra("id2", id2);
intent.putExtra("id3", id3);
startActivity(intent);
finish();
}
// ListActivity retrieving intent data
Intent intent = getIntent();
if (intent != null) {
this.id1 = intent.getExtras().getString("id1");
this.id2 = intent.getExtras().getString("id2");
this.id3 = intent.getExtras().getString("id3");
}
// ListActivity clearing intent data
#Override
public void onPause() {
super.onPause();
// Clear intent data
Intent intent = getIntent();
intent.putExtra("id1", "");
intent.putExtra("id2", "");
intent.putExtra("id3", "");
}
I want to note that I have also tried using intent.removeExtra("id1") but that too did not work.
Any idea what is going on? It is as if Android is keeping the old intent even though onPause() is always called to clear the intent data.
actually this is due to Android starting the app from the history hence the intent extras are still in there
refer to this questions Android: Starting app from 'recent applications' starts it with the last set of extras used in an intent
so adding this conditional to handle this special case fixed it for me
int flags = getActivity().getIntent().getFlags();
if ((flags & Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY) != 0) {
// The activity was launched from history
// remove extras here
}
I believe the difference here is that the Back key is actually causing your Activity to finish, where as pressing Home causes your activity to be paused, but not finished.So when your process is brought back to the front in the Home case, it is simply resuming an already existing Activity instance, whereas in the Back case, the system is instantiating a new copy of your Activity, calling onCreate(), and handing it a fresh copy of the last Intent recorded for that activity.
In onPause() you are clearing the extras in a "copy" of the Intent. You can try adding
setIntent(intent);
to onPause() after you've cleared the extras (although calling removeExtra() would probably also work instead of setting extras to empty strings).
NOTE:
However, I would suggest that this design is flawed. You shouldn't use the Intent to keep track of state in your application. You should save some state in shared preferences because this will survive your app being killed/restarted, a reboot of the phone, or whatever.
The problem is that the new Intent is not persisted, so that If the user presses the HOME button and your app goes to the background and then Android kills your app because it is not active, when the user returns to the app, Android will create a new process for your app and it will recreate the activity using the original Intent.
Also, if you read the documentation for getIntent() it says that it returns the Intent that started the activity.
To get around the issue I was facing, I opted to use SharedPreferences as a means to pass data between activities.
I know SharedPreferences isn't typically used for this purpose, but it solved my issue and works.
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 two apps, which I will refer to as app A and app B. App B is a single task app and normally, if you start this app from the Home screen and use the Back button, you will not be allowed to return to the Home screen. Now suppose app A needs to call app B using an Intent. If the user then uses the Back button in app B, I really do want them to return to app A. But since I am overriding the Back button, it is not possible to return to app A using the Back button.
How can I return to app A but make sure app B remains running if it was running when app A called it? If app B was not running when app A called it, app B should shutdown (get destroyed) when the Back button is pressed.
I am using Android 2.2
UPDATE:
I tried the following:
#Override
public void onBackPressed()
{
try
{
if (this.returnToClient)
moveTaskToBack (true);
this.returnToClient = false;
}
catch (Exception ex)
{
}
}
I set returnToClient to true if the activity is launched by a calling app by checking some bundle data that gets passed in.
Now if I press the Back button, app B will move to the background and app A comes to the foreground. Looks good. Now if I press the Home button and then launch app B, app B just picks up where it left off. Also good. Now the bad part. If I do a long press on the Home button to bring up the history list and then tap on the icon for app B, the onNewIntent method gets called exactly the same with and with the same data being passed in as though app A had initiated the activity. So what I am guessing is that Android treats launching an app from the Home screen different than it does from the History list. Why? I have no idea. It seems that the history has to do with whoever launched the activity last and persists the bundle data as part of that history. That is weird and it results in unwanted behavior making app B look like it just got called from app A.
Have AppA launch AppB using an Intent with an EXTRA that indicates that it was launched from AppA, something like this:
Intent intent = new Intent(this, AppB.class);
intent.putExtra("returnToAppA", "true");
startActivity(intent);
Then, when AppB traps the "back" key, it can check if it was launched from AppA and if so, it can return to appA like this:
Intent intent = new Intent(this, AppA.class); // Use the starting
// (root) Activity of AppA here
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
Setting FLAG_ACTIVITY_NEW_TASK will ensure that a new instance of AppA will not be created, but it will just return to the existing task containing AppA.