我有一个类DownloadAndSave
,它来自AsyncTask
。在其doInBackground
方法中,它从http连接检索数据并使用OrmLite保存数据,但也清除数据库中的旧条目。所以,像这样:
doInBackground()
{
clearDb();
dataList = fetchDataFromHttp();
saveToDb(dataList);
}
我经常遇到数据库异常:
尝试重新打开已关闭的对象:SQLiteDatabase
在clearDb()和saveToDb()函数中。
这很糟糕,因为之前调用DownloadAndSave
的旧数据与来自DownloadAndSave
的新数据混合在一起。
在我看来,我需要确保当我开始一个线程时,来自DownloadAndSave
类的所有其他步骤都已完成,或者换句话说,我需要运行最多一个{{1}的实例1}}一次。所以问题是:我如何确保只有DownloadAndSave
的一个实例可以在任何时间点运行?
答案 0 :(得分: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可以保证任务以串行方式执行。
答案 1 :(得分:2)
自Android API的API版本11(HONEYCOMB
)起,AsyncTask
在给定executed上可为Executor
。您可以使用默认的SerialExecutor按顺序执行任务。
答案 2 :(得分:0)
如果在doInBackground中使用db操作,则应该为一个线程锁定db。
public void insertToDb(){
SQliteDatabase db;
...
db.beginTransaction();
...//operation
db.yieldIfContendedSafely();
db.setTransactionSuccessful();
db.endTransaction();
}
答案 3 :(得分:0)
我相信您遇到的问题是您正在从活动中启动AsyncTask。您的活动是扩展ORMLiteBaseActivity,它打开帮助程序(以及数据库)onCreate并将其关闭onDestroy。当您退出活动并且后台任务仍然没有完成时,那么当您尝试写入数据库时,您最终会关闭一个数据库。
ORMLite在内部处理同步,我从来不需要用它来执行同步块。我在需要数据库的所有项目中使用它。
另外,对于其他答案,错误是一个封闭的数据库而不是并发写操作,因此同步没有意义。