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"

Below you will come across the link to some sites that we believe you need to visit.

We came across a cool web page that you simply could possibly delight in. Take a search if you want.

Below you?ll uncover the link to some web pages that we consider you must visit.

Although websites we backlink to below are considerably not associated to ours, we feel they may be essentially really worth a go via, so have a look.

Usually posts some really exciting stuff like this. If you?re new to this site.

The time to study or pay a visit to the material or internet sites we have linked to below.

Every when in a whilst we select blogs that we read. Listed beneath would be the most current web-sites that we opt for.

Here are some hyperlinks to sites that we link to due to the fact we believe they are worth visiting.

Here is a good Weblog You may Discover Intriguing that we encourage you to visit.

Although web sites we backlink to below are considerably not related to ours, we feel they are essentially worth a go via, so have a look.

Wonderful story, reckoned we could combine a handful of unrelated data, nevertheless genuinely worth taking a search, whoa did 1 discover about Mid East has got a lot more problerms as well.

Usually posts some extremely intriguing stuff like this. If you?re new to this site.

The time to read or take a look at the content material or web sites we have linked to below.

We came across a cool web page which you may take pleasure in. Take a look in the event you want.

That could be the finish of this post. Here you will uncover some sites that we think you?ll appreciate, just click the hyperlinks.

Please go to the sites we stick to, which includes this one particular, as it represents our picks from the web.

Tengo un blog de sexo gay donde se habla de estas cosas http://www.videosdegaysx.com/

Here are some links to web sites that we link to simply because we assume they’re worth visiting.

Woah! I’m really enjoying the template/theme of this blog. It’s simple, yet effective. A lot of times it’s difficult to get that “perfect balance” between superb usability and appearance. I must say you’ve done a awesome job with this. In addition, the blog loads extremely fast for me on Safari. Superb Blog!

Usually posts some quite fascinating stuff like this. If you?re new to this site.

That may be the finish of this article. Right here you?ll discover some web pages that we consider you?ll value, just click the hyperlinks.

Although internet sites we backlink to beneath are considerably not connected to ours, we feel they may be truly worth a go through, so possess a look.

Although web sites we backlink to below are considerably not associated to ours, we really feel they are in fact really worth a go as a result of, so have a look.

Usually posts some pretty exciting stuff like this. If you?re new to this site.

We came across a cool site that you just may delight in. Take a appear in case you want.

Usually posts some extremely interesting stuff like this. If you?re new to this site.

Usually posts some extremely fascinating stuff like this. If you?re new to this site.

Here are a few of the internet sites we recommend for our visitors.

Here is a good Blog You might Find Intriguing that we encourage you to visit.

We came across a cool site that you could take pleasure in. Take a look in the event you want.

Although web-sites we backlink to below are considerably not associated to ours, we feel they may be really really worth a go via, so have a look.

Every once inside a though we decide on blogs that we study. Listed beneath are the most up-to-date web sites that we opt for.

Leave a Reply