2013-10-08 31 views
3

我有一个类,DownloadAndSave,从AsyncTask延伸。在其doInBackground方法中,它从http连接中检索数据并使用OrmLite保存数据,但也清除数据库中的旧条目。所以,这样的事情:如何确保只有一个AsyncTask在后台运行

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

我经常得到一个DB例外:

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

在clearDb

()和saveToDb()函数。

而这是不好的,因为来自前一个DownloadAndSave调用的旧数据与来自DownloadAndSave的新数据混合在一起。

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

+0

您是否正在扩展ORMLite附带的活动并在异步任务中使用getHelper? – DArkO

+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可确保任务按顺序执行。

+0

感谢您的评论,关于方法一,我已经尝试过,但问题是我不能使用发布进度,而代码是在同步块中,我需要发布进度来显示线程的进度,关于ormLite异常Im仍然没有尝试它,但我写了有关结果后,我有它,再次感谢 – user1796624

+0

在WorkerClass中添加一个回调接口,并在publishProgress中实现... performWork在后台线程中工作,而publishProgress正在做它的东西在UI线程中。我将很快更新答案 – gunar

+0

关闭的数据库并不意味着并发写入操作。所以同步没有意义 – DArkO

0

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

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

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

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

对于其他答案,错误是一个封闭的数据库,而不是并发写操作,所以同步没有意义。

+0

感谢您的评论,实际上我没有扩展ORMLiteBaseAchatic DatabaseHelper dbHelper,并在clearDb()和saveToDb()函数中实现了DatabaseHelper.getHelper()。getDao()in try(),catch(),finally {},最后{}我使用OpenHelperManager.releaseHelper() ; – user1796624

相关问题