3

我有一堂课,DownloadAndSaveAsyncTask. 在其doInBackground方法中,它从 http 连接检索数据并使用 OrmLite 保存数据,但也从数据库中清除旧条目。所以,像这样:

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

我经常遇到数据库异常:

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

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

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

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

4

4 回答 4

3

选项 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 可以保证任务是按顺序执行的。

于 2013-10-08T12:02:45.383 回答
2

HONEYCOMB由于Android API 的API 版本 11 ( ),AsyncTask可以给定的Executor. 您可以使用默认的SerialExecutor顺序执行任务。

于 2013-10-08T12:32:56.627 回答
0

如果在 doInBackground 中使用 db 操作,则应将 db 锁定为一个线程。

public void insertToDb(){
 SQliteDatabase db;
 ...
 db.beginTransaction();
 ...//operation
 db.yieldIfContendedSafely();
 db.setTransactionSuccessful();
 db.endTransaction();
}
于 2013-10-08T12:02:00.673 回答
0

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

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

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

于 2013-10-08T12:16:42.650 回答