Showing posts with label android. Show all posts
Showing posts with label android. Show all posts

Wednesday, February 27, 2019

How To Pass User Defined Properties To Android APK

We were looking around for ways to pass additional information to our Android app at run time. Main intent behind this was, to effectively test certain flow in the app - one such example would be the In-App Purchase flow.

One way of achieving this is by setting properties via ADB and reading their values from within the app via code. This post is about documenting the steps needed to achieve this.

There are two main parts to the solution
  • Setting the properties via ADB on the command line
  • Reading the property value from within the app via code and using its value to alter the app behaviour.

Without further ado, let's look at the actual code needed to achieve both parts.


The Solution

Setting the properties via ADB is pretty straightforward and we can easily do it with one line of code as follows


Here we are setting the property "log.tag.GITIAP" to value "DEBUG"

Reading the property value from within the app via code, needs a little bit of work. Here is the full code that will let you read the property "log.tag.GITIAP".


That should do it! When you call the method "PropertyHelper.initializeProperty()" it will set the value of "gitIAPValue" to the value that was passed via ADB.


Saturday, March 31, 2018

How to Debug A Pre-built APK

Android Studio 3.0 added a nifty little feature -- The ability to debug and profile pre-built APK's. For developers working with a mix of Native (C/C++) and Java code for their applications, this is an extremely valuable feature.

I stumbled upon it, while I was looking for something else. Wrote this post with the intent that more people will be able to find this feature and make good use of it!

Here are the steps needed to debug a pre-built apk:
  • On the launch screen of Android Studio 3.0+, select the option "Profile or debug APK"
 

  • It will open up a dialog which will let you choose the APK you want to debug.
  • Ensure that the APK is build with debugging enabled
  • Next, Android Studio will try and create a new project in this folder ~/ApkProjects
  • Once it finishes loading the APK it will open up a screen that looks like this
  • As you can see it has unpacked the APK. It shows various part of the APK along with their sizes.
  • It has not fully decompiled *.dex files into *.java files. It show them as *.smali files. 
  • When you open the *.smali file, it will give you an opportunity to Attack Java Sources
 
  • Clicking the link Attach Java Sources will open up a dialog which will let you select the folder where Java sources are located.
  • Once you do this, you should see the Java classes in their full glory. You can now attach breakpoints and debug through the APK as if it was real source code.
  • If your project contains native code, it will let you attach a library containing debug symbols for that too.
  • Hitting the Debug or Run icons on the IDE will popup a dialog which lets you select the Device on which you want to install the APK and start debugging.

  • On selecting the device, IDE will install APK on the device and attach the debugger.
  • You should see a screen like this on the device

  • In a second or so, you should see your app's first screen loaded and ready to be debugged!
  • That's about all that is needed, you can debug, step through the code, evaluate variables and what not!
As you can see its a valuable little feature which can help in locating the bug in tricky situations!

Friday, July 29, 2016

Monster Math - Journey to the Android launch!

Its been a thrilling roller coster ride for all of us at Makkajai.  I remember the days when we were building our first game Monster Math Classic on iOS,

  • We had no clue of how to develop a game?
  • How to market it?
  • How to get customers etc.  
All we knew was that, we had an idea and a lot of determination to execute it :D

In November 2014 we launched Monster Math Classic our first game on iOS.  Even though this was our very first game, we still managed to get lot of love from parents, teachers and students.  They had very kind words to say about our game.  Not just that, they also gave us some very awesome feedback, which could take user engagement to the next level.  We heard our customers and we incorporated their feedback which made them even more happier.

Somewhere in October 2015 we launched two new games Monster Math and Monster Math Multiplayer which got an even better acceptance than Monster Math Classic.  All these were still iOS only games.

One question which kept on coming from our customers was: When is it getting launched on Android!

It was not as if we didn't want to launch on Android.  We wanted to, but since our game was using Cocos2d (A game engine only for iOS), we couldn't do it just by a flip of a switch.

Somewhere in March 2016, we decided we need to launch our game on all major platforms, so that more and more kids can take advantage of our solution.  We started the effort on porting Monster Math solution to Cocos2dx.

When I first started to port, it felt like a never ending task.  We had around 50K+ line of Objective C code to be ported to C++.  Just the though of doing this humongous task -- that too all alone -- gave me nightmares :D.

There were many many problems to solve before we could could even compile an APK.  But as our dear friend Mark Watney (The Martian) says:

At some point, everything's gonna go south on you... everything's going to go south and you're going to say, this is it. This is how I end. Now you can either accept that, or you can get to work. That's all it is. You just begin. You do the math. You solve one problem... and you solve the next one... and then the next. And If you solve enough problems, you get to come home!

So thats exactly what we did, we started solving one problem at a time.  First problem was how can we quickly port Objective C code to C++ with minimal effort?

Instead of manually re-writing 50K+ line of Objective C code to C++, I wrote a quick and ugly Objective C to C++ translator.  It reads and parses any Objective C file and translates code into C++.  Simple right?  This translator does not generate compilable C++ code (because that would be difficult and time consuming).  It only get 90-95% of the job done!

This one step alone saved us few months of mundane work :D

  • After the initial translation was done, I manually fixed the compilation errors.  
  • Replaced Core Data/Realm with SQLite.
  • Added memory management code, since there is no ARC to cover us.
  • Replaced various SDK's with cross-platform equivalent.
  • Where a cross-platform equivalent SDK was not available, we used platform specific code to integrate native SDK's.
After solving innumerable such small problems, on July 14 2016 (after around 4 months of starting the project) we launched Monster Math on Android!

I am very grateful to have gotten this opportunity, I learned (and unlearned :P) so many things in such a short duration.  I am super excited (and proud at the same time) to have achieved this feat.

Finally, I hope Monster Math on Android gets even more love from its users.  Keep Calm and Have Fun!

Thursday, June 30, 2016

How to enable Immsersive Full Screen mode on Android with Cocos2dx

We are executing a project to port our flagship solution Monster Math 2 from Cocos2d to Cocos2dx.  This would enable us to release the solution on variety of different platforms including Android and Windows Mobile.

During the port, I came across one simple yet interesting problem -- Need to make the game UI truly full screen.

A lot of the Android devices have software navigation buttons at the bottom of their screens.

Android System Navigation Buttons
They seem to occupy part of the screen and block some part of the game UI.  Needless to say this does not give a great experience to the end users.  A better experience would be to hide these buttons.  But hey, if they are hidden then how do users navigate to the home screen or different apps?

Ideal experience would be to hide System navigation buttons at all times, but have some gesture to bring them back for a short duration when user needs them.

Android 4.4 (API Level 19) natively supports this functionality using the flag "SYSTEM_UI_FLAG_IMMERSIVE_STICKY".  This mode is called the immersive full screen mode.  When immersive full-screen mode is enabled, game continues to receive all touch events.  The user can reveal the system bars with an inward swipe along the region where the system bars normally appear.  System bars will automatically hide again after a few moments.  Perfect isn't it!

Usually setting this flag is enough to achieve the desired functionality, however in certain edges cases we need to do some additional work.  For example if you have a text field which accepts user input, once the on screen keyboard is dismissed the system navigation bars seem to stick around and do not hide until you kill the app and open it again.

In this post we are going to see how exactly to handle all situations so that the immersive full screen mode will always stick around for the app.

How Do They Do It!

What we need to do is basically setup SystemUiVisibilityChangeListener and FocusChangeListener and hide the system status bars in the callbacks.

Here is the sample code on how to do it.
That's it.  Once you run this Activity you should see that the game launches into immersive full-screen mode and remains in that mode!

Saturday, June 25, 2011

How to show turn by turn directions on Android

As you can probably make out, these days I am working on an Android project.  And I will tell you one thing, I am loving it!
I have worked on iOS, BREW and Simbian OS in the past but the productivity, while developing on Android is far better than the other platforms!

Excellent job Android guys!

Coming back to the post topic, recently I in one of the Android projects, we had a requirement that we wanted to show turn by turn directions between two geo points.

We are all familier with the excellent support for Turn by turn directions on the native Google Maps application.

Although, Android API permits us embed a maps view in the application, but it does not provide a way to show turn by turn directions between two geo points.

In early days of Android (SDK 1.0), Google had provided the DrivingDirections class.  Using this class it was possible to get the driving directions between two geo points.  However, since SDK 1.1, Google removed the DrivingDirections class from the API. 

Why would they remove something as useful as this?

Because it violated some of the legal agreements made by Google.  Extract from the Google Maps terms states that
8.3 Content License. Subject to these Terms (including but not limited to Section 9 (License Requirements) and Section 10 (License Restrictions)), Google gives you a personal, worldwide, royalty-free, non-transferable, non-assignable, and non-exclusive license to access, use, publicly perform and publicly display the Content in your Maps API Implementation, as the Content is provided in the Service, and in the manner permitted by the Terms. Specifically, you understand the following:


(a) Content (including but not limited to map data, traffic, directions, and places) is provided for planning purposes only. You may find that weather conditions, construction projects, closures, or other events may cause road conditions or directions to differ from the results depicted in the Content. You should exercise judgment in your use of the Content.
(b) Certain Content is provided under license from third parties, including Tele Atlas B.V. ("Tele Atlas"), and is subject to copyright and other intellectual property rights owned by or licensed to Tele Atlas and/or such third parties. You may be held liable for any unauthorized copying or disclosure of this content. Your use of Tele Atlas map data and certain other Content (including certain business listings Content) is subject to additional restrictions located in the Legal Notices page.

 In simple terms, Google has tied up with many Third party companies to get the mapping and other information.  The terms of the agreement do not allow them to expose those functionality in an open source project.  This is the reason why they removed the DrivingDirections API since SDK 1.1

All right fine!  Google could not expose that as API's, but we sill have this requirement to fulfill.  We want to show turn by turn directions between two geo points on Android platform.

How do we do it?

As we all know that the native Google Maps application (which comes pre-installed on all Android devices) does a great job of showing Turn by Turn driving directions.  The updated application also provides a link to Google Navigate (beta) which shows 3D maps and updates the route as the user location changes.

We should definitely try and make use of this feature for our requirement.  After all, why reinvent the wheel!

Hence now, our tasks are:
  • To invoke the native google maps application
  • Show turn by turn directions between two geo points on the native google maps application
One very big plus of the Android platform is that, it has multitasking support.  Because of this, when user clicks the back button on the phone, they will come back to our application, user does not feel they are navigating away from our application.  This enhances the user experience quite a lot!

So the questions is how do we invoke the native Google Maps application to show turn by turn direction between two geo points!

Inter process/activity communication on Android platform is done via an Intent.  Hence the answer to our question is: Via an Intent!

Yes and that's the correct answer!  But what Intent, what will be the URL, what should be the parameters?

Slow down, slow down, lets tackle one problem at a time!

This is how they do it!

Looking at this URL it seems that we can invoke the native maps application using the following URLs

One line description for the above url's is
Opens the Maps application to the given location or query. The Geo URI scheme (not fully supported) is currently under development.
The z field specifies the zoom level. A zoom level of 1 shows the whole Earth, centered at the given lat,lng. A zoom level of 2 shows a quarter of the Earth, and so on. The highest zoom level is 23. A larger zoom level will be clamped to 23.
Basically, the description says that, The above URLs will show the maps application which is centered around the given geo point

Hence,

This code will actuall open up the native map application which is centered around the given geo point. We have solved one task from our task list. We have managed to invoke the native google maps application!

But wait!  We want to show two points not just one point on the map.  We also want to show turn by turn directions between those points!

Using the URL i.e. the geo:x:y in the above format, we cannot specify two geo points.  Damn!

I tried many permutations & combinations to specify the second geo point, but nothing worked.

Finally, after a lot of trials and errors I found a workaround to this problem.

This is how its actually done!

The URL geo:x,y does not support the second geo point, hence we can't use that URL.  What is the other URL we could use, which will show turn by turn directions between two geo points?

After some more googling, I found that, we might be able to use the URL format used by  maps.google.com website.  The maps.google.com follows a simple url pattern

The maps.google.com uses two parameters "saddr" (source address) and "daddr" (destination address). If we pass those two parameters correctly it shows, turn by turn directions between those points.
Web Based Turn-By-Turn Directions on Google Maps

Why are we even bothered about viewing turn by turn directions on the web?

Because guess what, we can use the same web based URL pattern on the Android platform!

What?  Yes, we can use the URL http://maps.google.com/maps?saddr=43.0054446,-87.9678884&daddr=42.9257104,-88.0508355 to open up the Google Maps application to see turn by turn directions between two geo points!

The above code surely works! It shows the user, turn by turn directions between the geo points [43.0054446,-87.9678884] and [42.9257104,-88.0508355].

There is only one problem though, Android platform identifies that the above URL can be processed by two Activities!
  • The Browser Activity - Since the URL starts with http:// 
  • The Google Maps Activity - Since the address we are opening up is maps.google.com
Whenever Android platform has more than one options to process an intent, it leaves the choice to users, gives them an option of both the applications and lets them chose the application to fulfill the intent.
User gets an option to chose the application for the processing the Maps URL
User can chose either application, both show driving directions between those two geo points.

Driving directions using the browser application

Driving directions using the Native Google Maps application

How to make this solution better:

Although we have achieved what we intended for.  But there is one extra step that user has to perform, i.e. select the application of his choice to see the driving directions.  At this point, user might notice that he is going out of the current application and into a different application.  There is nothing wrong with this approach but, it does not integrate the Google Maps application seamlessly with our application.

How do we eliminate this extra step of choosing the application to view turn by turn directions?

The answer is simple and we can do this by providing a hint in the Intent we are firing.

The line intent.setClassName("com.google.android.apps.maps", "com.google.android.maps.MapsActivity"); does the trick. We are passing additional information in the Intent. We are informing that, the class name of the activity that should fulfill the intent is "com.google.android.apps.maps/com.google.android.maps.MapsActivity"

That's it! Now Android platform knows that, user wants to see the turn by turn directions on the native google maps application and not on the browser. The extra step of chosing the application is eliminated.

User directly goes to this view
There are many advantage of this approach
  • User can choose to start navigation using Google Navigate (beta) (without us doing anything).
  • User can click back button and return to our application as well!
As we can see, Android platform is pretty awesome, when it comes to ease of development!  Something as complex as showing turn by turn driving directions between two geo points can be achieved by writing 3 lines of code!

Wednesday, June 22, 2011

How to change the text color of Android options menu

As promised in the previous post, here comes the second installment of styling the options menu.  In the previous post we saw how we could change the background color of the options menu.  This time we are going to look at how we could change the text color of Android options menu.

We already know that styling the options menu is not really easy.  As shown in the previous post, its a eight step process.  To change the text color of the options menu we need to put in another hack.  We need to add a ninth step.  Lets look at all nine steps once again.
  1. Setting the custom LayoutInflater.Factory instance.
  2. Implementing the onCreateView method that will actually set the background selector for the options menu.
  3. In the implementation of onCreateView, check if the view that is to be created is of type com.android.internal.view.menu.IconMenuItemView.  Yes, I know, its an *internal* class!
  4. If the view is of type IconMenuItemView then create the view using the LayoutInflater.
  5. At this point we have an instance of IconMenuItemView but we cannot change the background color of the view directly.  Even if we change the background color at this point, framework updates it again and our changes are overwritten
  6. We have to change the background color after the view has rendered, using the Handler API.
  7. Change the background color in run method of the Runnable instance that we pass to the Handler's post method.
  8. Change the text color using reflection.  This is the new step.  We need to change the text color using reflection.
  9. Catch all exceptions that could occur in the entire process.  Notice that, we are using an internal class there are high changes that its behavior could change without any notice.  In fact this approach does not work on Android 2.3.  In this case we have to fallback to the default menu styling.
Lets look at code to make things clear

The menu_selector.xml and colors.xml have been kept unchanged from the previous post.  The comments are embedded in the code.  One new methods has been added setTextColor.  This method does the job for us!
The above screenshot shows the menu item color changes when its pressed.

That's it!  We have successfully changed the background color and text color of Android options menu.

Saturday, June 18, 2011

How to change the background color of Android options menu

I have been trying my hand at developing apps with Android.  I have had my fair share of leanings.  Today I am going to share my experience around styling the options menu in Android.

What is the options menu?

Options menu is the menu that is shown to the user when the Menu key is pressed on the Android phone.

Lets look at an example, that will make things easier to understand.

The layout file.

The above code shows the following GUI
As you can see from the above screenshot the background color of the Activity is greenish while the default Color of the selected element of the options menu is Orange.

It definitely looks inconsistent and ugly.  This is the reason we need to style the options menu to match the rest of the application theme.

Android platform is highly configurable.  One can change all aspects of look and feel on the android platform.  Hence, when this task was given to me, I thought it would be a 2 min fix.  But unfortunately it took much longer than I expected.

All I wanted to do is change the background selector of the options menu.  Android does not provide a straight forward way to do this.  In fact, it meant writing quiet some code.  I decided to write a post on this, so that other can benefit from my learning's.

So back to the original question.  How do we change the background color of Android options menu?

How do they do it?

Now there is nothing fancy about the above code.  But to change the background color we have to write some fancy code :)

Changing the options menu background color is a 8 step process
  1. Setting the custom LayoutInflater.Factory instance.
  2. Implementing the onCreateView method that will actually set the background selector for the options menu.
  3. In the implementation of onCreateView, check if the view that is to be created is of type com.android.internal.view.menu.IconMenuItemView.  Yes, I know, its an *internal* class!
  4. If the view is of type IconMenuItemView then create the view using the LayoutInflater.
  5. At this point we have an instance of IconMenuItemView but we cannot change the background color of the view directly.  Even if we change the background color at this point, framework updates it again and our changes are overwritten
  6. We have to change the background color after the view has rendered, using the Handler API.
  7. Change the background color in run method of the Runnable instance that we pass to the Handler's post method.
  8. Catch all exceptions that could occur in the entire process.  Notice that, we are using an internal class there are high changes that its behavior could change without any notice.  In fact this approach does not work on Android 2.3.  In this case we have to fallback to the default menu styling.
Yep, I know, it looks like a lot of work and pretty complex too.  Lets look at the code to make things more clear.

The menu_selector is an XML file that choses the background color based on the state of the menu item.  My menu_selector.xml looks like this

The colors.xml file looks like

The comments are embedded in the code. One new methods has been added called setMenuBackground. This method does the job for us!

The screenshots of the styled options menu
 As we can see the Options Menu background color has been changed from Orange to greenish.

That's all folks!

We have successfully changed the background color of Android options men.  But wait a minute, how to change the default text color of the Android options menu?  If this question is bothering you stay tuned, in the next post I am going to explain exactly that!

Saturday, May 14, 2011

Fixing the "skia decoder->decode returned false" error while downloading images on Android

I had to implement a common requirement in one of my Android project.  I had to show a image that was hosted on the web, in my Android application.  Now that is a very common situation right?  I am sure you must have faced this situation before.

I would have imagined, showing the images from the web would be as simple as setting the correct image source URL to the ImageView.  But as it turns out life is not always that simple. 

So how do we show the images from the web using the ImageView?

  • We have to first download the image using the HttpClient
  • Decode the image data using BitmapFactory and convert it into Bitmap
  • Associate the Decoded Bitmap with the ImageView
Lets look at the code to show the web image in the ImageView

The above code works and works well, it does show the image hosted on the web in the ImageView.  However, sometimes, I get an error in the log saying

Now, this is something unexpected. Whenever I get this error the image download stops and image is not shown in the ImageView.
The Cause:

Googled a little and as usual, I was not the only one to face this issue.  There are lots of threads online, that mention this particular issue (here and here), "decoder returned false". 

It seems that when skip method of the InputStream class does not skip the given number of bytes then, the BitmapFactory fails to decode the InputStream.  Usually, the issue occurs on a slow internet connection.  However, I cant confirm that, I have a 2Mbps dedicated internet connection, even on this connection issue is reproduicable! 

The Fix:

There are two ways of fixing this issue.

Method 1 - Method that involves writing some custom code

This method makes sure that, the skip method of InputStream actually skip's the mentioned number of bytes.

To do this, we will need to wrap the InputStream into a custom class, override the skip method and ensure that we skip the given number of bytes no matter what.  This can be achieved by subclassing the FilterInputStream class and overriding the skip method.  Lets look at how the new implementation of the skip method.

As seen in the above code, the skip method simply makes sure that we skip the give number of bytes.  The class FlushedInputStream now needs to be used while we decode the image. The updated code with the FilteredInputStream looks like

Method 2 - Method that involves using the BufferedInputStream

This method is very simple and straight forward we simply need to wrap the imageContentInputStream with the BufferedInputStream. This also seems to fix the problem. The updated code looks like

Yep, these two methods fix the "decode returned false" issue.

Sunday, April 24, 2011

Fixing the java.lang.ClassNotFoundException com.test.model.SomeModelClass in loader dalvik.system.PathClassLoader on Android

Recently, I had faced a very interesting issue on one of my Android project.  The issue was the dreadful java.lang.ClassNotFoundException.

The Android App, that was facing the ClassNotFoundException was tested on multiple devices.  Some of the devices that we tested the app on were
The app worked fine on all devices without any problems at all.  We decided to go live with the App on Android Market.

Everything looked great till one day when one of the QA's downloaded the app on HTC MyTouch 4G.  The app refused to work on this device.  The app threw ClassNotFoundExceptions.  The stack trace looked like

After looking at the stack trace, I was thinking, Hmm this is weird, the app works on all these devices without an issue.  Moreover, the app cannot compile if the class com.test.model.SomeModelClass was not found.  Then why it doesn't work on HTC MyTouch 4G?

My initial reaction was, may be the app was not downloaded correctly from the Market.  May be the downloaded APK was corrupt?

I requested the QA's to uninstall the app and re-install it again from the market.  I was hoping that this could fix the issue.

But software development has taught me one thing
Nothing changes, If Nothing changes
Yep, the reinstall didnt work.  The app was still throwing the ClassNotFoundException.

We were using ProGuard.  Proguard is a free Java class file shrinker, optimizer, obfuscator, and preverifier.  Another thought that crossed my mind was, Is ProGuard removing the class com.test.model.SomeModelClass?

I created the APK without running ProGuard on it.  Requested the QA to test it.

That didn't work either.  ProGuard was not at fault.

By now, I was really confused.  What could be the issue with the app?  I thought, may be, if I try to load the class explicitly as the first thing in the app, then would it fix the issue?  

I updated the APK, loaded the class explicitly when the app starts, requested the QA to retest the APK.

Nope, that didn't fix the issue.  Interesting thing that I noticed about about this change was, the class loads successfully when I load it explicitly, but the class is not found when the app really needs it at a later stage!

History has shown us, class loader issues are not easy to fix.

I was quickly running out of options.  People were downloading the app on their device from the Market and may be some of them were facing the ClassNotFoundException issue with the app.  I needed a solution and that too quickly!  We didn't want to make a wrong first impression.  What should I try next?

At the back of my mind, I was sure that its some sort of a class loader issue.  When I explicitly load the class its found, but when the class is needed later in the app, its not found.  Surely something to do with a different class loader.  I decided to go back to basics, let's to do it step by step.

First step, 

When does the app need the class?

The app makes a HTTP call to get some information.  The information is returned in form of JSON responses.  As mentioned in my previous post, I was using Gson to parse the JSON response.  Gson is an excellent library with it comes to JSON manipulation.

Gson converts JSON response into Java Model Objects.  This is the point when the Java Model Class com.test.model.SomeModelClass is loaded.  The problem lies here, Gson tries to load the class com.text.model.SomeModelClass dynamically and its unable to find it!

Why Gson does not find the class?

The real confusion in my mind was, why Gson is able to load the class on all other devices but HTC MyTouch 4G?  My reasoning to that was, may be, Gson is loaded in a different class loader in HTC MyTouch 4G?  Is that even possible?  

After some intense googling and trying our numerous things, I finally figured out what was issue and what was solution.

This issue occurs only when all of the following conditions are met
  • The App uses Gson to manipulate JSON
  • The device is HTC Desire HD or MyTouch 4G on T-Mobile
The issue is HTC - The device manufacturer, also uses Gson library and they have made it public.  

Somehow, when the JVM is loaded on such devices, the Gson is also loaded along with it.  Because of this, the Gson library that is bundled with the app never gets loaded.  

When the global Gson tries to load classes from our domain model, it fails to find them.  This is because, the class loader that loaded the global Gson library does not have our app on its classpath!

That explained what the problem was, let's see how we can fix it!

The Fix

The fix was pretty simple.  We need to change the package name of the Gson library so that the global Gson library does not interfere with the local Gson library.  To change the package name of local Gson library, I used JarJar project.

I followed the following steps to change the package name of the local Gson library
  • Download jarjar project.
  • Put jarjar-1.1.jar and gson-1.6.jar in the same directory
  • Create a new text file in this directory, lets call it rules.txt.
  • Write the following line in the rules.txt file: rule com.google.gson.** com.google.myproject.@1
  • Open a command prompt and execute the command, java -jar jarjar.jar process rules.txt gson-1.6.jar myproject-gson-1.6.jar.
  • Replaced the gson library reference in the project with myproject-gson-1.6.jar
  • Update the imports to use the new package name
  • Compile and build the new APK
  • Requested the QA to test the updated APK
To look at more details visit this link.

And that was it, It worked!

It was such a relief!  I am glad that, I faced this issue, makes me love the job that I am doing!

Saturday, April 16, 2011

How to work with JSON on Android - Part - 2

As mentioned in my previous post, Gson is an excellent lightweight opensource library to do JSON manipulations.  I have used this library on the Android platform, it works great!

We have seen that, converting JSON to Java model objects and Java model Objects to JSON is pretty straight forward with Gson.

In this post lets look at the various hooks that Gson provides to deal with not so straight forward scenarios.

Lets take an example.  Lets say you want to convert the JSON string value "08:00" into Java model Time object.  A very valid scenario right?

Basically, we need to serialize and deserialize the Time object in a special way.  Gson provides a way in which we can hookup our own serializer and deserializer for a given type.  This serializer and deserializer will be invoked to convert the Java model object into JSON String and JSON string into Java model object.

The approach taken by Gson to do this task is pretty natural and easy to follow.  Great job guys!

Lets look at the code to put things in perspective.

The Time class has two fields one to represent the hour and other represents the minute of the day.  Let's say that, we want the JSON representation of Time objects to be of in the format "HH:MM".  Let's first look at the code to convert Java model Time object into JSON

Gson provides an interface called JsonSerializer.  We can provide an implementation of JsonSerializer to serialize the Time object in the way we want.  The code to do this would look like

Ok so the serializer does not look very complex. How do we tell Gson to use TimeSerializer when it serializes the Time object?

Turns out, Gson providers a class called GsonBuilder.  This class can be used to register custom serializers and deserializers with Gson.  GsonBuilder class has the responsibility to construct an instance of Gson with registered serializers and deserializers.  Let's look at the code

Does not look too difficult right?

Serialization done, let's look at deserialization.  Any guesses?

I am sure you got it right.  Gson provider an interface called JsonDeserializer.  We have implement this interface to provide a custom deserializer for the Time Java model class.  Let's look at the deserializer code.

The code of deserializer looks pretty simple. The code to integrate the deserializer is exactly the same as the code to integrate the serializer.

Thats all folks! Gson is a really good framework to manipulate JSON.

We have effectively used it in Android projects. If you have to do JSON manipulation in your project, I would suggest to have a look at Gson for sure!

Monday, April 11, 2011

How to work with JSON on Android

Recently, I have been working quite a bit on Android.  In my experience, there are lot of times when one has to deal with JSON while building apps for Android.

In one of my projects, I had a situation where, I had to invoke a web-service which returned JSON response.  JSON response has to be parsed, information has to be extracted from it and shown to the user.

The JSON response returned by the web-service was pretty big, with lots of fields, objects, lists and lists of objects.  In sort, the JSON response was pretty complex, it would have been a lot of work to extract information out of it, construct domain objects and then use it to show the information on the GUI.

Android provides a package org.json which has class like JSONObject, JSONArray, etc which help us parse the JSON responses.  I could have used those class and parsed the JSON response, extracted the information out of it, converted that into domain objects and used them to show it on the GUI.  But I am a lazy developer!  I am always in an hunt for ways to reduce my work!

I was in no mood to write the such a lot of code just to parse the JSON response.  Over and above it, there are multiple problems with writing such code

  • Quite some code just to parse the JSON response
  • Code has to be tested very well.  We have to make sure that it works in all situations.
  • This approach is error prone.  For example, if we decide to change the JSON keys, a lot of code have to be updated and there is no compile time check to find out errors if any while updating the keys.
So what is the alternate?  Simple, search for a library that does the job for you :)

The perfect library for the task is Gson.  Gson is an opensource project that helps us convert JSON to JavaBeans or JavaBeans to JSON using one line of code!

This effectively means we could convert the JSON response to our model Objects with one line of code.  Isn't it awesome!

How do they do it?

An example explains things much faster.  So lets not waste any time and head straight to see Gson in action.

Lets say that the JSON response returned by the service looked like

As we can see, the web services returns us the searched Address and Points of Interest (POI) around the searched address in the JSON response.

We want to convert this JSON response into the POIResponse Java domain object.  Lets look at how the POIResponse class looks like

The model class are pretty standard.  They just have fields with the same name as the keys in the JSON response.  Notice that we do have complex objects like Address and POI and list of POI in POIResponse class.

For Gson to work only one condition has to meet and that is, the name of fields in the model class should be same as the JSON keys.  This is based on the convention over configuration principal.

Also notice that we do not have getters and setters in our domain classes.  Gson uses reflection to set the values directly into the fields.  Gson find private fields as well.

Lets look at the code to convert the JSON response into model Java object.

Thats all we need to do to convert JSON response into POIResponse object!  As promised its just one line of code.

Gson has excellent support for Generics.  Notice that, we did not have to caste the return type of fromJson method to POIResponse.

Gson can convert POIResponse to JSON with the same ease.

The string reference json holds the JSON representation of the poiResponse instance.

Gson is an excellent lightweight library when it comes to working with JSON.

In the next post I will show how Gson provides enough hooks to provide custom serializers and deserializers.

Till then, stay tuned!

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!
Have some Fun!