为啥 getExternalFilesDirs() 在某些设备上不起作用?
Posted
技术标签:
【中文标题】为啥 getExternalFilesDirs() 在某些设备上不起作用?【英文标题】:Why getExternalFilesDirs() doesn't work on some devices?为什么 getExternalFilesDirs() 在某些设备上不起作用? 【发布时间】:2016-01-25 19:38:03 【问题描述】:我的应用在 android 5.0 上运行。我使用方法getExternalFilesDirs()
来检查外部SD 卡是否可用。如果返回超过 1 个File
,则表示存在外置 SD 卡。
但在某些设备上(例如 Elephone G2),方法 getExternalFilesDirs()
仅返回一个主存储目录。我确定该设备有外部 SD 卡 (/storage/sdcard1/)。
谁能给我答案?
【问题讨论】:
据推测,Elephone 的制造商决定不允许开发人员访问可移动媒体。或者,也许他们在配置 ROM 时搞砸了。 @CommonsWare 应该是答案。我真的不明白为什么getExternalFilesDirs()
不起作用。它适用于几乎所有设备。
您的 AndroidManifest.xml 文件中有 android.permission.WRITE_EXTERNAL_STORAGE 吗?
@Shark 当然可以。正如我所说,它几乎可以在设备上运行。
@Sunshinetpu 看起来你偶然发现了一个半途而废的供应商 ROM:/
【参考方案1】:
为了让 getExternalFilesDirs 返回 sdcard 的路径,OEM 必须在设备特定的 init.rc 文件中设置 SECONDARY_STORAGE
环境变量,如下所述:
https://source.android.com/devices/storage/config-example.html
在这里查看getExternalFilesDirs
的来源:
http://androidxref.com/5.1.1_r6/xref/frameworks/base/core/java/android/app/ContextImpl.java#1039
该值是从Environment.buildExternalStorageAppFilesDirs
获得的。在此处查看该来源:
http://androidxref.com/5.1.1_r6/xref/frameworks/base/core/java/android/os/Environment.java#206
该值取决于mExternalDirsForApp
,而后者又通过读取 SECONDARY_STORAGE 变量的内容来填充:
http://androidxref.com/5.1.1_r6/xref/frameworks/base/core/java/android/os/Environment.java#136
如您所见,如果没有设置 SECONDARY_STORAGE 变量,则不会返回 sdcard 路径。
您可以通过转到adb shell
并查看echo $SECONDARY_STORAGE
的输出来交叉检查这一点
【讨论】:
谢谢。那么如果没有设置 SECONDARY_STORAGE 变量,我们就无法访问外部 sd 卡? 如果未设置该环境变量,则无法使用 getExternalFilesDirs 写入 sdcard,因为它不会返回 sdcard 路径。但是,您可以通过 SAF 询问用户写入 sdcard 的权限。看看这个链接:***.com/questions/26744842/… 实际上,如果设备不支持$SECONDARY_STORAGE
,您只需请求WRITE_EXTERNAL_STORAGE权限即可。无需其他修改,我对此进行了测试。【参考方案2】:
在我使用此代码的项目中,我没有任何问题。
getExternalFilesDirs 方法返回长度为 2 的数组。
Dirs[0] ==> Internal Sorage
Dirs[1] ==> External Storage
File[] Dirs = ContextCompat.getExternalFilesDirs(MyApp.GetContext(), null);
【讨论】:
您有 WRITE_EXTERNAL_STORAGE 权限吗?你能用你的方法创建文件吗? OP 专门要求一种方法不起作用...您在答案中使用... @MHossein 我会测试你的代码。你能解释一下你为什么使用ContextCompat
吗?我使用Context
的方法getExternalFilesDirs(String fileName)
。它适用于几乎所有设备。
需要注意的是,MHossein 使用的是ContextCompat.getExternalFilesDirs
而不是Context. getExternalFilesDirs
。 Src link
@MHossein 为什么文件路径必须包含“sdcard”?【参考方案3】:
一些联想设备也存在这个问题。
我的解决方案是这样的。
String EXTERNAL_SD_PATH1;
String EXTERNAL_SD_PATH2;
public boolean hasExternalSDCard()
try
String state = Environment.getExternalStorageState();
if(Environment.MEDIA_MOUNTED.equals(state) || Environment.MEDIA_MOUNTED_READ_ONLY.equals(state))
return true;
catch (Throwable e)
return false;
@SuppressLint("SdCardPath")
protected synchronized void _prepareStorage()
EXTERNAL_SD_PATH1 = null;
EXTERNAL_SD_PATH2 = null;
if (hasExternalSDCard())
try
if(VERSION_SDK_INT > 18)
Context context = getContext();
File[] sds = getExternalFilesDirs("");
if(sds == null)
return;
if(sds.length >= 2)
EXTERNAL_SD_PATH1 = TextWorker.getSubStringBeforeLastMark(sds[1].getAbsolutePath(),"/Android/");
if(sds.length > 2)
EXTERNAL_SD_PATH2 = TextWorker.getSubStringBeforeLastMark(sds[2].getAbsolutePath(),"/Android/");
else
String internal = sds[0].getAbsolutePath();
internal = TextWorker.getSubStringBeforeLastMark(internal,"/Android/");
int len = internal.length();
int num = Integer.valueOf(internal.substring(len - 1));
String ex1 = internal.substring(0, len-1) + (num+1);
File sd1 = new File(ex1);
if(sd1.exists())
EXTERNAL_SD_PATH1 = sd1.getAbsolutePath();
String ex2 = internal.substring(0, len-1) + (num+2);
File sd2 = new File(ex2);
if(sd2.exists())
EXTERNAL_SD_PATH2 = sd2.getAbsolutePath();
else
File sd = Environment.getExternalStorageDirectory();
String path = sd.getAbsolutePath();
if (sd.exists() && (path.contains("/mnt/") || path.contains("/storage") || path.contains("/sdcard")) && (!path.contains("emulate")))
EXTERNAL_SD_PATH1 = path;
catch (Throwable e)
public static String getSubStringBeforeLastMark(String str,String mark)
int l = str.lastIndexOf(mark);
if(l == -1 || l == 0)
return "";
return str.substring(0, l);
【讨论】:
以上是关于为啥 getExternalFilesDirs() 在某些设备上不起作用?的主要内容,如果未能解决你的问题,请参考以下文章
在 API 23 及更高版本中插入 SD 卡时,getExternalFilesDirs() 未在 ApplicationContext 中更新