Monday, March 28, 2011

How to handle Screen Orientation changes in Android - Part - 2

Adapting the GUI when screen orientation changes is extremely important for a good user experience experience.  We saw in my previous post, how Android framework does an excellent job at adapting the GUI when screen orientation changes.

Android *destroys* the current activity and *re-creates* the same activity all over again.  

We also saw that in certain situations this architectural choice could lead to bad user experience.

For example

In the above example think about the user experience when, he/she changes the screen orientation while viewing SomeActivity
  • User has waited 5 seconds for the activity to load completely
  • He/She changes the screen orientation
  • Current activity is destroyed
  • New activity is re-created
  • User has to wait for 5 more seconds for the activity to be loaded completely with the new screen orientation.
While the default behavior of destroying and recreating the activity is powerful, its sometimes confusing for new Android developers, who wonder why their activity is destroyed and recreated.

Moreover, if we do not handle this correctly, user experience goes for a toss.  He has to wait 5 extra seconds for no apparent reason.

Because of this, some developers decide to handle the configuration changes (like screen orientation changes) themselves.  This is done by adding the "configChanges" attribute to the Activity declaration in AndroidManifest.xml

The "configChanges" attribute tells Android Platform that, some of the config changes will be handled by the activity by themselves. Platform does not need to do any special handling for these.

The above code tells Android platform that Screen orientation changes will be handled by the activity on its own. In this case Android platform will not destroy the current activity and re-create it.

In general, this is a short-term solution that will only complicate developers lives later.

The Android Platforms automatic resource handling is a very efficient and easy way to adapt an application's user interface to various devices and devices configurations. Hence, its *not advisable* to use the above config value for handling screen orientation!

So what is the alternate?

How do they do it?

Android platform provides two elegant ways to handle this situation.  Lets look at them

Method #1:

The Activity class has a special method called onRetainNonConfigurationInstance()

This method can be used to pass any arbitrary object to your *future self*.  

What does that sentence mean?  

As the name suggests, we can retain an instance of a non configuration object using this method.  The return type of onRetainNonConfigurationInstance method is Object.  The value that you return from this method gets passed to the new activity instance that will be created because of the screen orientation change.

Android Platform is smart enough to call this method only when needed.  For example, in our case we would return an instance of SomeExpensiveObject class that was created earlier.  This way the new instance of SomeActivity will have access to an instance of SomeExpensiveObject automatically and it does not need to create the instance again.

Code is better than 1000 words, lets look at how this is done.

Question arises, how do we get hold of SomeExpensiveObject instance in onCreate method of the new instance of SomeActivity?

To get access to the instance of non configuration object that we saved earlier, we have to invoke the  getLastNonConfigurationInstance() method.  In our example, to get the instance of SomeExpensiveObject class which we retained earlier, we have to invoke the getLastNonConfigurationInstance method. Lets look at how the updated code would look like.

Have a look at the updated code. We first try to get the instance of SomeExpensiveObject using the getLastNonConfigurationInstance() method. If that instance is null then only we create a new instance of SomeExpensiveObject class.


Think of the user experience when, he/she changes the screen orientation while viewing the SomeActivity with updated code.
  • User has waited 5 seconds for the activity to load
  • He/She changes the screen orientation
  • Android platform calls onRetainNonConfigurationInstance()
  • Current activity is destroyed
  • New activity is recreated
  • We try to get the instance of SomeExpensiveObject using the getLastNonConfigurationInstance()
  • Since we will find the instance of SomeExpensiveObject we do not create another instance and hence user does not need to wait for 5 more seconds!
  • End result, user is happy.  Everyone loves to have happy users!


Disclaimer: 

Be very careful with the object you pass through onRetainNonConfigurationChange(), though. 

If the object you pass is for some reason tied to the Activity or Context, you will leak all the views and resources of the activity. This means you should never pass a View, a Drawable, an Adapter, etc.  Finally, remember that onRetainNonConfigurationChange() should be used only to retain data that is expensive to load. Otherwise, keep it simple and let Android do everything.

Method #2:

Android provides another elegant way of achieving this.  To achieve this, we have to override a method called onSaveInstanceState().  Android platform allows the users to save any instance state.  Instance state can be saved in the Bundle.  Bundle is passed as argument to the onSaveInstanceState method.

Android calls onSaveInstanceState before pausing/destroying the activity.

This method is called before an activity may be killed so that when it comes back some time in the future it can restore its state.  This gives us an opportunity to save any instance state we want in the Bundle.

In our case we are putting the SomeExpensiveObject instance in the Bundle.  For this to work we have to mark SomeExpensiveObject as Serializable.  We can also put primitives in the Bundle.

When Android recreates the activity we can get back the saved instance state as follows

As we can see, we can load the saved instance state from the Bundle passed as argument to the onCreate method. We can also load the saved instance state in "onRestoreInstanceState" method. But I will leave that for the readers to figure out.

We are now creating the instance of SomeExpensiveObject only if we are not able to get the instance from the saved state.

Think of the user experience when, he/she changes the screen orientation while viewing the SomeActivity with updated code.
  • User has waited 5 seconds for the activity to load
  • He/She changes the screen orientation
  • Android platform calls onSaveInstanceState()
  • Current activity is destroyed
  • New activity is recreated
  • We try to get the instance of SomeExpensiveObject using the Bundle argument passed to the onCreate method
  • Since we will find the instance of SomeExpensiveObject, we do not create another instance and hence user does not need to wait for 5 more seconds!
  • End result.  Users are happy!
Both these methods are the recommended ways of saving the instance state and getting it back.  Which one to use, is a choice left to the developers to decide.

Android is really a very powerful mobile development platform, but as Spider-Man's uncle Ben once said

With great power comes great responsibilities!

Use the Android platform in the correct way and you will enjoy your time with it!

Saturday, March 26, 2011

How to handle Screen Orientation changes in Android - Part - 1

In one of my Android projects, we had a requirement that, when user changes the orientation of his phone from portrait to landscape or visa-a-versa, the GUI should adapt itself and render appropriately.

Android, is an awesome mobile development platform.  I have worked on iOS, Brew, Symbian and Android platforms but I can tell you one thing, the kind of productivity you get while developing apps for Android platform is higher than any other mobile platform.

Android does a lot of things automatically for you.  One of them is screen orientation change.  Android platform detects that the screen orientation has changed and adapts the GUI accordingly.  How does Android platform achieve this?

What happens when Android detects that the screen orientation has changed?

Android *destroys* the current activity and *recreates* the same activity all over again.  

Yes, you read it right!  And I will say it again, 

It *destroys* the current activity and *recreates* the same activity all over again.

Why does it do that?

Normally, in the portrait mode the screen has more hight than the width.  In landscape mode the scene is reversed.  The screen has more width than the height.  This means that if we go by the default behavior, user might see lot of blank spaces on the right side in the landscape mode.

Screen in Portrait mode
Screen in landscape mode

Have a look at the images of an activity in Portrait and Landscape mode.  In Portrait mode the screen looks decent, but in landscape mode the screen looks ugly. There is too much gap between the logo image on the left corner and "some screen" button on the right hand corner.  Moreover, the text box with the hint "Enter Zip or City, State" looks is way to long in the landscape mode.

Android has provided us a way to get around this problem.  We as developers can provide different layouts for landscape and portrait modes.

The layouts that should be used for landscape mode should be placed in a directory called layout-land


Landscape layout XML

Lets say we updated the layout for the landscape mode so that the icon, button, text box and the Search button appear all in one line.  The updated screen would look like

Updated screen in landscape layout
As you can see in the updated screenshot, the layout in the landscape mode looks much better now.  

Using different layouts for landscape and portrait mode enables us to effectively use the space.

Because of this reason, when screen orientation changes, Android destroys the current activity and recreates the activity all over again by choosing the correct layouts and configuration.  

This behavior lets you declare resources like layout's and drawable's based on the orientation, screen size, locale, etc.

This architectural choice, helps Android adapt the GUI easily and effectively when screen orientation changes. 

Think over this approach for a moment, do you think there are any problems with this approach?

What are the problems with this approach?
What if your activity performs some expensive operation when activity is created?
For example

As show in the above code when SomeActivity is created we creating an instance of SomeExpensiveObject class.  To indicate that creating the instance of this class is expensive, I have added a sleep of 5 seconds in the constructor of SomeExpensiveObject class.

Think about the user experience, when user changes screen orientation while viewing SomeActivity.
  • User has waited 5 seconds for the activity to load completely
  • He/She changes the screen orientation
  • Current activity is destroyed
  • New activity is re-created
  • User has to wait for 5 more seconds for the activity to be loaded completely with the new screen orientation.
How do we solve this problem?

In the next post I will show how effectively we can handle this problem.  Android provides not just one but two elegant solutions to the above problem.  All that and more in the next post.  Stay tuned! 

Monday, March 21, 2011

Telerik Controls - A perfect example of how not to do things!

As you might have known already from my previous post, in one of my projects we use Telerik Controls extensively for showing various GUI controls.

I personally *hate* using Telerik controls.  Lot of people have asked me, why I hate them, hence for the benefit of the community, I have decided to document the reasons of my hatred for Telerik controls.

Telerik has provided a lot of controls that could be used in variety of situations.  They have provided lots of demos for various controls that they provide.  Looking at just the demo, anyone will be impressed with these controls and would want to give them a shot.  But, once you start using them, you will realize how badly they have been architected.

Oh! by the way, tell me one thing.

What are demo websites meant for?

I would say, to showcase the power of the product/tool.  Demo websites make the first impression about any product/tool.  Its extremely important to get this right.  But, for me, Telerik has failed in making a solid impression.

The Telerik controls demo website does not working in Firefox 64 bit!  

My hatred starts here.  More and more machines are getting 64 bit OS pre-installed on them.  Companies and People are moving towards 64 bit platform.  If entire Telerik demo website not working on Firefox 64 bit, its a shame if not anything else.

I am going to bitch about some of the basic Telerik controls, because I believe, if you can't get the basics right, you cant get it right at all!


Lets talk about the most basic Telerik control, the RadTextBox.  You might feel, surely there is nothing wrong with the text box right!  But unfortunately, Telerik has got the most basic control wrong.

The asp.net code to use the RadTextBox in your page looks like

Nothing fancy here right? Yes, I would agree. The asp.net code does not look too bad. Lets look at the generated HTML for a moment.

What? Where did the "span" and two extra "input" tags come from?

Yep, believe it or not. One RadTextBox gets rendered as a span and three input tags!

Why would any one decide to render one Text box as using three input tags!

Whats the problem with rendering one TextBox as three input tags?

Well, none of your traditional JavaScript would work!

For e.g. lets say, you were using jQuery for your JavaScript manipulation (BTW, jQuery is an excellent JavaScript framework.  I recommend it for every web based project!  Great work guys!), the code to update the value of the text field to "Hello World" should look like

But unfortunately, the above code does not work. Since Telerik uses 3 input tags to render one text box the above JavaScript code does not set the value of the text field!

Instead, Telerik provides JavaScript wrappers for their controls.  In this case to update the value of the first name text box we have to use the following JavaScript.

Update: $find function is part of the Telerik JavaScript.  $find is part of the "MicrosoftAjax.js".  Thanks bugventure for pointing me to the right direction.

This effectively means none of the awesome jQuery api can be used with any of the Telerik Controls.

Yes, you read it right.  I will say it again, JQuery api would not work as expected with Telerik Controls. 

Imagine, how you will show/hide, enable/disable the text box. What about adding/removing a class from the text box. These are just a few examples of what you will not be able to do using jQuery because of Telerik controls.  Believe me, without jQuery, JavaScript manipulation is going to be tough!

Now you understand my frustration?

Lets look at one more control and I promise we will be done after that.

RadComboBox:

This one is my favorite control, I just love bitching about this control.  I am amazed at how badly they have messed this up.

The asp.net code to use the RadComboBox in your asp.net page would look like

The above RadComboBox is suppose to show users a list of countries. Notice that, we have not attached any special behavior to it.

Before looking at the generated HTML, do you want to take a guess at how should it look like?

10 Bucks if you get this right!

But, I can guarantee that,  the generated html looks nothing like you would have thought

Usually for us "the mortal developers", Combo Box is rendered via the "select" tag.  We use CSS to style it.

But, Telerik had different plans for the Combo Box.  May be, Telerik thought,

"Oh! that is too simple, lets make peoples lives complicated". 

Telerik uses a complex tree of "div's, ul, li, table, tr, td, a, input and an hidden input", for something that could have been easily achieved using a simple "select" tag, some JavaScript and some CSS!


Telerik, did you forget the KISS principle?

I am simply speechless!  What can I say, its a disaster.  Needless to say that, the traditional JavaScript does not work with Telerik RadComboBox.

This is just developer side of the problem.
  • What about automated functional tests?  
  • What about the QA's who take so much effort to write functional tests using selenium and other tools?
Tools like selenium rely heavily on use of traditional JavaScript, because of this functional tests written using these tools do not work well with Telerik Control.

For e.g. looking at the html generated for a simple combo box, imagine what will the code look like to select a country from the drop down.  Its just terrible.

One last thing and I will stop.

Lets say, if you wanted to do something when client side onblur event occurs for a RadTextBox and RadComboBox.  This is how you will have to do it.

The above code shows how we attached an client side onblur event with RadTextBox. Lets see how we have to attach the client side onblur event for the RadComboBox

Did you notice the inconsistency between two Telerik controls themselves?

I can only say, surely there are better ways of doing things!


Telerik, if you are reading this, you better pull up your socks and start doing some major rearchitecting!

I think that is enough bitching for a post.

Ah, almost forgot, if you are still interested in using Telerik Controls in your project, you need to pay for it, They are not free!

Wednesday, March 9, 2011

31 reasons to hate IE. Styles not loading up?

Recently, I have been facing quite a few issues with IE.  And believe me all of them are really weird.  My hatred for IE is at all time high :)

I mentioned about a bug in IE8’s Lookahead Downloader in one of my previous post.  This post is dedicated to another such bug in IE.

What was the issue we were facing?

The problem we were facing was weird.  A page would render correctly on all browsers except IE (of course :)).

Yea, I know, nothing new about such behavior right?  But this issue is special in many ways.  Why?

Because:

I have decided to stay away from Telerik controls as much as possible.  If you asked me, I would only suggest to never ever, never ever, never ever, use them in your project.  The more I use them, more I get convinced not to use them ever.  

Why I hate Telerik controls so much?  

May be I will write that in a separate post.  

Why are we using it in our project?  

Client is not yet ready to move on.  

Anyways, Let me stop bitching about Telerik controls and focus on the issue we were facing.

The frameworks that we were using, assure that the site renders correctly on most modern browsers including IE.  Then why would it not render correctly on IE?

What were the rendering issues we were facing?

List box does not have proper styles
Alert box does not have proper style
Menu bar is unaligned and does not have proper styles

Look at the things highlighted in red in the above screenshot.

The issues we were facing were:
  • Sometimes List Box would lose its styles
  • Sometimes Alert box would lose its styles
  • Sometimes Tab Strip would lose its styles

Initially, I was really confused, didn't know what exactly was going on.  

Decided to intercept the HTTP traffic using Fiddler, to find out what is wrong with IE.  Why is it not sending requests for certain styles?

Found out that, IE does send requests for all style sheets.  But, IE just prefers to ignore a few style sheets (of course without showing any error)!  Typical IE, isn't it?

Googling a little we found that:
  • IE will load only the first 31 style sheets and will ignore the rest of the styles for a page request. This includes the <style> attribute tag as well if defined on the page
  • IE load only 4095 CSS selectors for a single request
  • On pages that uses the @import rule to continuously import external style sheets that import other style sheets, style sheets that are more than three levels deep are ignored.

Have a look at this link for more details.

That was it, we discovered another hidden treasure of IE!  Don’t we love IE for such hidden treasures?

The solution was simple enough, we removed few unused CSS references from the page.  Bingo, the page started working!

PS:  Why where unused CSS referred on the page?  Long story.  We will keep that for some other post.  Till then keep having fun with IE.

Have some Fun!