问题
I have a GridView with a custom adapter that wont refresh.
In the debugger I can see that getView
is not being called after notifyDataSetChanged
.
I have no idea why... I can see that the underlying data is being changed but nothing is happening to the GridView.
I tried several solutions which didn't work, so I'm posting what I think should be the right one (even though it clearly isn't...)
This is in my main activity
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();
}
});
}
And the custom adapter
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;
}
}
回答1:
As far as I can see, the problem is your getView is only inflating and populating a view if the convertview is null. In my experience, the convertview is only null on the initial loading of the list and from then on the views are reused. You should check to see if the view both exists and has the proper data. If it has the wrong data then populate with new data (or just always populate with new data.)
This is why the viewholder pattern can be helpful.
For example:
if( view == null || ((Holder)view.getTag()).getItem().equals(getItem()) )
{
...
You should probably break up that check into multiple lines, but that's the idea.
OR
Move everything except the inflation to the outside of the if statement.
回答2:
- From your posted code, there's no need to override the
getCount()
andgetItem()
methods. Just thegetView()
will work fine. - You cannot update the external Tile list (in the activity) and expect the adapter to update. This is bad for many reason. Basically it boils down to your external list is not guaranteed to be the same list reference in the adapter. Can read more about it here: ArrayAdapter Constructor - Issues
- If you need to add items to the gridAdapter then use it's
addAll()
method directly. If you need to clear items from the adapter...use it'sclear()
method.
来源:https://stackoverflow.com/questions/24874177/gridview-is-not-refreshing-view-after-data-changed