Background to this problem. I have an appwidget associated with my app that updates at set intervals periodically, using an Update Service that does http posts to server and updates the widget with data received from the server.
What I have noticed from my tests and user reports is that this particular instance of force close happens periodically (but rare) when its time for the widget to update and the network state changes from available to unavailable. Since I have noticed this on my phone in NYC subways.
While debugging I figured that if the http post has happened and the network state changes before the response has been received, it basically receives a IOException. So I handled this exception and updated the widget in this particular case with a default update. It worked fine.
But interestingly I have noticed this Force Close again and am running out of ideas how to resolve this.
Has anyone encountered this before and know how I can handle this?
java.lang.NullPointerException
at android.widget.RemoteViews$ReflectionAction.writeToParcel(RemoteViews.java:399)
at android.widget.RemoteViews.writeToParcel(RemoteViews.java:1003)
at com.android.internal.appwidget.IAppWidgetService$Stub$Proxy.updateAppWidgetProvider(IAppWidgetService.java:402)
at android.appwidget.AppWidgetManager.updateAppWidget(AppWidgetManager.java:283)
at com.tyu.android.TyuWidget$UpdateService$1.run(TyuWidget.java:167)
Some code snippets that might help all you experts to better understand the problem and help a beginner.
@Override
public void onReceive(Context context, Intent intent) {
check_intent = intent.getAction();
if(check_intent.equals("android.appwidget.action.APPWIDGET_UPDATE")){
this.onUpdate(context, intent);
}
}
Here is the OnUpdate method code snippet.
public void onUpdate(Context context, Intent intent){
Intent widgetUpdate = new Intent(context, TyuWidget.class);
widgetUpdate.setAction(AppWidgetManager.ACTION_APPWIDGET_UPDATE);
AlarmManager alarms = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
PendingIntent newPending = PendingIntent.getBroadcast(context, 0, widgetUpdate,PendingIntent.FLAG_UPDATE_CURRENT);
alarms.set(AlarmManager.ELAPSED_REALTIME, SystemClock.elapsedRealtime()+ PERIOD, newPending);
context.startService(new Intent(context, UpdateService.class));
}
Thread inside OnStart method of UpdateService class that updates the widget.
widgetUpdateThread = new Thread(){
@Override
public void run(){
RemoteViews updateViews = buildUpdate(getApplicationContext());
if(updateViews!=null){
ComponentName thisWidget = new ComponentName(getApplicationContext(), TyuWidget.class);
AppWidgetManager manager = AppWidgetManager.getInstance(getApplicationContext());
manager.updateAppWidget(thisWidget, updateViews);
}
else{
updateViews = new RemoteViews(getApplicationContext().getPackageName(), R.layout.tuwidget);
updateViews.setImageViewResource(R.id.ad, R.drawable.tyu_null_game);
Intent defineIntent1 = new Intent(getApplicationContext(), Tyu3.class);
PendingIntent pendingIntent1 = PendingIntent.getActivity(getApplicationContext(),
0 /* no requestCode */, defineIntent1, 0 /* no flags */);
updateViews.setOnClickPendingIntent(R.id.tuwidget, pendingIntent1);
ComponentName thisWidget = new ComponentName(getApplicationContext(), TyuWidget.class);
AppWidgetManager manager = AppWidgetManager.getInstance(getApplicationContext());
manager.updateAppWidget(thisWidget, updateViews);
}
}
};
widgetUpdateThread.start();
buildUpdate method code snippet.
public RemoteViews buildUpdate(Context context) {
httppost.setEntity(new UrlEncodedFormEntity(nameValuePairs));
response = httpclient.execute(httppost);
entity = response.getEntity();
is = entity.getContent();
//etc etc...and then I return the update view and it gets updated.
}
Thanks for the help.
The thread inside OnStart() method of the UpdateService class which extended the Service class was creating the problem.
Solution:
Got rid of the widgetUpdateThread thread and instead of extending Service class, used IntentService. This automatically spawns a thread and works like a charm. Instead of OnStart, when using IntentService I put the code inside @Override onHandleIntent and Voila! No force close even when using apps in parallel that are very very CPU and memory intensive like FruitNinja.
Guys! IntentService is highly recommended by the developer community and Android Framework engineers. So check it out while updating widgets.