0

我正在使用这个库:https ://github.com/alxrm/audiowave-progressbar来提供像 Soundcloud 音乐播放器一样的音频波效果。

这就是我实现的方式:

byte[] data = convert(songsList.get(currentSongIndex).get("songPath"));

final AudioWaveView waveView = (AudioWaveView) findViewById(R.id.wave);

waveView.setScaledData(data);
waveView.setRawData(data, new OnSamplingListener() {
    @Override
    public void onComplete() {

    }
});

waveView.setOnProgressListener(new OnProgressListener() {
    @Override
    public void onStartTracking(float progress) {

    }

    @Override
    public void onStopTracking(float progress) {

    }

    @Override
    public void onProgressChanged(float progress, boolean byUser) {

    }
});

这是使用所述文件的路径将文件转换为字节数组的方法

public byte[] convert(String path) throws IOException {

    FileInputStream fis = new FileInputStream(path);
    ByteArrayOutputStream bos = new ByteArrayOutputStream();
    byte[] b = new byte[1024];

    for (int readNum; (readNum = fis.read(b)) != -1;) {
        bos.write(b, 0, readNum);
    }

    byte[] bytes = bos.toByteArray();

    return bytes;
}

也许问题是由于没有异步获取数组,但我不确定。

谁能帮我这个?

编辑:正如@commonsware 正确建议的那样,我这样做了:

 class AudioWave extends AsyncTask<String,Integer,String>{
     private Context mContext;
     private View rootView;
     public MusicPlayerActivity m;
     final AudioWaveView waveView = (AudioWaveView) m.findViewById(R.id.wave);

     public AudioWave(MusicPlayerActivity m1){
         m = m1;
     }
     // Runs in UI before background thread is called
     @Override
     protected void onPreExecute() {
         super.onPreExecute();

         // Do something like display a progress bar
     }
    byte[] b2;
     // This is run in a background thread
     @Override
     protected String doInBackground(String... params){
         // get the string from params, which is an array
         String path = params[0];
         try {
             FileInputStream fis = new FileInputStream(path);
             ByteArrayOutputStream bos = new ByteArrayOutputStream();
             byte[] b = new byte[1024];
             try {
                 for (int readNum; (readNum = fis.read(b)) != -1; ) {
                     bos.write(b, 0, readNum);
                 }

             }catch(IOException e){

             }

         byte[] bytes = bos.toByteArray();
             b2=bytes;
             new MusicPlayerActivity().setData(b2);
         }
         catch (FileNotFoundException e){

         }
         return "lol";
     }

     // This is called from background thread but runs in UI
     @Override
     protected void onProgressUpdate(Integer... values) {

         super.onProgressUpdate(values);

         // Do things like update the progress bar
     }

     // This runs in UI when background thread finishes
     @Override
     protected void onPostExecute(String result) {
         waveView.setScaledData(b2);
         waveView.setRawData(b2, new OnSamplingListener() {
             @Override
             public void onComplete() {

             }
         });

         waveView.setOnProgressListener(new OnProgressListener() {
             @Override
             public void onStartTracking(float progress) {

             }

             @Override
             public void onStopTracking(float progress) {

             }

             @Override
             public void onProgressChanged(float progress, boolean byUser) {

             }
         });

         super.onPostExecute(result);
         // Do things like hide the progress bar or change a TextView
     }
 }
4

3 回答 3

1

以您的方式加载本地文件是完全低效的:

  1. 您正在使用一个非常小的 1024 字节缓冲区。缓冲区越大,您获得的速度就越好,特别是考虑到智能手机使用闪存,而闪存在内部使用更大的内存块。

  2. 您正在使用ByteArrayOutputStream. 这是一个动态增长的字节数组。每次它超过当前缓冲区的大小时,都会将所有内容从旧缓冲区复制到新缓冲区。由于它是一个本地文件,您知道文件大小,因此您可以使用完整大小初始化缓冲区。但是你不再需要 ByteArrayOutputStream 了。

因此,您可以使用一个读取命令简单地加载文件:

File f = new File(path);
int size = (int) g.length();
byte[] fileData = new byte[size];
try (DataInputStream in = new DatInpuStream(FileInputStream(f)))) {
    in.readFully(fileData);
}

无论如何,这仅适用于“小”文件,因为您将其完全加载到内存中。如果您的 AudioWaveView 支持它,您应该使用流式处理方法:将 FileInputStream 与 BufferedInputStream 包装在一起,并将其缓冲区大小设置为 512KB 左右。

于 2017-01-31T16:27:38.110 回答
0

在主应用程序线程上执行 I/O 将在该 I/O 期间冻结您的 UI,这意味着您的 UI 将无响应。将 I/O 移动到后台线程对于表现良好的 UI 是必要的。

Android 坚持我们只能从主应用程序线程安全地更新 UI,这意味着您需要使用AsyncTask、aThread和诸如runOnUiThread()RxJava/RxAndroid 之类的东西,或其他方法来安排后台工作并在后台工作时更新 UI完毕。

在您的情况下,在convert()后台线程上执行逻辑并waveView在主应用程序线程上更新应该会有所帮助。

于 2017-01-31T18:16:01.410 回答
-1

请使用此功能来提高性能---

private static byte[] readBytesFromFile(String filePath) {

        FileInputStream fileInputStream = null;
        byte[] bytesArray = null;

        try {

            File file = new File(filePath);
            bytesArray = new byte[(int) file.length()];

            //read file into bytes[]
            fileInputStream = new FileInputStream(file);
            fileInputStream.read(bytesArray);

        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (fileInputStream != null) {
                try {
                    fileInputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

        }

        return bytesArray;

    }
于 2017-01-31T18:33:41.637 回答