应用程序通过计算WAV文件的长度(以秒为单位)来减慢速度

时间:2013-04-12 16:52:40

标签: android performance listview size duration

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

  1. 首先,我为soundFiles的实例创建一个ArrayList。
  2. 然后在for循环中,我通过soundFile.setLength(calculateLength(file [i]))将数据添加到实例。
  3. 在此之后,我启动了CustomArrayAdapter并将其应用到我的listView。
  4. 在我的CustomArrayAdapter中我应用它:tvFileLength.setText(soundFile.getLength()); (虽然持有人......)
  5. 但是因为我这样做,我的应用程序比乌龟慢! (有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个问题:

    1. 这看起来好不过有效吗?
    2. 它适用于我的listview中的前100个元素,之后它显示0秒,它与onProgressUpdate有关,我认为,但我不知道如何才能使这个工作。

1 个答案:

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

编辑以回答其他问题:

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

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

  3. 您可以将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]);
      }