开发者

Rare crash of IntentService used for AppWidget update

What am I doing?

I am updating an AppWidget using an IntentService.

What is the problem?

Everything works perfectly well except for some rare times probably every 12-15 hours or I might say random, the widget updates don't happen. After debugging through the situation here is the logcat message which appears to be the problem.

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

Below are some more logcat messages - It is really hard to replicate this since this happen once in a while but this happened when I relaunched the app on my real device connected through USB port using the debug mode.

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

Here are the code snippets for onReceive(), onUpdate() and onHandleIntent() for the UpdateService class extending 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);
}

Here is onUpdate where the startService method is called

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         
    }
}

Finally here is the code for 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);
    }   

} 

What I also wanted to mention for the UpdateService Class extended from IntentService is

  1. I am not using onStartCommand
  2. onCreate() is as below

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

The widget updates at correct intervals and everything works normally and no Force Closes at all but I am totally lost as to why the updates do not happen only some times.

I have not provided code for buildUpdate function that returns the RemoteViews to update the widget because I am 110% sure that part works without problems.

Update: What I have noticed is that whenever this problem occurs I see an earlier instance of the IntentService still running in Applications -> Running Services which means onDestroy() is not being called sometimes and the service do开发者_开发问答es not stop automatically as it is supposed to. Interestingly what I did was create a Shared Pref to store the state of the service as running or stopped and toggle it from onCreate() and onDestroy(). Now before I call startService() I check the state of the shared pref and if an instance of the service is still running I call stopService() first and then startService(). I am still testing it but after coding this workaround the problem hasn't occurred yet!!


This log indicates that someone called into the activity manager to kill your app:

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

Prior to Android 2.2, this would be the force stop API that for example task managers used to kill applications and stop all of their services etc. Check to make sure you don't have any task manager kind of apps installed on your device that are doing nasty things.

As of 2.2, the API the task managers used was changed to allow them to only kill background processes. It looks like this is what is going on here -- the process is being killed, but the entire app isn't being force stopped because the service is being left to be restarted later. (Basically this exact same is also a normal scenario if the device is running seriously low on memory to the point where the system can't keep all background services running for a while.)

Because you are seeing this we are actually in the normal operation case:

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

That is, your process was killed while in the background. Okay, that is fine and normal, and we will reschedule your services to be restarted in a little bit. This is why the service remains in the Running Services UI, because it is still started, it just doesn't right now have a process to run in.

In this case, yes, your onDestroy() is not called because the entire service went away. Again this is normal.

So from the logs I don't see that there is anything wrong with what is going on (except that some app may be causing it to happen more often than you normally would experience). Your app definitely needs to handle this situation and just not crash. :)

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜