Android @ Kiowok

Singletons

There is often a need to store information so that it is not stored local to a single activity or service. Some possible storage mechanisms are SharedPreferences, files, storing the data on a remote server, in an SQLite database, in an Application object or in a singleton. These notes show how to set up an singleton object.

The example below keeps track of a single String value named value in a singleton named ShareData. Normally, many data values (ints, doubles, arrays, ArrayLists, etc.) would be kept in the singleton.

Define the Singleton Class

Create the singleton class. Note that sData is static, and is accessed via the public method get. To guarantee that only one object is ever created, the constructor is private, and is accessed onloy through the get method.

public class ShareData {
	private static ShareData sData;  // NOTE: static reference sData
	
	private String value;
   // declare other variables here, or change value to a reference to a Model object
	
	private ShareData() {
		value = "default";
	}
	
	public static ShareData get() {
		if (sData == null) {
			sData = new ShareData();
		}
		return sData;
	}
   
	public void setValue(String s) {
		value = s;
	}
	
	public String getValue() {
		return value;
	}
   
   // Put additional set and get methods here
}

Accessing the Singleton

Any activity or service that wishes to access the singleton can do so with the following code. To retrieve value from the singleton:

        String s = ShareData.get().getValue();

To set value:

        ShareData.get().setValue("other");

Saving and Restoring the Singleton Values

If the data stored in the singleton is relatively small, then it might be reasonable to save the data frequently, such as after each change, or possibly each time an activity is paused. Large amounts of data might require another solution, such as an SQLite database.

Add the save and restore Methods to the Singleton

Here the data is saved using ObjectOutputStream (which is handy when writing out larger data structures, such as an ArrayList). The new code is in bold font.

public class ShareData {
	public static final String filename = "my_data.dat";
	private static final String TAG = "*** YOUR TAG ***";

	private static ShareData sData;
	
	private String value;
   // declare other variables here
	
	private ShareData() {
		value = "default";
	}
	
	public static ShareData get() {
		if (sData == null) {
			sData = new ShareData();
		}
		
		return sData;
	}
   
	public void setValue(String s) {
		value = s;
	}
	
	public String getValue() {
		return value;
	}
   
    // Put additional set and get methods here
	
	public boolean save(Context context){
	    FileOutputStream fos;
	    ObjectOutputStream os;
	    
	    try {
	        fos = context.openFileOutput(filename, Context.MODE_PRIVATE);
	        os = new ObjectOutputStream(fos);    
	        os.writeObject(value);    // write value
	        os.flush();
	        os.close();
	    }
	    catch (FileNotFoundException e) {
	        Log.d(TAG, "Error when saving: " + e);
	        return false;
	    }
	    catch (IOException e) {
	        Log.d(TAG, "Error when saving: " + e);
	        return false;
	    }
	    return true;
	}
	
	public boolean restore(Context context) {
	    FileInputStream fis;
	    ObjectInputStream is;
	    
	    try {
	    	fis = context.openFileInput(filename);
	    	is = new ObjectInputStream(fis);
	    	value = (String) is.readObject();
	    	is.close();
	    }
	    catch (FileNotFoundException e) {
	        Log.d(TAG, "Error when restoring: " + e);
	        return false;
	    }
	    catch (IOException e) {
	        Log.d(TAG, "Error when restoring: " + e);
	        return false;
	    } 
	    catch (ClassNotFoundException e) {
			Log.d(TAG, "Error when restoring: " + e);
	        return false;
		}
	    return true;
	}
}

A common place to save is in onPause:

	@Override
	public void onPause() {
		super.onPause();
		ShareData.get().save(getApplicationContext());
	}

A common place to restore is in onCreate:

	@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_jobs_your_name);  
        ShareData.get().restore(getApplicationContext());
        ...
    }

Miscellaneous

There are lots of ways to do I/O. One key consideration is buffered versus unbuffered I/O.

If you are using readObject and writeObject, all of the elements that are being written should implement the Serializable interface.

Top