dcsimg

Global Variables in Android Apps

Using the Application object to cure a case of the Android flip flops

Losing your religion

I love software — really I do.

I love to create stuff.

Some of my favorite words to hear are: "Would it be possible to…?"

The answer to this oft-spoken query is usually something between: "Why would you want to do that?" and "Of course, let’s see it in action."

I love the "Get it done" aspect to writing software. Creating proto-types to test out an idea is arguably my favorite thing to do professionally.

Production code is OK — if you can make a living writing it. It tends to get boring very quickly.

If the code can be written well, that is great too.

And if the code is easily maintained over time, that is even better. And usually, my code is. Except for the spurious comment that just says:

// punt

My development team often laughs at these lines and asks me just what I meant when I wrote it. If I remembered why I wrote it, I probably wouldn’t have a development team to back me up, but that is a story for another day!

I admit, I am probably a bit too loose with my programming style at times. Perhaps it is a character flaw but I have often had a difficult time when people take their programming languages (and themselves) too seriously.

One line I often hear is this: "I am a Java programmer". Great, welcome to the human race, Mr./Ms. Java Programmer.

I have a good friend who is always asking me if my code can be easily re-factored. Of course. Who doesn’t?

While I respect good programming practices, I shy away from people who “worship” one style of programming over another.

If you have been around programmers like these for any period of time, particularly “object oriented programmers”, you have likely heard some of these lines:

  • Never use globals. Never.
  • Your code will not be easy to maintain — break it into more classes.
  • Use hunGarian notation.
  • Encapsulate or perish.

Most of this advice is good — in reasonable doses. Some of it is just limiting the imagination — or the other evil — burdening us with excessive programming constructs. Heretical, I admit.

So, what does this have to do with Android you ask?

Simply that there are some things in Android which are quite happily solved through the use of the often maligned global variable — let’s have a look.

Activity Flip-Flopping

No, Android is not yet running for office, so we have little fear that the story will change over night.

We are concerned here with the funny behavior of our trusted friend Android when a device’s orientation is switched from Portrait to Landscape or vice versa.

In a prior article we learned how to take a photo with a simple Android application.

Taking a picture
Taking a picture

Unfortunately, if the phone is rotated, the Android Activity is re-created (onCreate() method is invoked) and our image is lost!

Losing the photo when rotating
Losing the photo when rotating

Placing a call to trace the execution of the onCreate method, we can actually see that the method is invoked again on each rotation.

05-10 23:15:23.601: INFO/com.msi.linuxmag.PhotoBooth2(7263): Activity Ready to Go!
05-10 23:15:24.481: INFO/ActivityManager(71): Displayed activity com.msi.linuxmag/.PhotoBooth2: 1180 ms (total 1180 ms)
05-10 23:15:27.361: DEBUG/ViewFlipper(134): updateRunning() mVisible=false, mStarted=true, mUserPresent=true, mRunning=false
05-10 23:15:30.401: INFO/WindowManager(71): Setting rotation to 1, animFlags=0
05-10 23:15:30.401: INFO/ActivityManager(71): Config changed: { scale=1.0 imsi=310/410 loc=en_US touch=3 keys=1/1/2 nav=3/1 orien=2 layout=34}
05-10 23:15:30.461: INFO/UsageStats(71): Unexpected resume of com.msi.linuxmag while already resumed in com.msi.linuxmag
05-10 23:15:30.641: INFO/com.msi.linuxmag.PhotoBooth2(7263): Activity Ready to Go!
05-10 23:15:34.171: INFO/WindowManager(71): Setting rotation to 0, animFlags=0
05-10 23:15:34.171: INFO/ActivityManager(71): Config changed: { scale=1.0 imsi=310/410 loc=en_US touch=3 keys=1/1/2 nav=3/1 orien=1 layout=34}
05-10 23:15:34.221: INFO/UsageStats(71): Unexpected resume of com.msi.linuxmag while already resumed in com.msi.linuxmag
05-10 23:15:34.291: INFO/com.msi.linuxmag.PhotoBooth2(7263): Activity Ready to Go!
05-10 23:15:37.301: INFO/WindowManager(71): Setting rotation to 1, animFlags=0
05-10 23:15:37.301: INFO/ActivityManager(71): Config changed: { scale=1.0 imsi=310/410 loc=en_US touch=3 keys=1/1/2 nav=3/1 orien=2 layout=34}

As a result of this "reload", any Activity-scoped variables are reset to their initial values — we need a solution to this obstacle.

In the log-listing above note the lines referring to "Config changed". This is at the root of what is happening — the configuration is changing.

Configuration here is somewhat broadly defined. It could refer to the keyboard layout changing — such as when a G1 or a Droid slides out its keyboard. Or a input language/locale changes. Or, in our case, the device is rotated.

An application can specifically declare within its AndroidManifest.xml which types of configuration changes it wants to handle. In absence of this declaration, the default behavior is for the currently running Activity to relaunch.

We will examine this declarative configuration management in more detail in an upcoming article. For now, we’re going to solve our problem with one of the oldest programming techniques around — using the global variable space.

Application object to the rescue

By default, the Android application that is created with the “File->New” Android project does not contain an implementation of the android.app.Application class. To make use of this class, we must first sub-class it, as shown below.

package com.msi.linuxmag;

import android.app.Application;
import android.graphics.Bitmap;
import android.util.Log;

public class PhotoBoothApp extends Application {
	public Bitmap b = null;
	public PhotoBoothApp ()
	{
		super();
		Log.i("PhotoBooth2","PhotoBoothApp constructor()");
	}
}

In our case, the class is really very simple — we extend the android.app.Application class, declare a “global” variable named b which will hold our Bitmap, and implement the constructor. The constructor is trivial as we simply invoke super() to ask the parent class to do its initialization and we drop a line to the log for a sanity check that this code is being called.

Now, for those who would rather go to the dentist than write code that contains a public member variable, you can wrap that in a “getter” if you prefer and make the Bitmap instance Private.

package com.msi.linuxmag;

import android.app.Application;
import android.graphics.Bitmap;
import android.util.Log;

public class PhotoBoothApp extends Application {
	private Bitmap b = null;
	public PhotoBoothApp ()
	{
		super();
		Log.i("PhotoBooth2","PhotoBoothApp constructor()");
	}
	public Bitmap getBitmap()
	{
		return b;
	}
	public void setBitmap(Bitmap newBitmap)
	{
		b = newBitmap;
	}
}

Regardless of how much encapsulation you prefer, the key here is that this code is accessible to all of the Activity instances in our application. Let’s have a look at how we access this newly minted class from our Activity. And just for fun, I’m going to use the version which marks the Bitmap instance as Public!

Within an Activity, we call the getApplication() method to return an instance of the one and only Application object implemented in our application. Sorry for the multiple uses of the word “application”. The capitalized form refers to the android.app.Application class.

Our Activity code has been updated to no longer rely on a Bitmap object defined at the Activity level — we’re now going to rely on our “global” Bitmap instance.

In the onCreate() method, we now look to see if we have a good reference to a Bitmap object. If so, we display it by assigning it to the ImageView widget defined in our screen layout.

       public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        Log.i(PhotoBooth2.class.getName(),"Activity Ready to Go!");

        final Button  btn = (Button) this.findViewById(R.id.TakePhoto);
        btn.setOnClickListener(new View.OnClickListener(){

        	public void onClick(View v){
        		Log.i(PhotoBooth2.class.getName(),"Button Clicked!");
        		try {
        			Intent action = new Intent("android.media.action.IMAGE_CAPTURE");
        			startActivityForResult(action,1);
        		} catch (Exception e) {
        			Log.e(PhotoBooth2.class.getName(),"Error occured [" + e.getMessage() + "]");
        		}
        	}
        });

        iv = (ImageView) this.findViewById(R.id.PictureFrame);
        PhotoBoothApp app = (PhotoBoothApp) getApplication();
        if (app.b != null) {
        	iv.setImageBitmap(app.b);
        }
    }

After successfully taking a photo, we want to store the image into our PhotoBoothApp object’s Bitmap instance.


    protected void onActivityResult(int requestCode,int resultCode,Intent data)
    {
    	try {
    		if (requestCode == 1) {
    			Log.i(PhotoBooth2.class.getName(),"resultCode is [" + resultCode + "]");
    			if (resultCode == RESULT_OK) {
	    			PhotoBoothApp app = (PhotoBoothApp) getApplication();
    				if (app.b != null) app.b.recycle();
	    			app.b = (Bitmap) data.getExtras().get("data");
	    			if (app.b != null) {
	    				iv.setImageBitmap(app.b);
	    			}
    			}
    		}
    	}catch (Exception e) {
    		Log.e(PhotoBooth2.class.getName(),"onActivityResult Error [" + e.getMessage() + "]");
    	}

    }

Now, we’re ready to handle orientation changes. Almost.

Modifying the code alone does not put the Application object into place for our application. We must also tell Android that our class has extended the android.app.Application. This takes place in the AndroidManifest.xml file — specifically as the android:name attribute of the Application tag.

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
      package="com.msi.linuxmag"
      android:versionCode="1"
      android:versionName="1.0">
    <application android:icon="@drawable/icon" android:label="@string/app_name" android:name="PhotoBoothApp">
        <activity android:name=".PhotoBooth2"
                  android:label="@string/app_name">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>
</manifest>

Testing the application

Let’s test out the newly modified application by taking a photo. As further evidence that I’ve got lots of junk in my office, I’ll take a photo of an old mouse-pad and mouse:

Take another photo
Take another photo

What happens if we rotate the phone? Before making these code changes, we lost the image. Let’s see what happens now:

Rotation successful!
Rotation successful!

We still have our image!

Another item to consider is this — Android applications don’t casually terminate like a desktop application. If you take a phone call or switch to another application and then return to your application we need to be prepared to restore the state. Storing data in a global place like an Application object can be an appropriate tool for this task.

Trivia time: One of the companies shown in the screen shot released a product named J++. Which one is it? The third person to answer this correctly will receive an electronic copy of Unlocking Android, Second Edition. Send your answer to fableson at msiservices.com.

Comments on "Global Variables in Android Apps"

fableson

The answer is Microsoft.

Congrats to Gil who named the correct answer and was the \”third\” to do so. Note to self… come up with more challenging questions as everyone has answered it correctly thus far!

Reply
rmetor

Hi Frank,

enjoying your articles. I wouldn’t call the Android Application object a “global variable” (container) though. Global / local variables are about scope and visibility whereas Application / Activities are about lifetime.

If you have an App with a couple of Activities that control interaction with an underlying data structure I do not see any reasonable argument against making the data structure part of a custom Application object. Again, I don’t see an alternative and doubt that getting references to the Application object breaks with encapsulation in the way global variables do.

Reply
rmcavalcante

Frank,

This is a very nice and direct article.
Congratulations.
Please try to be as objetive as you were here on your next book.
Don’t forget that the way you pass information on a site is different than the way you should present it on a book.

Reply
linxmax

Well, seriously, this is the kind of attitude that paves way for iconic software’s and sometimes legendary ones. Take the case of Apple for instance, the “Would it be possible to” and “Get it done” phrases you said here can be heard there very often and that is why most of us enjoy flawless products like the iphone app design, iPod, Macs or whatever that is Apple. I totally agree with you regarding the production codes. Coming up with one may take some time and is certainly tiresome but when it is well written and maintained over time, it usually ends in top-class!

Reply

I’ve been exploring for a little bit for any high quality articles or weblog posts on this sort of area . Exploring in Yahoo I ultimately stumbled upon this site. Studying this information So i’m glad to convey that I have an incredibly just right uncanny feeling I came upon exactly what I needed. I such a lot undoubtedly will make certain to don?t fail to remember this web site and provides it a glance regularly.

Reply

I’ve been browsing on-line greater than 3 hours as of late, but I by no means discovered any interesting article like yours. It?s pretty price sufficient for me. In my opinion, if all website owners and bloggers made just right content as you did, the internet might be a lot more helpful than ever before.

Reply

Great Post! I am new to Java and Android.. This solved and cleared up a bunch of issues for me… Kind Regards, Mike

Reply

Really enjoyed your fun and challenging puzzles.
We really hope android app development‘s fast growth rate drives in more passionate developers and gives a chance to the users to explore innovative stuff.

Reply

Thanks a lot for the post.Really looking forward to read more. Cool.

Reply

An impressive share, I simply given this onto a colleague who was doing a bit of evaluation on this. And he in reality purchased me breakfast as a result of I found it for him.. smile. So let me reword that: Thnx for the deal with! But yeah Thnkx for spending the time to debate this, I really feel strongly about it and love studying extra on this topic. If possible, as you turn out to be experience, would you thoughts updating your weblog with more particulars? It is extremely helpful for me. Huge thumb up for this weblog post!

Reply

Do you mind if I quote a couple of your posts as long as I provide credit and sources back to your site? My website is in the very same area of interest as yours and my users would really benefit from a lot of the information you provide here. Please let me know if this ok with you. Thanks a lot!

Reply

Leave a Reply

Your email address will not be published. Required fields are marked *

*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>