Редкий сбой IntentService, используемый для обновления AppWidget - PullRequest
3 голосов
/ 28 мая 2011

Что я делаю?

Я обновляю 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, это

  1. Я не использую onStartCommand
  2. onCreate () как показано ниже

    @Override
    public void onCreate() {
        super.onCreate();
        Log.e("UpdateService", "Service Started.. ");
    }
    

Виджет обновляется с правильными интервалами, и все работает нормально, и принудительное закрытие вообще не происходит, но я совершенно не понимаю, почему обновления не происходят только несколько раз.

Я не предоставил код для функции buildUpdate, которая возвращает RemoteViews для обновления виджета, потому что я на 110% уверен, что эта часть работает без проблем.

Обновление: я заметил, что всякий раз, когда возникает эта проблема, я вижу более ранний экземпляр IntentService, все еще работающий в приложениях -> Запуск служб, что означает, что onDestroy () иногда не вызывается, и служба не останавливается автоматически, как и положено. Интересно то, что я сделал, это создал Shared Pref, чтобы сохранить состояние службы как работающей или остановленной и переключать ее из onCreate () и onDestroy (). Теперь, прежде чем вызвать startService (), я проверяю состояние общего префа, и, если экземпляр службы все еще работает, я сначала вызываю stopService (), а затем startService (). Я все еще тестирую его, но после написания этого обходного пути проблема еще не возникла !!

1 Ответ

1 голос
/ 22 июня 2011

Этот журнал указывает, что кто-то вызвал в диспетчере активности, чтобы убить ваше приложение:

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

До Android 2.2 это был API принудительной остановки, который, например, диспетчеры задач использовали для уничтожения приложений, остановки всех их служб и т. Д. Убедитесь, что на вашем компьютере не установлены приложения типа диспетчера задач. Устройство, которое делает гадости.

Начиная с 2.2, API, используемый менеджерами задач, был изменен, чтобы позволить им уничтожать только фоновые процессы. Похоже, что это то, что происходит здесь - процесс завершается, но все приложение не принудительно останавливается, потому что сервис оставляется для перезапуска позже. (По сути, это то же самое, что является нормальным сценарием, если на устройстве слишком мало памяти, и система не может некоторое время поддерживать все фоновые службы.)

Поскольку вы видите это, мы на самом деле в нормальном рабочем режиме:

05-27 20:21:17.332: WARN/ActivityManager(97): Scheduling restart of crashed service com.myApp.android/.myAppWidget$UpdateService in 5000ms

То есть ваш процесс был убит в фоновом режиме. Ладно, это нормально и нормально, и мы перенесем перезапуск ваших служб через некоторое время. Вот почему служба остается в пользовательском интерфейсе Running Services, поскольку она все еще запущена, и сейчас у нее просто нет процесса для запуска.

В этом случае, да, ваш onDestroy () не вызывается, потому что весь сервис исчез. Опять же это нормально.

Так что из журналов я не вижу, что что-то происходит неправильно с тем, что происходит (за исключением того, что какое-то приложение может вызывать это чаще, чем вы обычно испытываете). Ваше приложение определенно должно справиться с этой ситуацией и просто не падать. :)

...