【问题标题】:how to make sure that only one AsyncTask runs in the background如何确保只有一个 AsyncTask 在后台运行
【发布时间】:2013-10-08 11:51:32
【问题描述】:

我有一个类,DownloadAndSave,它从 AsyncTask 扩展而来。在其doInBackground 方法中,它从http 连接检索数据并使用OrmLite 保存数据,但也从数据库中清除旧条目。所以,是这样的:

doInBackground()
{
  clearDb();
  dataList = fetchDataFromHttp();
  saveToDb(dataList);
}

我经常遇到数据库异常:

尝试重新打开一个已经关闭的对象:SQLiteDatabase

在 clearDb() 和 saveToDb() 函数中。

这很糟糕,因为先前调用 DownloadAndSave 的旧数据与来自 DownloadAndSave 的新数据混合在一起。

在我看来,我需要确保当我启动一个线程时,DownloadAndSave 类中的所有其他线程都已完成,或者换句话说,我最多需要运行 DownloadAndSave 的一个实例一次。所以问题是:我如何确保在任何时间点只有一个 DownloadAndSave 实例会运行?

【问题讨论】:

  • 您是否扩展了 ORMLite 附带的活动并在异步任务中使用 getHelper?
  • 您是否尝试过同步为您的目的?

标签: android sqlite android-asynctask ormlite


【解决方案1】:

选项 1。上移:

clearDb();
dataList = fetchDataFromHttp();
saveToDb(dataList);

在与类对象同步的单独类中:

public class WorkerClass {
    private WorkerListener workerListener;

    public static interface WorkerListener {
        public void publishWorkProgress(String data);
    }

    public WorkerClass(WorkerListener workerListener) {
        this.workerListener = workerListener;
    }

    public void performWork() {
        synchronized (WorkerClass.class) {
             clearDb();
             publish("Cleared DB");
             dataList = fetchDataFromHttp();
             publish("Got http data");
             saveToDb(dataList);
             publish("There! saved!");
        }
    }

    private void publish(String message) {
        if(workerListener != null) {
            workerListener.publishWorkProgress(message);
        }
    }

}

活动期间:

public class SampleActivity extends Activity {

    public void doTheThing() {
        new MyAsyncTask().execute();
    }

    private static class MyAsyncTask extends AsyncTask<Void, String, Void> implements WorkerListener {
        @Override
        protected Void doInBackground(Void... params) {
            new WorkerClass(this).performWork();
            return null;
        }

        @Override
        public void publishWorkProgress(String data) {
            publishProgress(data);
        }
    }
}

选项 2:将上面的代码移动到 IntentService:

public class WorkerIntentService extends IntentService {
   public WorkerIntentService() {
       super(null);
   }

   @Override
    protected void onHandleIntent(Intent intent) {
       clearDb();
       dataList = fetchDataFromHttp();
       saveToDb(dataList);
    }
}

使用 IntentService 可以保证任务是串行执行的。

【讨论】:

  • 感谢您的评论,关于方法一,我试过了,但问题是我不能在代码处于同步块时使用发布进度,我需要发布进度来显示进度线程,关于ormLite异常我还没有尝试过,但是一旦有结果我会写下结果,再次感谢
  • 在 WorkerClass 中添加一个回调接口并在 publishProgress 中实现它...... performWork 在后台线程中工作,而 publishProgress 在 UI 线程中完成它的工作。我会尽快更新答案
  • 关闭数据库并不意味着并发写操作。所以同步没有意义
  • 应用程序至少启动两个作业是有意义的。同步部分就是为了满足这个需求:all of the other treads from the DownloadAndSave class have finished, or in other words I need to run at most one instance of DownloadAndSave at a time.
  • attempt to re-open an already-closed object:SQLiteDatabase - 这不是表明您正在重复使用相同的 SQLiteOpenHelper 对象吗?
【解决方案2】:

自 Android API 的 API 版本 11 (HONEYCOMB) 起,AsyncTask 可以是给定 Executor 上的 executed。您可以使用默认的SerialExecutor 顺序执行任务。

【讨论】:

    【解决方案3】:

    如果你在doInBackground中使用db操作,你应该锁定一个线程的db。

    public void insertToDb(){
     SQliteDatabase db;
     ...
     db.beginTransaction();
     ...//operation
     db.yieldIfContendedSafely();
     db.setTransactionSuccessful();
     db.endTransaction();
    }
    

    【讨论】:

      【解决方案4】:

      我相信您面临的问题是您正在从活动启动 AsyncTask。您的活动正在扩展 ORMLiteBaseActivity,它打开助手(以及数据库)onCreate 并关闭它 onDestroy。当您退出活动且后台任务仍未完成时,当您尝试写入数据库时​​,您最终会得到一个关闭的数据库。

      ORMLite 在内部处理同步,我从来不需要用它做同步块。我在所有需要数据库的项目中都使用它。

      对于其他答案,错误是关闭的数据库而不是并发写入操作,因此同步没有意义。

      【讨论】:

      • 感谢您的评论,实际上我并没有扩展 ORMLiteBaseAchatic DatabaseHelper dbHelper,并且在 clearDb() 和 saveToDb() 内部我在 try() 中执行 DatabaseHelper.getHelper().getDao(), catch(),finally{} 和 finally{} 我使用 OpenHelperManager.releaseHelper() 销毁;
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-01-09
      • 1970-01-01
      • 1970-01-01
      • 2020-10-24
      • 2017-10-01
      • 2020-09-21
      • 1970-01-01
      相关资源
      最近更新 更多