您的位置:首页 > 移动开发 > Android开发

获取Android设备上的所有存储设备

2016-10-12 11:47 375 查看
Android系统提供了Environment.getExternalStorageDirectory()接口获得存储设备的路径,但是这个接口往往给出的结果并不是我们想要的,在某些设备上它返回的是手机内部存储,某些设备上返回的手机外部存储。还有就是某些Android设备支持扩展多个sdcard,这个时候想要获得所有存储器的挂载路径,这个接口是没有办法办到的。

那么,Android系统的文件管理器是如何把所有挂载的存储设备加载出来的呢?通过查看文件管理器的源码发现是在MountPointManager类中处理的,通过调用StorageManager类的getVolumeList()方法获取的。

[java] view
plain copy

/** 

    * This method initializes MountPointManager. 

    *  

    * @param context Context to use 

    */  

   public void init(Context context) {  

       mStorageManager = (StorageManager) context.getSystemService(Context.STORAGE_SERVICE);  

       final String defaultPath = getDefaultPath();  

       LogUtils.d(TAG, "init,defaultPath = " + defaultPath);     

       if (!TextUtils.isEmpty(defaultPath)) {  

           mRootPath = ROOT_PATH;  

       }  

       mMountPathList.clear();  

       // check media availability to init mMountPathList  

       StorageVolume[] storageVolumeList = mStorageManager.getVolumeList();  

       if (storageVolumeList != null) {  

           for (StorageVolume volume : storageVolumeList) {  

               MountPoint mountPoint = new MountPoint();  

               mountPoint.mDescription = volume.getDescription(context);  

               mountPoint.mPath = volume.getPath();  

               mountPoint.mIsMounted = isMounted(volume.getPath());  

               mountPoint.mIsExternal = volume.isRemovable();  

               mountPoint.mMaxFileSize = volume.getMaxFileSize();  

               LogUtils.d(TAG, "init,description :" + mountPoint.mDescription + ",path : "  

                       + mountPoint.mPath + ",isMounted : " + mountPoint.mIsMounted  

                       + ",isExternal : " + mountPoint.mIsExternal + ", mMaxFileSize: " + mountPoint.mMaxFileSize);  

               mMountPathList.add(mountPoint);  

           }  

       }  

       IconManager.getInstance().init(context, defaultPath + SEPARATOR);  

   }  

系统提供了StorageManager类,它有一个方法叫getVolumeList(),这个方法的返回值是一个StorageVolume数组,StorageVolume类中封装了挂载路径,挂载状态,以及是否可以移除等信息。下面是这个方法的源码。

[java] view
plain copy

/** 

 * Returns list of all mountable volumes. 

 * @hide 

 */  

public StorageVolume[] getVolumeList() {  

    if (mMountService == null) return new StorageVolume[0];  

    try {  

        Parcelable[] list = mMountService.getVolumeList();  

        if (list == null) return new StorageVolume[0];  

        int length = list.length;  

        StorageVolume[] result = new StorageVolume[length];  

        for (int i = 0; i < length; i++) {  

            result[i] = (StorageVolume)list[i];  

        }  

        return result;  

    } catch (RemoteException e) {  

        Log.e(TAG, "Failed to get volume list", e);  

        return null;  

    }  

}  

getVolumeList()方法是隐藏的,不能在应用代码中直接调用,所以我们只能通过反射来调用这个方法了。

通过反射机制获取Android设备的所有存储设备

[java] view
plain copy

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);  

    }  

    @Override  

    public String toString() {  

        return "StorageInfo [path=" + path + ", state=" + state  

                + ", isRemoveable=" + isRemoveable + "]";  

    }  

}  

[java] view
plain copy

public static List<StorageInfo> listAllStorage(Context context) {  

    ArrayList<StorageInfo> storages = new ArrayList<StorageInfo>();  

    StorageManager storageManager = (StorageManager) context.getSystemService(Context.STORAGE_SERVICE);  

    try {  

        Class<?>[] paramClasses = {};  

        Method getVolumeList = StorageManager.class.getMethod("getVolumeList", paramClasses);  

        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);  

  

                Method getVolumeState = StorageManager.class.getMethod("getVolumeState", String.class);  

                String state = (String) getVolumeState.invoke(storageManager, info.path);  

                info.state = state;  

  

                Method isRemovable = obj.getClass().getMethod("isRemovable", new Class[0]);  

                info.isRemoveable = ((Boolean) isRemovable.invoke(obj, new Object[0])).booleanValue();  

                storages.add(info);  

            }  

        }  

    } catch (Exception e) {  

        e.printStackTrace();  

    }  

    storages.trimToSize();  

    return storages;  

}  

  

public static List<StorageInfo> getAvaliableStorage(List<StorageInfo> infos){  

    List<StorageInfo> storages = new ArrayList<StorageInfo>();  

    for(StorageInfo info : infos){  

        File file = new File(info.path);  

        if ((file.exists()) && (file.isDirectory()) && (file.canWrite())) {  

            if (info.isMounted()) {  

                storages.add(info);  

            }  

        }  

    }  

      

    return storages;  

}  

调用上述方法:

[java] view
plain copy

List<StorageInfo> list = listAllStorage(this);  

for(StorageInfo info : list){  

    Log.e(TAG, info.toString());  

}  

Log.e(TAG, "-----------------");  

List<StorageInfo> infos = getAvaliableStorage(list);  

for(StorageInfo info : infos){  

    Log.e(TAG, info.toString());  

}  

  

Log.e(TAG, "Environment.getExternalStorageDirectory(): " + Environment.getExternalStorageDirectory());  

连上手机进行验证,输出Log信息:



可以看到,通过listAllStorage()方法获取到了手机上的所有存储设备,通过getAvaliableStorage()方法的过滤获取到了挂载状态的所有存储设备。由于该手机只有一个可读写的存储设备,因此与Environment.getExternalStorageDirectory()方法获取到的结果一致。

注意:由于在getAvaliableStorage()方法中我们获取的是可写(canWrite)的设备,需要加上相应权限: <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> ,否则获取不到存储设备。

转载自:http://blog.csdn.net/wangsf1112/article/details/51427007
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息