IntentService在Android 4.2(Jelly Bean)上有错误吗?

时间:2017-06-05 15:58:32

标签: android service

我正在编写一个需要每分钟与远程服务器同步的应用程序。无法使用推送通知,因为应用程序仅供内部使用,并且不会在Google Play上发布。 我发现我可以使用AlarmManager和IntentService达到我的目标。因此,我计划每分钟发送待处理的意图,并在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分钟缩短到500毫秒,以便更快地重现问题。所以现在需要一分钟,但无论如何结果都是一样的:

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

我想知道这样琐碎的应用程序可能会导致错误。我稍微检查了IntentService实现,发现在意图处理后服务是自愿停止的。

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

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

我使用特定设备来运行我的应用。这是RugGear RG500。问题不会在仿真器上重现,因此可能是设备运行时的问题。

P.S。目前,我通过一些修改将IntentService实现应用到我的项目中解决了这个问题。我注释掉了stopSelf方法调用以尽可能地保持Looper / Thread活着。它不能完全解决问题,因为Android可能会在内存不足的情况下停止服务并最近再次启动它。

1 个答案:

答案 0 :(得分:0)

由于我之前没有检查过内存泄漏,因此需要一些时间才能找出它发生了什么。看起来设备制造商做了一些Looper代码的工具来跟踪分配。它只打印错误消息并转储调用堆栈,但应用程序同时非常稳定。我认为这是特定于供应商的代码,因为我没有在Android SDK的源代码中找到此消息。

如果打开内存分配监视器,您将看到内存在一段时间内稳定分配并最终释放。这意味着垃圾收集是由JVM启动的。分配的存储器的峰值在连续的时间段内保持不变。它可能在预期的时间内不会大幅增长。

此外,GC后错误消息消失。我假设分配计数器只是在检测类的finalize方法中重置。