У меня есть IntentService со своим собственным процессом, вот так:
AndroidManifest.xml
<service
android:name="com.app.services.UpdateDatabaseService"
android:process=":updateDatabaseService"
android:label="@string/service_name"
android:exported="false" >
</service>
Затем, когда IntentService работает, он создает два потока. Одна из задач этого потока — это длинная задача (более 1 мин). И я получаю проблему ANR.
10-24 18:51:27.923: E/ActivityManager(148): ANR in com.app:FooService
10-24 18:51:27.923: E/ActivityManager(148): Reason: Executing service com.app/.services.FooService
10-24 18:51:27.923: E/ActivityManager(148): Load: 1.08 / 0.48 / 0.21
10-24 18:51:27.923: E/ActivityManager(148): CPU usage from 13433ms to 1122ms ago:
10-24 18:51:27.923: E/ActivityManager(148): 92% 1375/com.emanga:updateMangaDatabase: 87% user + 5.7% kernel / faults: 5740 minor
10-24 18:51:27.923: E/ActivityManager(148): 0.4% 148/system_server: 0.2% user + 0.1% kernel / faults: 13 minor
10-24 18:51:27.923: E/ActivityManager(148): 0.2% 45/adbd: 0% user + 0.2% kernel
10-24 18:51:27.923: E/ActivityManager(148): 0.1% 758/logcat: 0% user + 0.1% kernel
10-24 18:51:27.923: E/ActivityManager(148): 0% 266/com.android.phone: 0% user + 0% kernel / faults: 2 minor
10-24 18:51:27.923: E/ActivityManager(148): 93% TOTAL: 87% user + 6.2% kernel + 0% irq
10-24 18:51:27.923: E/ActivityManager(148): CPU usage from 1804ms to 2442ms later:
10-24 18:51:27.923: E/ActivityManager(148): 70% 1375/com.emanga:updateMangaDatabase: 65% user + 4.9% kernel / faults: 123 minor
Пользовательский интерфейс никогда не блокируется. Итак, если служба находится в отдельном процессе (не в потоке пользовательского интерфейса), почему я получаю эту ошибку?
ИЗМЕНИТЬ 1:
Я изменил IntentService на Service, но все еще получаю ту же проблему. Я постараюсь объяснить, что я хочу получить. В архитектуре моего приложения есть действия, которые показывают данные, восстановленные из базы данных с помощью загрузчиков. Если в базе данных нет запрошенных данных, то она запросит службу, которая восстановит данные из Интернета (служба управляет интернет-запросами, анализирует некоторые html, обновляет базу данных новыми данными, и в конце служба уведомляет об изменениях). )
У этой службы есть собственный процесс, потому что, хотя служба улавливает исключения, которые могут возникнуть, таким образом приложение становится более устойчивым к сбоям в Интернете или синтаксическом анализаторе (приложение не аварийно завершает работу).
Цель загрузчиков — получить данные из базы данных, а цель службы — получить данные из Интернета и обновить базу данных. Связь между загрузчиками и службами предназначена только для уведомления об изменениях или запросах.
Наконец, у этой службы есть очередь задач и исполнитель, который запускает задачи.
public class UpdateDatabaseService extends Service {
private static final String ACTION = "com.app.services.UpdateDatabaseService";
public static final String ACTION_TASK_1 = ACTION + ".latestChapters";
public static final String ACTION_TASK_2 = ACTION + ".latestMangas";
private static final byte PARALLELTASKS = 2;
public LinkedBlockingQueue<Runnable> tasks = new LinkedBlockingQueue<Runnable>();
private ExecutorService executor = Executors.newFixedThreadPool(PARALLELTASKS);
private final IBinder mBinder = new MyBinder();
public class MyBinder extends Binder {
public UpdateDatabaseService getService() {
return UpdateDatabaseService.this;
}
}
@Override
public IBinder onBind(Intent arg0) {
return mBinder;
}
@Override
public void onCreate(){
// By default always it does DefaultTask1
tasks.put(new DefaultTask1());
if(!isEmptyTable("tableFoo")){
tasks.put(new DefaultTask2());
}
executor();
}
public int onStartCommand(Intent intent, int flags, int startId) {
if(intent != null && intent.getAction() != null) {
String action = intent.getAction();
if(action == ACTION_TASK_1){
tasks.put(new Task1());
} else
if(action == ACTION_TASK_2){
tasks.put(new Task2());
}
}
// We want this service to continue running until it is explicitly
// stopped, so return sticky.
return START_STICKY;
}
private void executor(){
while(true){
executor.execute(tasks.take());
}
}