androidandroid-asynctaskandroid-1.6-donut

AsyncTask to run on Activity start fails after previously getting cancelled


I am using an AsyncTask to fetch the ring tone for a contact when my application starts, it works fine until after my Activity closes a couple of times during the AsyncTask, after this happens the AsyncTask will only ever get to onPreExecute() and never doInBackground, so I can never fetch the ringtone then until either a force stop or device restart.

Can anyone explain why this might be happening?

Why the AsyncTask would get to onPreExecute but then never run doInBackground()?

Here is my code: (Following the Shelves source code)

public void getRingTone(){
Log.d("cda", "Into getRingTone");  
if (audio_service.getStreamVolume(AudioManager.STREAM_RING) > 0) { 
    if(aRingTone != null){ 
        oRingtone = RingtoneManager.getRingtone(this, 
              Uri.parse(aRingTone));
    }
    this.setVolumeControlStream(AudioManager.STREAM_RING);

 }
}

private void saveRingToneTask(Bundle outState) {
final SelectRingtoneTask task = srtt;
if (task != null && task.getStatus() != AsyncTask.Status.FINISHED) {
    task.cancel(true);

    srtt = null;
}
}

private void restoreRingToneTask(Bundle savedInstanceState) {

        srtt = (SelectRingtoneTask) new SelectRingtoneTask().execute();

}

private void onAddRingTone() {
srtt = (SelectRingtoneTask) new SelectRingtoneTask().execute();

}

private void onCancelAddRingTone() {
if (srtt != null && srtt.getStatus() == AsyncTask.Status.RUNNING) {
    srtt.cancel(true);
    srtt = null;
}
}

--

@Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
restoreRingToneTask(savedInstanceState);
}

@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
if (isFinishing()) {
    saveRingToneTask(outState);
}
}

private class SelectRingtoneTask extends AsyncTask<String, Void, Void> {


@Override
public void onPreExecute() {
    Log.d("cda", "Into selectRingToneTask - onPreExecute() - " + selectRingtoneFinished);
    findViewById(R.id.answercallimage).setOnClickListener(new OnClickListener() {
        public void onClick(View v) {
            try {
                    serviceBinder.answer(lineId);
                    onCancelAddRingTone();
                } catch (RemoteException e) {

                    e.printStackTrace();
                }
        }
});


    findViewById(R.id.declinecallimage).setOnClickListener(new OnClickListener() {
        public void onClick(View v) {

            mNotificationManager.cancel(2);
            callConnected = false;

            try {
                serviceBinder.reject(lineId);
                onCancelAddRingTone();
            } catch (RemoteException e) {

                e.printStackTrace();
            }
        }
});

}



public Void doInBackground(String... params) {
    Log.d("cda", "Into selectRingToneTask - !!!!!!!!!!!!!!!");
    if(!this.isCancelled()){
    getRingTone();
    }
    return null;

}

@Override
public void onCancelled() {
    Log.d("cda", "Into selectRingToneTask - onCancelled() - ");
}

@Override
public void onPostExecute(final Void unused) {
     selectRingtoneFinished = true;
       Log.d("cda", "Into selectRingToneTask - onPostExecute - " + selectRingtoneFinished);
       if(oRingtone != null && playRingTone){
            Log.d("cda", "Into getRingTone - PLAY RINGTONE");  
           oRingtone.play();
        }
}
}

And onAddRingtone() is used in onCreate and onCancelRingTone() is used in onDestroy() as well as where you can see if in the code above.

I have spent 3 days on this and I haven't been able to find a solution? Am I taking the wrong approach? Using cancel wrong? Is there a bug?


Solution

  • I believe what is happening is that your AsyncTask has a handle on the old activity, when you create a new one in the middle of the task you have essentially leaked your AsyncTask. The DroidFu library has a workaround for this by keeping track of the active activity in an overridden Application class and an overridden AsyncTask dependent on the Application. Luckily its open source so you can see how they do it. Additional Info