我正在尝试按照this explanation和this code将自己的警报音复制到Android系统。
问题是我无法将文件从原始资源复制到外部存储器。我在这里看了其他问题,但似乎没有答案对我有用。
这是我的AndroidManifest(我将WRITE_EXTERNAL_STORAGE置于应用程序标记之外,如here所述):
...
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<application...
这是我的代码。它运行在从我的主要活动的onCreate开始的新线程上。从该新线程调用方法“void onFirstTime()”,并且该方法重复调用“void copyRawRingtone(File dstPath,int resId)”:
void copyRawRingtone(File dstPath, int resId) {
final String fileName = getResources().getResourceEntryName(resId) + ".mp3";
File dstFile = new File(dstPath, fileName);
if (!dstFile.exists()) {
InputStream srcStream = getResources().openRawResource(resId);
FileOutputStream dstStream = null;
try {
dstFile.createNewFile(); // THIS THROWS THE EXCEPTION
dstStream = new FileOutputStream(dstFile);
byte[] buffer = new byte[1024];
int bytesRead;
while ((bytesRead = srcStream.read(buffer)) > 0) {
dstStream.write(buffer, 0, bytesRead);
}
// Set the file metadata
final String mimeType = "audio/mpeg";
final String dstAbsPath = dstFile.getAbsolutePath();
ContentValues contentValues = new ContentValues();
contentValues.put(MediaStore.MediaColumns.DATA, dstAbsPath);
contentValues.put(MediaStore.MediaColumns.TITLE, fileName);
contentValues.put(MediaStore.MediaColumns.MIME_TYPE, mimeType);
contentValues.put(MediaStore.Audio.Media.IS_ALARM, true);
contentValues.put(MediaStore.Audio.Media.IS_NOTIFICATION, false);
contentValues.put(MediaStore.Audio.Media.IS_RINGTONE, false);
contentValues.put(MediaStore.Audio.Media.IS_MUSIC, false);
// Add the metadata to the file in the database
Uri contentUri = MediaStore.Audio.Media.getContentUriForPath(dstAbsPath);
Uri newUri = getContentResolver().insert(contentUri, contentValues);
// Tell the media scanner about the new ringtone
MediaScannerConnection.scanFile(
this,
new String[]{newUri.toString()},
new String[]{mimeType},
null
);
} catch (Exception e) {
e.printStackTrace();
} finally {
if (dstStream != null) {
try {
dstStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
try {
srcStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
// First time initialization (called in a new thread from onCreate)
void onFirstTime() {
if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
File dstPath = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_ALARMS);
// This returns false but since I run it on an emulator, I don't know how to check if it actually exists:
dstPath.mkdirs();
Field[] rawResources = R.raw.class.getFields();
final ProgressBar installProgress = (ProgressBar) findViewById(R.id.progressBar);
final int length = rawResources.length;
runOnUiThread(new Runnable() {
@Override
public void run() {
installProgress.setMax(length);
}
});
for (int i = 0; i < length; ++i) {
try {
int resId = rawResources[i].getInt(rawResources[i]);
copyRawRingtone(dstPath, resId); // Call the method above
} catch (IllegalAccessException e) {
e.printStackTrace();
}
final int progress = i + 1;
runOnUiThread(new Runnable() {
@Override
public void run() {
installProgress.setProgress(progress);
}
});
}
}
}
行:dstFile.createNewFile();抛出异常:
java.io.IOException: open failed: ENOENT (No such file or directory)
我不明白可能是什么问题。我在模拟器上运行它:Nexus_S_API_21_armeabi-v7a。
我没有在我的电脑下看到模拟器的存储,所以我认为电脑模拟器存储没有安装在我的电脑上,所以我不认为this could be the problem。
在异常时刻,这些是一些变量值:
dstPath="/storage/sdcard/Alarms"
fileName="whistle_alarm.mp3"
dstFile="/storage/sdcard/Alarms/whistle_alarm.mp3"
因为这返回true:
Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)
媒体似乎已挂载且可写(不是MEDIA_MOUNTED_READ_ONLY)。所以我不知道会出现什么问题!有没有人有任何想法??
修改
我添加了这两行(我还在前面放了一行,后面有一行在上下文中看到它:
File dstPath = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_ALARMS);
final boolean exists = dstPath.exists(); // Added. exists=true
final boolean canWrite = dstPath.canWrite(); // Added. canWrite=true
dstPath.mkdirs();
我也删除了:
dstFile.createNewFile(); // THIS THROWS THE EXCEPTION
它现在有效!
但是我已经多次测试过没有这个createNewFile()行,但它没有用。确实,我添加了这一行,看看我是否可以使用它。所以我再次尝试使用那条线,它也有效!
我怀疑实际的解决方案是重启模拟器。