Android Persistence: External Storage (SD Card)

Of all the options for Android storage discussed previously, storing files externally on the phone’s SD card appears the least desirable option, for a number of reasons:

  1. There is a security issue as a (non-encrypted) file can be read by other applications
  2. There is an availability problem as the user can unmount  or remove the file

There is however at least one use case where the SD card option is desirable, and that is when we explicitly want the user to have the option of transferring the file via USB to the computer for backup for example, or even onto another phone running the same application.

Storing on the SD card requires some amount of defensive programming. We first want to make sure that the SD card is mounted before saving files on it. A way to do just that is to do the check in the main Activity of our Android application as it loads:

public class MainActivity extends Activity {
 /** called when the Activity is first created */
   @Override
   public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        checkSDCard(); // need SD card

        // other initialization code
        // ...
  }
}

The checkSDCard() method will check for two conditions to be true before proceeding:

  1. The SD card needs to be mounted
  2. It needs to be writable

If both of the above conditions are not satisfied, the application will bring up an alert dialog to inform the user. Once the user will acknowledge the problem and click the OK button, the dialog will close our application.

private static boolean SDCARD_OK;

 /******************************************
  * Check if SD card is mounted and writable
 ********************************************/
 private void checkSDCard(){

	String state = android.os.Environment.getExternalStorageState();
	boolean sdcard_avail =  state.equals(android.os.Environment.MEDIA_MOUNTED);
	boolean sdcard_readonly =  state.equals(android.os.Environment.MEDIA_MOUNTED_READ_ONLY);

        if ( ! sdcard_avail || sdcard_readonly ){
               	SDCARD_OK = false;
        	LayoutInflater inflater = getLayoutInflater();
		View dview = inflater.inflate(R.layout.cardalert, null);
		final Dialog dialog = new Dialog(this);
		dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
		dialog.setContentView(dview);
		TextView tv = (TextView)  dview.findViewById(R.id.alert);
		tv.setText( !sdcard_avail ? R.string.no_sdcard :  R.string.sdcard_read_only);
		Button btn_ok = (Button) dview.findViewById(R.id.btn_ok);
		btn_ok.setOnClickListener(new View.OnClickListener() {
		    @Override
		    public void onClick(View v) {
			dialog.dismiss();
			MainActivity.this.finish();
		   }
		});
		dialog.show();
        }
        else{
        	SDCARD_OK = true;
        }

}

The alert UI used by the SD card checker method is a simple XML layout file (cardalert.xml) with a TextView and a Button:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
                 android:orientation="vertical"
                 android:layout_width="fill_parent"
                 android:layout_height="wrap_content">
    <TextView android:id="@+id/alert"       .../>
    <Button   android:id="@+id/btn_ok"    ...  />
</LinearLayout>

And the actual texts (R.string.no_sdcard and R.string.sdcard_read_only) are stored in the res/values/strings XML file, as they should be in any well-behaved internationalized application:

<resources>
...
<string name="no_sdcard">
No SD card detected.\nPlease check your Settings.
</string>
<string name="sdcard_read_only">
SD card is read-only.\nPlease check your Settings.
</string>

</resources>

Here’s what we would get on the phone screen:

Screenshot taken from the K-Memo application

Last but not least, we have to request the user permission to write on the SD card in our Android Manifest file:

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

That’s it. We now can start saving and retrieving files on the phone’s SD card using standard Java I/O.

Advertisements

,

  1. Leave a comment

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: