Android screen management - android

This is a very basic question, I have a few screens, now when you go from one to another you can then press back and cycle back through all the windows.
I'd rather that when you pressed back it took you to a specific window for instance:
Menu Screen
---->User clicks Info
Info Screen
---->User clicks Ride Info
Ride Info
---->User clicks back
Info Screen
Now is this to do with the hierarchical parent, will this define where it goes back to?
The second part of my question is if I don't have any resources to release or information to store for an on-resume what should I do when the user pauses my app? At the moment if you go back to the menu screen and re-select the app it will start a new instance rather than resuming. Do I just simply implement:
#Override
public void onPause() {
super.onPause(); // Always call the superclass method first
}
and
#Override
public void onResume() {
super.onResume(); // Always call the superclass method first
}
Apologies if this is a bit basic!

You might want to look in to setting FLAGS for your intent while opening new activity Android Dev
Something like this -
Intent a = new Intent(this,A.class);
a.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(a);

There is no basic questions here :)
Easiest way to do this is to override the onBackPress() function.
Sample :
#Override
public void onBackPressed() {
//Do what you want here
}
For saving variables when users leave the app, you need to override onSaveInstanceState(Bundle bundle)
#Override
protected void onSaveInstanceState(Bundle bundle) {
super.onSaveInstanceState(outState);
bundle.putInt("sample", 1);
}

For your two parts:
1) It's almost always best to let Android handle the back button, the order of which is determined by the back stack: see here for an explanation. If you want hierarchical navigation, I would recommend looking into the up button - see this developer page for a good explanation of how to use the different navigation tools.
Additionally, if you don't want to have an activity appear in your back stack, you can set the attribute android:noHistory="true" in your manifest, which will mean that the user can't return to it using the back button.
2) If the user has left your app, it's automatically paused, you don't need to implement onPause or onResume for this to happen. However, it's also up for collection to be terminated by the OS. If this happens, then it will be restarted when the user opens it from the launcher again. Any previously running instances of the app should automatically be opened.

Related

Activity backstack handling

Suppose I have activities A, B, C, D, E.
when I open application with activity A and switch to activity B and further to activity C. Suppose, somehow B gets destroyed by system. and when I press back button, I came out of app. What I really wanted was to be able to go to B if it exists otherwise A (landing page). In normal cases it's working smoothly but it's some cases where I have to interact with other apps/interfaces for eg. open url in browser. After sometime if I go back to app, I see latest page as it is but when I press back button app exits.
I have searched for solutions but couldn't find one so posting it as a question.
I know the idea of passing extra in intent and starting new intent on back press but these would not work in some cases or requires creating a backstack handler of own.
There is no guarantee that your activities will stay in memory and this is an intentional behaviour.
Your option is use to onRestoreInstanceState and onSaveInstanceState so that user do not lose critical data.
#Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
// Get data
super.onRestoreInstanceState(savedInstanceState);
}
#Override
protected void onSaveInstanceState(Bundle outState) {
// Save data
super.onSaveInstanceState(outState);
}
One way which I have used in the past to validate activity state is to add e.g. a boolean attribute in your activity, set this true when activity starts, if your activity is destroyed after some time this will be false. Check state by overriding the activities onBackPressed method?
e.g.
onBackPressed(){
if status{
/*activity live*/
}
else{
/*activity destroyed/*
}
}
This might work If I understand you issue correctly.

What is the default implementation of onBackPressed() in Activity

I want to know the default implementation of onBackPressed() in Activity. How to deal with the Activity recover in the default implementation of onBackPressed()?.
The following is the issues I suffer from. I have a test Activity code like this:
public class MainActivity extends Activity {
public static boolean test = false;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
#Override
protected void onResume() {
super.onResume();
Toast.makeText(this,"is "+test,Toast.LENGTH_LONG).show();
test = !test;
}
}
When I first enter the app, I get 'is false'. Then I click back button and get to the home screen. After that, when I enter the app, I get the Toast 'is true'. I think the onBackPressed() should kill my app when it gets back to the home screen, but It does not. This is my question.
If I override onBackPressed() like this
#Override
public void onBackPressed() {
// super.onBackPressed();
finish();
try {
android.os.Process.killProcess(android.os.Process.myPid());
} catch (Exception e) {
e.printStackTrace();
}
}
I always get the Toast 'is false' after I enter the app.
Can anyone explain this problem and tell me what the default implementation of onBackPressed()?
I'd like to know the flow process in onBackPressed() in detail. I have read some of the source code on onBackPressed(), but I couldn't understand it well.
Thanks in advance.
The default implementation of Activity's onBackPressed() probably won't tell you a lot about the actual Activity/application lifetime. You should dig much dipper to understand the internal Android (and Linux) "mechanics" on application/process killing.
What an application developer should know is that once an Activity is in background (Home button pressed, incoming call received etc., i.e. onPause() followed by onStop() have been invoked) its process may (similar to what you did with android.os.Process.killProcess(...)) or may NOT be killed. See Multitasking the Android Way by Dianne Hackborn for the reference.
As to finishing an Activity by pressing the back button, it does not mean its instance will be immediately killed and the memory garbage collected (see this answer). It just means a new instance of the Activity will be created next time you navigate back to it.
Regarding your code and the statement that
When I first enter the app, I get 'is false'. Then I click back button and get to the home screen. After that, when I enter the app, I get the Toast 'is true'. I think the onBackPressed() should kill my app when it gets back to the home screen, but It does not.
This is the case when the system didn't kill the process while the Activity were in background (again, it is not guaranteed). If it did, the Toast would have shown false.
In order to check that a new instance of MainActivity is created each time you press the back button and then navigate back to the app, I don't recommend to use a static variable, - it appears to be not that obvious (see, for instance, is it possible for Android VM to garbage collect static variables... or Are static fields open for garbage collection?).
Besides you're simply switching between true and false that might be confusing. Instead of using a static variable you might use a non-static one incrementing it, for example, or toast the hash code of the current Activity instance, like Toast.makeText(this,"is " + this.hashCode(), Toast.LENGTH_LONG).show(). By doing this the Activity lifecycle should act as per the documentation.
If I override onBackPressed() ... I always get the Toast 'is false' after I enter the app.
This is more or less similar to what if the system kills your app's process.
From the AOSP Activity class found here:
/**
* 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.
*/
public void onBackPressed() {
if (mActionBar != null && mActionBar.collapseActionView()) {
return;
}
if (!mFragments.getFragmentManager().popBackStackImmediate()) {
finishAfterTransition();
}
}
So basically when you call finish, the process is not actually destroyed. You can read more about that here. This means that the memory in your app isn't destroyed, so when you restart your app, the boolean value from before is remembered.
In the case of your overridden implementation, you are explicitly destroying the process, which will clear memory of your activity state, so when you restart the app, the boolean initialization will occur again.

Capturing the behaviour of "back" button

I have an app that consists of two activities: the "main" activity (M) and the "settings" activity (S). S can only be launched from M. The purpose of S is to modify settings which affect M. S has a "done" button that finishes the activity and goes back to M (through M's onActivityResult method, with an Intent that contains the new settings for M to apply).
My problem is: if I go back from S to M using the hardware "back" button (instead of S's "done" button) the system brings M to the top without any knowledge of the modified settings. Can this behaviour be modified? Ideally I would like to alter the behaviour of the hardware "back" button when S is on top, so that it cause S to finish (that way M would get the new settings).
If that's not possible, and more generally: what would you do you to have the settings applied on a "back" button pressing?
You can simply override onBackPressed()
#Override
public void onBackPressed()
{
// check if settings have been changed
super.onBackPressed();
}
Since this is a "closing action" do the super call after you have done your other work.
Following up on comments left on blackbelt's answer (now deleted comments) you may want to consider, if you haven't already, asking the user if they are sure they want to exit without saving in case they went into settings and decided not to change anything. What if they press the back button because they decided not to save the changes? You may already have something in place for this like a cancel button.
you have to override the onBackPressed from Activity and manage the same logic from the done button
You can also introduce a new java class to your package with static fields holding your settings.
Write to them as user changes settings & read from them as soon as in Activity's OnResume() method or later as needed.
You can achieve what you want by overriding onbackpressed method
#Override
public void onBackPressed() {
Intent intent = new Intent();
//get your settings from your views
intent.putExtra("setting1","on");
intent.putExtra("setting2","off");
setResult(RESULT_OK);
finish();
}
The answers above will do what you want, however:
Have you looked into using the built in android SharedPreferences? That way changes to the settings (made in S) will be stored to the device and then you can tell activity M to look at the settings and update appropriately in the onResume method. Plus the settings will be saved forever and it doesn't matter what happens to S.

How to clear activity stack trace on back press event?

I have created an application that has multiple pages and navigation from one to another represents a crucial flow. I don't want the user to be able to press the back button and escape the activity without first warning him and then finally deleting all stack trace such that when the activity is launched again it starts afresh.
As of yet I have been using something similar to the function below :
#Override
public void onBackPressed()
{
this.finish();
Intent int1= new Intent(this, Home.class);
int1.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(int1);
super.onBackPressed();
}
But sometimes when after quitting the application when I launch it again it restarts from some random page or the one from where I quit the application (basically not the home screen from where it is expected to start)
I cannot think of a cleaner way to quit the application other than clearing all the previous activity flags as described in the code.
Any help on the above is appreciated!
EDIT :
Anytime during the flow of my activity if the user presses the back button, I want the control to be thrown back to the main page (clearing all the previous activity stack traces). Such that in case someone re-lanches the application it will re start normally from the main page.
You don't need any of this custom code in onBackPressed(). All you need to do is add this to all of your <activity> definitions in the manifest (except the root activity):
android:noHistory="true"
This ensures that none of your activities (expect the root activity) is recorded in the back stack. When the user clicks the BACK key, it will just return to the root activity.
Another benefit of this is that if the user leaves your app (by clicking HOME or by pulling down the notification bar and clicking on a notification, when he returns to your app it will also just return to your root activity.
Anytime during the flow of my activity if the user presses the back
button, I want the control to be thrown back to the main page
(clearing all the previous activity stack traces).
This can be done just by finishing all the activities as they move forward, except the MainActivity.
Such that in case someone re-lanches the application it will re start
normally from the main page.
Is it like if user is in Activity_5 and uses Home Button and relaunches the app again, MainActicity must appear?
IF so, you can call finish() in onPause() of every Activity except MainActivity
EDIT:
Might not be the perfect solution, but this is what I did to achieve exactly the same(logout in my application):
OnBackPressed() in any activity updates a boolean shared preference say backPressed to true and in onResume() of all the Activities, except MainActivity check its value and finish if true.
#Override
protected void onResume() {
super.onResume();
SharedPreferences mSP = getSharedPreferences(
"your_preferences", 0);
if (mSP .getBoolean("backPressed", false)) {
finish();
}
}
Back Button is used to go back to the previous activity. So i would not override the back button to clear activity stack. I suggest you use a Action Bar for this purpose. Navigate to Home Screen of the application using the application icon.
http://developer.android.com/guide/topics/ui/actionbar.html
Also check this link and comments below the answer by warrenfaith
android - onBackPressed() not working for me
#Override
public void onBackPressed()
{
moveTaskToBack(true);
android.os.Process.killProcess(android.os.Process.myPid());
System.exit(1);
}
you can use that code, it's work for me!

OnRestart vs. OnResume - Android Lifecycle Question

My end-goal is to have an application that runs a block of code when it (the application, not the activity) is opened up after being left ( back from home screen, etc... )
According to the Activity Lifecycle, this should be the onRestart() event on a per activity basis ( at least how I interpret it )
Both onRestart() and onResume() are being called whether I am returning to the Activity within the application (back button) AND when the app is called back up.
Given this diagram
I am interpreting it this way:
RED = movement between activities within the application
BLUE = moving to an activity outside the Application
Is my understanding incorrect?
EDIT (Clarifying specific use case)
I'm attempting to use onRestart() to replicate some security logic (PIN Validation) found in onCreate(), but it's being called even when I press the back button inside the application...
My observation is that its hard to tie the lifecycle events to user behavior on the device or emulator. Where your app is paused, if the device needs memory or wants to recover resources, it will terminate the activity, causing onCreate to be called. There is just too many scenarios to build an adequate state machine to tell yourself "how" or "why" your activity was terminated.
The only way I've found to manage this is to create a service to hold the application state and manually manage the state. The problem is trying to use the Activity state to manage the application state. The Activity design seems to have limitations that just make it a poor choice for achieving the goal you've stated.
That would be because when unless your are using Fragments each "screen" in your application is a new activity, when you click the back button it restarts the activity of the page before it.
If I am understanding what you want to do correctly you want to put your code on onCreate, not onRestart.
SEE COMMENT THREAD FOR ANSWER
Here is how to do this:-
Have a base activity that all your activities are derived from.
Add in to the base activity:-
int nAppState;
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
nAppState = 0;
.
.
}
protected override void OnStop()
{
AppState();
base.OnStop();
}
public static int IMPORTANCE_BACKGROUND = 400;
protected override void AppState()
{
ActivityManager am = (ActivityManager)GetSystemService(Context.ActivityService);
IList<ActivityManager.RunningAppProcessInfo> list2 = am.RunningAppProcesses;
foreach (ActivityManager.RunningAppProcessInfo ti in list2)
{
if (ti.ProcessName.ToLower() == "com.mycompany.myapp")
{
nAppState = ti.Importance;
break;
}
}
}
protected override void OnRestart()
{
base.OnRestart();
if (nAppState == IMPORTANCE_BACKGROUND)
{
// Show a log in screen
RunOnUiThread(delegate { StartActivity(new Intent(this, typeof(LoginAppearActivity))); });
nAppState = 0;
}
}
Please note that this is in Mono C#, it will be the same code for Java, I'll leave it up to you to convert it!!
Yes, your assertions for red and blue are correct.
However, note the alternate pathway from onPause() and onStop(). Process being killed for memory reasons is a) out of your control and b) imperceptible to you if you only use onRestart() to detect "coming back" to the activity.
You have an option to avoid the previous activity by avoiding/removing the activity to come in Stack by setting some flag before calling the startActivity(intent):
intent.setFlags(i.getFlags() | Intent.FLAG_ACTIVITY_NO_HISTORY);
This will avoid the present activity to get called on back press. Alternatively you can also ovverride the onBackPressed() method of the current activity.

Categories

Resources