【问题标题】:GridView is not refreshing view after data changed数据更改后,GridView 不刷新视图
【发布时间】:2014-07-21 20:31:45
【问题描述】:

我有一个带有不会刷新的自定义适配器的 GridView。

在调试器中,我可以看到 getViewnotifyDataSetChanged 之后没有被调用。 我不知道为什么...我可以看到基础数据正在更改,但 GridView 没有发生任何事情。

我尝试了几种不起作用的解决方案,所以我发布了我认为应该是正确的解决方案(即使它显然不是......)

这是我的主要活动

private GridView grid;

private TileGridAdapter gridAdapter;
private ArrayList<Tile> list;
private GameManager gameManager;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    gameManager = new GameManager(4);

    list = (ArrayList<Tile>) gameManager.getTiles();

    grid = (GridView) findViewById(R.id.grid);

    gridAdapter = new TileGridAdapter(this, list);
    grid.setAdapter(gridAdapter);

    grid.setOnTouchListener(new OnSwipeTouchListener(MainActivity.this) {
        public void onSwipeTop() {
            gameManager.move(Direction.Up);
            list.clear();
            list.addAll(gameManager.getTiles());
            gridAdapter.notifyDataSetChanged();
        }

        public void onSwipeRight() {
            Toast.makeText(MainActivity.this, "right", Toast.LENGTH_SHORT).show();
        }

        public void onSwipeLeft() {
            Toast.makeText(MainActivity.this, "left", Toast.LENGTH_SHORT).show();
        }

        public void onSwipeBottom() {
            Toast.makeText(MainActivity.this, "bottom", Toast.LENGTH_SHORT).show();
        }
    });

}

还有自定义适配器

public class TileGridAdapter extends ArrayAdapter<Tile> {

    Context context;
    ArrayList<Tile> tiles;

    public TileGridAdapter(Context context, ArrayList<Tile> tiles) {
        super(context, R.layout.cell_layout, tiles);

        this.context = context;
        this.tiles = tiles;
    }       

    @Override
    public int getCount() {
        return tiles.size();
    }

    @Override
    public Tile getItem(int position) {
        return tiles.get(position);
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {

        View view = convertView;

        if (view == null) {
            LayoutInflater inflater = ((Activity) context).getLayoutInflater();
            view = inflater.inflate(R.layout.cell_layout, parent, false);

            Tile tile = tiles.get(position);

            TextView tv = (TextView) view.findViewById(R.id.cell_view);
            if (tile != null) {
                tv.setText(String.valueOf(tile.getValue()));
            }
        }

        return view;
    }
}

【问题讨论】:

  • 您确定 GameManager.getTitles() 实际上返回的是您认为的列表,还是返回相同的列表(因此,显示不会改变)?
  • 列表不同。我运行调试器并观察了tiles数组,它正在更新
  • 哦,原因如下:您正在清除您创建的列表,而不是实际的适配器。尝试调用 gridAdapter.clear();然后 gridAdapter.addAll(gameManager.getTitles());
  • 不。现在试了一遍又一遍。我单独尝试了这两条新线,而这两条线与前两条线(list.XXX)一起尝试。我还覆盖了适配器的 addAll ,但仍然没有。在这两种情况下,我都看到了瓷砖数组正在改变,但视图却没有
  • 使用调试器查看适配器中的列表是否实际上正在更改,并且与您正在查看的引用相同。

标签: android gridview android-arrayadapter


【解决方案1】:

据我所知,问题是如果 convertview 为空,您的 getView 只会膨胀和填充视图。以我的经验,convertview 仅在列表的初始加载时为空,从那时起视图被重用。您应该检查视图是否既存在又具有正确的数据。如果它有错误的数据,则用新数据填充(或者总是用新数据填充。)

这就是viewholder pattern 可以提供帮助的原因。

例如:

if( view == null || ((Holder)view.getTag()).getItem().equals(getItem()) ) 
{
    ...

您可能应该将该检查分成多行,但这就是想法。



将除通货膨胀之外的所有内容移到 if 语句之外。

【讨论】:

    【解决方案2】:
    1. 根据您发布的代码,无需覆盖getCount()getItem() 方法。只需 getView() 即可。
    2. 您无法更新外部 Tile 列表(在活动中)并期望适配器更新。这很糟糕,原因有很多。基本上它归结为您的外部列表不能保证与适配器中的列表引用相同。可以在这里阅读更多信息:ArrayAdapter Constructor - Issues
    3. 如果您需要向 gridAdapter 添加项目,请直接使用它的addAll() 方法。如果您需要从适配器中清除项目...使用它的 clear() 方法。

    【讨论】:

    • 好吧,我尝试使用 gridAdapter 方法(请参阅我的问题的 cmets),但它仍然无法正常工作。我还删除了你说的被覆盖的方法是多余的,以防它们“中断”。
    • 您能否更新您发布的代码以反映更改?
    猜你喜欢
    • 2013-05-12
    • 2016-05-07
    • 1970-01-01
    • 1970-01-01
    • 2023-03-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多