I need to handle orientation changes in my Android application. For this purpose I decided to use OrientationEventListener convenience class. But his callback method is given somewhat strange behavior.
My application starts in the portrait mode and then eventually switches to the lanscape one. I have some custom code executing in the callback onOrientationChanged method that provides some additional UI handling logic - it has a few calls to findViewById.
What is strange is that when switching back from landscape to portrait mode onOrientationChanged callback is called twice, and what's even worse - the second call is dealing with bad Context - findViewById method starts returning null. These calls are made right from the MainThread
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
listener = new OrientationListener();
}
#Override
protected void onResume() {
super.onResume();
// enabling listening
listener.enable();
}
#Override
protected void onPause() {
super.onPause();
// disabling listening
listener.disable();
}
I've replicated the same behavior with a dummy Activity without any logic except for one that deals with orientation hadling.
I initiate orientation switch from the Android 2.2 emulator by pressing Ctrl+F11
What could be wrong?
Upd:
Inner class that implements OrientationEventListener
private class OrientationListener extends OrientationEventListener {
public OrientationL() {
super(getBaseContext());
}
#Override
public void onOrientationChanged(int orientation) {
toString();
}
}
}
This is a documented bug in the emulator ONLY. A real device will not exhibit this double-lifecycle-events behavior. I had the same issue a while ago and it disappears on a real device.
I would suggest ignoring the problem if you can by only testing orientation changes in one direction until you get your hands on a physical phone. Otherwise you might be able to "skip" the second set of lifecycle calls by keeping a static boolean around indicating you've already gone through the first set.
See this issue report for more info.
Have you tried using onConfigurationChanged?
#Override
public void onConfigurationChanged(Configuration newConfig) {
if(newConfig.equals(Configuration.ORIENTATION_LANDSCAPE)…
Add android:configChanges="orientation" in manifest file in activity tag like
<activity android:label="#string/app_name"
android:configChanges="orientation"
android:name=".com.androidpeople">
Related
My application having landscape and portrait mode. so I designed two layouts for each mode. In manifest file I set the below code.
android:configChanges="orientation"
it's working fine but the activity restarts on every orientation changes. so I add the following line to avoid the recreate issue.
android:configChanges="keyboardHidden|orientation|screenSize"
Now the activity is not recreating but it also not taking the landscape mode design.
please help me to solve this issue friends
I would recommend letting the Application recreate itself on orientation change.
If you need to preserve state then store information when onSaveInstanceState is called.
/**
* On min or rotate save state info.
*
* #param bundle saved values
*/
public void onSaveInstanceState(Bundle bundle) {
bundle.putBoolean("SomeKey", someKeyValue);
super.onSaveInstanceState(bundle);
}
and then recover the values in onCreate
if (savedInstanceState != null) {
if (savedInstanceState.containsKey("SomeKey")) {
someKeyValue=
savedInstanceState.getBoolean("SomeKey");
}
}
Using onConfigChanges: is a slippery slope that works well until it doesn't.
Behavior varies and gets more complex with each OS release.
In my case my app work fine in both orientation here is what i doing may it help you,
use same code in public void onCreate(Bundle savedInstanceState) { // your code } and public void onConfigurationChanged(Configuration newConfig) { // your code }
and in AndroidManifest file
use like
<activity
android:name="YourActivity"
android:configChanges="orientation|screenSize"
android:windowSoftInputMode="stateHidden" />
that's it. if any issue post your comment
Well basically, I press a button, this opens up your default camera app by using the camera intent. After a picture is taken, it will save the things needed and redirect to another activity.
In this activity, I have an AsyncTask that can succesfully upload pictures. So what is my problem you may ask. My problem is that it re-creates my activity and therefore reset my ProgressDialog together with it. ( It runs the activity, does the aSyncTask, dies before it can finish it and re-creates my Activity to do the asynctask once again. )
It does not always do this. I think it does this because it changes the Orientation from the phone from Landscape to Portrait. ( I have a Samsung. When I go to the Camera it changes to landscape and when I finish it, it goes back to portrait. )
I've already done my homework and added these things to my manifest:
android:configChanges="orientation|keyboardHidden"
android:screenOrientation="portrait" >
I've made sure to "lock" my app in the portrait orientation but I still see my app change orientation and I believe this is why my activity gets re-created.
I was planning to add all kinds of checks but I believe this is not the right way to handle this situation, since it sometimes does not re-create the activity.
The check I am talking about is to use:
protected void onSaveInstanceState(Bundle outState) {
outState.putString("started", "1");
}
Anyway, can somebody help me out? I just want it to load the activity without it self-destructing on me.
PS: The VM doesn't have any problems. The VM loads the activity and finishes it without re-creating it.
PPS: Did extra testing, on my Samsung if I keep it on landscape-mode it will work. So it is definately the camera that is destroying my activity with it's orientation change.
I had the same issue, turns out you also need to listen for screen size changes in API level 13 or higher as explained here; https://stackoverflow.com/a/11483806
android:configChanges="orientation|screenSize"
For this to fix, I had to use following in my manifest file:
android:screenOrientation="portrait"
android:launchMode="singleTop"
android:configChanges="keyboardHidden|orientation|screenSize"
Try creating a fragment activity to handle displaying and updating the progress dialog
In the fragment activity make sure and set "setRetainInstance(true);" This will make sure it isn't destroyed when the main activity gets created/destroyed.
It's probably a good idea to put the entire image capture process inside this fragment, including the asynctask. Make sure you don't reference the parent activity's context from within the doInBackground() in the AsyncTask. If you do this and the orientation changes (i.e. the activity is destroyed) it will throw an error.
here's a rough example:
public class MyFragment extends FragmentActivity {
private ProgressBar mProgressBar;
private boolean mAsyncTaskActive = false;
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
setRetainInstance(true);
// grab reference to progress bar
mProgressBar = (ProgressBar) getActivity().findViewById(R.id.my_progress_bar);
// check to see if the async task is active and set the progress bar visibility accordingly
if (mAsyncTaskActive) {
mProgressBar.setVisibility(View.VISIBLE);
mProgressBarText.setVisibility(View.VISIBLE);
}
}
// this method is called from your main activity when the user does something (i.e. clicks a button)
// make sure you have already instantiated the fragment
public void startSomething() {
if (mAsyncTaskActive == false) {
mProgressBar.setVisibility(View.VISIBLE);
new MyAsyncTask().execute();
mAsyncTaskActive = true;
}
}
private class MyAsyncTask extends AsyncTask<Void, Void, Void> {
Context applicationContext;
#Override
protected Void doInBackground(String... params) {
// do stuff
publishProgress(//some number);
return null;
}
#Override
protected void onProgressUpdate(Integer... progress) {
setProgressPercent(progress[0]);
}
}
You should also take a look at how to implement fragments if you're not already familiar. The Android dev blog has a good post on DialogFragments, same priniciples. http://android-developers.blogspot.com/2012/05/using-dialogfragments.html
I have a simple activity that loads a bitmap in onCreate. I find that if I rotate the device I can see from the logs that onCreate called again. In fact, because all instance variables are set to default values again I know that the entire Activity has been re-instantiated.
After rotating 2 times I get an FC because not enough memory can be allocated for the bitmap. (Are all instances of the activty still alive somewhere? Or does the GC not clean up fast enough?)
#Override
public void onCreate(Bundle savedInstanceState) {
File externalStorageDir = Environment.getExternalStorageDirectory();
File picturesDir = new File(externalStorageDir, "DCIM/Camera");
File[] files = picturesDir.listFiles(new FilenameFilter(){
public boolean accept(File dir, String name) {
return name.toLowerCase().endsWith(".jpg");
}});
if (files.length > 0) {
Bitmap bm = BitmapFactory.decodeStream(new FileInputStream(files[0]));
ImageView view = (ImageView) findViewById(R.id.photo);
view.setImageBitmap(bm);
}
}
From all that I read, onCreate should be called once during the lifetime of an application. Am I wrong about this? How can re-orienting the device cause the activity to be recreated?
android:configChanges="keyboardHidden|orientation|screenSize"
Caution: Beginning with Android 3.2 (API level 13), the "screen size"
also changes when the device switches between portrait and landscape
orientation. Thus, if you want to prevent runtime restarts due to
orientation change when developing for API level 13 or higher (as
declared by the minSdkVersion and targetSdkVersion attributes), you
must include the "screenSize" value in addition to the "orientation"
value. That is, you must decalare
android:configChanges="orientation|screenSize". However, if your
application targets API level 12 or lower, then your activity always
handles this configuration change itself (this configuration change
does not restart your activity, even when running on an Android 3.2 or
higher device).
From docs: http://developer.android.com/guide/topics/resources/runtime-changes.html
What happen when orientation changed
Life Cycle of orientation
onPause();
onSaveInstanceState();
onStop();
onDestroy();
onCreate();
onStart();
onResume();
---- app recreated and now is running ---
If you do long operation in onCreate() and want prevent re-create your activity add configChanges attribute in your mainfest
<activity android:name=".MyActivity"
android:configChanges="orientation|keyboardHidden|screenSize"
android:label="#string/app_name">
screenSize if you targeting api >= 13
Activity is recreated after each rotation by default. You can override this behaviour with configChanges attribute of the activity tag in AndroidManifest. For further details and different options, see http://developer.android.com/guide/topics/resources/runtime-changes.html
Actvity Lifecycle when you rotate screen
onPause
onSaveInstanceState
onStop
onDestroy
onCreate
onStart
onRestoreInstanceState
onResume
If you want to prevent FC from not enough memory, you need to deallocate resources in onStop() or onPause(). this allows you to use fresh memory in onCreate().
This is an alternate solution to preventing the recreation of the activity by using
android:configChanges="keyboardHidden|orientation"
As sometimes your activity's layout is different in portrait and landscape (layout, layout-land).
preventing recreate on orientation change will prevent your activity from using the other orientation's layout.
Yes, activity's onCreate() is called everytime when the orientation changes but you can avoid the re-creation of Activity by adding configChanges attribute of Activity in your AndroidManifest file in the activity tag.
android:configChanges="keyboardHidden|orientation"
On Create method will call everytime when you do orientation, to avoid this you have to use
//Define Below in you Manifest file.
<activity
android:name="com.ecordia.activities.evidence.MediaAttachmentView"
android:configChanges="keyboardHidden|orientation|screenSize"
</activity>
//Define Below in your activity.
#Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT) {
//your code
} else if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) {
//your code
}
}
It will works like a charm!!
Manifest XML activity Tag:
android:configChanges="keyboardHidden|orientation"
#Override
public void onConfigurationChanged(Configuration newConfig) {
// TODO Auto-generated method stub
super.onConfigurationChanged(newConfig);
}
Use the above code to perform changes related to orientation in your Activity Java Code
Cheers!!!
One of the most common and suggested “solutions” to dealing with orientation changes is to not deal with them. You can do this by setting the android:configChanges flag on your Activity in AndroidManifest.xml as shown below:
<activity
android:name=".MyActivity"
android:label="#string/title_my_activity"
android:configChanges="orientation|screenSize|keyboardHidden" />
This is NOT the correct way to deal with orientation changes.
CORRECT way is to implement the onSaveInstanceState method (this could be in your Activity, Fragment or both) and place the values you need to save in the Bundle argument that gets passed to the method.
It is nicely described here: http://code.hootsuite.com/orientation-changes-on-android/
While it may seem a bit tedious to implement, handling orientation changes properly provides you with several benefits: you will be able to easily use alternate layouts in portrait and landscape orientations, and you will be able to handle many exceptional states such as low memory situations and interruptions from incoming phone calls without any extra code.
While the Manifest way may work, there is a better and proper solution for these types of problems. The ViewModel class. You should have a look here: https://developer.android.com/topic/libraries/architecture/viewmodel
Basically, you extend the ViewModel class and define all the data members in it which we want to be unchanged over re creation of the activity (in this case orientation change). And provide relevant methods to access those from the Activity class. So when the Activity is re created, the ViewModel object is still there, and so are our data!
Kindly see my way of doing it:-
http://animeshrivastava.blogspot.in/2017/08/activity-lifecycle-oncreate-beating_3.html
snippet is:-
#Override
protected void onSaveInstanceState(Bundle b) {
super.onSaveInstanceState(b);
String str="Screen Change="+String.valueOf(screenChange)+"....";
Toast.makeText(ctx,str+"You are changing orientation...",Toast.LENGTH_SHORT).show();
screenChange=true;
}
#Override
public void onCreate(Bundle b) {
super.onCreate(b);
ctx=getApplicationContext();
if(!screenChange) {
String str="Screen Change="+String.valueOf(screenChange);
// ...
}
}
I had the same problem, in which my onCreate is called multiple times when the screen orientation is changed. My problem got solved when i add android:configChanges="orientation|keyboardHidden|screenSize" in the activity tag in manifest
I had the same problem and I did some workaround
Define didLoad boolean variable with false value
private boolean didLoad = false;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity);
if (!this.didLoad){
// Your code...
this.didLoad = true;
}
I have a gestureOverlayView in my layout which I am using for drawing digital Signature. The problem arises when I draw in a certain orientation (say landscape) and then change the orientation - the overlayView just clears. I have tried including onConfigurationChanged();but no effect. I have also attempted the following with onSaveInstance and onRestoreInstance, but it gives me no solution:
#Override
protected void onSaveInstanceState(Bundle outState) {
Gesture gesture = overlay.getGesture();
outState.putParcelable("gesture", (Parcelable) gesture);
super.onSaveInstanceState(outState);
}
#Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
Gesture gesture = (Gesture) savedInstanceState.getParcelable("gesture");
overlay.setGesture(gesture);
mDoneButton.setEnabled(true);
super.onRestoreInstanceState(savedInstanceState);
}
I have also tried including:
android:configChanges="fontScale|uiMode|screenLayout|navigation|touchscreen|mcc|mnc|orientation|keyboardHidden|keyboard">
But even this is of no use.
Does anyone have a solution for this problem?
I tried your code in my application and had the same issue. The result of getGesture() is null within onSaveInstanceState, onStop, and onPause, so I'm guessing that the GestureOverlayView is invalidated somewhere between the screen rotation and the calling of those methods.
A workaround is to override onGesturePerformed, assuming your Activity implements OnGesturePerformedListener and you call addOnGesturePerformedListener(this) on your overlay, and save a member instance of the most recent Gesture. Something like:
#Override
public void onGesturePerformed(GestureOverlayView overlay, Gesture gesture) {
mCurrentGesture = gesture;
}
Then in your onSaveInstanceState, simply get and package the member instance instead of calling getGesture(). Now setGesture() should work as expected when the Activity recreates itself.
Use android:configChanges="fontScale|uiMode|screenLayout|navigation|touchscreen|mcc in manifest or try onSavedInstance;
When the orientation changes it restarts the activity. You could try restrict the orientation of the app in the manifest file.
android:screenOrientation="portrait"
I need to handle orientation changes in my Android application. For this purpose I decided to use OrientationEventListener convenience class. But his callback method is given somewhat strange behavior.
My application starts in the portrait mode and then eventually switches to the lanscape one. I have some custom code executing in the callback onOrientationChanged method that provides some additional UI handling logic - it has a few calls to findViewById.
What is strange is that when switching back from landscape to portrait mode onOrientationChanged callback is called twice, and what's even worse - the second call is dealing with bad Context - findViewById method starts returning null. These calls are made right from the MainThread
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
listener = new OrientationListener();
}
#Override
protected void onResume() {
super.onResume();
// enabling listening
listener.enable();
}
#Override
protected void onPause() {
super.onPause();
// disabling listening
listener.disable();
}
I've replicated the same behavior with a dummy Activity without any logic except for one that deals with orientation hadling.
I initiate orientation switch from the Android 2.2 emulator by pressing Ctrl+F11
What could be wrong?
Upd:
Inner class that implements OrientationEventListener
private class OrientationListener extends OrientationEventListener {
public OrientationL() {
super(getBaseContext());
}
#Override
public void onOrientationChanged(int orientation) {
toString();
}
}
}
This is a documented bug in the emulator ONLY. A real device will not exhibit this double-lifecycle-events behavior. I had the same issue a while ago and it disappears on a real device.
I would suggest ignoring the problem if you can by only testing orientation changes in one direction until you get your hands on a physical phone. Otherwise you might be able to "skip" the second set of lifecycle calls by keeping a static boolean around indicating you've already gone through the first set.
See this issue report for more info.
Have you tried using onConfigurationChanged?
#Override
public void onConfigurationChanged(Configuration newConfig) {
if(newConfig.equals(Configuration.ORIENTATION_LANDSCAPE)…
Add android:configChanges="orientation" in manifest file in activity tag like
<activity android:label="#string/app_name"
android:configChanges="orientation"
android:name=".com.androidpeople">