You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android自定义Adapter中TextView的setText无法更新UI问题

解决AlertDialog更新ListView项TextView不持久的问题

嘿,我看了你遇到的问题——在AlertDialog里修改单词和翻译后,TextView的setText只能临时生效,滚动或者编辑其他项就打回原形,重启Activity才会显示正确内容。这问题其实出在Adapter的数据源不同步上,咱们一步步理清楚:

问题根源

你的DictionaryAdapter继承自ArrayAdapter<String>,初始化时传入的是new ArrayList<>(source.keySet())作为默认数据源,但你修改dict的时候,完全没同步更新这个ArrayList!

当你调用notifyDataSetChanged()时,Adapter会重新遍历它自己维护的那个旧的单词列表,在getView里通过getItem(position)拿到旧单词,然后又把holder.word.setText(word)给覆盖了你手动设置的新内容。这就是为什么你手动setText后看起来生效,但一滚动或者其他操作就恢复原状的原因。

另外你代码里还有个小笔误:if(position < visibleText.length)应该是visibleButtons.length,不然会有数组越界风险。

解决方案

核心思路是自己维护Adapter的数据源列表,确保修改dict时同步更新这个列表:

1. 新增自定义数据源列表

在Adapter里添加一个wordList来代替ArrayAdapter默认的数据源:

public class DictionaryAdapter extends ArrayAdapter<String> { 
    private LayoutInflater inflater; 
    private int layout; 
    private Map<String, String> dict; 
    private boolean[] visibleButtons; 
    private Context mContext; 
    private List<String> wordList; // 新增:自己维护单词列表
    static class ViewHolder { 
        TextView word; 
        TextView translation; 
        FloatingActionButton edit; 
    }
    // ...
}

2. 修改构造函数,初始化自定义列表

把原来传给super的ArrayList替换成自己的wordList,同时不再依赖ArrayAdapter的默认数据源:

public DictionaryAdapter(Context context, int layout, Map<String, String> source) {
    super(context, layout); // 这里不再传数据源,我们自己维护
    mContext = context;
    inflater = LayoutInflater.from(context);
    this.layout = layout;
    dict = source;
    wordList = new ArrayList<>(source.keySet()); // 初始化自定义列表
    visibleButtons = new boolean[dict.size()];
}

3. 重写getCount和getItem方法

让Adapter使用我们的wordList来提供数据:

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

@Override
public String getItem(int position) {
    return wordList.get(position);
}

4. 同步更新editWord方法

修改editWord时,不仅要更新dict,还要找到旧单词在wordList中的位置,替换成新单词:

private void editWord(String oldWord, String newWord, String newTranslation) {
    MainApplication.getDataUtils().editWordInDict(mContext, DictionaryActivity.currentDictionaryName, oldWord, newWord, newTranslation); 
    // 更新字典映射
    dict.remove(oldWord);
    dict.put(newWord, newTranslation);
    // 同步更新单词列表
    int oldIndex = wordList.indexOf(oldWord);
    if (oldIndex != -1) {
        wordList.set(oldIndex, newWord);
    }
    // 通知Adapter刷新
    notifyDataSetChanged();
}

5. 修正笔误

把if(position < visibleText.length)改成if(position < visibleButtons.length),避免数组越界异常。

为什么之前的方法没用?

  • holder.word.post(Runnable)和自定义changeText:只是临时修改了当前View的内容,但数据源没更新,当ListView复用View或者调用notifyDataSetChanged时,getView又会从旧数据源取数据覆盖掉临时修改。
  • runOnUiThread:其实你的操作本来就在UI线程里(AlertDialog的点击事件是UI线程),所以这个操作完全没用。

现在修改后,你不需要在AlertDialog的点击事件里手动调用holder.word.setText(wordInput)了,因为notifyDataSetChanged()会触发getView重新绘制,自动从更新后的wordList和dict里取新值设置给TextView。当然如果你想即时看到变化,保留手动setText也没问题,现在数据源同步了,不会再被覆盖。

内容的提问来源于stack exchange,提问作者Tom

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 07:15:22