Что я делаю?
Я обновляю AppWidget с помощью IntentService.
В чем проблема?
Все работает отлично, за исключением некоторых редких времен, вероятно, каждые 12-15 часов, или, я бы сказал, случайных, обновления виджетов не происходят. После отладки по ситуации вот сообщение logcat, которое, похоже, является проблемой.
05-27 20:21:13.122: WARN/ActivityManager(97): Scheduling restart of crashed service com.myapp.android/.myAppWidget$UpdateService in 5000ms
Ниже приведены еще несколько сообщений logcat - это действительно трудно повторить, поскольку это происходит время от времени, но это произошло, когда я перезапустил приложение на своем реальном устройстве, подключенном через порт USB, в режиме отладки.
05-27 20:21:16.712: DEBUG/AndroidRuntime(24419): --- registering native functions ---
05-27 20:21:16.742: INFO/global(24420): Default buffer size used in BufferedInputStream constructor. It would be better to be explicit if an 8k buffer is required.
05-27 20:21:16.842: DEBUG/Configuration(24420): active site = local
05-27 20:21:16.872: DEBUG/FREESPACE(24420): Bytes to fill: 580550656
05-27 20:21:16.942: VERBOSE/AlarmManager(97): Adding Alarm{46389f38 type 2 com.google.android.apps.maps} Jan 01 09:30:42 am
05-27 20:21:17.032: INFO/ActivityManager(97): Start proc com.myApp.android for broadcast com.myApp.android/.myAppWidget: pid=24431 uid=10080 gids={1015, 3003}
05-27 20:21:17.092: DEBUG/dalvikvm(24420): GC_FOR_MALLOC freed 3967 objects / 320968 bytes in 162ms
05-27 20:21:17.172: DEBUG/FREESPACE(24420): Bytes to fill: 580550656
05-27 20:21:17.252: ERROR/UpdateService(24431): Service Started..
05-27 20:21:17.332: INFO/ActivityManager(97): Force stopping package com.myApp.android uid=10080
05-27 20:21:17.332: INFO/Process(97): Sending signal. PID: 24431 SIG: 9
05-27 20:21:17.332: WARN/ActivityManager(97): Scheduling restart of crashed service com.myApp.android/.myAppWidget$UpdateService in 5000ms
05-27 20:21:17.332: INFO/ActivityManager(97): Starting activity: Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10000000 cmp=com.myApp.android/.myApp3 }
05-27 20:21:17.372: INFO/ActivityManager(97): Start proc com.myApp.android for activity com.myApp.android/.myApp3: pid=24444 uid=10080 gids={1015, 3003}
05-27 20:21:17.402: DEBUG/AndroidRuntime(24419): Shutting down VM
Вот фрагменты кода для onReceive (), onUpdate () и onHandleIntent () для класса UpdateService, расширяющего IntentService
@Override
public void onReceive(Context context, Intent intent) {
check_intent = intent.getAction();
if (check_intent.equals("android.appwidget.action.APPWIDGET_UPDATE")) {
if (!getLock(context).isHeld()) { // fail-safe for crash restart
getLock(context).acquire();
}
try {
this.onUpdate(context, intent);
} finally {
getLock(context).release();
}
}
if (check_intent.equals("android.appwidget.action.APPWIDGET_ENABLED")) {
this.onEnabled(context);
}
if (check_intent.equals("android.appwidget.action.APPWIDGET_DELETED")) {
this.onDeleted(context);
}
if (check_intent.equals("android.appwidget.action.APPWIDGET_DISABLED")) {
this.onDisabled(context);
}
super.onReceive(context, intent);
}
Вот onUpdate
, где метод startService
называется
public void onUpdate(Context context, Intent intent) {
mAppPreferences = PreferenceManager.getDefaultSharedPreferences(context);
int saved_num_widgets = mAppPreferences.getInt(NUM_WIDGETS, 0);
if (saved_num_widgets > 0) {
Intent widgetUpdate = new Intent(context, myAppWidget.class);
widgetUpdate.setAction(AppWidgetManager.ACTION_APPWIDGET_UPDATE);
AlarmManager alarms =
(AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
PendingIntent newPending =
PendingIntent.getBroadcast(context,
0,
widgetUpdate,
PendingIntent.FLAG_CANCEL_CURRENT);
alarms.set(AlarmManager.ELAPSED_REALTIME,
SystemClock.elapsedRealtime() + PERIOD,
newPending);
context.startService(new Intent(context, UpdateService.class));
} else {
//Show Notification
}
}
Наконец, вот код для onHandleIntent()
@Override
protected void onHandleIntent(Intent intent) {
// here is where your long running task goes
RemoteViews updateViews = buildUpdate(this);
// Push update for this widget to the home screen
if (updateViews != null) {
ComponentName thisWidget = new ComponentName(this, myAppWidget.class);
AppWidgetManager manager = AppWidgetManager.getInstance(this);
manager.updateAppWidget(thisWidget, updateViews);
} else {
updateViews = new RemoteViews(getApplicationContext().getPackageName(),
R.layout.tuwidget);
updateViews.setImageViewResource(R.id.ad, R.drawable.myApp_null_game);
Intent defineIntent1 = new Intent(getApplicationContext(), myApp3.class);
PendingIntent pendingIntent1 =
PendingIntent.getActivity(getApplicationContext(),
0 /* no requestCode */,
defineIntent1,
0 /* no flags */);
updateViews.setOnClickPendingIntent(R.id.tuwidget, pendingIntent1);
ComponentName thisWidget = new ComponentName(this,myAppWidget.class);
AppWidgetManager manager = AppWidgetManager.getInstance(this);
manager.updateAppWidget(thisWidget, updateViews);
}
}
То, что я также хотел упомянуть для класса UpdateService, расширенного из IntentService, это
- Я не использую onStartCommand
onCreate () как показано ниже
@Override
public void onCreate() {
super.onCreate();
Log.e("UpdateService", "Service Started.. ");
}
Виджет обновляется с правильными интервалами, и все работает нормально, и принудительное закрытие вообще не происходит, но я совершенно не понимаю, почему обновления не происходят только несколько раз.
Я не предоставил код для функции buildUpdate, которая возвращает RemoteViews для обновления виджета, потому что я на 110% уверен, что эта часть работает без проблем.
Обновление: я заметил, что всякий раз, когда возникает эта проблема, я вижу более ранний экземпляр IntentService, все еще работающий в приложениях -> Запуск служб, что означает, что onDestroy () иногда не вызывается, и служба не останавливается автоматически, как и положено. Интересно то, что я сделал, это создал Shared Pref, чтобы сохранить состояние службы как работающей или остановленной и переключать ее из onCreate () и onDestroy (). Теперь, прежде чем вызвать startService (), я проверяю состояние общего префа, и, если экземпляр службы все еще работает, я сначала вызываю stopService (), а затем startService (). Я все еще тестирую его, но после написания этого обходного пути проблема еще не возникла !!