如何刷新GridView数据?修改按钮颜色后适配器不即时更新求助
解决GridView按钮颜色无法即时更新的问题
看起来你的核心问题有两个:主线程阻塞导致UI更新延迟,以及适配器没有和数据模型绑定,直接修改View导致复用混乱。咱们一步步来解决:
1. 首先修复主线程阻塞问题
你在game函数里直接调用Thread.sleep(1000),这是在UI线程执行的,会完全阻塞主线程——包括所有UI渲染操作。也就是说,你调用drawTheMove后做的按钮修改,要等1秒sleep结束后才会显示出来,看起来就像是“没即时更新”。
把sleep替换成Handler.postDelayed,这样不会阻塞主线程:
if (compLevel != 0) { // 对战电脑逻辑 new Handler(Looper.getMainLooper()).postDelayed(new Runnable() { @Override public void run() { // 这里写电脑要执行的操作,比如自动落子 } }, 1000); }
2. 让适配器依赖数据模型,而不是直接修改View
GridView的View是复用的,你直接修改单个Button的背景和文本,当这个View被复用到其他位置时,旧的状态会保留。正确的做法是让适配器持有一个数据模型,所有UI更新都通过修改数据模型,再通知适配器刷新。
第一步:定义数据模型
创建一个类来保存每个格子的状态:
public class GridCell { private int clickNumber; // 点击的数字 private int backgroundResId; // 背景资源ID // 构造函数、getter、setter public GridCell(int clickNumber, int backgroundResId) { this.clickNumber = clickNumber; this.backgroundResId = backgroundResId; } public int getClickNumber() { return clickNumber; } public void setClickNumber(int clickNumber) { this.clickNumber = clickNumber; } public int getBackgroundResId() { return backgroundResId; } public void setBackgroundResId(int backgroundResId) { this.backgroundResId = backgroundResId; } }
第二步:修改适配器
让适配器持有List<GridCell>,并在getView里根据数据模型更新UI:
public class GridViewAdapter extends BaseAdapter { private Context context; private List<GridCell> cellList; private GameManager gm; // 你的游戏管理类 // 构造函数 public GridViewAdapter(Context context, List<GridCell> cellList, GameManager gm) { this.context = context; this.cellList = cellList; this.gm = gm; } // ... 其他重写方法(getCount、getItem等) @Override public View getView(final int position, View convertView, ViewGroup viewGroup) { View row = convertView; ViewHolder holder; if (row == null) { LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); row = inflater.inflate(R.layout.single_item, viewGroup, false); holder = new ViewHolder(row); row.setTag(holder); } else { holder = (ViewHolder) row.getTag(); } holder.btnSqure = changeBtnSize(holder.btnSqure); GridCell currentCell = cellList.get(position); // 根据数据模型更新按钮状态 holder.btnSqure.setText(currentCell.getClickNumber() > 0 ? String.valueOf(currentCell.getClickNumber()) : ""); holder.btnSqure.setBackgroundResource(currentCell.getBackgroundResId()); // 点击事件:点击后更新数据模型,再通知适配器刷新 holder.btnSqure.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if (gm.getUserClicks) { Point p = intPositionToPoint(position); gm.game(p, position); // 这里传入position,而不是按钮 } } }); return row; } // 提供方法更新数据并刷新 public void updateCell(int position, int clickNumber, int backgroundResId) { GridCell cell = cellList.get(position); cell.setClickNumber(clickNumber); cell.setBackgroundResId(backgroundResId); notifyDataSetChanged(); } }
第三步:修改drawTheMove方法
不再直接修改按钮,而是通过适配器更新数据模型:
public void drawTheMove(int position) { int clickNum = getNumOfClick(); Player player = getLastPlayerPlay(); gameScreen.board.gridViewAdapter.updateCell(position, clickNum, player.getImageId()); // 移除invalidateViews(),notifyDataSetChanged已经足够 }
同时修改game函数里的调用:
if (isValid(p)) { addChoice(p); int position = pointToIntPosition(p); // 实现Point转position的方法 drawTheMove(position); // 传入position if (!onePlayer) { gameScreen.changeImageTurn(numOfClick); turn++; } // 电脑逻辑用Handler延迟,不再阻塞主线程 if (compLevel != 0) { new Handler(Looper.getMainLooper()).postDelayed(new Runnable() { @Override public void run() { // 执行电脑落子逻辑 } }, 1000); } }
3. 移除不必要的特殊处理
你的getView里有position!=0||postion0flag==false的特殊逻辑,这可能导致第一个位置的按钮无法正确更新状态。建议去掉这个判断,让所有位置的按钮都统一处理,避免逻辑漏洞。
为什么之前的notifyDataSetChanged没用?
因为你没有更新适配器依赖的数据模型,只是直接修改了单个View的状态。当GridView复用View时,旧的状态会被带到新的位置,而且notifyDataSetChanged触发后,getView没有根据最新数据刷新UI,所以看起来没效果。
内容的提问来源于stack exchange,提问作者Nakash.i
相关产品推荐
相关产品推荐

