Activity control - android

Suppose assume that there are 3 Activities A ,B and C. On the first launch of my application B is created through A. But on subsequent uses of the application I want the application to launch from B and go to C. How do I do that?
(for example Activity A asks for the number of buttons created and in B so many buttons are created for further activities performed by C. A should be used only on the initialisation and not on further use of app. But the state of the activity created by A in B has to remain the same)
Any references or sample code could be helpful
Thanks in advance.

You can always start your application through activity A. In A, check if it is first time or not. If it is first time then do number of initialization operations and start B. Otherwise directly start B.
You can store isFirstTime flag into preferences.

Use this code in your A, B And C Class
public boolean onKeyDown(int keyCode, KeyEvent event)
{
if(keyCode == KeyEvent.KEYCODE_BACK){
finish();
}
return super.onKeyDown(keyCode, event);
}

This can be accomplished a number of ways, but not too many sure fire ones: the basic approach you will use is a splash screen along with a flag variable stored somewhere. As one of your comments mentions, whenever you enter Activity A, you can always set the flag in a SharedPreferences. When you go back to this activity in the future, you can simply check whether or not the flag is set and then perhaps make a new Intent to start activity C from B. You can also do a similar thing with A, where checking the flag you choose to go to the app. One tricky situation is how to reset the flag. There are a few options, you could conservatively reset the flags in onStop(), which may or may not be a good idea, after you think about the lifecycle. You may also register a boot completed handler, and then reset the flags there, which would essentially let you restart the behavior each time the system boots.

Related

How to show disclaimer once per run of app

This is harder than it sounds, which is why I'm asking for solutions.
Basically I only want the disclaimer Toast shown once per run of the app.
The app is in two parts, all are Activities.
It's shown when it starts in the first part, but you can hit a menu button
taking you to the second part of the app, which has another menu button
to take you back to the first.
The problem is that whatever initial settings you try to make in the first
part, when it starts up, are run again when returning from the second
part of the app, so it'll show again.
My last idea was that in the first part's onDestroy(), when the app exits, but is not the case in this situation, you set a boolean in settings,
to reset that the disclaimer can be shown, but apparently, onDestroy() is called on the first part before it goes to the second part.
Or, if you can get it to not show the first run, but behave properly
every time after that, that would be okay.
And there doesn't seem to be any method to be called when the app truly
is "killed", if there was that would be the way to do it, you could reset it there. Or if there was a method that was only called when the app first started..
Thanks!
You just need a boolean flag. Say we call it disclaimerShown. In onCreate() of Activity A, we check both the Intent Bundle and the savedInstanceState Bundle for this flag.
You can add the boolean to a Bundle when launching the Intent to start Activity A from Activity B.
If the user is in Activity B and presses the Back button to return to Activity A, you can override onBackPressed() in Activity B and include your flag there as well (though you'll have to catch this flag on onActivityResult() in Activity A).
If system initiated process death occurs in Activity A, the system will call onSaveInstanceState(Bundle bundle). So you add your flag to this bundle as well.
And if system initiated process death occurs in Activity B, you have nothing to worry.
And that handles all possible cases.
An elegant solution for this problem would be the ProcessLifecycleOwner.
This class provides callbacks to the lifecycle of your whole app (not individual activities) and you could use the Lifecycle.Event.ON_CREATE callback to show your toast once. Look at this stackoverflow question for a usage example of the ProcessLifecycleOwner.
It turns out that I already had an Activity that started before
my "Activity A", and I moved my disclaimer Toast there
and it works fine. You can't beat that simplicity lol.
Thanks for your answers!

Problem with bundle value

I have 3 activities A,B and C. Activity A contains a list of items. When we click a row in Activity A, it calls Activity B which describes the item. In activity B i have another list. When I click on a row in it, it calls Activity C.
I have to pass id field from A to B and then to C.
Suppose I have values
Small
Medium
in Activity A.
I am clicking Small from this and going to Activity B and then to C. Everything works fine. The id passed is also correct throughout the activities.
Now from C, I am clicking phone's back button and going to B and then agin clicking phone's back button and going to A.
Now I am clicking Medium from the list. The id is correctly passed to B. But when I reach C, its not going to onCreate() instead to onResume(). There I am getting id value as the old one, of that of Small. But I want the correct id. What may be the reason for this issue? Could anyone please help. Thanks in advance.
I think.. U have to finish the activity when u r handling the back button in Activity C
public boolean onKeyDown(int keyCode, KeyEvent event) {
if ((keyCode == KeyEvent.KEYCODE_BACK)) {
finish();
}
return super.onKeyDown(keyCode, event);
}
The problem occurs because Activity C doesn't get killed, only suspended.
I haven't tested, but I'm fairly certain that if you pass the data via Intent.putExtra, you should get the behaviour you're looking for (I sincerely hope different extra-data causes a new instance to get launched)
Hope this helps,
Phil Lello
As per my knowledge in android activity get destroyed when you press back button(by default).
I suspect you might be dong something wrong while passing data between activities.
But still if you fill it is related to activity is not getting destroyed. You can finish your Activity C in onPause() method. It will resolve your problem.

Navigating through multiple activities

I have 2 Activities A and B. Now these are my objectives.
When I'm in B and if I press the Home button, the state of the Activity should be saved. (No problem with this.)
When I start B from A after step 1 a new instance of B should be created (i.e) Previous state should be discarded.
But in Step 2 the state of B still prevails. How do I accomplish my objective?
I think one possible solution woudl be to pass some extra information inside the starting Intent, when you start Activity B from A (like a boolean value). And in the "onStart()" of B, you check if you can find this extra info in the intent (you get it with getIntent()). If it's not present, that means you do reload the activity's previous state. If it is, then you don't reload it.
refer this url
Android; How can I initialise state in one activity, then have another refresh that?
You don't even need to send a boolean like Scythe suggested. The Bundle savedInstanceState will be null in onCreate for Activity B if Activity A just started it, whereas it will be non-null if you are coming back from a saved state.

Use a persistent notification to allow the user to return to running Android app

I am developing an app with numerous Activities. I would like to create a persistent notification that (more or less) says, "AppName - Return to AppName" that will be present whenever my background services are running. Creating and disposing of the notification was no problem.
Now, the user could be on any of several screens/Activities, leave the application, then want to re-enter the app via the notification. The problem is, the notification must have an intent, which launches a predetermined Activity. I want the notification to re-enter the app in whatever Activity is at the top of the history stack.
My first attempt at an ugly workaround was to make an activity (let's call it "returnFromNotify") whose only job was to "finish" itself in it's "onCreate". The notification would open "returnFromNotify" in the scope of the applications history, which would then immediately remove itself, sending the user back to the previous history state in the application stack. This seems to work... unless the user has used "back" to completely back out of the app. Then, when they hit the notification, "returnFromNotify" loads, then finishes, sending them back out to the home screen (as there are no activities in the history stack for the app).
I considered trying to detect if there was anything in the history stack before "returnFromNotify", and if not, fire up my main Activity. I can't seem to find a way to do this, either.
Any input or suggestions for a Java/Android novice? FYI, My primary history is with script-based languages.
I like your original idea of creating a "returnFromNotify" activity better than your proposed workaround, as it is possible to detect if the ResumeActivity is at the bottom of the stack (and therefore the only activity in the stack).
Here's how you can do it:
Add your ResumeActivity to the manifest and specify the noHistory attribute:
<activity android:name=".ResumeActivity" android:noHistory="true" />
Specifying noHistory will make sure this Activity won't stay in the stack as soon as it finishes. This way you know that only a currently running instance of the ResumeActivity will show up in the stack.
In order to check the application stack, you'll also have to ask for the GET_TASKS permission:
<uses-permission android:name="android.permission.GET_TASKS" />
Now you can use ActivityManager::getRunningTasks() to determine if ResumeActivity is the only activity in the stack:
public class ResumeActivity extends Activity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if(isOnlyActivityInStack()) { //check the application stack
//This activity is the only activity in the application stack, so we need to launch the main activity
Intent main = new Intent(this, MainActivity.class);
main.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(main);
} else {
//Return the user to the last activity they had open
this.finish();
}
}
/**
* Checks the currently running tasks. If this activity is the base activity, we know it's the only activity in the stack
*
* #return boolean This activity is the only activity in the stack?
**/
private boolean isOnlyActivityInStack() {
ActivityManager manager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
boolean onlyActivityInStack = false;
for(RunningTaskInfo tasks : manager.getRunningTasks(Integer.MAX_VALUE)) {
if(tasks.baseActivity.getPackageName().equals(this.getPackageName())) { //find this package's application stack
if(tasks.baseActivity.getClassName().equals(this.getClass().getName())) {
//If the ResumeActivity is the base activity, we know that it is the only activity in the stack
onlyActivityInStack = true;
break;
}
}
}
return onlyActivityInStack;
}
}
I know you asked this question over 2 years ago, but I'm providing this answer in case anyone else runs in to this particular situation (as I did). I think you were on the right track with the solution you were originally working towards.
Okay, I believe that I have found a satisfactory work-around for my specific case. I've added a static integer to my "mainActivity", and each time it's "onCreate" is fired, it increments the integer. Each time it's "onDestroy" is fired, it decrements.
In my "returnFromNotify", I look at the static integer to see if it is greater than 0. If so, I assume there is an active "mainActivity", and that running "finish" inside "returnFromNotify" will return there. Otherwise, it assumes the users has "backed" out, finishes itself, then uses "startActivity" to fire up a new instance of "mainActivity".
This is not a universal solution, but for my purposes, I think it will suffice. I am still open to other answers, and if someone can punch a hole in my logic, please do so - constructive criticism is welcome. Thanks.
I guess there is no easy way to do this but instead of adding a counter in the mainActivity I would extend Application:
Base class for those who need to
maintain global application state. You
can provide your own implementation by
specifying its name in your
AndroidManifest.xml's
tag, which will cause that class to be
instantiated for you when the process
for your application/package is
created.
I would mantein the logic there and have a method like:
public Intent getIntentForLastActivityShown();
to be called when the notification item is clicked.
My first approach would be to use SharedPreferences and store a key value pair called something like lastDisplayedActivity. Then in each Activity's onResume (and possibly `onCreate') you would have a line like this:
sharedPreferences.edit().putInteger("lastDisplayedActivity", ReturnFromNotify.THIS_ACTIVITY_NAME);
In other words, you store an application-wide variable indicating which activity was last displayed. Then you just grab this variable from SharedPreferences and launch the corresponding activity.
I usually use activity named "Launcher" that checks state of my application model and starts activities (or does other things) depending on model rules. I put Model object in my Application class. Model can use Preferences to store its state. I do it to avoid static fields in activities.

Does pressing Back always cause Activity to finish()?

I've heard that pressing the back button will essentially cause the current Activity to finish(). Is this always the case? Seems like it would be with the way it pops the Activity off the stack.
The one situation I'm not so sure about is when the root Activity in a Task has back pressed. I'm currently experiencing a very weird effect, described as follows:
On loading my application, the first Activity is for initialization, and once it finishes, it calls my main Activity (a TabActivity). This first init activity has android:noHistory="true" set in the Manifest so pressing Back from my main Activity won't go back to that. It goes to the Launcher. When I click on my App in the Launcher a second time, the initialization activity loads again, and loads the main Activity when done. Almost immediately after, it loads a second instance of my main Activity. But ONLY after the Application has already been run once, and was exited by pressing BACK from the main Activity. It does it every subsequent time until I force quit the app or load a new version from the IDE.
Based on this, I am suspecting some kind of Activity instance is lying around and being reused, since it only happens on the second+ time I run the application (and exit with BACK -- using HOME just returns to the last state of the app, no big deal). Anyone have any thoughts??
I've heard that pressing the back button will essentially cause the current Activity to finish(). Is this always the case?
No it is not. The most activities have this behaviour but not all. For example you could create a Dialog and set it setCancelable(false) and it won't close if you click BACK button.
Furthermore you could customize activity behaviour on BACK button pressed by overriding onBackPressed
Called when the activity has detected the user's press of the back key. The default implementation simply finishes the current activity, but you can override this to do whatever you want.
About your application behaviour..Did you verify if the activity launcher is finished after it loads your main activity? I mean if the onDestroy() method is called. Maybe after it runs the main activity it remains there and when you click back you just go back to the old Launcher...
hope this helps..
Read through the Activity and Task design guidelines on the Android developer site; they explain how the Home and Back buttons work. Obviously, if you override the default behavior (as mentioned by hara above), the back button will not finish the activity.
On your specific issue, check your logcat. You should be able to see there whether it is bringing an old process back to life or starting up a new one. If that is unclear, insert a couple of log statements into onCreate, onPause, onDestroyed, etc., so that you can see exactly what is happening with your process.
You can control BACK-BUTTON by writing the following code.
public boolean onKeyDown(int keyCode, KeyEvent event)
{
if (keyCode == KeyEvent.KEYCODE_BACK ) {
//preventing default implementation previous to
//android.os.Build.VERSION_CODES.ECLAIR
return false;
}
return super.onKeyDown(keyCode, event);
}
Are you running your activities with any special flags, such as singleInstance or singleTop? Those could be causing the oddities you're seeing. The easiest way to track down what's causing your problem is to absolutely fill it with debugging messages. For example:
In your initialisation activity, add a log in the beginning of onCreate to get the name of the activity such as this.toString(). More on why you want this line later.
When it launches the main tabbed activity, get the name of the launching activity and a message saying it's launched the tabbed one.
Override the onPause(), onStop() and onDestroy() callbacks and add debugging lines with this.toString() and also a message telling you which callback it is.
What this will do is tell you whether you've got multiple instances of the initialisation activity lying around. To this by comparing the name of the activities calling your main activity with the ones that were just created and the ones that went through to onDestroy.
If you don't know how to debug, use Log.d(LOG_TAG, "Your message here");. And then define a constant LOG_TAG String somewhere. After that, show the LogCat perspective in Eclispe by going to Window, show perspective (or view, don't remember exactly), other, Android, LogCat. The purpose of having a LOG_TAG constant is that you can set up LogCat to filter to that String and only show you those messages. It will make it easier to see them among the mass of system log messages.
The short answer to the original question is 'no'. This is largely because, unfortunately, not every developer follows the guidelines referenced by previous answers.
Yet the guidleines themselves mention exceptions, when the Back key should not call finish(). the most prominent exception is the Web browser, which has its own "back stack" for each window, so it must have its own custom handling of the Back key.
If there are no fragments on the back stack and a developer has not overridden onBackPressed, the activity will finish when the back button is pressed.
Here is the source code for Android 4.4.2 Activity.onBackPressed():
public void onBackPressed() {
if (!mFragments.popBackStackImmediate()) {
finish();
}
}
just override onbackpressed().. on back press this method will get execute remove super and do what u want to do.

Categories

Resources