0

在文件夹中声音文件的 ListView 中,我想以秒为单位显示文件的长度。我采取的步骤:

  1. 首先,我为 soundFiles 的实例创建一个 ArrayList。
  2. 然后在 for 循环中,我通过 soundFile.setLength(calculateLength(file[i])) 将数据添加到实例中。
  3. 在此之后,我启动了我的 CustomArrayAdapter 并将它应用到我的 listView。
  4. 在我的 CustomArrayAdapter 我应用它: tvFileLength.setText(soundFile.getLength()); (虽然有一个持有人..)

但是因为我这样做了,所以我的应用程序比乌龟还慢!(有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();

异步任务

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;

    }

太棒了,它部分工作,但是!我还有两个问题:

  1. 这看起来不错且有效吗?
  2. 它适用于让我们说我的列表视图中的前 100 个元素,之后它显示 0 s,它与我假设的 onProgressUpdate 有关,但我不确定如何使它工作。
4

1 回答 1

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()

编辑以回答其他问题:

  1. 它看起来和您的原始代码一样高效。现在的不同之处在于用户仍然可以与您的应用程序交互,因为工作将在后台线程中完成。可能有一种更有效的方法来读取音频文件的长度,但我不知道那是什么。如果您知道采样率和编码,我可以想象您可以编写代码来计算音频的长度,而无需将其加载到 MediaPlayer 中,这需要更长的时间。不过,再一次,其他人将不得不提供帮助。

  2. 我不确定我是否理解问题所在,但我想您是在问如何使用 onProgressUpdate 更新 UI 并将长度添加到 ListView?

您可以将 AsyncTask 生成的中间参数更改为AsyncTask<Void, String, Void>, that tells onProgressUpdate what you will be passing to it. You can then call来自 doInBackground 的字符串(或其他)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]);
  }
于 2013-04-12T17:05:00.000 回答