为什么 getExternalFilesDirs() 在某些设备上不起作用?
Why getExternalFilesDirs() doesn't work on some devices?
我的应用程序在 Android 5.0 上运行。我使用方法 getExternalFilesDirs()
来检查外部 SD 卡是否可用。如果returns大于1File
,说明存在外置SD卡。
但在某些设备上(例如 Elephone G2),方法 getExternalFilesDirs()
returns 只有一个主存储目录。我确定该设备有外部 SD 卡 (/storage/sdcard1/)。
谁能给我答案吗?
在我使用此代码的项目中,我没有遇到任何问题。
getExternalFilesDirs 的方法return 长度为 2 的数组。
Dirs[0] ==> Internal Sorage
Dirs[1] ==> External Storage
File[] Dirs = ContextCompat.getExternalFilesDirs(MyApp.GetContext(), null);
对于 getExternalFilesDirs 到 return SD 卡的路径,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变量,则不会return编辑sdcard路径。
您可以通过转到 adb shell
并查看 echo $SECONDARY_STORAGE
的输出来交叉检查
联想的部分设备也存在这个问题
我的解决方案是这样的。
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);
}
我的应用程序在 Android 5.0 上运行。我使用方法 getExternalFilesDirs()
来检查外部 SD 卡是否可用。如果returns大于1File
,说明存在外置SD卡。
但在某些设备上(例如 Elephone G2),方法 getExternalFilesDirs()
returns 只有一个主存储目录。我确定该设备有外部 SD 卡 (/storage/sdcard1/)。
谁能给我答案吗?
在我使用此代码的项目中,我没有遇到任何问题。
getExternalFilesDirs 的方法return 长度为 2 的数组。
Dirs[0] ==> Internal Sorage
Dirs[1] ==> External Storage
File[] Dirs = ContextCompat.getExternalFilesDirs(MyApp.GetContext(), null);
对于 getExternalFilesDirs 到 return SD 卡的路径,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变量,则不会return编辑sdcard路径。
您可以通过转到 adb shell
并查看 echo $SECONDARY_STORAGE
联想的部分设备也存在这个问题
我的解决方案是这样的。
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);
}