我有一个带有自己进程的IntentService,就像这样:
安卓清单.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
UI 在任何时候都不会被阻止。因此,如果服务位于单独的进程中(不是 UI 线程),为什么会出现此错误?
编辑 1:
我将意图服务更改为服务,但我遇到了同样的问题。我会试着解释我想要得到什么。我的应用的体系结构具有显示使用加载程序从数据库中恢复的数据的活动。如果数据库没有要求的数据,那么它将请求一个服务,该服务将从互联网恢复数据(该服务管理互联网请求,它解析一些html,用新数据更新数据库,最后服务通知更改)
此服务有自己的进程,因为尽管服务捕获了可能发生的异常,但这样应用程序可以更可靠地抵御 Internet 或解析器故障(应用程序不会崩溃)
加载器的目的是从数据库中获取数据,该服务的目的是从互联网获取数据并更新数据库。加载程序和服务之间的通信仅用于通知更改或请求。
最后,此服务具有任务队列和运行任务的执行程序。
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());
}
}
每个进程都有一个主应用程序 (UI) 线程。它是调用组件生命周期方法(例如Service
的onStartCommand()
)的线程。而且,您不能捆绑该线程,否则您将获得ANR。
通常,这不是IntentService
的问题。任何IntentService
子类都不应该创建自己的线程,因此只有两个重要的线程:主应用程序线程和IntentService
提供的后台线程(调用onHandleIntent()
的线程)。确保您的所有工作都处于onHandleIntent()
中。如果您要自己分叉其他线程,请摆脱它们,或者从IntentService
切换到常规Service
,以便您可以安排Service
仅在所有线程完成其工作时才关闭,而不是在onHandleIntent()
完成时关闭。
另外,我强烈建议您摆脱android:process
,因为您正在浪费CPU和RAM,而不会给用户带来明显的额外好处。