应用程序小部件更新服务有时会强制关闭 - 需要帮助!
这个问题的背景。我有一个与我的应用程序关联的应用程序小部件,它使用更新服务定期更新,该服务将 http 发布到服务器并使用从服务器接收的数据更新小部件。
我从测试和用户报告中注意到,当小部件更新并且网络状态从可用变为不可用时,这种强制关闭的特定实例会定期发生(但很少见)。因为我在纽约地铁的手机上注意到了这一点。
在调试时,我发现如果发生了 http post 并且网络状态在收到响应之前发生了变化,它基本上会收到 IOException。因此,我处理了这个异常,并在这种特殊情况下使用默认更新更新了小部件。效果很好。
但有趣的是,我再次注意到这个强制关闭,并且已经没有办法解决这个问题了。
有没有人遇到过这种情况并知道我该如何处理?
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)
一些代码片段可能会帮助所有专家更好地理解问题并帮助初学者。
@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);
}
}
这是 OnUpdate 方法的代码片段。
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));
}
UpdateService 类的 OnStart 方法内的线程用于更新小部件。
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方法代码片段。
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.
}
感谢您的帮助。
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.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
扩展 Service 类的 UpdateService 类的 OnStart() 方法内的线程造成了问题。
解决方案:
摆脱了 widgetUpdateThread 线程,而不是扩展 Service 类,而是使用 IntentService。这会自动生成一个线程并且像一个魅力一样工作。当使用 IntentService 时,我将代码放在 @Override onHandleIntent 中,而不是 OnStart,瞧!即使并行使用 CPU 和内存密集型应用程序(如 FruitNinja),也不会强制关闭。
伙计们! IntentService受到开发者社区和Android Framework工程师的强烈推荐。因此,在更新小部件时请检查一下。
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.
我认为 manager.updateAppWidget(thisWidget, updateViews) 中的 thisWidget 值可能为 null。
希望这有帮助。
光盘。
I think thisWidget value may be null in manager.updateAppWidget(thisWidget, updateViews).
Hope this helps.
CD.