IntentService застревает

Я создал приложение, которое использует IntentService для управления базой данных приложения и вызова веб-служб.

Пример:

У меня есть активность, которая представляет собой список элементов. Этот список заполняется CursorAdapter. У каждого элемента есть флажок, и список упорядочен по отмеченным (неотмеченные элементы вверху и отмеченные элементы внизу). Когда флажок элемента установлен, я отправляю Intent в свой IntentService, сообщая ему, чтобы отметить отмеченный столбец в таблице базы данных для этого элемента, затем передается сообщение, действие видит его и повторно запрашивает курсор.

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

Насколько я понимаю, намерения, переданные в IntentServices, не обрабатываются асинхронно. Это правильно? Он ведет себя почти так, как будто мне нужно использовать семафоры, но я не могу понять, почему, если намерения ставятся в очередь и обрабатываются индивидуально.

Допустим, я установил 3 флажка; поэтому в очереди 3 намерения. После первого я передаю сообщение, которое получает действие, сообщая ему, что нужно запросить его курсор. Может ли потенциальная проблема заключаться в том, что я повторно запрашиваю курсор одновременно с обработкой второго намерения (обновлением другой строки в таблице)? Запрос курсора происходит в потоке пользовательского интерфейса.

^ Я думаю, что это моя проблема. Что я должен использовать для синхронизации этого? Семафоры? Может ли кто-нибудь указать мне на некоторые документы/примеры?

Другая потенциальная проблема заключается в том, что если моя активность управляет курсором на столе; также мой IntentService запрашивает курсор из той же таблицы. У меня есть случаи, когда это происходит, когда мой IntentService просматривает каждую строку в курсоре, чтобы найти элементы для отправки в веб-службу. Хотя я не думаю, что это будет проблемой, пока курсоры не запрашивают одновременно?

У кого-нибудь есть другие идеи?


person Andrew    schedule 06.10.2010    source источник
comment
Несколько быстрых мыслей: я бы добавил ведение журнала в каждую часть системы, чтобы действительно найти, в чем проблема. Является ли уровень доступа к БД ContentProvider (они не предназначены для многопоточности)? Кроме того, зачем использовать IntentService, когда подойдет обработчик в действии? Аналогичным образом, зачем беспокоиться об асинхронной публикации обновлений, если действие все равно запрашивает БД в основном потоке, а не (скажем) в AsyncQueryHandler?   -  person Christopher Orr    schedule 06.10.2010
comment
Да, мой доступ к БД осуществляется через ContentProvider. Я посмотрю на AsyncQueryHandler   -  person Andrew    schedule 07.10.2010


Ответы (1)


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

Это похоже на «бьюик, чтобы прихлопнуть муху».

Насколько я понимаю, намерения, переданные в IntentServices, не обрабатываются асинхронно. Это правильно?

onHandleIntent() в вашем IntentService вызывается в фоновом потоке, а startService() всегда асинхронно.

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

Отдельные Intents ставятся в очередь и последовательно обрабатываются IntentService.

Может ли потенциальная проблема заключаться в том, что я повторно запрашиваю курсор одновременно с обработкой второго намерения (обновлением другой строки в таблице)?

Это, конечно, не помогает.

Что я должен использовать для синхронизации этого? Семафоры?

Я бы просто использовал synchronized(someStaticDataMember), но семафоры должны работать.

Хотя я не думаю, что это будет проблемой, пока курсоры не запрашивают одновременно?

Фактический запрос не выполняется до тех пор, пока не коснется Cursor (например, moveToFirst(), getCount()). После этого, пока набор результатов запроса меньше 1 МБ, результаты полностью находятся в папке Cursor.

Я частично согласен с Кристофером: используйте ведение журнала, чтобы точно выяснить, что происходит, и подумайте о том, чтобы сделать это немного более легким (например, AsyncTask для записи в базу данных, а не IntentService).

person CommonsWare    schedule 06.10.2010
comment
Что, если я создам поток для записи в базу данных, но действие будет восстановлено до того, как поток завершится? Я понимаю, что вероятность невелика, поскольку запись — это быстрая операция, но скажем, я пишу массив объектов. Эти данные связаны с действием, и, если действие восстановлено, у моего потока проблемы. Можете ли вы указать мне пример синхронизации статического члена? Я делал это на конструкторах singleton, но я не совсем уверен, как обернуть его вокруг двух отдельных блоков кода. - person Andrew; 07.10.2010
comment
Я также должен отметить, что мои вставки/обновления/удаления базы данных находятся в IntentService из-за видео, которое я смотрел. Есть презентация Google I/O 2010, в которой инженер Google рассказывает о моделях для создания приложений с большим объемом веб-сервисов. Он утверждает, что длительные операции, включая вызовы базы данных, должны выполняться в Сервисе. - person Andrew; 07.10.2010
comment
@Andrew: если действие восстановлено, у моего потока проблемы - почему? AsyncTask будет выполняться до завершения. Можете ли вы указать мне пример синхронизации статического члена? -- не совсем, это тривиальная Java. Если вы можете написать IntentService, использование ключевого слова synchronized() должно быть легкой прогулкой! Он утверждает, что длительные операции, включая вызовы базы данных, должны выполняться в Сервисе. -- Я был там. IntentService — не единственный шаблон для выполнения работы вне основного потока приложения, и мы с гуглером просто расходимся во мнениях по некоторым вещам. - person CommonsWare; 07.10.2010
comment
@Andrew: И я не говорю, что вам нужно отказаться от использования IntentService, просто я бы не стал использовать IntentService для чего-то столь тривиального, как простая операция с базой данных. - person CommonsWare; 07.10.2010
comment
Предположим, у меня есть переменные-члены, принадлежащие Activity, в которых хранятся некоторые фрагменты данных. Я хочу записать эти фрагменты в базу данных. Я запускаю асинтаск для их записи, и, пока асинтаск выполняется, Activity восстанавливается системой или уничтожается (поворот экрана). Не вызовет ли это проблемы? - person Andrew; 07.10.2010
comment
Как мне не получить доступ к данным из основного приложения, когда именно там живут данные, и это то, что мне нужно сохранить? Или вы предлагаете копировать эти данные в переменные в AsyncTask, и операция AsyncTask воздействует на эти переменные? - person Andrew; 07.10.2010
comment
@Andrew: Как мне не получить доступ к данным из основного приложения, когда именно там живут данные, и это то, что мне нужно сохранить? -- Activity - это класс, а не приложение. Или вы предлагаете копировать эти данные в переменные в AsyncTask, и операция AsyncTask воздействует на эти переменные? -- да, скопируйте данные в AsyncTask, точно так же, как вы копируете данные в Intent, используемый с вашим IntentService. - person CommonsWare; 07.10.2010
comment
Мне жаль. Я часто все еще читаю Activity, когда вижу Application. Должен ли я действительно делать эту AsyncTask статической? Предположим, пользователь выполняет несколько действий, каждое из которых требует записи в базу данных. Предположим, что одно из этих действий вызывается до того, как результирующая операция предыдущего действия будет завершена AsyncTask? - person Andrew; 07.10.2010
comment
@Andrew: Это совершенно отдельная проблема, с которой вы столкнетесь независимо от того, как вы выполняете операции с базой данных (AsyncTask, IntentService и т. д.). Типичный подход заключается в блокировании пользовательского ввода, который может повлиять на базу данных, пока выполняется ввод-вывод базы данных. Это одна из причин, по которой вы можете проводить преждевременную оптимизацию. Только протестировав свое приложение, вы сможете определить, действительно ли вам нужно выполнять некоторые или все записи в базу данных в фоновом режиме, что добавляет всю эту головную боль. Обязательно протестируйте на оборудовании (ввод-вывод флэш-памяти отличается от ввода-вывода жесткого диска). - person CommonsWare; 07.10.2010
comment
Но блокировка пользовательского ввода во время ввода/вывода базы данных не совсем приемлема, не так ли? В этот момент вы могли бы также запустить все в основном потоке. Разве IntentService не ставит намерения в очередь для обработки после завершения обработки текущего намерения? (Я знаю, что задавал этот вопрос раньше, извините, просто хочу быть уверенным). В любом случае, если операции ввода-вывода базы данных накапливаются, не будет ли уместно запихнуть эту часть в службу? Я не против использования AsyncTask. Я просто хочу использовать то, что в конечном итоге будет работать со многими частыми вызовами базы данных. - person Andrew; 07.10.2010
comment
@Andrew: Но блокировка пользовательского ввода во время ввода-вывода базы данных не совсем приемлема, не так ли? -- в большинстве случаев ввод-вывод базы данных занимает порядка нескольких миллисекунд. Опять же, здесь в игру вступает тестирование. Разве IntentService не ставит намерения в очередь для обработки после завершения обработки текущего намерения? -- да. В любом случае, если операции ввода-вывода базы данных накапливаются, не будет ли уместно запихнуть эту часть в службу? - это возможность, но это не обязательное требование. - person CommonsWare; 07.10.2010
comment
В порядке. Я посмотрю, что я могу собрать с этой информацией. Спасибо за твою помощь! (с этим вопросом и другими) - person Andrew; 07.10.2010