Как убедиться, что только одна AsyncTask работает в фоновом режиме

У меня есть класс DownloadAndSave который простирается от AsyncTask . В методе doInBackground он извлекает данные из http-соединения и сохраняет данные с помощью OrmLite, но также очищает старые записи из базы данных. Итак, что-то вроде этого:

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

Я часто получаю исключение БД:

Попытка повторного открытия уже закрытого объекта: SQLiteDatabase

В функциях clearDb () и saveToDb ().

И это плохо, поскольку старые данные предыдущего вызова DownloadAndSave смешиваются с новыми данными из DownloadAndSave .

На мой взгляд, мне нужно убедиться, что при запуске потока все остальные шаги из класса DownloadAndSave закончены, или, другими словами, мне нужно запустить не более одного экземпляра DownloadAndSave за раз. Поэтому возникает вопрос: как я могу убедиться, что только один экземпляр DownloadAndSave будет работать в любой момент времени?

Вариант 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 гарантирует, что задачи выполняются последовательно.

Поскольку API версии 11 ( HONEYCOMB ) API Android, AsyncTask может быть выполнен на данном Executor . Вы можете использовать SerialExecutor по умолчанию для выполнения задач последовательно.

Если вы используете операцию db в doInBackground, вы должны заблокировать db для одного потока.

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

Я считаю, что проблема, с которой вы сталкиваетесь, заключается в том, что вы запускаете AsyncTask из активности. Ваша деятельность расширяет ORMLiteBaseActivity, которая открывает помощника (и с этой базой данных) onCreate и закрывает его onDestroy. Когда вы выходите из действия, а фоновая задача еще не завершена, при попытке записи в базу данных вы получаете закрытую БД.

ORMLite обрабатывает синхронизацию внутри себя, и мне никогда не приходилось делать с ней синхронизированные блоки. Я использую его во всех моих проектах, требующих базы данных.

Кроме того, для других ответов ошибка представляет собой закрытую базу данных, а не одновременные операции записи, поэтому синхронизация не имеет смысла.

Intereting Posts