javaandroidperformancebytearrayinputstream

Converting file to byte array slowing down the app


I'm using this library: https://github.com/alxrm/audiowave-progressbar to give an audio wave effect like Soundcloud music player.

This is how I implemented:

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

    }
});

This is the method that converts the file to byte array using the said file's path

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;
}

Maybe the problem is due to not getting the array asynchronously, but I'm not sure.

Can anyone help me with this?

EDIT: As @commonsware suggested correctly, I did this:

 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
     }
 }

Solution

  • Doing I/O on the main application thread will freeze your UI for the duration of that I/O, meaning that your UI will be unresponsive. Moving I/O to a background thread is necessary for a well-behaved UI.

    Android's insistence that we can only safely update the UI from the main application thread means that you need to use an AsyncTask, a Thread and stuff like runOnUiThread(), RxJava/RxAndroid, or other approaches to arrange both the background work and updating the UI when that background work is done.

    In your case, doing the convert() logic on a background thread, and updating the waveView on the main application thread, should help.