IntentService在Android 4.2(Jelly Bean)上是越野车



我正在编程一个需要每分钟与远程服务器同步的应用程序。由于应用程序旨在内部使用,因此无法在Google Play上发布,因此无法使用推送通知。我发现我可以使用AlarmManager和IntentService来实现目标。因此,我安排预定意图每分钟交付,并以意愿服务来执行网络I/O。听起来很简单,但我面临以下问题:应用程序后以下错误失败(我想大约100分钟(。

05-27 06:52:05.845 32176-32732/ru.infotecs.intentservice E/Looper: WARNING: The Looper class instance count has over a limit(100). There should be some leakage of Looper or HandlerThread.
05-27 06:52:05.845 32176-32732/ru.infotecs.intentservice E/Looper: Looper class instance count = 101
05-27 06:52:05.845 32176-32732/ru.infotecs.intentservice E/Looper: Current Thread Name: IntentService[BackgroundService]

我创建了非常简单的示例来仔细检查问题。因此看起来像:

活动:

public class MainActivity extends AppCompatActivity {
    private AlarmManager alarmManager;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);
        PendingIntent pi = PendingIntent.getService(getBaseContext(), 0, BackgroundService.getIntent(getBaseContext()), PendingIntent.FLAG_UPDATE_CURRENT);
        alarmManager.setRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP, 0, 500, pi);
    }
}

服务:

public class BackgroundService extends IntentService {
    private final static String TAG = BackgroundService.class.getSimpleName();
    private final static String ACTION_START = "ru.infotecs.intentservice.action.START";
    private static volatile int counter = 0;
    public BackgroundService() {
        super(TAG);
        counter = 0;
    }
    public static Intent getIntent(Context context) {
        Intent intent = new Intent(context, BackgroundService.class);
        intent.setAction(ACTION_START);
        return intent;
    }
    @Override
    protected void onHandleIntent(Intent intent) {
        if (intent != null) {
            final String action = intent.getAction();
            if (ACTION_START.equals(action)) {
                counter++;
                Log.d(TAG, ACTION_START + " - "+ counter);
            }
        }
    }
}

您可以看到,从1分钟开始,我将时间间隔减少到500ms,以更快地再现问题。所以现在大约需要一分钟,但无论如何结果是相同的:

05-27 06:52:04.348 32176-32717/ru.infotecs.intentservice D/BackgroundService: ru.infotecs.intentservice.action.START - 1
05-27 06:52:04.846 32176-32720/ru.infotecs.intentservice D/BackgroundService: ru.infotecs.intentservice.action.START - 1
05-27 06:52:05.349 32176-32726/ru.infotecs.intentservice D/BackgroundService: ru.infotecs.intentservice.action.START - 1
05-27 06:52:05.845 32176-32732/ru.infotecs.intentservice E/Looper: WARNING: The Looper class instance count has over a limit(100). There should be some leakage of Looper or HandlerThread.
05-27 06:52:05.845 32176-32732/ru.infotecs.intentservice E/Looper: Looper class instance count = 101
05-27 06:52:05.845 32176-32732/ru.infotecs.intentservice E/Looper: Current Thread Name: IntentService[BackgroundService]
05-27 06:52:05.845 32176-32732/ru.infotecs.intentservice I/System.out: java.lang.ThreadGroup[name=main,maxPriority=10]
05-27 06:52:05.845 32176-32732/ru.infotecs.intentservice I/System.out:     Thread[main,5,main]
05-27 06:52:05.846 32176-32732/ru.infotecs.intentservice I/System.out:     Thread[Thread-5,5,main]
05-27 06:52:05.847 32176-32732/ru.infotecs.intentservice I/System.out:     Thread[Binder_1,5,main]
05-27 06:52:05.847 32176-32732/ru.infotecs.intentservice I/System.out:     Thread[Binder_2,5,main]
05-27 06:52:05.847 32176-32732/ru.infotecs.intentservice I/System.out:     Thread[IntentService[BackgroundService],5,main]
05-27 06:52:05.848 32176-32732/ru.infotecs.intentservice W/System.err: java.lang.Throwable: stack dump
05-27 06:52:05.848 32176-32732/ru.infotecs.intentservice W/System.err:     at java.lang.Thread.dumpStack(Thread.java:489)
05-27 06:52:05.848 32176-32732/ru.infotecs.intentservice W/System.err:     at android.os.Looper.prepare(Looper.java:105)
05-27 06:52:05.849 32176-32732/ru.infotecs.intentservice W/System.err:     at android.os.Looper.prepare(Looper.java:86)
05-27 06:52:05.849 32176-32732/ru.infotecs.intentservice W/System.err:     at android.os.HandlerThread.run(HandlerThread.java:53)
05-27 06:52:05.850 32176-32732/ru.infotecs.intentservice D/BackgroundService: ru.infotecs.intentservice.action.START - 1

我想知道这种琐碎的应用如何导致错误。我稍微检查了一点点的意图服务实现,并发现服务在意图处理后自愿停止。

private final class ServiceHandler extends Handler {
    public ServiceHandler(Looper looper) {
        super(looper);
    }
    @Override
    public void handleMessage(Message msg) {
        onHandleIntent((Intent)msg.obj);
        stopSelf(msg.arg1);
    }
}

每次服务都会被销毁时,也会停止Looper:

@Override
public void onDestroy() {
    mServiceLooper.quit();
}

所以我完全不知道怎么了。有什么想法吗?

我使用Speific设备运行我的应用程序。它是RG500。问题不会在模拟器上重现,因此可能是设备运行时的问题。

P.S。目前,我通过对项目进行了一些修改来解决我的项目,解决了这个问题。我评论了停止方法调用,以使循环/线程尽可能保持活力。它并没有完全解决问题,因为Android可能会在记忆短缺的情况下停止服务并重新开始。

需要一些时间才能找出正在发生的事情,因为我以前没有检查过内存泄漏。看起来设备制造商对Looper代码进行了一些仪器来跟踪分配。它只是打印错误消息并转储呼叫堆栈,但该应用程序同时稳定。我认为这是供应商特定的代码,因为我没有在Android SDK的源代码中找到此消息。

如果打开内存分配监视器,您将看到内存在一段时间内稳步分配,并最终发布。这意味着垃圾收集是由JVM发起的。在连续的时间内,分配的内存的峰值保持不变。它不会像预期的那样随着时间的流逝而显着增长。

另外,错误消息在GC之后消失。我认为分配计数器只是以仪器类的最终化方法重置。

最新更新