banner



How Has The Apparent Orientation Of The E Changed

Handling Orientation Changes on Android

Handling orientation changes on Android is one of the most frustrating things to deal with as an Android engineer. I promise to make that challenge just a little bit easier and to help you better understand exactly what's happening when you rotate your Android device. I'one thousand going to cover what not to exercise when handling orientation changes, and what you should do in some common scenarios including dealing with Fragments, AsyncTasks and ListViews.

Android Orientation Changes

Groundwork

When you rotate your device and the screen changes orientation, Android usually destroys your awarding'south existing Activities and Fragments and recreates them. Android does this so that your application can reload resources based on the new configuration. When it destroys your Activities and Fragments information technology will end up creating new instances of them which volition wipe out all of your member variables. To work around this, Android gives you the opportunity to save your app'due south state before destroying your Activities and Fragments, and the opportunity to restore your state when recreating them. Proper treatment of orientation changes centers around saving this state and also avoiding memory leaks.

While it may seem a fleck slow to implement, handling orientation changes properly provides you with several benefits: you volition be able to easily use alternate layouts in portrait and landscape orientations, and you will be able to handle many infrequent states such as low memory situations and interruptions from incoming phone calls without whatsoever extra code.

What Non To Do

android:configChanges

One of the nigh common "solutions" to dealing with orientation changes is to not bargain with them. You lot tin do this by setting the android:configChanges flag on your Activity in AndroidManifest.xml as shown beneath:

This flag signals to the Android platform that you are going to manually handle orientation, screenSize and keyboard advent/disappearance changes for this Activity. So instead of destroying and recreating your Activity, Android will just rotate the screen and call one of the lifecycle methods: onConfigurationChanged. If you have a Fragment attached to this Activeness, information technology will besides receive a telephone call to its onConfigurationChanged method. This means that the same instances of your Activities and Fragments will be in use and your member variables volition remain untouched. If you do want something to be unlike when the orientation changes, such as using a new layout, you would accept to implement onConfigurationChanged and manually discard the quondam layout/View, inflate the new layout and display it — which is a lot more work and can brand your lawmaking difficult to work with in the futurity.

Android - configChanges - With the Flag - Portrait

[explanation id="attachment_3243" align="aligncenter" width="500"]

Android - configChanges - With the Flag - Landscape

With the configChanges flag the same layout will be used in landscape and portrait unless you manually change it[/caption]

Android - configChanges - Without the Flag - Portrait

[explanation id="attachment_3245" align="aligncenter" width="500"]

Android - configChanges - Without the Flag - Landscape

Without the configChanges flag you can utilize unlike layouts in landscape and portrait[/caption]

Fragment.setRetainInstance(true)

Calling setRetainInstance(true) on a Fragment is like to setting the android:configChanges flag on an Activity. It signals to Android that you want to continue using the same example of the electric current Fragment, so all of your member variables will remain untouched. If y'all rotate your device when you take an Activity that is Not using the configChanges flag and a Fragment that IS being retained, the following lifecycle methods will exist called on the Fragment:

          onPause
onSaveInstanceState
onStop
onDestroyView
onDetach
onAttach
onCreateView
onActivityCreated
onStart
onResume

Detect that Android does not phone call onCreate and onDestroy because we retained the Fragment; nor does it phone call the constructor, because the same Fragment instance will be used afterwards the orientation alter. Android volition call all of the other callbacks considering the Fragment's parent Activeness IS being destroyed and recreated, so the Fragment does take to go through the process of existence detached then reattached. Alternatively, if your Activity HAS the configChanges flag set up and your Fragment IS retained, all that volition happen is the screen volition rotate and both your Activity and Fragment volition receive calls to their corresponding onConfigurationChanged methods. Calling setRetainInstance(true) on a Fragment is generally a bad thought for the aforementioned reasons as using the configChanges flag on an Action is a bad thought: yous won't be able to reload resources that may need to be refreshed. There is 1 state of affairs in which retaining a Fragment is a skilful idea and we'll explore that in more than detail in the Handling AsyncTasks department.

android:screenOrientation

Finally, another "solution" to the orientation change problem is to ready the android:screenOrientation flag on your activity:

This altogether prevents orientation changes from happening while the user is in the Action with the flag set. And so if yous rotate your device the screen won't rotate with it. While there are certainly situations in which this is the desired behavior, you should, if possible, allow your app to be used in both mural and portrait orientations considering information technology greatly increases your app'southward usability.

Saving Land

The most of import aspect of handling orientation changes is saving state. In almost cases this involves implementing the onSaveInstanceState method (this could be in your Action, Fragment or both) and placing the values yous need to salvage in the Bundle argument that gets passed to the method.

Most of the time you don't have to worry about saving the land of your Views because Android automatically calls the View.onSaveInstanceState method on each of the views in your view hierarchy as long as you phone call through to the super method in onSaveInstanceState. This also ways that if y'all use whatever custom Views, they should contain an implementation of onSaveInstanceState. Practise note, that in order for a View's state to be saved information technology MUST have an android:id attribute considering this is essentially used as the central for that particular View's land.

One matter to watch out for is a ListView. The super method of onSaveInstanceState will take intendance of saving sure things such every bit scroll position, but it is up to you to save the contents of the adapter in your onSaveInstanceState method. If you are using an ArrayList of a model object to populate your ListView, then i option is to ensure your model object implements Serializable and in onSaveInstanceState, place it in the Bundle through putSerializable. 1 thing to go on in mind: fifty-fifty though it is good do to "code to interface" and declare your ArrayList as a List (List items = new ArrayList<>()), in this detail case, you will have to declare it every bit an ArrayList (ArrayList items = new ArrayList<>()) because the compiler needs to know that your Listing implements Serializable (which List itself does not, but ArrayList does) in order to pass it to Package.putSerializable(String, Serializable).

onSaveInstanceState gets chosen before onStop but it is not guaranteed to be called earlier or later on onPause. Android will besides only call it when your application needs to salvage temporary state which includes when orientation changes occur and when your Activeness is killed for its memory resources. Information technology will non exist called in certain situations such as finishing an Activity commonly or putting an Activeness into the background.

Restoring State

The mode you restore state can vary betwixt different Activities and between Activities and Fragments. In a typical Activity, you would check the savedInstanceState argument that gets passed to your onCreate method. If savedInstanceState != nothing, you would retrieve your state from that Bundle.

Some other selection in an Activity is to implement onRestoreInstanceState which also gets passed a savedInstanceState Bundle. The simply reason to have this approach is if y'all desire to expect for all of your onCreate initialization to be washed before restoring state or if you want to let subclasses to specifically handle restoring state. If y'all choose to implement onRestoreInstanceState, yous must call through to the super method if you want your View states restored. Once again, if you utilise any custom Views, they should implement their ain onRestoreInstanceState. An Activity's onRestoreInstanceState is called after onStart and before onResume.

In a Fragment you tin restore state in several unlike callbacks (these are listed in the order they get called): onCreate, onCreateView, onActivityCreated, or onViewStateRestored. Where yous cull to bank check your savedInstanceState Package depends entirely on what you need to have happened earlier restoring your state. If y'all need to brand sure your parent Action'south view hierarchy has been created, y'all should restore state in onActivityCreated. If y'all need to make sure your own Fragment's view hierarchy has been created and had its state restored, you lot should restore state in onViewStateRestored.

ListViews once more pose an extra requirement for restoring state. If you want your ringlet position to exist saved and restored properly, yous must call up your saved ArrayList of model objects, create an adapter and assign it to the ListView earlier it gets its state restored (i.e. you take to do it in onCreateView or onActivityCreated).

Android - Recreating a ListView - Portrait

Android - Recreating a ListView - Landscape

See beneath for examples of how and where yous can restore state in a Fragment:

In the example higher up, nosotros restored state in two different places. That was only for the purposes of the example. In reality, information technology is much better to only restore state in 1 place.

Adding Fragments

Ane of the mutual pitfalls of handling orientation changes with Fragments is accidentally re-instantiating and re-adding them every time the Action is recreated. If you allow Android to handle orientation changes, it will take intendance of re-instantiating your fragments, re-adding them to the activity, and recreating the fragment backstack, when it recreates the parent Activeness. Therefore, you should only instantiate or add a fragment to an Activity if the savedInstanceState bundle passed to your Activity callbacks is null.

If you need to obtain a reference to the Fragment you tin can practice so through the FragmentManager using a tag. This means that when you add the Fragment to the Activity you take to provide a tag argument. When y'all need a reference to your Fragment you lot can call FragmentManager.findFragmentByTag(Cord) and pass in the tag you used when adding the Fragment. The FragmentManager will have care of everything related to re-instantiating and re-adding the Fragment and it will make sure to render the right case of the Fragment from findFragmentByTag. Run across below for an case of how to implement this:

Handling AsyncTasks

Starting an AsyncTask tin can pose bug if your Activities and Fragments are randomly getting recreated, so you lot will have to pay special attending to how you lot handle them. At that place are a few dangerous things that could happen with improperly handled AsyncTasks: memory leaks and crashes.

Memory Leaks

Memory leaks can occur if your AsyncTask holds on to a reference to an Activity or a Fragment. When Android destroys your Activity or Fragment because of an orientation change (or any other configuration change), it will not destroy whatever AsyncTasks that you started. And so if an AsyncTask has a reference to a now-destroyed Activeness or Fragment, the garbage collector won't be able to collect that Activity or Fragment fifty-fifty though it should never be used again. You are especially susceptible to memory leaks if you have an AsyncTask declared as a non-static inner class of an Activity or Fragment considering that AsyncTask will implicitly concord a reference to its parent class (in this case the Action or Fragment) even though it appears equally though it doesn't have this reference.

IllegalArgumentExceptions

The other problem you can run into is an bodily crash. If, for example, you are displaying a ProgressDialog in the onPreExecute method of your AsyncTask and dismissing it (calling ProgressDialog.dismiss()) in the onPostExecute or onCancelled method a few things will happen.

Android - Task Running

If you rotate the device earlier the task is finished you'll immediately see a WindowLeaked exception printed out to the logs. This indicates that Android couldn't release the resources for that window (your ProgressDialog) because you are still referencing it in your AsyncTask. This exception won't actually crusade a crash. However, when the task eventually does consummate, and you call ProgressDialog.dismiss(), you will get an IllegalArgumentException: View…not attached to window manager. This is indicating that you are trying to dismiss a dialog that'southward non actually attached to annihilation and it will crusade a crash.

Android - Handling AsyncTasks

Cancelling AsyncTasks

One way to avoid this is to cancel AsyncTasks in your Activeness or Fragment's onDestroy method. Y'all tin too save the state of your task (if it'due south running or not) in the onSaveInstanceState method. When your Activeness or Fragment is recreated, you can utilise that to determine if you need to restart the chore.

Using a Retained Fragment

At present, it is not always an pick (or at least a expert option) to cancel and restart your AsyncTasks whenever an orientation change occurs. For example if you take a task that is downloading a file and it's almost done when suddenly the user rotates the device, it would be an extremely unpleasant user feel for the task to exist cancelled then restarted after that. This brings us back to something I mentioned earlier: calling setRetainInstance(true) on a Fragment. As I had described, setRetainInstance(true) tells Android to non destroy a Fragment when a configuration change happens. If you use a retained Fragment to host your AsyncTask, you can avoid ever having to restart your tasks. There are all the same a few things you should keep in mind though. Your retained Fragment should have no UI. Instead, you lot can declare an interface that your Activeness volition implement and that your Fragment will employ to tell the Activity to update the UI (or anything else). In onAttach, you should cast your Activity to that interface and save it in a listener member variable. In onDetach y'all must set that listener variable to cipher, and then yous don't leak an Action reference. In the AsyncTask callbacks (onPreExecute, onProgressUpdate, onPostExecute and onCancelled), you should make sure the listener isn't nothing then trigger the advisable callback on the listener and allow it handle the residuum. Here's an case of how to implement this:

So Where Does That Leave Us?

Hopefully, past this point, you are familiar with iv main ideas to help you with your orientation changes: saving state, restoring land, just adding/instantiating Fragments when you're not recreating an Action, and using retained Fragments to host AsyncTasks. Even though it may seem like a lot of extra piece of work at start, it will as well make the user'due south experience with your app much better.

Noah Tajwar

About the Author

Noah Tajwar is a Loftier School Co-op on the Android team, inbound Grade 12 at Riverside Secondary Schoolhouse. In his spare time, he enjoys writing Android/Java applications, playing soccer and playing piano.

Source: https://medium.com/hootsuite-engineering/handling-orientation-changes-on-android-41a6b62cb43f

Posted by: motteavelifire1986.blogspot.com

0 Response to "How Has The Apparent Orientation Of The E Changed"

Post a Comment

Iklan Atas Artikel

Iklan Tengah Artikel 1

Iklan Tengah Artikel 2

Iklan Bawah Artikel