![](/img/trans.png)
[英]RemoteViews setOnClickPendingIntent not firing for Widget ListView
[英]ListView in widget adds randomly items on scrolling and resizing (nested remoteviews)
更新: 我创建了一个包含较少代码的存储库 ,以使其更容易理解。
我正在尝试创建一个小部件。 我就像这里描述的那样: https : //stackoverflow.com/a/6093753/2180161
它部分工作,但我有一个非常奇怪的错误。 我做了一个截屏视频 ,所以更容易理解我的意思: http : //c.maysi.de/c6H9
如您所见,有一些项目是随机添加的。 ( RemoteViews
其中加入到另一个RemoteViews
对象) 时我调整插件同样的情况。
我在日志中打印的内容与预期的一样。 没有错误的数据。 滚动时也没有新的日志条目。
这是我的代码:
RemoteViewsFactory:
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
public class MyWidgetViewsFactory implements RemoteViewsService.RemoteViewsFactory {
private static ArrayList<Item> items = new ArrayList<>();
private static int itemnr = 0;
private static int subitemnr = 0;
private int appWidgetId;
private Context context;
public MyWidgetViewsFactory(Context context, Intent intent) {
this.context = context;
appWidgetId = intent.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID,
AppWidgetManager.INVALID_APPWIDGET_ID);
//Some random data to display
for (int i = 0; i < 10; i++) {
Item item = new Item(String.valueOf(itemnr++));
for (int j = 0; j < 3; j++) {
String[] subitem = {String.valueOf(subitemnr++), String.valueOf(subitemnr++), String.valueOf(subitemnr++)};
item.addSubitem(subitem);
}
items.add(item);
}
}
@Override
public void onCreate() {
// no-op
}
@Override
public void onDestroy() {
// no-op
}
@Override
public int getCount() {
return items.size();
}
@Override
public RemoteViews getViewAt(int position) {
Log.d("MyWidgetViewsFactory", "getViewAt(" + position + "):" + items.get(position));
Item item = items.get(position);
RemoteViews itemView = new RemoteViews(context.getPackageName(), R.layout.widget_listview_item);
itemView.setTextViewText(R.id.textView_itemnr, item.getItemNr());
for (String[] s : item.getSubitems()) {
Log.d("MyWidgetViewsFactory", "subitem:" + s[0] + "|" + s[1] + "|" + s[2]);
RemoteViews subitem = new RemoteViews(context.getPackageName(), R.layout.widget_listview_subitem);
subitem.setTextViewText(R.id.textView_1, s[0]);
subitem.setTextViewText(R.id.textView_2, s[1]);
subitem.setTextViewText(R.id.textView_3, s[2]);
itemView.addView(R.id.linearLayout_item_body, subitem);
}
return itemView;
}
@Override
public RemoteViews getLoadingView() {
return (null);
}
@Override
public int getViewTypeCount() {
return (1);
}
@Override
public long getItemId(int position) {
return (position);
}
@Override
public boolean hasStableIds() {
return (true);
}
@Override
public void onDataSetChanged() {
// no-op
}
class Item {
private ArrayList<String[]> subitems = new ArrayList<>();
private String itemnr = "";
Item(String itemnr) {
this.itemnr = itemnr;
}
Item() {
}
public void addSubitem(String[] subitem) {
this.subitems.add(subitem);
}
public ArrayList<String[]> getSubitems() {
return subitems;
}
public String getItemNr() {
return itemnr;
}
public void setItemNr(String itemnr) {
this.itemnr = itemnr;
}
}
}
的AppWidgetProvider
public class MyWidgetProvider extends AppWidgetProvider {
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
@Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
// There may be multiple widgets active, so update all of them
Log.d("MyWidgetProvider", "appWidgetIds.lenght:" + appWidgetIds.length);
for (int appWidgetId : appWidgetIds) {
Intent svcIntent = new Intent(context, MyWidgetService.class);
svcIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
RemoteViews widget = new RemoteViews(context.getPackageName(), R.layout.widget_root);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH)
widget.setRemoteAdapter(R.id.listView_widget, svcIntent);
else
widget.setRemoteAdapter(appWidgetId, R.id.listView_widget, svcIntent);
/*
Intent clickIntent = new Intent(context, MainActivity.class);
PendingIntent clickPI = PendingIntent.getActivity(context, 0, clickIntent, PendingIntent.FLAG_UPDATE_CURRENT);
widget.setPendingIntentTemplate(R.id.listView_widget, clickPI);*/
appWidgetManager.updateAppWidget(appWidgetId, widget);
}
}
@Override
public void onEnabled(Context context) {
// Enter relevant functionality for when the first widget is created
}
@Override
public void onDisabled(Context context) {
// Enter relevant functionality for when the last widget is disabled
}
}
RemoteViewsService
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
public class MyWidgetService extends RemoteViewsService {
@Override
public RemoteViewsFactory onGetViewFactory(Intent intent) {
return (new MyWidgetViewsFactory(this.getApplicationContext(), intent));
}
}
您可以在GitHub的回购中找到 所有其他资源 。
Logcat输出:
08-08 02:11:10.858 32427-32444/? D/MyWidgetViewsFactory﹕ getViewAt(0):de.mayerhofersimon.listviewproblem.MyWidgetViewsFactory$Item@3e7179c9
08-08 02:11:10.860 32427-32444/? D/MyWidgetViewsFactory﹕ subitem:0|1|2
08-08 02:11:10.864 32427-32444/? D/MyWidgetViewsFactory﹕ subitem:3|4|5
08-08 02:11:10.866 32427-32444/? D/MyWidgetViewsFactory﹕ subitem:6|7|8
08-08 02:11:10.927 32427-32443/? D/MyWidgetViewsFactory﹕ getViewAt(0):de.mayerhofersimon.listviewproblem.MyWidgetViewsFactory$Item@3e7179c9
08-08 02:11:10.927 32427-32443/? D/MyWidgetViewsFactory﹕ subitem:0|1|2
08-08 02:11:10.927 32427-32443/? D/MyWidgetViewsFactory﹕ subitem:3|4|5
08-08 02:11:10.927 32427-32443/? D/MyWidgetViewsFactory﹕ subitem:6|7|8
08-08 02:11:10.931 32427-32443/? D/MyWidgetViewsFactory﹕ getViewAt(1):de.mayerhofersimon.listviewproblem.MyWidgetViewsFactory$Item@23e248ce
08-08 02:11:10.931 32427-32443/? D/MyWidgetViewsFactory﹕ subitem:9|10|11
08-08 02:11:10.931 32427-32443/? D/MyWidgetViewsFactory﹕ subitem:12|13|14
08-08 02:11:10.931 32427-32443/? D/MyWidgetViewsFactory﹕ subitem:15|16|17
08-08 02:11:10.933 32427-32443/? D/MyWidgetViewsFactory﹕ getViewAt(2):de.mayerhofersimon.listviewproblem.MyWidgetViewsFactory$Item@16dbf3ef
08-08 02:11:10.933 32427-32443/? D/MyWidgetViewsFactory﹕ subitem:18|19|20
08-08 02:11:10.933 32427-32443/? D/MyWidgetViewsFactory﹕ subitem:21|22|23
08-08 02:11:10.933 32427-32443/? D/MyWidgetViewsFactory﹕ subitem:24|25|26
08-08 02:11:10.936 32427-32443/? D/MyWidgetViewsFactory﹕ getViewAt(3):de.mayerhofersimon.listviewproblem.MyWidgetViewsFactory$Item@19d3defc
08-08 02:11:10.936 32427-32443/? D/MyWidgetViewsFactory﹕ subitem:27|28|29
08-08 02:11:10.936 32427-32443/? D/MyWidgetViewsFactory﹕ subitem:30|31|32
08-08 02:11:10.936 32427-32443/? D/MyWidgetViewsFactory﹕ subitem:33|34|35
08-08 02:11:10.938 32427-32443/? D/MyWidgetViewsFactory﹕ getViewAt(4):de.mayerhofersimon.listviewproblem.MyWidgetViewsFactory$Item@ee985
08-08 02:11:10.938 32427-32443/? D/MyWidgetViewsFactory﹕ subitem:36|37|38
08-08 02:11:10.938 32427-32443/? D/MyWidgetViewsFactory﹕ subitem:39|40|41
08-08 02:11:10.938 32427-32443/? D/MyWidgetViewsFactory﹕ subitem:42|43|44
08-08 02:11:10.941 32427-32443/? D/MyWidgetViewsFactory﹕ getViewAt(8):de.mayerhofersimon.listviewproblem.MyWidgetViewsFactory$Item@335e23da
08-08 02:11:10.941 32427-32443/? D/MyWidgetViewsFactory﹕ subitem:72|73|74
08-08 02:11:10.941 32427-32443/? D/MyWidgetViewsFactory﹕ subitem:75|76|77
08-08 02:11:10.941 32427-32443/? D/MyWidgetViewsFactory﹕ subitem:78|79|80
08-08 02:11:10.943 32427-32447/? D/MyWidgetViewsFactory﹕ getViewAt(9):de.mayerhofersimon.listviewproblem.MyWidgetViewsFactory$Item@229de00b
08-08 02:11:10.943 32427-32447/? D/MyWidgetViewsFactory﹕ subitem:81|82|83
08-08 02:11:10.943 32427-32447/? D/MyWidgetViewsFactory﹕ subitem:84|85|86
08-08 02:11:10.943 32427-32447/? D/MyWidgetViewsFactory﹕ subitem:87|88|89
08-08 02:11:10.945 32427-32444/? D/MyWidgetViewsFactory﹕ getViewAt(5):de.mayerhofersimon.listviewproblem.MyWidgetViewsFactory$Item@2afdeee8
08-08 02:11:10.945 32427-32444/? D/MyWidgetViewsFactory﹕ subitem:45|46|47
08-08 02:11:10.945 32427-32444/? D/MyWidgetViewsFactory﹕ subitem:48|49|50
08-08 02:11:10.945 32427-32444/? D/MyWidgetViewsFactory﹕ subitem:51|52|53
08-08 02:11:10.948 32427-32444/? D/MyWidgetViewsFactory﹕ getViewAt(7):de.mayerhofersimon.listviewproblem.MyWidgetViewsFactory$Item@1c599901
08-08 02:11:10.948 32427-32444/? D/MyWidgetViewsFactory﹕ subitem:63|64|65
08-08 02:11:10.948 32427-32444/? D/MyWidgetViewsFactory﹕ subitem:66|67|68
08-08 02:11:10.948 32427-32444/? D/MyWidgetViewsFactory﹕ subitem:69|70|71
08-08 02:11:10.951 32427-32447/? D/MyWidgetViewsFactory﹕ getViewAt(6):de.mayerhofersimon.listviewproblem.MyWidgetViewsFactory$Item@368aa3a6
08-08 02:11:10.951 32427-32447/? D/MyWidgetViewsFactory﹕ subitem:54|55|56
08-08 02:11:10.951 32427-32447/? D/MyWidgetViewsFactory﹕ subitem:57|58|59
08-08 02:11:10.951 32427-32447/? D/MyWidgetViewsFactory﹕ subitem:60|61|62
所以数据传递正确。 它只是没有得到正确显示...
顺便说一句:这应该是它的样子: http : //c.maysi.de/cB8K
可能是,问题是因为嵌套的远程视图? 因为所有外部远程视图都显示正确...
您对ListView回收问题背后的想法是正确的。 你需要了解事情在地面上的运作方式。
MVC模式
Android图形适用于MVC模式,即模型视图和控制器模式。 Model是您的数据,在您的情况下是数据库,View是您的布局或图形部分,例如ListView或RecyclerView或RemoteView。 控制器在数据更新后更改您的视图,在您的情况下,父View或ViewGroup
RemoteViewsService.RemoteViewsFactory
是控制器。 我建议通过谷歌搜索MVC模型进一步阅读。
模式如何实现?
每次数据更改时,控制器都应更新视图。 Android框架为您提供了通过覆盖getViewAt(int position)
在数据的给定位置显示视图的机会。控制器调用getViewAt(int position)
以获取ListView或RecyclerView中给定位置的视图。 ListView或RecyclerView仅在屏幕上呈现可见行。 例如,如果ListView中有100个项目,并且屏幕上只显示7个项目,则会调用getItemAt(int)7次。 每次滚动时,都会为可见行调用getItemAt(int)。 ListView和RemoteView可以自由地回收/重用getItemAt(int position)返回的先前传递的View。 它确保应用程序的图形部分消耗的内存有限
为什么有奇怪的行为?
首先,屏幕上每个可见的东西都是一个View
,如TextView,ImageView和ListView等。如果没有,它就无法在屏幕上显示。 RemoteView不是View。 您使用RemoteView(View + Data)传递要显示的布局和数据。
在这里,我指的是您的截屏视频 。
1) 初始化 :在你的情况下,
ListView
最初根据屏幕上的可见空间创建6行,如果getCount()
返回1,则调用getViewAt(int position)
一次。我请求检查getCount()的返回值列表适配器。
2) 向下滚动 :ListView
和新行的渲染没有任何反应。
3) 你向上滚动:再次调用getPositionAt(int position)并传回RemoteView。现在可以看到两行。 我请求检查getCount()返回值。 它应该是2,如果不是原因可能是ListView缓存行。
4) 向下滚动 :ListView
和新行的渲染没有任何反应。
5) 你向上滚动 :参考3. getCount()应为3,依此类推。
你应该怎么做?
根据您的实现,您只创建了一次RemoteView并尝试在getItemAt(int)
重用相同的视图,可能是为了节省布局通胀时间。
要解决这个问题,每次调用getItemAt(int)
都必须提供FRESH RemoteView
。
@Override
public RemoteViews getViewAt(int position)
{
Log.d("VplanWidgetViewsFactory", "getViewAt("+position+"):"+stunden.get(position));
//TODO: Store context when constructor is called.
RemoteView rv = new RemoteViews(context.getPackageName(), R.layout.fragment_stunde_widget);
rv.setTextViewText(R.id.textView_lesson_nr, "" + (position + 1) + "."); <= I have not tested this.
return rv;
//return stunden.get(position); <=COMMENT THIS
}
我自己找到了答案。
要解决在滚动和调整大小时奇怪添加视图的问题,您必须在添加子视图的布局上调用removeAllViews
:
@Override
public RemoteViews getViewAt(int position) {
...
RemoteViews itemView = new RemoteViews(context.getPackageName(), R.layout.widget_listview_item);
itemView.removeAllViews(R.id.linearLayout_item_body);
...
return itemView;
}
并且未显示视图的问题是由于颜色:添加后
subitem.setTextColor(R.id.textView_1, context.getResources().getColor(R.color.abc_primary_text_material_light));
subitem.setTextColor(R.id.textView_2, context.getResources().getColor(R.color.abc_primary_text_material_light));
subitem.setTextColor(R.id.textView_3, context.getResources().getColor(R.color.abc_primary_text_material_light));
显示所有视图:
你的问题似乎在:
if(stundenContainer[j]!=null)
Log.d("VplanWidgetViewsFactory", "stundenContainer["+j+"]:" + stundenContainer[j].toString());
else
Log.d("VplanWidgetViewsFactory", "stundenContainer[" + j + "]:null");
if (stundenContainer[j] == null) {
//Freistunde
Log.d("VplanWidgetViewsFactory", "Freistunde");
// HERE -----
stunden.add(new RemoteViews(context.getPackageName(), R.layout.fragment_stunde_widget));
faecher.add(new RemoteViews(context.getPackageName(), R.layout.fragment_fach));
stunden.get(stunden.size() - 1).setTextViewText(R.id.textView_lesson_nr, "" + (j + 1) + ".");
} else if (!stundenContainer[j].get(0).getSubject().equals("ignore")) {
Log.d("VplanWidgetViewsFactory", "stundenContainer[j].get(0).getSubject(): " + stundenContainer[j].get(0).getSubject());
// HERE -----
stunden.add(new RemoteViews(context.getPackageName(), R.layout.fragment_stunde_widget));
您要添加两次..,但仅当第一项未被忽略时,它才会显示为随机。
stunden.add(new RemoteViews(context.getPackageName(), R.layout.fragment_stunde_widget));
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.