在文件夹中的声音文件的ListView中,我想显示文件的长度(以秒为单位)。我采取的步骤:
但是因为我这样做,我的应用程序比乌龟慢! (有400个文件) 有什么方法可以解决这个速度吗?
private int calculateLength(File yourFile)
throws IllegalArgumentException, IllegalStateException, IOException {
MediaPlayer mp = new MediaPlayer();
FileInputStream fs;
FileDescriptor fd;
fs = new FileInputStream(yourFile);
fd = fs.getFD();
mp.setDataSource(fd);
mp.prepare();
int length = mp.getDuration();
length = length / 1000;
mp.release();
return length;
}
**EDIT**
我有新代码:
活动
myList = new ArrayList<RecordedFile>();
File directory = Environment.getExternalStorageDirectory();
file = new File(directory + "/test/");
File list[] = file.listFiles();
for (int i = 0; i < list.length; i++) {
if (checkExtension(list[i].getName()) == true) {
RecordedFile q = new RecordedFile();
q.setTitle(list[i].getName());
q.setFileSize(readableFileSize(list[i].length()));
//above is the size in kB, is something else but I
//also might move this to the AsyncTask!
myList.add(q);
}
}
new GetAudioFilesLength(myList).execute();
的AsyncTask
List<RecordedFile> mFiles = new ArrayList<RecordedFile>();
public GetAudioFilesLength(List<RecordedFile> theFiles) {
mFiles = theFiles;
}
@Override
protected String doInBackground(Void... params) {
File directory = Environment.getExternalStorageDirectory();
// File file = new File(directory + "/test/");
String mid = "/test/";
for (RecordedFile fileIn : mFiles) {
File file = new File(directory + mid + fileIn.getTitle());
try {
int length = readableFileLengthSeconds(file);
fileIn.setFileLengthSeconds(length);
} catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalStateException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// Do something with the length
// You might want to update the UI with the length of this file
// with onProgressUpdate so that you display the length of the files
// in real time as you process them.
}
return mid;
}
@Override
protected void onProgressUpdate(Void... values) {
}
@Override
protected void onPostExecute(String result) {
// Update the UI in any way you want. You might want
// to store the file lengths somewhere and then update the UI
// with them here
}
/*
* @Override protected void onPreExecute() { }
*/
public int readableFileLengthSeconds(File yourFile)
throws IllegalArgumentException, IllegalStateException, IOException {
MediaPlayer mp = new MediaPlayer();
FileInputStream fs;
FileDescriptor fd;
fs = new FileInputStream(yourFile);
fd = fs.getFD();
mp.setDataSource(fd);
mp.prepare(); // might be optional
int length = mp.getDuration();
length = length / 1000;
mp.release();
return length;
}
太棒了,它的确有效,但是!我还有2个问题:
答案 0 :(得分:1)
读取文件以便MediaPlayer可以找到持续时间显然需要一些时间。由于您在UI线程上运行此操作,这将减慢整个应用程序的速度。
我对如何加快这个过程没有任何建议,但如果你在AsyncTask的后台线程中完成这项工作,你可以使你的应用程序运行得更顺畅。这可能看起来像这样:
private class GetAudioFilesLength extends AsyncTask<Void, Void, Void> {
List<File> mFiles = new ArrayList<File>();
public GetAudioFilesLength(List<File> theFiles){
mFiles = theFiles;
}
@Override
protected String doInBackground(String... params) {
for(File file : mFiles){
int length = calculateLength(file);
// Do something with the length
// You might want to update the UI with the length of this file
// with onProgressUpdate so that you display the length of the files
// in real time as you process them.
}
}
@Override
protected void onPostExecute(String result) {
// Update the UI in any way you want. You might want
// to store the file lengths somewhere and then update the UI
// with them here
}
@Override
protected void onPreExecute() {
}
@Override
protected void onProgressUpdate(Void... values) {
}
}
如果您想开始处理,只需致电new GetAudioFilesLength(files).execute()
编辑以回答其他问题:
它看起来和原始代码一样高效。现在的区别是用户仍然可以与您的应用程序进行交互,因为工作将在后台线程中完成。有可能有一种更有效的方式来读取音频文件的长度,但我不知道那是什么。如果你知道采样率和编码,我可以想象你可以编写代码来计算音频的长度,而无需将其加载到MediaPlayer中,这需要更长的时间。但是,再一次,其他人将不得不提供帮助。
我不确定我是否理解问题是什么,但我想您是在问如何使用onProgressUpdate更新UI并将长度添加到ListView?
您可以将doyncTask生成的中间参数更改为doInBackground中的String(或其他)AsyncTask<Void, String, Void>, that tells onProgressUpdate what you will be passing to it. You can then call
publishProgress`以相应地更新UI。
@Override
protected String doInBackground(Void... params) {
for(File file : mFiles){
int length = calculateLength(file);
// Do something with the length
// You might want to update the UI with the length of this file
// with onProgressUpdate so that you display the length of the files
// in real time as you process them.
publishProgress("The length of " + file.getName() + " is: " + length);
}
}
@Override
protected void onPostExecute(Void result) {
// Update the UI in any way you want. You might want
// to store the file lengths somewhere and then update the UI
// with them here
}
@Override
protected void onProgressUpdate(String... values) {
// You'll have to implement whatever you'd like to do with this string on the UI
doSomethingWithListView(values[0]);
}