Reputation: 65
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
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