Android IntentService中具有自己进程的ANR
我有一个IntentService,它有自己的流程,就像这样: AndroidManifest.xmlAndroid IntentService中具有自己进程的ANR,android,android-service,intentservice,Android,Android Service,Intentservice,我有一个IntentService,它有自己的流程,就像这样: AndroidManifest.xml <service android:name="com.app.services.UpdateDatabaseService" android:process=":updateDatabaseService" android:label="@string/service_name" android:exported="false" > </se
<service
android:name="com.app.services.UpdateDatabaseService"
android:process=":updateDatabaseService"
android:label="@string/service_name"
android:exported="false" >
</service>
用户界面在任何时候都不会被阻止。那么,如果服务位于单独的进程(而不是UI线程)中,为什么会出现此错误
编辑1:
我将IntentService更改为Service,但我仍然遇到相同的问题。我会尽力解释我想要得到什么。我的应用程序的体系结构包含一些活动,这些活动显示使用加载程序从数据库恢复的数据。如果数据库没有所请求的数据,那么它将请求一个服务,该服务将从internet恢复数据(该服务管理internet请求,解析一些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());
}
}
公共类UpdateDatabaseService扩展服务{
私有静态最终字符串ACTION=“com.app.services.UpdateDatabaseService”;
公共静态最终字符串ACTION\u TASK\u 1=ACTION+“.latestChapters”;
公共静态最终字符串ACTION\u TASK\u 2=ACTION+“.latestMangas”;
私有静态最终字节并行任务=2;
public LinkedBlockingQueue tasks=新建LinkedBlockingQueue();
私有ExecutorService executor=Executors.newFixedThreadPool(并行任务);
私有最终IBinder mBinder=新MyBinder();
公共类MyBinder扩展了Binder{
public UpdateDatabaseService getService(){
返回UpdateDatabaseService.this;
}
}
@凌驾
公共IBinder onBind(意图arg0){
返回mBinder;
}
@凌驾
public void onCreate(){
//默认情况下,它始终执行DefaultTask1
tasks.put(新的DefaultTask1());
如果(!isEmptyTable(“tableFoo”)){
tasks.put(新的DefaultTask2());
}
执行人();
}
公共int onStartCommand(Intent Intent、int标志、int startId){
if(intent!=null&&intent.getAction()!=null){
String action=intent.getAction();
if(action==action\u TASK\u 1){
tasks.put(新任务1());
}否则
if(action==action\u TASK\u 2){
tasks.put(新任务2());
}
}
//我们希望此服务继续运行,直到显式恢复
//停止,所以返回粘性。
返回开始时间;
}
私人无效执行人(){
虽然(正确){
executor.execute(tasks.take());
}
}
每个进程都有一个主应用程序(UI)线程。它是调用组件生命周期方法的线程,例如服务的onStartCommand()
。并且,您不能绑定该线程,否则您将获得ANR
通常情况下,IntentService
没有问题。没有IntentService
子类应该创建自己的线程,因此只有两个重要线程:主应用程序线程和IntentService
提供的后台线程(调用onHandleIntent()
).确保您的所有工作都在onHandleIntent()中
。如果您要自己分叉额外的线程,请将它们清除,或者从IntentService
切换到常规服务
,这样您就可以安排服务
仅在所有线程完成工作时关闭,而不是在onHandleIntent()
完成工作时关闭
另外,我强烈建议您放弃android:process
,因为您浪费了CPU和RAM,对用户没有明显的额外好处。发布您可以从服务中获得的代码,这里没有任何有用的内容。一个有用的解释。我添加了一些关于此问题的代码和信息(编辑1)因为我需要这个过程来填充应用程序的数据库,然后服务将使用internet资源管理更新数据库。我认为这对用户是有益的,而且只是第一个关键案例。@Franb:“这项服务有自己的流程,因为尽管服务捕捉到可能发生的异常,但这样应用程序对internet或解析器故障更为健壮(应用程序不会崩溃)“--这不是在资源受限的环境(如移动设备)中使用多个进程的正当理由。同样,您在浪费RAM、CPU和电池。那么,什么时候使用单独的进程而不是线程?或者在哪些情况下,好的做法是使用进程?@Franb:“哪些情况下是好的实践使用流程?”--我想不出任何情况。人们使用流程的任何情况都可以通过其他方式处理,而不需要第二个流程。例如,有些人使用它在Android 1.x/2.x上获得更多堆空间,但您可以将NDK用于类似目的。
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());
}
}