Расписание обслуживания в будущем и конфликт базы данных - PullRequest
0 голосов
/ 17 декабря 2011

Я создал службу переднего плана, которая работает с работающим объектом, который запланирован через некоторое время. Работает долго. Сначала у меня был этот код в сервис:

private final Handler handler = new Handler();
...
...
public int onStartCommand(...
    handler.postDelayed(sendUpdatesToUI, 50); 
...

   private Runnable sendUpdatesToUI = new Runnable() {
        public void run() {
            try {
                DBAdapter DB = new DBAdapter(MyService.this);
                DB.open();
                DB.insertData(System.currentTimeMillis(), "",
                    cronometro.tiempo_original, 0) ;
                DB.close();
            } catch (Exception e) {
                Toast.makeText(MyService.this, e.toString(),Toast.LENGTH_LONG).show();
            }
            SendInfo();
            handler.postDelayed(this, 300000); 
     }
    };

Но в приведенном выше коде есть проблема: обработчик запускается в потоке пользовательского интерфейса, поэтому, если действия пользовательского интерфейса не находятся в памяти, функция с задержкой не работает, так как рабочий поток больше не активен. Поэтому я изменил код, чтобы использовать системный планировщик между планировщиком (обработчиком) конкретной активности. Теперь код выглядит так:

private final ScheduledExecutorService schedulerService = Executors.newScheduledThreadPool(1);
private ScheduledFuture scheduleFuture;
...
...
public int onStartCommand(...
    scheduleFuture = schedulerService.schedule(sendUpdatesToUI,50, TimeUnit.MILLISECONDS);
...


   private Runnable sendUpdatesToUI = new Runnable() {
        public void run() {
            try {
                DBAdapter DB = new DBAdapter(MyService.this);
                DB.open();
                DB.insertData(System.currentTimeMillis(), "",
                    cronometro.tiempo_original, 0) ;
                DB.close();
            } catch (Exception e) {
                Toast.makeText(MyService.this, e.toString(),Toast.LENGTH_LONG).show();
            }
            SendInfo();
            scheduleFuture = schedulerService.schedule(sendUpdatesToUI,300000,TimeUnit.MILLISECONDS);
     }
    };

Этот второй код является правильным способом сделать это для долгой службы, деятельность которой не будет впереди. Как видите, код делает то же самое, но он позволяет избежать проблемы использования обработчика, который зависит от основного потока пользовательского интерфейса.

Если я прокомментирую код SQL для обоих, они отлично работают, пока основное действие находится на вершине. Но если я не комментирую SQL-код, второй пример зависает и не запускается. Он останавливается на sqlcode, потому что DatabaseHelper нужен действительный контекст, а поскольку executors является системным контекстом, он не работает. Любой контекст, который я помещаю в DBAdapter (context) (например, getApplicationContext (), getBaseContext () или MyService.this), не работает.

Кто-нибудь знает, как я могу предоставить действительный контекст для второго примера?

1 Ответ

2 голосов
/ 17 декабря 2011

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

Службы совместно используют тот же основной поток приложения («поток пользовательского интерфейса»), что и действия.AFAIK, это должно «работать» независимо от состояния интерфейса.Это плохая реализация по другим причинам (см. Ниже).

Этот второй код является правильным способом сделать это для долгой службы, деятельность которой не будет впереди.

Это постепенно лучше, чем первая реализация.Оба бедны.Пожалуйста, используйте AlarmManager и IntentService, чтобы не тратить ресурсы пользователя, пока ваша служба ничего не делает в течение пяти минут.

Останавливается на sqlcode, потому что DatabaseHelper нужен действительный контексти, поскольку executors является системным контекстом, он не запускается.

Ваша заявка не имеет смысла.Вы используете объект Service, который является допустимым Context, пока работает Service.ScheduledExecutorService является обычным объектом Java и не может предоставить Context.Я понятия не имею, что вы думаете о «системном контексте».

Любой контекст, который я помещаю в DBAdapter (context) (например, getApplicationContext (), getBaseContext () или MyService.this), не работает.

Тогда возникает другая проблема, такая как проблема синхронизации / взаимоблокировки с несколькими потоками, обращающимися к базе данных, или, возможно, ваш Service уничтожен (и, следовательно, вы пропустили этот фоновый поток).

Если вы используете AlarmManager и IntentService и выполняете ввод / вывод в базу данных в onHandleIntent(), используя SQLiteOpenHelper, который используется всеми компонентами (этой службой и вашими действиями),у вас должны быть лучшие результаты.

...