gpt4 book ai didi

android - 小部件中的 ListView 在滚动和调整大小时随机添加项目(嵌套远程 View )

转载 作者:可可西里 更新时间:2023-11-01 19:06:36 26 4
gpt4 key购买 nike

更新:I created a repository使用更少的代码使其更容易理解。

我正在尝试创建一个小部件。我像这里描述的那样做了:https://stackoverflow.com/a/6093753/2180161

它部分起作用,但我有一个非常奇怪的错误。我制作了一个截屏视频,这样更容易理解我的意思: http://c.maysi.de/c6H9

截图: enter image description here

如您所见,有些项目是随机添加的。 (添加到另一个 RemoteViews 对象的 RemoteViews)当我调整小部件大小时也会发生同样的情况。

我在日志中打印出来的东西和预期的一样。没有错误的数据。滚动时也没有新的日志条目。

这是我的代码:

远程 View 工厂:

@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));
}
}

所有其他资源 can you find in the repo at 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

难道问题出在嵌套的远程 View 上?因为所有外部远程 View 都显示正确...

最佳答案

您对 ListView 回收问题的想法是正确的。您需要了解底层的运作方式。

MVC 模式

The Android graphics works on the MVC pattern i.e. Model-View and Controller pattern. Model is your data, database in your case, View is your layout or graphical portion,such as ListView or RecyclerView or RemoteView. Controller changes your view after data update, parent View or ViewGroup in your case the RemoteViewsService.RemoteViewsFactory is the controller. I suggest to read further by googling the MVC model.

Pattern是如何实现的?

任何时候数据改变, View 应该由 Controller 更新。 Android 框架让您有机会通过覆盖 getViewAt(int position) 在给定位置显示您的 View 和您的数据。 Controller 调用 getViewAt(int position) 来获取 ListView 或 RecyclerView 中给定位置的 View 。 ListView 或 RecyclerView 仅呈现屏幕上可见的行。例如,如果您在 ListView 中有 100 个项目并且只有 7 个在屏幕上可见,那么它将调用 getItemAt(int) 7 次。每次滚动时,都会为可见行调用 getItemAt(int)。 ListView 和 RemoteView 可以自由回收/重用之前通过 getItemAt(int position) 返回的 View 。它确保应用程序的图形部分消耗的内存是有限的

为什么会有奇怪的行为?

首先,屏幕上所有可见的东西都是一个View,例如TextView、ImageView和ListView等。如果不是,它就不能显示在屏幕上。 RemoteView不是 View 。您传递要使用 RemoteView( View + 数据)显示的布局和数据。

此处我指的是您的截屏视频以进行解释。

1) Initialization: The ListView in your case, initially creates say 6 rows based on the visible space on screen and getViewAt(int position) is called once if getCount() returns 1. I request to check the return value of the getCount() of the List adapter.
2) You scrolled down: Nothing happens to the ListView and rendering of new Rows.
3) You Scrolled Up: getPositionAt(int position) is called again and RemoteView is passed back.Two rows are visible now. I request to check the getCount() return value. It should be 2 if not than the reason could be caching of rows by ListView.
4) You scrolled down: Nothing happens to the ListView and rendering of new Rows.
5) You Scrolled Up: Refer 3. The getCount() should be 3 and so on.

你应该做什么?

根据您的实现,您只创建了一次 RemoteView 并尝试在 getItemAt(int) 中重复使用相同的 View ,可能是为了节省布局膨胀时间。
要解决此问题,您必须在每次调用 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
}

关于android - 小部件中的 ListView 在滚动和调整大小时随机添加项目(嵌套远程 View ),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31713373/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com