I have a file open on the SD card. When someone mounts the SD card, it winds up crashing my application. I am trying to register for the ACTION_MEDIA_EJECT broadcast event, and i receive that, but it seems like i'm getting that too late. By the time I get that, it's already crashed my application. Is there any way to get notified before crashing my application?
Added some very simple sample code. When I do this, it winds up crashing the service when I turn on USB (MSC mode).
Test.java
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
try {
startService(new Intent(this, TestService.class));
bindService(new Intent(this, TestService.class), serviceConnection, Context.BIND_AUTO_CREATE);
} catch (Exception e) {
}
}
protected TestService testService;
private ServiceConnection serviceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
TestService.LocalBinder binder = (TestService.LocalBinder) service;
testService = binder.getService();
}
@Override
public void onServiceDisconnected(ComponentName name) {
testService = null;
}
};
TestService.java
@Override
public void onCreate() {
super.onCreate();
try {
mFileOutputStream = new FileOutputStream("/sdcard/test2", true);
} catch (Exception e) {
}
}
@Override
public IBinder onBind(Intent intent) { return binder; }
public static class LocalBinder extends Binder {
public static TestService getService() {
return _this;
}
}
It is killing your application because it is a documented design decision in android to kill any process holding an open handle to the sdcard when the sdcard needs to be unmounted from the device (for example to be USB mounted to a connected PC).
A file system which still has open file handles cannot be cleanly unmounted. At the operating system level, there's no way to revoke a file handle, short of killing the process to which it was granted, so that is what android ultimately does.
if (Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())) {
//access external file
}
Without knowing more about what exceptions are being thrown, this is about all I can recommend.
Also, the following code from the Environment class documentation may help:
BroadcastReceiver mExternalStorageReceiver;
boolean mExternalStorageAvailable = false;
boolean mExternalStorageWriteable = false;
void updateExternalStorageState() {
String state = Environment.getExternalStorageState();
if (Environment.MEDIA_MOUNTED.equals(state)) {
mExternalStorageAvailable = mExternalStorageWriteable = true;
} else if (Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)) {
mExternalStorageAvailable = true;
mExternalStorageWriteable = false;
} else {
mExternalStorageAvailable = mExternalStorageWriteable = false;
}
handleExternalStorageState(mExternalStorageAvailable,
mExternalStorageWriteable);
}
void startWatchingExternalStorage() {
mExternalStorageReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
Log.i("test", "Storage: " + intent.getData());
updateExternalStorageState();
}
};
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_MEDIA_MOUNTED);
filter.addAction(Intent.ACTION_MEDIA_REMOVED);
registerReceiver(mExternalStorageReceiver, filter);
updateExternalStorageState();
}
void stopWatchingExternalStorage() {
unregisterReceiver(mExternalStorageReceiver);
}