Android IntentService中具有自己进程的ANR

Android 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

我有一个IntentService,它有自己的流程,就像这样:

AndroidManifest.xml

<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());

    }


}