In this tutorial we will walk through the process of integrating Google Maps API V2 into an Android project.
The version 2 of Google Maps now is part of the Google Play services SDK, that is why google-play-services lib should be installed first.
After the sdk manager completes the installation, go to <android_sdk_folder>/extras/google/google_play_services/libproject and copy the google-play-services_lib to the location where you maintain your Android projects.
Then import the library project into your workspace, and reference it in your Android project.
In order to use Google Maps API in your project you need a valid Google Maps API key. The key can be obtained via the Google APIs Console. You will have to provide the SHA-1 fingerprint and the package name of your application.
Please note that if you already hold a map key from the Google Maps Android V1, also known as MapView, you still will need get a new API key, as the old key won’t work with the V2 API.
To display the SHA-1 fingerprint, first you need to decide for what type of certificate do you need to generate the fingerprint: for the debug certificate, or for the release certificate.
In this example we well consider displaying the fingerprint for the debug certificate.
The file name of debug certificate is called debug.keystore, and it is located on C:\Users\your_user_name\.android\ on Windows, and on ~/.android/ on Linux.
Copy the SHA1 fingerprint and store it somewhere for later use.
c) In the resulting dialog, enter the SHA-1 fingerprint, followed by a semicolon, and then your application package name.
replacing the YOUR_API_KEY with your real API key.
Displaying the maps is as simple as declaring a fragment in the xml layout with the name com.google.android.gms.maps.MapFragment.
If you would like to make your application compatible with older devices, then you’ll have to use the Android Support Library and reference SupportMapFragment instead of MapFragment. The below example uses the Android Support Library.
If everything was configured correctly, then when running this example you should see a map.
If you are working on a relatively complex project, chances are that you may need to build the application against different environments, such as a development, a staging, and a production environment. Assuming you are using Maven as a build tool, here’s one solution how Maven could help with this.
For the sake of this example let assume that you are working on an Android app that consumes web services. You have a dedicated development environment where you spent most of the time, but once every two weeks you need to make a version of the app that is built for production.
Let assume that the endpoint for the testing environment is dev.mysite.com, and for the production environment is: prod.mysite.com.
But as an aspiring developer and after reading a bunch of books about best practices, you can no longer accept to just go and manually edit the source files by changing all over the place one environment with another, and you ask yourself if Maven could help with this.
It can, and here’s how.
The main idea is to store all the properties, in this particular example all the urls, in separate resource files. Then, using maven resource plugin copy the corresponding property file into values/environment.xml.
2. Then fill the content of the resource files with appropriate values.
Now, every time you’ll need to prepare a build against a specific environment, the only thing you’ll need to do will be to run one of those commands.
A common task in Android is to perform some background activity in another thread, meanwhile displaying a ProgressDialog to the user. Example of these tasks include downloading some data from internet, logging into an application, etc. Implementing an AsyncTask is fairly a simple job, the big challenge is how to handle it properly when an orientation change occurs.
In this article I will walk though a series of potential solutions to address the screen orientation issues when using an AsyncTask.
So, lets create a proof of concept application that makes use of an AsyncTask which does not handle configuration changes yet, and then present a few solutions.
– doInBackground() – this will be called by the AsyncTask on a background thread, and performs all the heavy work. For the sake of this example, I just wrote a simple loop with a delay of 1 sec between iterations to simulate a task that takes some time.
– The constructor of the class takes a listener as a parameter. The listener will be used to delegate the work of onPreExecute()/onPostExecute() to the calling Activity.
The Activity implements the TaskListener interface and provides appropriate implementation for its methods, displaying the ProgressDialog when the task is started, and dismissing it when the task is finished. The AsyncTask is fired when clicking on a button.
Now, if you run this example without changing the screen orientation, the AsyncTask will start and finish its work normally. Problems begin to appear when the device orientation is changed while the AsyncTask is in the middle of the work. The application will crash, and an exception similar to these ones will be thrown: java.lang.IllegalArgumentException: View not attached to window manager, or Activity has leaked window com.android.internal.policy….
The cause relies in the Activity life cycle. A change in device orientation is interpreted as a configuration change which causes the current activity to be destroyed and then recreated. Android calls onPause(), onStop(), and onDestroy() on currently instance of activity, then a new instance of the same activity is recreated calling onCreate(), onStart(), and onResume(). The reason why Android have to do this, is because depending of screen orientation, portrait or landscape, we may need to load and display different resources, and only through re-creation Android can guarantee that all our resources will be re-requested.
But don’t panic, you are not alone, there are several solutions that will help us to deal with this situation.
Solution 1 – Think twice if you really need an AsyncTask.
AsyncTasks are good for performing background work, but they are bound to the Activity which adds some complexity. For things like making HTTP requests to a server perhaps you should consider an IntentService. IntentService used in conjunction with a BroadcastReceiver or ResultReceiver to deliver results, could do a better job than an AsyncTask in certain situations.
Solution 2 – Put the AsyncTask in a Fragment.
Using fragments probably is the cleanest way to handle configuration changes. By default, Android destroys and recreates the fragments just like activities, however, fragments have the ability to retain their instances, simply by calling: setRetainInstance(true), in one of its callback methods, for example in the onCreate().
There’s however one aspect that should be taken in consideration in order to achieve the desired result. Our AsyncTask uses a ProgressDialog to signal when the AsyncTask is started, and dismisses it when the task is done. This complicates a bit the things because even if we are using setRetainInstance(true), we should close all windows and dialogs when the Activity is destroyed, otherwise we will get an: Activity has leaked window com.android.internal.policy… exception. This happens when you try to show a dialog after you have exited the Activity.
In order to address this issue, we will add some logic to keep track of AsyncTask status (running/not running). We will dismiss the ProgressDialog when the fragment is detached from activity, and check in onActivityCreated() the status of AsyncTask. If the status is “running”, this means we are returning from a screen orientation and we will just re-create and display the ProgressDialog to show that the AsyncTask is still working.
Solution 4 – Prevent the Activity from being recreated.
This is the easiest way to handle configuration changes, but the less advised. The only thing you need to do is to specify the configChanges attribute followed by a list of values that specifies when the activity should prevent itself from restarting.
Using this approach however, is not recommended, and this is clearly stated in the Android documentation: Using this attribute should be avoided and used only as a last-resort.
As it turns out, not only a screen orientation causes the Activity to recreate, there are also other events which may produce configuration changes and restart the Activity, and there’s a good chance that we won’t handle them all. This is why the use of this technique is discouraged.