Mardini
Mardini

Reputation: 65

Android UI thread time issue

I have a question regarding the UI Thread in Android:

My activity extends AsyncTask to do some calculations on wave file. If I run the application once, it takes around 15 min to finish. This is not problem for me. I want to start the process multiple times(for example 4 times, because I have 4 wave files) so I expect the time to be 1 h (15 min* 4= 1h), but this is not the case, it lasts for about 3 hours !

In order to start the process multiple times, I created a function that calls "new ProcessTask().execute();" 4 times, and I call this function within the "onPostExecute"

Do u have any ide why it requires more time when I run it multiple times?

Thanks in advance for your help

public  void processingRespiratoryFiles() {

        if(p<=MainActivity.count)
        {
        filePath = Environment.getExternalStorageDirectory() + "/external_sd/AudioRecorder/audio"+p+".wav";

        File filein = new File(filePath);
        if (filein.exists()) 
            new ProcessTask().execute();


        }
        else
        {
        RespiratoryHandling(ODI_Sum,0);
        Index.setText(Double.toString(ODI_Sum));
        message2=ODI_Sum;
        }


    }





private class ProcessTask extends AsyncTask<Void, Void, Integer> {

        ProgressDialog dialog;

        @Override
        protected Integer doInBackground(Void... params) {
            return process(filePath);
        }

        @Override
        protected void onPostExecute(Integer result) {////////////////////////////////////////////////////////
            dialog.dismiss();
            if (result > -1)
            {
                p++;
                ODI=(double)result/NumberOfHours;
                ODI_Sum+=ODI;
                processingRespiratoryFiles();


            }
        }

        @Override
        protected void onPreExecute() {
            dialog = ProgressDialog.show(
                    Diagnose.this, "Diagnosing, please wait",
                    "Processing...");
        }
    }


    /**
     * Reset ring buffer for filter process before filtering signal
     * @param alength number of a coefficients
     * @param blength number of a coefficients
     */
    public void resetRingBuffer(int alength, int blength) {
        xv = new double[blength + 1];
        yv = new double[alength + 1];

        px = 0;
        py = 0;
    }

    /**
     * Filter each second of signal and then compute the energy of output
     * @param din input stream of audio file
     * @param length number of read samples
     * @param numChannels number of channels of signal
     * @return energy value of 1 second filtered signal 
     */
    public double readEnergyFiltered(DataInputStream din, int length,
            int numChannels) {
        double energy = 0.0;

        try {
            byte[] byteBuffer = new byte[length * 2 * numChannels]; // 16 bit

            // read length samples from file's stream
            int r = din.read(byteBuffer); // bytes read
            // if reach to end of file
            if (r == -1)
                return -1.0;
            r = r / (2 * numChannels); // samples read

            // apply the filter
            for (int i = 0; i < r; ++i) {
                // get the new sample
                short sample = (short) ((byteBuffer[2 * numChannels * i] & 0xff) | (byteBuffer[2
                        * numChannels * i + 1] & 0xff) << 8);
                xv[px] = (double) sample / 32768.0;

                // compute the output
                double y = bcoef[0] * xv[px];
                for (int j = 1; j < bcoef.length; ++j)
                    y += bcoef[j] * xv[(px - j + xv.length) % xv.length];
                for (int j = 1; j < acoef.length; ++j)
                    y -= acoef[j] * yv[(py - j + yv.length) % yv.length];

                // save the result
                yv[py] = y;

                // update energy
                energy += y * y;

                // increment the index of the ring buffer
                px = (px + 1) % xv.length;
                py = (py + 1) % yv.length;
            }

            return energy;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return -1.0;
    }

    /**
     * Process the filtering, computing energy and estimating number of events 
     * @param filePath path to audio file on sd card
     * @return number of events
     */
    private int process(String filePath) {
        try {
            int event = 0;
            double sum =0.0;

            byte[] header = new byte[44];

            File filein = new File(filePath);
            FileInputStream fin = new FileInputStream(filein);
            BufferedInputStream bin = new BufferedInputStream(fin);
            DataInputStream din = new DataInputStream(bin);

            din.read(header);

            // Sample Rate
            int fs = (header[24] & 0xff) | (header[25] & 0xff) << 8
                    | (header[26] & 0xff) << 16 | (header[27] & 0xff) << 24;
            double Ts = 1.0 / fs;
            Log.v("PERM", "Sample Rate: " + String.valueOf(fs));

            // Num Channels
            int numChannels = (header[22] & 0xff) | (header[23] & 0xff) << 8;
            Log.v("PERM", "Num Channel: " + String.valueOf(numChannels));

            // Bits Per Sample
            int bitsPerSample = (header[34] & 0xff) | (header[35] & 0xff) << 8;
            Log.v("PERM", "Bits per sample: " + String.valueOf(bitsPerSample));

            // Sample Rate
            int numBytes = (header[40] & 0xff) | (header[41] & 0xff) << 8
                    | (header[42] & 0xff) << 16 | (header[43] & 0xff) << 24;
            int N = numBytes / numChannels / (bitsPerSample / 8);
            Log.v("PERM", "Data Length: " + String.valueOf(N));

            // Calibration phase
            // Find average energy for the first 180 seconds
            double energy = 0.0;
            resetRingBuffer(acoef.length, bcoef.length);
            for (int i = 0; i < 30; i++) {
                sum = readEnergyFiltered(din, fs, numChannels);
                energy += sum * Ts;
            }
            if(MainActivity.count==1)
            {
             mean_energy = energy / 30.0;
             ThresholdR = 0.8 * mean_energy;
            }

            Log.v("PERM", "Threshold: " + String.valueOf(ThresholdR));

            // process hold file
            resetRingBuffer(acoef.length, bcoef.length);
            din.close();
            bin.close();
            fin.close();

            fin = new FileInputStream(filein);
            bin = new BufferedInputStream(fin);
            din = new DataInputStream(bin);
            din.read(header);

            N = N / fs;
            int j = 1;
            while (j <= N) {
                int counter = 0;
                //int trigger = 0;
                energy = readEnergyFiltered(din, fs, numChannels) * Ts;
                if (energy >= 0.) {

                    Log.v("PERM", "Energy " + String.valueOf(energy));
//while ((energy <= Threshold) || (trigger < 4))
                    while ((energy < ThresholdR)) {
                        counter++;
                        energy = readEnergyFiltered(din, fs, numChannels) * Ts;
                        Log.v("PERM", "Inner Energy " + String.valueOf(energy));
                        if (energy < 0)
                            break;
                        //trigger++;
                    }
                }

                if (counter > 10)
                    event++;

                if (counter > 0)
                    j += counter;
                else
                    j++;
            }

            Log.v("PERM", "Event: " + String.valueOf(event));

            din.close();
            bin.close();
            fin.close();

            return event;
        } catch (Exception e) {
            e.printStackTrace();
        }

        return -1;
    }

Upvotes: 0

Views: 268

Answers (1)

Joe Malin
Joe Malin

Reputation: 8641

This really needs to be done in an IntentService. If you use AsyncTask and accidentally flip your device, your Activity will restart and the AsyncTask will be gone. An IntentService will allow you to "move" away from the current Activity.

Although, I have to say, if you're willing to wait 15 minutes for the AsyncTask to finish, then your app is unusual.

Upvotes: 3

Related Questions