如果使用工作线程如何防止ANR?

时间:2014-04-04 13:19:23

标签: android

我的应用程序在首次启动时从原始文件中下载并解压缩一些数据。 所有长时间运行的进程都在后台线程中执行,所以我相信ANR没有明显的原因(纠正我)。

@Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        ResultReceiver receiver = intent.getParcelableExtra(RECEIVER);
        job = extractJob(intent);
        InstallResultSender sender = new InstallResultSender(receiver);

        // add one more receiver
        synchronized (senders) {
            senders.add(sender);
        }

        if (thread == null) {
            thread = new InitThread(job);
            thread.start();
        }

        // no need to restart service or redeliver intent
        return Service.START_NOT_STICKY;
    }

使用android ResultReceiver将进度和状态消息发送到活动:

private ResultReceiver receiver;

public void sendProgress(int percent) {
        Bundle data = new Bundle();
        data.putInt(InstallResultReceiver.DATA_PROGRESS, percent);
        receiver.send(InstallResultReceiver.RESULT_PROGRESS, data);
    }

该活动只显示ProgressDialog并更新百分比和状态消息。

问题是在下载/安装ANR时发生,然后Android发送信号6(中止)。我该如何预防/绕过这个?

ANR原因是亚马逊应用内购买结算接收方,但我相信并不重要。

日志:

04-04 13:01:51.016: DEBUG/ActivityInstallListener(1912): on started INSTALL ArmstrongNumber c (1)
04-04 13:01:53.695: DEBUG/ActivityInstallListener(1912): saved repository (9233 bytes)
04-04 13:01:53.695: DEBUG/ActivityInstallListener(1912): on started INSTALL HarmonicNumberSeries c (1)
04-04 13:01:53.885: ERROR/ActivityManager(275): ANR in name.mycompany.android.myapp
        Reason: Broadcast of Intent { act=com.amazon.inapp.purchasing.NOTIFY flg=0x10000010 pkg=name.mycompany.android.myapp cmp=name.mycompany.android.myapp/com.amazon.inapp.purchasing.ResponseReceiver (has extras) }
        Load: 6.71 / 6.75 / 3.23
        CPU usage from 0ms to 5942ms later:
        59% 1912/name.mycompany.android.myapp: 50% user + 8.4% kernel / faults: 809 minor
        24% 275/system_server: 18% user + 6.3% kernel / faults: 1131 minor
        4% 29/mmcqd: 0% user + 4% kernel
        0.6% 505/com.android.phone: 0.4% user + 0.2% kernel / faults: 150 minor
        1% 47/adbd: 0% user + 1% kernel
        0% 519/com.amazon.tcomm: 0% user + 0% kernel / faults: 135 minor
        0% 1715/com.amazon.client.metrics: 0% user + 0% kernel / faults: 236 minor
        0% 12/pdflush: 0% user + 0% kernel
        0.8% 40/mediaserver: 0.1% user + 0.6% kernel
        0% 552/com.amazon.imp: 0% user + 0% kernel / faults: 123 minor
        0.1% 909/com.android.systemui: 0% user + 0% kernel / faults: 104 minor
        0% 459/com.lab126.softkeybar: 0% user + 0% kernel / faults: 110 minor
        0% 539/com.android.providers.downloads: 0% user + 0% kernel / faults: 99 minor
        0.3% 545/android.process.media: 0.1% user + 0.1% kernel / faults: 167 minor
        0% 988/com.nuance.swype.input: 0% user + 0% kernel / faults: 97 minor
        0.5% 13/kswapd0: 0% user + 0.5% kernel
        0.1% 319/logcat: 0% user + 0.1% kernel / faults: 20 minor
        0.3% 1343/com.amazon.ags.app: 0.3% user + 0% kernel / faults: 174 minor
        0% 1//init: 0% user + 0% kernel / faults: 85 minor
        0% 1944/com.amazon.mas.test: 0% user + 0% kernel / faults: 19 minor
        100% TOTAL: 73% user + 25% kernel + 0.1% irq + 0.1% softirq
        CPU usage from 5132ms to 5817ms later:
        62% 1912/name.mycompany.android.myapp: 56% user + 6.4% kernel / faults: 12 minor
        35% 1912/ndroid.myapp: 35% user + 0% kernel
        33% 1957/Thread-208: 22% user + 11% kernel
        1.6% 1919/Compiler: 1.6% user + 0% kernel
        15% 275/system_server: 5.7% user + 10% kernel / faults: 1 minor
        11% 293/ActivityManager: 4.3% user + 7.2% kernel
        13% 29/mmcqd: 0% user + 13% kernel
        0.7% 12/pdflush: 0% user + 0.7% kernel
        1.4% 40/mediaserver: 0% user + 1.4% kernel
        1.4% 40/mediaserver: 0% user + 1.4% kernel
        0.4% 47/adbd: 0% user + 0.4% kernel
        0.4% 47/adbd: 0% user + 0.4% kernel
        100% TOTAL: 62% user + 35% kernel + 1.4% irq
04-04 13:01:53.925: INFO/ActivityManager(275): Tablet:Platform:package=name.mycompany.android.myapp;DV;1,event=app-anr;DV;1:NR
04-04 13:01:53.925: INFO/Process(275): Sending signal. PID: 1912 SIG: 6

3 个答案:

答案 0 :(得分:1)

文档http://developer.android.com/guide/components/services.html陈述

Caution: A services runs in the same process as the application in which it is declared and in the main thread of that application, by default. So, if your service performs intensive or blocking operations while the user interacts with an activity from the same application, the service will slow down activity performance. To avoid impacting application performance, you should start a new thread inside the service.

此外,您可以通过打开Debug视图并查看线程的状态来检查eclipse中的线程状态。

我有点困惑为什么你选择使用AsyncTaskIntentService上的服务,它处理为你创建一个非ui线程。

答案 1 :(得分:0)

在应用程序的主线程中调用

onStartCommand。看看this。相反,如果你使用IntentService,你应该覆盖onHandleIntent(Intent intent),它实际上是在工作线程中调用的。

答案 2 :(得分:0)

很抱歉没有发布完整的源代码,原因在于: 我正在处理ResultReceiver.onReceiveResult()中服务权的结果。通过使用Handler解决了这个问题,所以我只需要将处理放在runnable队列中。此外,我在收到每个意图后减少了状态保存调用次数(减少了对ui线程的调用次数)并最终保存了一次。

private Handler handler = new Handler();

/**
 *
 */
private class ReceiveResultRunnable implements Runnable {

    private int resultCode;
    private Bundle resultData;

    public ReceiveResultRunnable(int resultCode, Bundle resultData) {
        this.resultCode = resultCode;
        this.resultData = resultData;
    }

    public void run() {
        switch (resultCode) {
            case RESULT_STARTED:
                listener.onStarted();
                break;

            case RESULT_MESSAGE:
                String message = resultData.getString(DATA_MESSAGE);
                listener.onMessage(message);
                break;

            case RESULT_PROGRESS:
                int progress = resultData.getInt(DATA_PROGRESS);
                listener.onProgress(progress);
                break;

            case RESULT_ERROR:
                Throwable t = (Throwable) resultData.getSerializable(DATA_ERROR);
                listener.onError(t);
                break;

            case RESULT_OK:
                int version = resultData.getInt(DATA_REPOSITORY_VERSION);
                listener.onFinished(version);
                break;

            // ...

        }
    }
}

@Override
protected void onReceiveResult(final int resultCode, final Bundle resultData) {
    super.onReceiveResult(resultCode, resultData);

    handler.post(new ReceiveResultRunnable(resultCode, resultData));
}