ANR在IntentService中有自己的进程

时间:2013-10-24 19:16:27

标签: 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" >
</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:

我将IntentService更改为Service,但我遇到了同样的问题。我会尝试解释我想要的东西。我的应用程序的体系结构具有显示使用Loaders从数据库恢复的数据的活动。如果数据库没有被询问的数据,那么它将向将要从互联网恢复数据的服务请求(该服务管理互联网请求,它解析一些html,用新数据更新数据库,最后服务通知有关变化)

此服务有自己的流程,因为虽然该服务可以捕获可能发生的异常,但这样一来,应用程序就是针对互联网或解析器故障的抢夺者(应用程序不会崩溃)

Loaders的目标是从数据库获取数据,服务的目标是从互联网获取数据并更新数据库。装载程序和服务之间的通信仅用于通知更改或请求。

最后,此服务有一个任务队列和一个运行任务的执行程序。

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

    }


}

1 个答案:

答案 0 :(得分:4)

每个进程都有一个主应用程序(UI)线程。调用组件生命周期方法的线程,例如onStartCommand()的{​​{1}}。并且,你不能绑定那个线程,否则你会得到一个ANR。

通常情况下,这不是Service的问题。没有IntentService子类应该创建自己的线程,因此只有两个重要的线程:主应用程序线程和IntentService提供的后台线程(调用IntentService的线程) 。确保您的所有工作都在onHandleIntent()。如果您要自己分支额外的线程,请将其删除,或者从onHandleIntent()切换到常规IntentService,这样您就可以安排Service仅关闭当所有你的线程完成他们的工作时,而不是Service完成时。

另外,我强烈建议你摆脱onHandleIntent(),因为你浪费了CPU和RAM,没有为用户带来明显的额外好处。