android - IntentService 在 Android 4.2 (Jelly Bean) 上有问题吗?

标签 android service

我正在编写一个需要每分钟与远程服务器同步的应用程序。无法使用推送通知,因为应用程序仅供内部使用,不会在 Google Play 上发布。 我发现我可以使用 AlarmManager 和 IntentService 来达到我的目标。因此,我安排每分钟传递一次挂起的 Intent ,并在 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]

我创建了一个非常简单的示例来更仔细地检查问题。所以它看起来像:

Activity :

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 实现,发现服务在 Intent 处理后自动停止。

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。问题不会在模拟器上重现,因此可能是设备运行时的问题。

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

最佳答案

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

如果你打开内存分配监视器,你会看到内存在一段时间内稳定分配,最后释放。这意味着垃圾收集是由 JVM 发起的。分配内存的峰值在连续的时间段内保持不变。它不会像预期的那样随着时间的推移急剧增长。

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

关于android - IntentService 在 Android 4.2 (Jelly Bean) 上有问题吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44372892/

相关文章:

android - Ionic Cordova Web 应用程序 cookie 未存储在 Android 或 iOS 上

Android Contacts Content Provider返回同一联系人的多个副本,联系人中没有重复的联系人

java - 服务和类之间的通信

ubuntu - 在 ubuntu 服务器上运行脚本作为服务

android - 将 Google Play Services jar 作为项目的一部分包含在内?

java - Android应用程序崩溃问题

android - android中adapter的filter类添加代码时出现String类型错误get(String)方法未定义

java - 使用自定义比较器排序的集合不起作用

service - 如何在特定 Nodeport 上公开 Kubernetes 服务?

android - Android Q(10) 中带有 MediaRecorder 的 AccessibilityService 30 秒音频,而调用接收(应答)无法工作