最近打算自己实现图片异步加载并实现三级缓存,其中保存文件部分使用到了sd卡保存,保存期间遇到了各种问题,下面细数一下遇到的问题及解决方式。
1、首先是sd卡是否存在及其路径获取问题
public static String getFileName(Context context, String url) {
String result;
String format = url.substring(url.lastIndexOf("."));
String img_name = getPathEnCodesMD5(url) + format;
if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)){
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT){
result = Environment.getExternalStorageDirectory() + "/Android/data/" + context.getPackageName() + "/cache/download_test/" + img_name;
} else {
File[] files = context.getExternalFilesDirs(Environment.DIRECTORY_PICTURES);
if (files.length > 1 && files[1] != null) {
result = files[1].toString() + "/" + img_name;
} else {
result = files[0].toString() + "/" + img_name;
}
}
} else {
result = context.getCacheDir().getPath() + "/Android/data/" + context.getPackageName() + "/cache/download_test/" + img_name;
}
return result;
}
通过上面的函数获取其中 context.getExternalFilesDirs(Environment.DIRECTORY_PICTURES);会自动创建目录并返回路径名,是一个二维数组,在上面的 Environment.getExternalStorageState(),已经做出了判断,所以我认为存在sd卡并且 files[1]指向sd卡 ,之前并没有添加 files[1] != null的条件判断。
然而在一些手机上,其获取的数组长度为2,该手机确实有sd卡,files[1]却为空。
2、上面的context.getExternalFilesDirs(Environment.DIRECTORY_PICTURES);获取路径的方式也应注意。
从api19 / Android 4.4 / KITKAT开始,Android为了更好的管理sd卡,对应用程序对sd卡的创建、删除、修改做了限制。只允许操作:sd卡路径下的Android/data/你的应用包名,该路径下的文件,这样是为了方便管理sd卡,防止应用卸载后在sd卡上残留一些文件。而该目录的创建官方给出了一些函数来实现,如下:
($rootDir)
+- /data -> Environment.getDataDirectory()
| |
| | ($appDataDir)
| +- data/com.srain.cube.sample
| |
| | ($filesDir)
| +- files -> Context.getFilesDir() / Context.getFileStreamPath("")
| | |
| | +- file1 -> Context.getFileStreamPath("file1")
| | ($cacheDir)
| +- cache -> Context.getCacheDir()
| |
| +- app_$name ->(Context.getDir(String name, int mode)
|
| ($rootDir)
+- /storage/sdcard0 -> Environment.getExternalStorageDirectory()
| / Environment.getExternalStoragePublicDirectory("")
|
+- dir1 -> Environment.getExternalStoragePublicDirectory("dir1")
|
| ($appDataDir)
+- Andorid/data/com.srain.cube.sample
|
| ($filesDir)
+- files -> Context.getExternalFilesDir("")
| |
| +- file1 -> Context.getExternalFilesDir("file1")
| +- Music -> Context.getExternalFilesDir(Environment.Music);
| +- Picture -> ... Environment.Picture
| +- ...
|
| ($cacheDir)
+- cache -> Context.getExternalCacheDir()
|
+- ???
3、上面的两个问题还好解决,在此期间遇到了一个奇葩问题,最开始我以为是程序问题,各种找,结果找了一天也没找到,最后发现竟然是因为设备问题,我的手机是华为5.1.1,sd卡手机显示是低速sd卡。
问题的现象是:目录通过上面的函数创建成功,可是在保存图片时,无法保存成功。提示错误是没有权限。检查了AndroidManifest.xml,里面明明已经声明了权限。
解决办法:将sd卡拔出,重新插入即可。。。
最后发现这个不是偶然现象,我每次调试程序后,sd卡都会无法保存文件,而重新插拔后可以保存。。
参考资料:http://www.tuicool.com/articles/AvUnqiy