我创建了一个Appwidget,它显示通过Uri提供给它的RemoteViews的图像文件(test.png)。在onUpdate中,我运行了一个更改文件内容的服务。我还为图像设置了一个onClickListener,它将调用onUpdate。
-如果我创建一个AppWidget实例,它会显示Uri文件的最新更改版本。
-如果我单击小部件,我的服务会对文件进行适当的更改(我可以使用文件资源管理器进行验证),但它不会更新AppWidget中显示的图像。
-(最重要的是)如果我删除AppWidget并创建一个新的,它会显示图像文件的当前/正确版本。
我知道我的服务可能需要很长时间才能在第一次通过时生效,但它应该在onUpdate的下一次onClick/调用中显示最新的图像。目前,AppWidget只显示onUpdate第一次调用时存在的图像文件的版本。
问题:
刷新Appwidget的RemoteView内容的正确方法是什么?我的方法中是否遗漏了什么?
谢谢你抽出时间!
更新:
我已尝试从AppWidgetProvider.onReceive()调用AppWidgetManager.notifyAppWidgetViewDataChanged()方法,但在onUpdate()之后仍未更改为RemoteViews内容。
public class CCWidgetProvider extends AppWidgetProvider {
@Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager,int[] appWidgetIds)
{
// Get all ids
ComponentName thisWidget = new ComponentName(context,CCWidgetProvider.class);
int[] allWidgetIds = appWidgetManager.getAppWidgetIds(thisWidget);
for (int widgetId : allWidgetIds)
{
RemoteViews remoteViews = new RemoteViews(context.getPackageName(),R.layout.widget_layout04);
/*
* it's here that I run a service that changes the content of the file /test/test.png
*/
RelativeLayout RL_widget = new RelativeLayout(context);
LayoutInflater inflater = (LayoutInflater)context.getSystemService( Context.LAYOUT_INFLATER_SERVICE );
RL_widget = (RelativeLayout)inflater.inflate(R.layout.widget_main, null);
Uri uri = Uri.parse(Environment.getExternalStorageDirectory().getPath()+"/test/test.png");
remoteViews.setImageViewUri(R.id.IV_widget_image,uri);
Intent intent = new Intent(context, CCWidgetProvider.class);
intent.setAction(AppWidgetManager.ACTION_APPWIDGET_UPDATE);
intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, appWidgetIds);
//PendingIntent pendingIntent = PendingIntent.getBroadcast(context,0, intent, PendingIntent.FLAG_CANCEL_CURRENT);
PendingIntent pendingIntent = PendingIntent.getBroadcast(context,0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
remoteViews.setOnClickPendingIntent(R.id.IV_widget_image, pendingIntent);
appWidgetManager.updateAppWidget(widgetId, remoteViews);
}
}
}
我发现有各种各样的东西会让小部件变得困难。
A。onUpdate并不是真正的更新机制
与听起来相反,onUpdate
只在两种情况下被调用:
- 创建小部件时
- 每当更新周期时间(在小部件的xml定义文件文件中定义的
updateMillis
)过去时
要点:onUpdate
在其他时间永远不会被调用。(就我在实践中所见)。
如果您希望小部件在其他时间更新,则有必要创建一个独立的机制,了解小部件和要触发的能力。通常,这将是一个Service
,您可以在onUpdate
例程中启动它。这可能看起来像:
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds )
{
// start the service in case it ain't started yet, this also force a widget update to ensure correct status on them
Intent intent = new Intent(context, MyService.class);
intent.putExtra('service.startCode', /*A number to identify what is going on*/);
context.startService(intent);
// Everything else is triggered from the service!!
}
然后,服务设置小部件的内容,并根据需要通过内部计时或使用Broadcast
机制对其进行更新。
B。您无法真正更新小部件
在创建小部件时创建一个remoteViews
,然后在情况发生变化时更新它或其中的视图,这似乎是合乎逻辑的。根据我的经验,这不是可以预见的。当您想更改小部件中的任何内容时,请创建一个新的remoteViews
,正确填写,然后将其分配给小部件。
我在RemoteView处理URI的方式上遇到了一些设备依赖性,并找到了这样的解决方案:
RemoteViews remoteViews = new RemoteViews(context.getPackageName(),R.layout.widget_layout);
Uri uri = Uri.parse("file://"+Environment.getExternalStorageDirectory().getPath()+"/test/test.png");
Bitmap bitmap = BitmapFactory.decodeResource(context.getResources(), R.drawable.crap);
bitmap = MediaStore.Images.Media.getBitmap(context.getContentResolver(), uri);
remoteViews.setImageViewBitmap(R.id.IV_widget_image, bitmap);
它还消除了循环RemoteViews的需要,就像我的另一个答案一样。
当然不优雅,也不节省内存,但我发现如果我复制了RemoteViews
RemoteViews remoteViews = new RemoteViews(context.getPackageName(),R.layout.widget_layout01);
RemoteViews remoteViews2 = new RemoteViews(context.getPackageName(),R.layout.widget_layout02);
复制它们周围的代码,并在图像更新之间间歇性地交换它们(有点像缓冲区),每次重置RemoteViews都会强制更新它们的内容!
目前对我有效,请随时提供更正确的解决方案。