用于AppWidget更新的IntentService罕见崩溃

时间:2011-05-28 02:58:55

标签: java android android-appwidget

我在做什么?

我正在使用IntentService更新AppWidget。

有什么问题?

一切都很好,除了可能每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

以下是扩展IntentService的UpdateService类的onReceive(),onUpdate()和onHandleIntent()的代码片段

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

} 

我还想提到从IntentService扩展的UpdateService类

  1. 我没有使用onStartCommand
  2. onCreate()如下所示

    @Override
    public void onCreate() {
        super.onCreate();
        Log.e("UpdateService", "Service Started.. ");
    }
    
  3. 小部件以正确的时间间隔更新,一切正常,根本没有强制关闭,但我完全不知道为什么更新不会只发生一次。

    我没有提供buildUpdate函数的代码,它返回RemoteViews以更新小部件,因为我110%确定该部分可以正常工作。

    更新:我注意到,每当出现此问题时,我都会看到早期的IntentService实例仍在应用程序中运行 - >运行服务意味着onDestroy()有时不会被调用,并且服务不会按预期自动停止。有趣的是,我所做的是创建一个Shared Pref来将服务状态存储为运行或停止,并从onCreate()和onDestroy()切换它。在我调用startService()之前,我检查共享pref的状态,如果服务的实例仍在运行,我先调用stopService()然后再调用startService()。我仍在测试它,但在编码此解决方法之后,问题还没有发生!!

1 个答案:

答案 0 :(得分:1)

此日志表示有人调用活动管理器来杀死您的应用:

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

也就是说,您的进程在后台被杀死了。好的,这很好,很正常,我们将重新安排您的服务,以便稍微重新启动。这就是为什么服务仍然在运行服务UI中,因为它仍然启动,它现在没有一个进程可以运行。

在这种情况下,是的,你的onDestroy()没有被调用,因为整个服务都消失了。这是正常的。

所以从日志中我看不出有什么错误与正在发生的事情(除了某些应用程序可能导致它比你通常会经历的更频繁)。你的应用程序肯定需要处理这种情况,而不是崩溃。 :)