AsyncTask在Android中无法正确重启

时间:2014-10-03 14:59:47

标签: java android multithreading android-asynctask

我正在开发一个Android应用程序,我需要根据共享首选项的变量不时显示提醒对话框。如果用户不想看到提醒消息,他也可以在我的PreferenceActivity中禁用此选项。我正在使用AsyncTask类不时向用户显示提醒消息。用户可以随时按选项按钮转到PreferenceActivity以启用/禁用提醒选项并在提醒之间设置暂停时间值,然后返回活动。所以我正在检查onResume方法中的所有值。如果用户不想看到提醒消息,我需要完成当前工作的AsyncTask,或者如果用户在提醒之间更改了值,我需要使用新的暂停值重新启动当前的AsyncTack。但我看到我的AsyncTack有一种不可预测的行为:有时会停止,有时不会继续工作并显示消息)))),有时它有效,有时 - 不是)))))。这是一段代码:

这是我的AsyncTack类

private class ReadReminderTask extends AsyncTask<Long, Void, Void> {
     private long mRemindTime;
     private volatile boolean running = true;
     public ReadReminderTask(){

     }
     @Override
     public Void doInBackground(Long... params){
         mRemindTime = params[0];
         while (running){
             try{
                 Thread.sleep(mRemindTime);
                 publishProgress();
             }
            catch (Exception e){
                e.printStackTrace();
            }
         }
         return null;
     }

    @Override
    protected void onProgressUpdate(Void... progress) {
        super.onProgressUpdate(progress);
        // showReminder is a method where I show remind message
        showReminder();
    }

    @Override
    protected void onCancelled() {
        running = false;
    }
 }

这是我的Activity的onResume方法,我需要在其中显示提醒消息:

if(!settings.getBoolean("needToRemind", false)) {
        mReadReminderTask.cancel(true);
    } else if(settings.getBoolean("needToRemind", false)) {
        mReadReminderTask = new ReadReminderTask();
        mReadReminderTask.execute(settings.getLong("timeRemind", 1));
    }

任何人都可以帮我解决问题吗?

4 个答案:

答案 0 :(得分:1)

这真的不是一个很好的方法。发生“不可预测的行为”是因为即使在Activity停止后您仍然运行任务。 cancel中对onResume的调用不仅太晚了,实际上根本没有做任何事情。

看看Handler.postDelayed。你想要这样的东西:

onCreate

hdlr = new Handler();
reminder = new Runnable() { public void run() { showReminder(); } }

已编辑为必须延期的第二个参数添加

...在onResume

hdlr.postDelayed(reminder, mRemindTime);

......以及onPause

hdlr.removeCallbacks(reminder);

答案 1 :(得分:1)

请注意,AsyncTask.cancel()并没有真正取消正在运行的任务。相反,它只设置一个标志来通知已请求取消。是否以及何时考虑此标志取决于AsyncTask实现。

Thread.sleep返回后,您当前的代码不会检查取消。正确的实施将是这样的:

public Void doInBackground(Long... params){
     mRemindTime = params[0];
     while (!isCancelled()){
         try{
             Thread.sleep(mRemindTime);
             if(!isCancelled())
                 publishProgress();
         }
        catch (Exception e){
            e.printStackTrace();
        }
     }
     return null;
 }

同时属性&#39;运行&#39;并且不需要asynctask中的onCancelled()方法。您可以使用方法&#39; isCancelled()&#39;代替。

答案 2 :(得分:0)

这通常是一个糟糕的解决方案。 AsyncTasks在处理配置更改时效果不佳。

根据延迟的时间长短,您可以使用AlarmManager.setInexactRepeating来显示这些对话框。您可以使用PendingIntentPendingIntent.getService创建新的PendingIntent.getBroadcast,具体取决于您希望如何实现显示对话框 - (来自Service您将只能显示系统状态对话框)。

AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
Intent intentStart = new Intent();
intentStart.setAction(SHOW_DIALOG_ACTION);
PendingIntent pendingIntentStart = PendingIntent.getBroadcast(context, 0, intentStart, 0);

注册一个BroadcastReceiver,它将处理显示对话框。

如果延迟时间不长,您可以创建一个自定义ThreadPoolExecutor,它可以满足您的需求。

答案 3 :(得分:0)

我不认为应该使用AsyncTask。 Thread.sleep(mRemindTime)也非常难看!如果您需要使用计时器CountDownTimer