У меня проблемы с завершением AsyncTask, хотя ИМХО, я придерживался рекомендованной практики пометки. В приведенном ниже коде учитывается только BackButton, но лучше всего иметь общее решение для всех видов выхода из действия.
У меня есть класс MeasurementLoadingsScreen, который связывает службу следующим образом:
ServiceConnection _connection = new ServiceConnection() {
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
_service = myService.Stub.asInterface(iBinder);
runMeasurementAsyncTask();
}
public void onServiceDisconnected(ComponentName componentName) {
_service = null;
}
};
@Override
protected void onStart() {
super.onStart();
Intent serviceIntent = new Intent();
serviceIntent.setPackage(myService.class.getPackage().getName());
serviceIntent.setAction(myService.class.getName() + ".ACTION_BIND");
bindService(serviceIntent, _connection, BIND_AUTO_CREATE);
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_measurement_loadingscreen);
findViewsById();
setDefaultVisibility();
intent = getIntent();
//myStuff
}
Экран MeasurementLoadingScreen содержит AsyncTask с WeakReference (или SoftReference, попробовал оба).
private void runMeasurementAsyncTask() {
//myStuff
meTask = new MeasurementTask(this);
meTask.execute();
}
private static class MeasurementTask extends AsyncTask<Integer, Integer, String> {
private WeakReference<MeasurementLoadingScreen> activityReference;
private ServiceHelper serviceHelper;
//myStuff
public static boolean isRunning = false;
MeasurementTask(MeasurementLoadingScreen context) {
activityReference = new WeakReference<>(context);
serviceHelper = new ServiceHelper(context._service);
}
@Override
protected String doInBackground(Integer... params) {
MeasurementLoadingScreen activityReference = this.activityReference.get();
isRunning = true;
//myStuff, it's ok to finish running this before cancelling
if (isCancelled()) {
return "cancelled";
}
// more myStuff
if (isCancelled()) {
return "cancelled";
}
[...]
@Override
protected void onCancelled(){
//myStuff: safely shutdown measurement process, might take a few seconds at worst
meTask.isRunning = false;
if(activityReference.get() != null) {
activityReference.get().finish(); //it does not work without this, either
}
super.onCancelled();
}
Когда я возвращаюсь дважды (независимо от поведения c), он должен (безопасно) прерваться AsyncTask:
@Override
public void onBackPressed()
{
if (mBackPressed + TIME_INTERVAL > System.currentTimeMillis())
{
if (meTask == null) {
super.onBackPressed();
return;
}
cancelTask();
Toast.makeText(getBaseContext(), "Cancelling Task", Toast.LENGTH_SHORT).show();
return;
}
else { Toast.makeText(getBaseContext(), "Tap back button in order to exit", Toast.LENGTH_SHORT).show(); }
mBackPressed = System.currentTimeMillis();
}
@Override
protected void onStop() {
super.onStop();
if (_connection != null)
unbindService(_connection);
finish();//
}
@Override
public void onPause() {
int i = 0;
super.onPause();
//poll state of task here
finish();
}
Кажется, мне не удается остановить выполнение задачи. Если я установил meTask = null; в onPause, например, он в конечном итоге будет go через onCancelled, а затем вызовет onStop, также завершив службу. Но нет никакого способа дождаться, пока onCancelled сделает свое дело и уведомит меня с помощью isRunningflag, getStatus или чего-то еще. Приложение просто зависает, однако я опрашиваю задачу, которая все время остается ВЫПОЛНЕННОЙ, если я не установил для нее значение null (конечно, нежелательно).
Изменить: я добавил попытку опроса, которая позволяет вызывать действие onPause / onStop в конечном итоге, но моя основная проблема связана с опросом, я никогда не вижу завершенную / завершающую задачу, хотя onCancelled вызывается в какой-то момент, но только после того, как я установил meTask = null;, он не продолжает отмену
public void onBackPressed() {
int i=0;
if (mBackPressed + TIME_INTERVAL > System.currentTimeMillis())
{
if (meTask == null) {
super.onBackPressed();
return;
}
cancelTask();
Toast.makeText(getBaseContext(), "Cancelling Task", Toast.LENGTH_SHORT).show();
while ((meTask.getStatus()== AsyncTask.Status.RUNNING) && (i < 20000)) {
//waiting etc., checking für isRunning doesn't work either
i++;
}
Log.d(TAG, "meTask " + meTask.getStatus());
meTask = null;
Log.d(TAG, "meTask null after " + i);
super.onBackPressed();
return;
Edit 2:
Content of cancelTask()
private void cancelTask() {
if (meTask != null) {
Log.d(TAG, "Async Task Cancel... ");
meTask.cancel(true);
}
}
Редактировать 3: Независимо от того, где я поставил отмену (true), например onPause, onStop, задача остается активной и дает мне только вывод журнала
if (isCancelled()) {
Log.d(TAG, "Cancel after XYZ");
return "cancelled";
}
и
@Override
protected void onCancelled() {
super.onCancelled();
isRunning = false;
Log.d(TAG, "...Async Task Cancelled ");
}
в самом конце, после завершения onPause, onStop, onDestroy. Я в своем уме. Неудивительно, что Задача продолжает работать некоторое время, но она должна остановиться до того, как служба освободится. Как дождаться завершения задачи sh?