会场布置方案,小年夜是哪天,湖北省旅游局
android 获取sd卡路径:
外置sd卡路径,也许很多同学在平时的工作中并不会用到,因为现在很多机型都不支持外置sd卡(这也是google目标),所以并不用考虑外置sd卡的路径问题。除了开发文件管理类的应用之外,其他应用使用 enviroment 这个类中的一些静态方法就能满足需要。但也有一些特殊需求需要用到外置sd卡路径,那怎么才能准确获得外置sd卡的路径呢?
方法一
//内置sd卡路径 string sdcardpath = system.getenv("external_storage"); //内置sd卡路径 string sdcardpath = environment.getexternalstoragedirectory().getabsolutepath(); //外置置sd卡路径 string extsdcardpath = system.getenv("secondary_storage"); 在enviroment类的源码中获得sd卡路径其实也是通过 system.getnv() 方法来实现的,如隐藏的方法: /** {@hide} */ public static file getlegacyexternalstoragedirectory() { return new file(system.getenv(env_external_storage)); }
注:更详细的内容还是去看enviroment源码。
另外要注意的是,在api 23版本中 secondary_storage 被移除。
方法二
private static string getstoragepath(context mcontext, boolean is_removale) { storagemanager mstoragemanager = (storagemanager) mcontext.getsystemservice(context.storage_service); class<?> storagevolumeclazz = null; try { storagevolumeclazz = class.forname("android.os.storage.storagevolume"); method getvolumelist = mstoragemanager.getclass().getmethod("getvolumelist"); method getpath = storagevolumeclazz.getmethod("getpath"); method isremovable = storagevolumeclazz.getmethod("isremovable"); object result = getvolumelist.invoke(mstoragemanager); final int length = array.getlength(result); for (int i = 0; i < length; i++) { object storagevolumeelement = array.get(result, i); string path = (string) getpath.invoke(storagevolumeelement); boolean removable = (boolean) isremovable.invoke(storagevolumeelement); if (is_removale == removable) { return path; } } } catch (classnotfoundexception e) { e.printstacktrace(); } catch (invocationtargetexception e) { e.printstacktrace(); } catch (nosuchmethodexception e) { e.printstacktrace(); } catch (illegalaccessexception e) { e.printstacktrace(); } return null; }
通过反射的方式使用在sdk中被 隐藏 的类 stroagevolume 中的方法getvolumelist(),获取所有的存储空间(stroage volume),然后通过参数is_removable控制,来获取内部存储和外部存储(内外sd卡)的路径,参数 is_removable为false时得到的是内置sd卡路径,为true则为外置sd卡路径。
在api 23 enviroment 类中的内部类 userenvironment 中有一方法getexternaldirs与此一样,代码如下:
public file[] getexternaldirs() { final storagevolume[] volumes = storagemanager.getvolumelist(muserid,storagemanager.flag_for_write); final file[] files = new file[volumes.length]; for (int i = 0; i < volumes.length; i++) { files[i] = volumes[i].getpathfile(); } return files; }
再看enviroment的getexternalstoragedirectory方法实现:
public static file getexternalstoragedirectory() { throwifuserrequired(); return scurrentuser.getexternaldirs()[0]; }
可以看出,在api 23时,先是通过getexternaldirs()获取到所有存储空间的file[]数组,这个数组的第一个值:getexternaldirs()[0],即为内置sd卡所在路径。
而在api 23 之前的版本中,并没有类似getexternaldirs()的方法通过storagevolume直接获得存储空间(storage volume),而时通过别的方式来实现的,看关键方法的源码:
public static file getexternalstoragedirectory() { throwifuserrequired(); return scurrentuser.getexternaldirsforapp()[0]; }
这里的 getexternaldirsforapp() 和上面的 getexternaldirs() 的作用是一样的,都是得到所有存储空间的file[]数组。
public file[] getexternaldirsforapp() { return mexternaldirsforapp; }
mexternaldirsforapp 是在 enviroment 类中的内部类 userenvironment 的构造方法中初始化的,enviroment#userenvironment构造函数源码如下:
public userenvironment(int userid) { // see storage config details at http://source.android.com/tech/storage/ string rawexternalstorage = system.getenv(env_external_storage); string rawemulatedsource = system.getenv(env_emulated_storage_source); string rawemulatedtarget = system.getenv(env_emulated_storage_target); string rawmediastorage = system.getenv(env_media_storage); if (textutils.isempty(rawmediastorage)) { rawmediastorage = "/data/media"; } arraylist<file> externalforvold = lists.newarraylist(); arraylist<file> externalforapp = lists.newarraylist(); if (!textutils.isempty(rawemulatedtarget)) { // device has emulated storage; external storage paths should have // userid burned into them. final string rawuserid = integer.tostring(userid); final file emulatedsourcebase = new file(rawemulatedsource); final file emulatedtargetbase = new file(rawemulatedtarget); final file mediabase = new file(rawmediastorage); // /storage/emulated/0 externalforvold.add(buildpath(emulatedsourcebase, rawuserid)); externalforapp.add(buildpath(emulatedtargetbase, rawuserid)); // /data/media/0 memulateddirfordirect = buildpath(mediabase, rawuserid); } else { // device has physical external storage; use plain paths. if (textutils.isempty(rawexternalstorage)) { log.w(tag, "external_storage undefined; falling back to default"); rawexternalstorage = "/storage/sdcard0"; } // /storage/sdcard0 externalforvold.add(new file(rawexternalstorage)); externalforapp.add(new file(rawexternalstorage)); // /data/media memulateddirfordirect = new file(rawmediastorage); } // splice in any secondary storage paths, but only for owner final string rawsecondarystorage = system.getenv(env_secondary_storage); if (!textutils.isempty(rawsecondarystorage) && userid == userhandle.user_owner) { for (string secondarypath : rawsecondarystorage.split(":")) { externalforvold.add(new file(secondarypath)); externalforapp.add(new file(secondarypath)); } } mexternaldirsforvold = externalforvold.toarray(new file[externalforvold.size()]); mexternaldirsforapp = externalforapp.toarray(new file[externalforapp.size()]); }
也可以根据这个方法得到一个获取所有存储空间的路径的方法getstoragedirectories():
/** * returns all available sd-cards in the system (include emulated) * <p/> * warning: hack! based on android source code of version 4.3 (api 18) * because there is no standard way to get it. * todo: test on future android versions 4.4+ * * @return paths to all available sd-cards in the system (include emulated) */ private static final pattern dir_separator = pattern.compile("/"); public list<string> getstoragedirectories() { // final set of paths final arraylist<string> rv = new arraylist<string>(); // primary physical sd-card (not emulated) final string rawexternalstorage = system.getenv("external_storage"); // all secondary sd-cards (all exclude primary) separated by ":" final string rawsecondarystoragesstr = system.getenv("secondary_storage"); // primary emulated sd-card final string rawemulatedstoragetarget = system.getenv("emulated_storage_target"); if (textutils.isempty(rawemulatedstoragetarget)) { // device has physical external storage; use plain paths. if (textutils.isempty(rawexternalstorage)) { // external_storage undefined; falling back to default. rv.add("/storage/sdcard0"); } else { rv.add(rawexternalstorage); } } else { // device has emulated storage; external storage paths should have // userid burned into them. final string rawuserid; if (build.version.sdk_int < build.version_codes.jelly_bean_mr1) { rawuserid = ""; } else { final string path = environment.getexternalstoragedirectory().getabsolutepath(); final string[] folders = dir_separator.split(path); final string lastfolder = folders[folders.length - 1]; boolean isdigit = false; try { integer.valueof(lastfolder); isdigit = true; } catch (numberformatexception ignored) { } rawuserid = isdigit ? lastfolder : ""; } // /storage/emulated/0[1,2,...] if (textutils.isempty(rawuserid)) { rv.add(rawemulatedstoragetarget); } else { rv.add(rawemulatedstoragetarget + file.separator + rawuserid); } } // add all secondary storages if (!textutils.isempty(rawsecondarystoragesstr)) { // all secondary sd-cards splited into array final string[] rawsecondarystorages = rawsecondarystoragesstr.split(file.pathseparator); collections.addall(rv, rawsecondarystorages); } rootmode = sp.getboolean("rootmode", false); if (rootmode) rv.add("/"); file usb = getusbdrive(); if (usb != null && !rv.contains(usb.getpath())) rv.add(usb.getpath()); return rv; } public file getusbdrive() { file parent; parent = new file("/storage"); try { for (file f : parent.listfiles()) { if (f.exists() && f.getname().tolowercase().contains("usb") && f.canexecute()) { return f; } } } catch (exception e) { } parent = new file("/mnt/sdcard/usbstorage"); if (parent.exists() && parent.canexecute()) return (parent); parent = new file("/mnt/sdcard/usb_storage"); if (parent.exists() && parent.canexecute()) return parent; return null; }
综上分析,通过方法一和方法二都可以正确的获取内外sd卡路径,但方法一会存在以下问题:
1、api>=23 时方法一无效(暂未测试)
2、有些厂商的rom改动太多,对相关原生api的支持存在问题,这时方法一可能会存在问题。
3、其他一些情况造成的原因(基本与2差不多,是rom等因素造成的)
所以,在使用时建议使用方法二来获取内外置sd卡路径,在api 23(android 6.0)之前使用getstoragedirectories() 应该也是ok的。
感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!
如对本文有疑问,请在下面进行留言讨论,广大热心网友会与你互动!! 点击进行留言回复
Android studio开发小型对话机器人app(实例代码)
Android通过Java sdk的方式接入OpenCv的方法
Android 通过cmake的方式接入opencv的方法步骤
Android Studio finish()方法的使用与解决app点击“返回”(直接退出)
Android 进度条 ProgressBar的实现代码(隐藏、出现、加载进度)
网友评论