Android中静态实例的生命周期

2012/05/24 09:27
阅读数 2.7K

Extending the Android Application class and dealing with Singleton

In this post I’m going to show the basic steps to extend the Android Application class and I’m also going to talk about why it could be useful to extend it in dealing with the Singleton design pattern.

The first thing to do is to create a MyApplication class that extends android.app.Application.


package com.devahead.extendingandroidapplication;

import android.app.Application;

public class MyApplication extends Application
{
	@Override
	public void onCreate()
	{
		super.onCreate();

		// Initialize the singletons so their instances
		// are bound to the application process.
		initSingletons();
	}

	protected void initSingletons()
	{
		// Initialize the instance of MySingleton
		MySingleton.initInstance();
	}

	public void customAppMethod()
	{
		// Custom application method
	}
}

In this class you can, for example, override the onCreate method to perform your initializations at the application startup and you can also implement your own methods to make them available to the rest of your application components. As you can see here we initialize also the singletons in case there are some in our application. I’ll talk later about why I do this here, but now let’s go on with the custom Application class.

The next thing we need to do is to open the AndroidManifest.xml file of our application and add a reference to MyApplication in the android:name attribute of the application tag, so in the end the manifest file will look similar to this one:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
	package="com.devahead.extendingandroidapplication"
	android:versionCode="1"
	android:versionName="1.0">

	<uses-sdk android:minSdkVersion="7"/>

	<application android:icon="@drawable/icon" android:label="@string/app_name"
		android:name="com.devahead.extendingandroidapplication.MyApplication">

		<activity android:name=".MainActivity"
			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>

That’s it. We now have a custom Application class that can be used to suit our needs. We can access to it from any Activity through the getApplication method (the same getApplication method is available also in a Service).

package com.devahead.extendingandroidapplication;

import android.app.Activity;
import android.os.Bundle;

public class MainActivity extends Activity
{
	protected MyApplication app;

	@Override
	public void onCreate(Bundle savedInstanceState)
	{
		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);

		// Get the application instance
		app = (MyApplication)getApplication();

		// Call a custom application method
		app.customAppMethod();

		// Call a custom method in MySingleton
		MySingleton.getInstance().customSingletonMethod();

		// Read the value of a variable in MySingleton
		String singletonVar = MySingleton.getInstance().customVar;
	}
}

As you can see there are references to the MySingleton class also here as an example like there were in the MyApplication class, but we haven’t seen the singleton yet, so here it is:

package com.devahead.extendingandroidapplication;

public class MySingleton
{
	private static MySingleton instance;

	public String customVar;

	public static void initInstance()
	{
		if (instance == null)
		{
			// Create the instance
			instance = new MySingleton();
		}
	}

	public static MySingleton getInstance()
	{
		// Return the instance
		return instance;
	}

	private MySingleton()
	{
		// Constructor hidden because this is a singleton
	}

	public void customSingletonMethod()
	{
		// Custom method
	}
}

The initInstance method lets the internal instance be initialized only once and this is done in the MyApplication class as we saw earlier. The getInstance method allows to access the instance from every part of our application and the MySingleton constructor is kept private because we don’t want to allow the creation of multiple instances.

At this point you may ask: "wait a moment… why is the singleton initialized in MyApplication??? Isn’t it supposed to be just a singleton so the instance can be initialized everywhere in the application like in an Activity?" Here comes the tricky part… I’ve been digging around the web and in books for a long time searching for information on the static variables lifecycle in Android because I found some weird behaviors when I started programming for Android, but unfortunately there seem to be different opinions about this topic, there is a bit of confusion and I still haven’t found a single definitive source of information.

If you know about the activities lifecycle in Android, you also know that they can be destroyed by the system in case they’re no more used and they’re not active or some resources are needed by the system, so it happens that during the life of an application, an activity could be destroyed and created many times, while the application process remains the same. While I was developing an application, I found that sometimes some static variables bound to activities happened to be uninitialized even though they’ve previously been initialized! I thought that when a static variable is initialized it stays so for the entire life of the application, but this doesn’t seem to be the case. Among all the information I found on the web, I tried to find out a safe and reliable way to initialize static variables (and you know that the singleton design pattern requires the use of a static variable). The explanation of the weird behavior I saw that makes more sense to me is that the static variables instances are bound to the class loader of the class that first initialized them. So what does this mean? This means that if a static variable inside any class has been initialized by an activity, when that activity is destroyed also its class might be unloaded and so the variable becomes uninitialized again! While if the variable is initialized by the application class, it’s life is the same as the application process so we’re sure that it will never become uninitialized again. That’s why I chose to initialize all the singletons in the MyApplication class.

I don’t know if the solution I found is correct and makes sense as it seems that this topic is not clear for many people dealing with Android and even the official documentation seems to make the people think that static variables are not problematic and behave exactly like we are used to in other environments with the Java virtual machine, but using the technique I explained actually solved my problems with static variables deinitialization and I never had the weird behaviors I was having when I was initializing them (as well as singletons) directly from my activities.

If someone found a better solution or doesn’t think this approach is correct, I would be happy to hear a different opinion. This is what the web is useful for and it’s interesting to read thoughts of experienced Android developers.

展开阅读全文
加载中
点击加入讨论🔥(6) 发布并加入讨论🔥
6 评论
3 收藏
0
分享
返回顶部
顶部