I want to implement both memory and disk cache for images. Investigating I’ve found this link and sample code (you can download it from the link on the right)
http://developer.android.com/training/displaying-bitmaps/cache-bitmap.html
Somewhere in code there is this method:
/**
* Get a usable cache directory (external if available, internal otherwise).
*
* @param context The context to use
* @param uniqueName A unique directory name to append to the cache dir
* @return The cache dir
*/
public static File getDiskCacheDir(Context context, String uniqueName) {
// Check if media is mounted or storage is built-in, if so, try and use external cache dir
// otherwise use internal cache dir
final String cachePath =
Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState()) ||
!isExternalStorageRemovable() ? getExternalCacheDir(context).getPath() :
context.getCacheDir().getPath();
return new File(cachePath + File.separator + uniqueName);
}
I’m wondering what’s the rationale behind this check:
Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState()) ||
!isExternalStorageRemovable()
The second part seems redundant to me. This can be read as “even if the external storage is not mounted let’s use it because it can not be removed” but obviously you can not use it for caching since it is not mounted.
Funny thing is happening on the emulator with this code. It crashes on AVD based on Galaxy Nexus and SD card not specified. The first part will return false (it see it as “removed”) and the second will return true (because “external” storage is not removable on GN). Thus it will try to use external storage and it will crash since it’s can not use it.
I’ve tested with my Galaxy Nexus to see what is the first part value when phone is hooked up to pa PC or Mac and it is true both times. It is still mounted but the PC or Mac can write to it non the less.
In case you need them here are other used methods in the above code:
/**
* Check if external storage is built-in or removable.
*
* @return True if external storage is removable (like an SD card), false
* otherwise.
*/
@TargetApi(9)
public static boolean isExternalStorageRemovable() {
if (Utils.hasGingerbread()) {
return Environment.isExternalStorageRemovable();
}
return true;
}
/**
* Get the external app cache directory.
*
* @param context The context to use
* @return The external cache dir
*/
@TargetApi(8)
public static File getExternalCacheDir(Context context) {
if (Utils.hasFroyo()) {
return context.getExternalCacheDir();
}
// Before Froyo we need to construct the external cache dir ourselves
final String cacheDir = "/Android/data/" + context.getPackageName() + "/cache/";
return new File(Environment.getExternalStorageDirectory().getPath() + cacheDir);
}
bonus question: Is someone using this code in production? Is this a good idea?
Posting my own comment as an answer. It may be helpful to someone else. :
getExternalStorageDirectory doesn’t always return the SDCard. That’s why the security check was implemented.
Similar answer i had posted here and it is a good practice to always check for it.
hope this will give you some hint about the double check.