Advanced Topic: Application Wide State
One common question is how to store application wide state. In general, it is preferable to have state saved by each instance such that one can have multiple instances of a class, each with their own state. In some cases, it is desirable to have state that is shared amongst all instances of a class. This can be done using thread safe static class variables.
In other cases, it is desired to have state that is persisted for the entire application. This can be done using preferences. If you do not wish to persist the Application wide state, you can store state in the Application Context. To do this, first create an additional class that extends android.app.Application as in:
package jalcomputing.context;
import android.app.Application;
public class MyApp extends Application {
private String myString="";
private int myInt=-1;
public MyApp() {;}
public String getMyString() {
return myString;
}
// ASSERT s not null
public void setMyString(String s){
if (s == null){throw new IllegalArgumentException();}
myString= s;
}
public int getMyInt() {
return myInt;
}
public void setMyInt(int i) {
myInt= i;
}
}
Now we need to reflect this change in the manifest.xml file as in:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="jalcomputing.context"
android:versionCode="1"
android:versionName="1.0">
<application android:name= ".MyApp" android:icon="@drawable/icon" android:label="@string/app_name">
<activity android:name=".TestAppContext"
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>
Note the android:name= ".MyApp"
As best I can tell, a single instance of MyApp will be created by the OS. You can access this instance of MyApp using getApplicationContext as in:
package jalcomputing.context;
import android.app.Activity;
import android.content.Context;
import android.os.Bundle;
import android.widget.TextView;
public class TestAppContext extends Activity {
private TextView textView;
private MyApp application;
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
application= (MyApp)getApplicationContext();
application.setMyInt(1);
application.setMyString("hello");
TextView textView= (TextView)findViewById(R.id.textView1);
textView.setText(((MyApp)getApplicationContext()).getMyString()); // demonstrates call from another class
}
}
Note the cast to MyApp.
Cool!
Thread Safety
If you use the application variables as flags or counters, they are not inherently thread safe. If you need atomic or thread safe variables, you will need to program accordingly as in:
private final Object syncLock= new Object();
private int uniqueID= 0;
public int getUniqueID()
{
synchronized(syncLock)
{
return uniqueID++; // returns zero at start
}
}
And call it as in:
textView.setText(new Integer(application.getUniqueID()).toString());
JAL