我正在编写一个需要每分钟与远程服务器同步的应用程序。无法使用推送通知,因为应用程序仅供内部使用,并且不会在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可能会在内存不足的情况下停止服务并最近再次启动它。
答案 0 :(得分:0)
由于我之前没有检查过内存泄漏,因此需要一些时间才能找出它发生了什么。看起来设备制造商做了一些Looper代码的工具来跟踪分配。它只打印错误消息并转储调用堆栈,但应用程序同时非常稳定。我认为这是特定于供应商的代码,因为我没有在Android SDK的源代码中找到此消息。
如果打开内存分配监视器,您将看到内存在一段时间内稳定分配并最终释放。这意味着垃圾收集是由JVM启动的。分配的存储器的峰值在连续的时间段内保持不变。它可能在预期的时间内不会大幅增长。
此外,GC后错误消息消失。我假设分配计数器只是在检测类的finalize方法中重置。