Application lifecycle. How to run something only when application starts - android

I have a dialog popup to indicate how long I want an activity to run.
Seems simple enough, but its difficult to determine when the activity is really starting.
If the user opens the keyboard on a G1 and thereby goes into landscape, that reruns the activities onCreate method.
I can't have a static for the class or even create an application class, because I can't determine when the 'application' goes away. Even after destroying the only activity, the application is apparently still alive.
Is there a way to determine that onCreate has been called because of the keyboard being extended or landscape mode invoked?
Thanks

In onSaveInstanceState you could store a flag indicating if it had run. If the app was being restored then in onCreate(Bundle savedInstanceState), the savedInstanceState will have the variable so you could check if savedInstanceState != null and saveInstanceState.get("restoring") != null then don't show the dialog.

I tried creating an application subclass, but still I could not determine when it would go away.
I tried another approach.
I added in the manifest within the activity,
android:configChanges="orientation|keyboardHidden"
Then within the activity I added,
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
}
This results in my onCreate method NOT being called when the orientation changes or the keyboard is hidden. I'm not sure why my view still looks correct in either case, but it works great. In fact it even handle text typed into the displayed dialog. The text is maintained when the orientation is changed.

Is there a way to determine that
onCreate has been called because of
the keyboard being extended or
landscape mode invoked?
There is a way to:
1. Check if the keyboard is being extended
2. a way to check the current orientation (landscape or portrait)
Determining whether onCreate() has been called or not will require some work on your part. For instance, you can have a variable to flag completion of onCreate() and save it in Activity's state Bundle.
You can put a check in onCreate() to determine if this is a first run or a restart due to Configuration changes, by making some sense out of values from 1,2 and the flag.
This is just a suggestion; better solutions might exist

Related

Android Activity instance state

What is the significance of:
super.onCreate(null);
instead of
super.onCreate(savedInstanceState);
With this change, I am able to avoid many problems that otherwise plague my Activitys each time a configuration change occurs (rotation, locale shift, permission toggle). It seems that with this change, the Activity is started afresh whenever a configuration change triggers it to restart. And I don't seem to lose any data or process state by doing this: all my Activitys are restored exactly to their former state.
My question is, can I do this with impunity henceforth, or am losing something in the bargain? I don't really understand why this works, whether it is safe or not, and what unintended effects it may have on my app.
I chanced upon this trick here.
Related Questions:
Calling super.onCreate() with null parameter?
Will 'Bundle savedInstanceState' be alive after Application is being killed?
Activity state instance - insights?
Activity's instance state: what is automatically stored and restored
onCreate() call first when activity is about to create, Also Android System manage activity lifecycle and can kill the activity with saving its instanceState, in case if acitvity out of focus for user for long time and system is on low memory situation.
An activity has essentially four states
super.onCreate(null) : Would always create activity as it is creating fisrt time , even Android system provide its savedInstanceState, and does't matter what orientation configurations are.
super.onCreate(savedInstanceState) : Activity can use 'savedInstanceState' to reset its state or component where it was last.
To achive this, acitivty's instance state need to be persist before activity lost user attention( that could be onStop or onDestroy)
savedInstaceState can also be important to handle if activity configuration got changed, Please check acitvity life cycle behavior on Configuration change
am losing something in the bargain?
Only if you are working with Fragments. see Calling super.onCreate() with null parameter?
Yes, onCreate(...) is necessary to start an Activity, but passing Bundle as an argument is required when you are working with fragments.
What did you infer from that?
The argument savedInstanceState is anyway null by default. So you aren't really losing anything in a bargain.
But wait, we usually use Bundles to maintain orientation change, right?
the following manifest code declares an activity that handles both the screen orientation change and keyboard availability change:
<activity android:name=".MyActivity"
android:configChanges="orientation|keyboardHidden"
android:label="#string/app_name">
Now, when one of these configurations change, MyActivity does not restart. Instead, the MyActivity receives a call to onConfigurationChanged(). This method is passed a Configuration object that specifies the new device configuration. By reading fields in the Configuration, you can determine the new configuration and make appropriate changes by updating the resources used in your interface. At the time this method is called, your activity's Resources object is updated to return resources based on the new configuration, so you can easily reset elements of your UI without the system restarting your activity.
the following onConfigurationChanged() implementation checks the current device orientation:
#Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
// Checks the orientation of the screen
if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) {
Toast.makeText(this, "landscape", Toast.LENGTH_SHORT).show();
} else if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT){
Toast.makeText(this, "portrait", Toast.LENGTH_SHORT).show();
}
}
But Remember: When you declare your activity to handle a configuration change, you are responsible for resetting any elements for which you provide alternatives. If you declare your activity to handle the orientation change and have images that should change between landscape and portrait, you must re-assign each resource to each element during onConfigurationChanged().
As far as I know a lot of data is saved in the bundle savedInstanceState.
E.g. all the views' states in your current layout, such as the current content of any EditText or CheckBox.
You could also look up some official sources to check whether you need to keep some data.
Here's a nice article about it
Basically it says that all View class implements the methods onRestoreInstanceState and onSaveInstanceState, which are saving and restoring any temporary states they were in before the state change.
The savedInstanceState is a reference to a Bundle object that is passed into the onCreate method of every Android Activity. Activities have the ability, under special circumstances, to restore themselves to a previous state using the data stored in this bundle.
It is very important to use savedInstantState to get values from Intent which is saved in the bundle.
All your data stored in class variables or local variables is lost whenever you change rotation of device, but in your activity it looks like you have not stored any data as long as user enters any data, but instead you are perhaps reading data on click of a button or something like that, your activity will behave and work normally, and all user inputs like text inside EditText will be restored by Android itself, because it identifies "IDs" (android:id="#+id/anyID") allotted to each view and can restore by itself all the values inserted by user.
I hope this this helps you...
Happy coding :)

Is there a way to know that an Activity was recreated because of a device rotation

I have an activity class that locks itself with a custom PIN whenever it is resumed/recreated (so that I can lend my phone to someone secure in the knowledge they can't see that app's data).
The problem this causes is that rotating the device recreates the Activity and redisplays the PIN lock, which is a bit unsmooth.
So, is there some way the Activity to know either
I am being destroyed because of an orientation change.
I am being created as a result of an orientation change.
I would like to avoid solutions based on android:configChanges="orientation|screenSize" if possible.
EDIT: For posterity, I ended up doing this by having all Activities in the app inherit from this LockableActivity class.
A very simple solution is to check the time passed between 'onPause' and 'onResume'. If it is less than 0.2 seconds then you haven't handed your phone over ...
In fact, you could make this a user controllable security feature: how long away from the activity before pin entry is needed again could be set by the user.
For the truly obsessive, you could ask the user to reorient their phone during the set up phase to determine the associated time lapse and set that as the minimum.
As noted elsewhere, you could also use onSaveInstanceState. In this approach that is when you would store the time for comparison later.
Put the below code in your activity, it will get triggered when the device is rotated
#Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
//perform your operations here
}
If you also want to check whether it is in landscape or portrait mode , you can apply below conditions
if(newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE){
}
else {
}
If your activity is normally destroyed, onSaveInstanceState() will never be called. During orientation change (or any other change that needs to load different resources), onSaveInstanceState() will be called. In this method, you can save your data that you want your activity to have during it's re-creation.
If your activity is normally created, savedInstanceState will be null. But if it was created because of re-creation (like change in orientation), then savedInstanceState will not be null and you can use this to fetch the data that you saved during onSaveInstanceState().
It's a bad idea to override onConfigurationChanged(), instead you could just use these methods that Android provide to persist your data or application logic . In your case, it could be something like this in your onCreate().
if(savedInstanceState != null){
boolean loggedIn= savedInstanceState.getBoolean("LoggedIn",false);
if(!loggedIn){
// Not logged in, hence show pinlock
}
}
You could do something like this.

Getting around onDestroy being called on orientation change?

I have a stock Nexus 5 running 4.4.2 (using ART if it matters) and I've found an interesting scenario. I have this as my onDestroy():
#Override
protected void onDestroy() {
super.onDestroy();
t.setText("onDestroy");
t.show();
}
It's a GPS oriented app so I'm up and walking around. I am using the technique mentioned in this question to show a lot of debug toast messages.
Anyway, when I rotate my app, the toast appears. I understand that the activity is destroyed and recreated for the new orientation, but how can I know what's really going on? How can I tell when my app is REALLY getting destroyed and not just being rotated? Similar to this question, I want to log out when a particular activity is destroyed.
Since Honeycomb, the isChangingConfigurations() method can be queried to check whether the Activity is being recreated due to configuration changes. Alternatively, the isFinishing() method can be queried on any API level to check whether the Activity is actually being finished, or is only being destroyed temporarily by the system.
As far as I can determine, the two methods should always return mutually consistent results in practice. The only point where they might have diverged is when the system kills the process to clear memory, but there are no callbacks or interaction with the app at that point.
The documentation of the onDestroy() method mentions the use of the isFinishing() method:
Perform any final cleanup before an activity is destroyed. This can happen either because the activity is finishing (someone called finish() on it, or because the system is temporarily destroying this instance of the activity to save space. You can distinguish between these two scenarios with the isFinishing() method.
You can put it in a fragment with setRetainInstanceState(true) set. Place your code in the onDestroy() method of the fragment. Then, the fragment will not be destroyed on orientation changes.
First of all, you should not use onDestroy() to do anything because its not guaranteed to be called. I would put things on the onPause() method; I wouldn't even put things in onStop().
Also, Im not sure why you want to log out a user when they navigate away from the app. I would rather implement some kind of timer on the app or server to log out after x time.
Now, the answer lies in the documentation: http://developer.android.com/reference/android/app/Activity.html#ConfigurationChanges
You might want to override onConfigurationChanged so that your activity is not restarted.
I found a couple of solutions which are really just patterns to detect when the screen rotates. Alternatively, you can determine that the device was actually destroyed by checking some static data member to see if it was initialized or not.
Configuration changed solutions:
The first one involves handling all of the configuration changes in the onConfigurationChanged callback.
"Note that this will only be called if you have selected
configurations you would like to handle with the configChanges
attribute in your manifest."
The second involves listening for Display.getRotation() which returns a Surface.ROTATION_* object. Which is the new orientation of your screen relative to the natural state of the device orientation.
Again, you can use the configuration changes along with the static member.
Add ConfigChanges.UiMode flag to the ConfigurationChanges attribute for your MainActivity class, and this solves the problem.
More details: Android Launcher "OnDestroy" gets called twice

Android AsyncTask return dismissing a ProgressDialog after screen rotation

Here's the scenario:
Account login page
Clicking on "Sign-in" triggers a login AsyncTask
To block the UI during network access, a ProgressDialog pops up
Upon returning, the ProgressDialog is dismissed and the user forwarded on
This flow works very well.
Here's the problem:
The user may rotate the screen while the AsyncTask is logging him/her in
Presently, the ProgressDialog is referenced by a class field, and dismissed using that pointer and call to .dismiss().
If the screen is rotated, though, everything crashes.
Probably because the Activity is re-created? My suspicion is that the closure around that field reference points to an object that is unreachable. What's your take?
How can I solve it reliably and elegantly? Just add if (... != null) checks?
More generally, I must confess I don't understand the "best practice" to apply in cases like this:
Activity A triggers an AsyncTask
The user navigates away from Activity A (back button? rotate screen? onClick that starts an Intent?)
The AsyncTask returns when Activity A is not the topmost one anymore yet its onPostExecute() has a UI effect , note: the original delegate observer is not available anymore.
Confused * (note: I am a beginner, so a thorough explanation would help me a lot)
Yes on changing the orientation, the activity is destroyed then recreated it again.
When a configuration change occurs at runtime, the activity is shut down and restarted by default, but declaring a configuration with this attribute will prevent the activity from being restarted. Instead, the activity remains running and its onConfigurationChanged() method is called.
Add this line android:configChanges="orientation|keyboardHidden" to your manifest file
<activity
android:name=""
android:label=""
android:configChanges="orientation|keyboardHidden" />
I recommend looking at Handling Runtime Changes. For a detailed explanation of the details of the methods available to you.
android:configChanges="orientation..." tells android your application will take care of resizing the current view hierarchy. As such, when you specify that in your manifest, your activity will not be destroyed and recreated, instead the system will just call your activity's `onConfigurationChanged()` method. As it so happens, most of the stock widgets will resize themselves when their container changes, so if you are using basic layouts, this usually "just works" by redrawing the view hierarchy in the new format. For custom widgets, this trick may not work.
The approved method is to save some configuration instance information when you are being destroyed in the onSaveInstanceState() method, and then recreate your state in onCreate()
In your case, the dialog is dismissed when then screen changes orientation, so you can either leave it that way, or reopen it in your onCreate().

My views are being reset on orientation change

I have a small activity with an EditText and an imageview and a button. When you press the button it launches camera for result, and when it returns it changes the imageview to the picture you've just taken.
But when the orientation changes, the imageview resets back to the default one on the layout.
What I tried doing was setting a boolean called custom, and when you take a picture it sets it to true. I overrid onConfigurationChanged() and if custom is set to true I restore the image.
My problem now is the EditText becomes erased -- How can I restore the EditText after configuration change? My first attempt was storing it's content into a String onPause() and then restoring it, but it always comes up blank.
Usually when UI view does not keep its state, first thing to check is that this UI view has id assigned. Without this id views cannot restore their state.
<EditText android:id="#+id/text" ... />
If this doesn't help, you need to save and restore state yourself. Take a look at Handling Runtime Changes. It pretty much explains what you should do:
To properly handle a restart, it is important that your Activity restores its previous state through the normal Activity lifecycle, in which Android calls onSaveInstanceState() before it destroys your Activity so that you can save data about the application state. You can then restore the state during onCreate() or onRestoreInstanceState(). To test that your application restarts itself with the application state intact, you should invoke configuration changes (such as changing the screen orientation) while performing various tasks in your application.
You should override onSaveInstanceState() and save your Acitivity state when its called:
#Override
protected void onSaveInstanceState(Bundle outState)
{
super.onSaveInstanceState(outState);
outState.putString("textKey", mEditText.getText().toString());
}
And then restore state in onCreate() or onRestoreInstanceState():
public void onCreate(Bundle savedInstanceState)
{
if(savedInstanceState != null)
{
mEditText.setText(savedInstanceState.getString("textKey"));
}
}
If this is still not sufficient, you can override onRetainNonConfigurationInstance() and return any custom Object that will be passed to new activity object, when its recreated. More details about how to use it can be found in Handling Runtime Changes. But this function is deprecated in Android 3.0+ (specifically for FragmentActivity where its final). So this cannot be used together with Fragments (which is fine, they have their mechanism to retain objects accross configuration changes).
And final one - never use android:configChanges. You must have very good reasons to use it, and usually these are performance reasons. It wasn't meant to be abused the way it is now: just to prevent UI state reset. If this attribute is used, then yes, Activity UI will not be re-set on config change, but Activity state still will be reset when destroyed and re-created later.
The documentation explains this option pretty well:
Note: Handling the configuration change yourself can make it much more
difficult to use alternative resources, because the system does not
automatically apply them for you. This technique should be considered
a last resort and is not recommended for most applications
You can force your activity not to reload after orientation changed by adding android:configChanges="orientation" to your activity line in manifest.

Categories

Resources