1.存储空间简介
Android存储空间主要分为三个部分:内存、机身存储和SD卡存储。内存用于程序计算,通常空间小,速度快而造价高。机身存储和SD卡存储可以用于保存文件,如照片、视频等。机身存储和SD卡存储不能用于程序计算,但是可以在断电时保存文件,空间大且造价小。所以内存和机身存储、SD卡存储的任务是不同的。在支持扩展存储空间的手机上,如果机身自带存储空间不够,可以插入SD卡来扩大空间。类比于电脑来说,手机内存相当于电脑内存条,机身存储相当于硬盘,而SD卡存储相当于可移动硬盘。机身存储和SD卡存储都不能用来进行程序计算,都是外存。
2.SD卡路径获取及手机内存路径获取
Android提供了一种获取存储路径的方法如下:
Environment.getExternalStorageDirectory().getAbsolutePath();//方法A
从名字上看,我们很容易会认为该方法就是获取外置SD卡的方法,这里我写了一个小程序做验证,同时使用这种方法和另外一种方法来获取路径。为了描述方便,上述方法下文称其为方法A,另一种接下来要介绍的方法称其为方法B。验证结果如下图:
图1
图1中的external路径是我用方法A获取到的路径,SD卡路径及机身存储路径是我用方法B获取到的。从图中可以看到,方法A获取到的是机身存储路径,而不是SD卡路径。由此看来,external在这里的含义就是外部存储,而并不是说获取的是SD卡路径。根据网上查阅的资料知,该方法由于厂商的不同,有的品牌手机上获取到的是机身存储路径,有的品牌手机上获取到的是SD卡路径。所以,想通过方法A来获取到正确的SD卡路径或机身存储路径是不可靠的。
接下来我们来介绍一下正确的SD卡路径及机身存储路径获取方法,主要分为以下两步:
(1)获取所有挂载的存储设备
a.先定义一个StorageInfo类记录每个挂载的存储设备的信息,信息包括路径,状态,是否可移除等。代码如下:
<span > </span>public class StorageInfo {
public String path;
public String state;
public boolean isRemoveable;
public StorageInfo(String path) {
this.path = path;
}
public boolean isMounted() {
return "mounted".equals(state);
}
}
getVolumeList来获取到所有挂载的存储设备,并记录存储设备信息。具体代码如下,最后返回一个存储设备信息列表:
public List getAvaliableStorage(Context context) {
ArrayList storages = new ArrayList();
StorageManager storageManager = (StorageManager) context.getSystemService(Context.STORAGE_SERVICE);
try {
Class<?>[] paramClasses = {};
Method getVolumeList = StorageManager.class.getMethod("getVolumeList", paramClasses);
getVolumeList.setAccessible(true);
Object[] params = {};
Object[] invokes = (Object[]) getVolumeList.invoke(storageManager, params);
if (invokes != null) {
StorageInfo info = null;
for (int i = 0; i < invokes.length; i++) {
Object obj = invokes[i];
Method getPath = obj.getClass().getMethod("getPath", new Class[0]);
String path = (String) getPath.invoke(obj, new Object[0]);
info = new StorageInfo(path);
File file = new File(info.path);
if ((file.exists()) && (file.isDirectory()) && (file.canWrite())) {
Method isRemovable = obj.getClass().getMethod("isRemovable", new Class[0]);
String state = null;
try {
Method getVolumeState = StorageManager.class.getMethod("getVolumeState", String.class);
state = (String) getVolumeState.invoke(storageManager, info.path);
info.state = state;
} catch (Exception e) {
e.printStackTrace();
}
if (info.isMounted()) {
info.isRemoveable = ((Boolean) isRemovable.invoke(obj, new Object[0])).booleanValue();
storages.add(info);
}
}
}
}
} catch (NoSuchMethodException e1) {
e1.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
storages.trimToSize();
return storages;
}
(2)根据是否能移除的状态来判断,能够移除的是SD卡,不能移除的是机身存储。遍历(1)中返回的存储设备列表,可以很容易地获取到SD卡的路径和机身存储路径。
for (int i=0;i < count;i++) {
item = storageList.get(i);
if (item.isRemoveable) {
<span > </span>mSDCardPath += item.path + ";";
} else {
<span > </span>mPhonePath += item.path + ";";
}
}
最后,通过遍历存储设备列表,很容易知道是否存在SD卡;根据存储设备列表的size就可以知道一共挂载了多少存储设备。这里不再赘述。