Android:ListView在调用notifyDataSetChanged()时未刷新

6

我有一个自定义的BaseAdapter和一个添加按钮在主活动中。该按钮打开一个带有文本框的对话框,您可以通过这种方式向列表添加新元素。问题是列表不会刷新。在onActivityResult()函数中,我打印列表中的元素数量,每次我在对话框框中点击确定时,数字都会增加,所以我知道只是刷新不起作用。以下是我的BaseAdapter和活动:

class ListaOrase extends BaseAdapter{
    private Activity context;
    ArrayList<String> orase;

    public ListaOrase(Activity context){
        this.context=context;
        orase=new ArrayList<String>();
    }
    public void add(String string){
        orase.add(string);
        this.notifyDataSetChanged();
    }

    public View getView (int position, View convertView, ViewGroup list)  {
        View element;
        if (convertView == null)
        {
         LayoutInflater inflater = context.getLayoutInflater();
         element = inflater.inflate(R.layout.lista, null);
        }
        else element = convertView;
        TextView elementLista=(TextView)element.findViewById(R.id.elementLista);    
        elementLista.setText(orase.get(position));
        return element;
    }

}

public class WeatherAppActivity extends ListActivity {

    Button buton;
    ListaOrase lista;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        lista=new ListaOrase(this);
        buton=(Button)findViewById(R.id.buton);


        lista.add("Bucuresti");
        lista.add("Sibiu");
        setListAdapter(lista);

    }

    public void add(View view){
        Intent intent=new Intent();
        intent.setClass(this, Adauga.class);
        startActivityForResult(intent, 0);
    }

    public void onActivityResult (int requestCode, int responseCode, Intent data){
        System.out.println("Apelata");
        if(responseCode==1){
            lista.add(data.getStringExtra("oras")); // e chiar getText()
            System.out.println(lista.getCount());
            lista.notifyDataSetChanged();
        }
    }
}

正如您所见,我正在尝试在添加新元素(在扩展BaseAdapter类中)和在方法onActivityResult中刷新(notifyDataSetChanged();),在对话框将新元素传递给主Activity后。我重申,该元素已添加到列表中,因为计数增加了,只是没有刷新。

感谢您的回答!


为什么你不在OnActivityResult中调用setListAdapter(lista)呢? - Abhi
它确实完成了工作,但项目为空。LogCat显示列表需要一个字符串,但它得到了一个SpannableString。那是什么,我该如何摆脱它?它是通过Intent从对话框获取的。 - FloIancu
我在我的答案中添加了一些代码,修改了你的代码,修复了一些问题并使用了一个数组适配器进行简化。有几个小的变化非常重要要遵循,希望能对你有所帮助,请告诉我! - gwvatieri
我现在完全遇到了同样的问题:但只在我的Android 4.2设备上!我也扩展了BaseAdapter - 每当内容更改时,我都会触发notifyDataSetChanged。在Android 4.3、4.4甚至2.1上,一切都正常工作!在notifyDataSetChanged之后,ListView被通知并为所有显示的元素调用getView!但是在我的4.2设备上,在notifyDataSetChanged之后没有被调用一次!为什么?!?! - Zordid
1个回答

7

正常情况下,它不会自动刷新。您正在向“lista”中添加一个项目,但适配器保留其自己的列表副本,因此您需要重新设置适配器中的列表,然后调用notifyDataChanged或将新项目添加到适配器。

无论如何,我看到了几件奇怪的事情,我认为您可以使用数组适配器简化所有内容,您不需要实现add等功能。我编写了一些代码来简化您的代码:

public class WeatherAppActivity extends ListActivity {

Button buton;
ItemsAdapter lista;

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);

    List<String> initialList = new ArrayList<String>();
    initialList.add("Bucuresti");
    initialList.add("Sibiu");

    lista=new ItemsAdapter(this, initialList);
    buton=(Button)findViewById(R.id.button1);
    buton.setOnClickListener(new OnClickListener() {
        @Override
        public void onClick(View v) {
             lista.add(""+System.currentTimeMillis()); // e chiar getText()
             lista.notifyDataSetChanged();

        }
    });

    setListAdapter(lista);

}

class ItemsAdapter extends ArrayAdapter<String> {

    public ItemsAdapter(Context context, List<String> list) {
        super(context, R.layout.lista, list);
    }

    @Override
    public View getView(final int position, View row, final ViewGroup parent) {
        final String item = getItem(position);

        ItemWrapper wrapper = null;
        if (row == null) {
            row = getLayoutInflater().inflate(R.layout.lista, parent, false);
            wrapper = new ItemWrapper(row);

            row.setTag(wrapper);
        } else {
            wrapper = (ItemWrapper) row.getTag();
        }
        wrapper.refreshData(item);

        return row;
    }

    class ItemWrapper {

        TextView text;

        public ItemWrapper(View row) {
            text = (TextView) row.findViewById(R.id.elementLista);
        }

        public void refreshData(String item) {
            text.setText(item);
        }

    }
    }    

}

这些是我使用过的 XML 文件:
main.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >

<Button
    android:id="@+id/button1"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_alignParentBottom="true"
    android:layout_centerHorizontal="true"
    android:layout_marginBottom="63dp"
    android:text="Button" />

<ListView
    android:id="@id/android:list"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_alignParentTop="true"
    android:layout_centerHorizontal="true" >
</ListView>

</RelativeLayout>

lista.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >

<TextView
    android:id="@+id/elementLista"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="Medium Text"
    android:textAppearance="?android:attr/textAppearanceMedium" />

</LinearLayout>

这是使用BaseAdapter的适配器版本:
class ItemsBaseAdapter extends BaseAdapter {

private List<String> items;
private Context mContext;

public ItemsBaseAdapter(Context context, List<String> list) {
    items = list;
    mContext = context;
}

public void addItem(String str) {
    items.add(str);
}

@Override
public View getView(final int position, View row, final ViewGroup parent) {
    final String item = (String) getItem(position);

    ItemWrapper wrapper = null;
    if (row == null) {
        row = getLayoutInflater().inflate(R.layout.lista, parent, false);
        wrapper = new ItemWrapper(row);

        row.setTag(wrapper);
    } else {
        wrapper = (ItemWrapper) row.getTag();
    }
    wrapper.refreshData(item);

    return row;
}

class ItemWrapper {

    TextView text;

    public ItemWrapper(View row) {
        text = (TextView) row.findViewById(R.id.elementLista);
    }

    public void refreshData(String item) {
        text.setText(item);
    }

}

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

@Override
public Object getItem(int position) {
    return items.get(position);
}

@Override
public long getItemId(int position) {
    // TODO Auto-generated method stub
    return 0;
}
}

这是包含左侧图像视图的列表项的版本:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal" >

<ImageView 
    android:layout_height="wrap_content" 
    android:src="@android:drawable/btn_star_big_on" 
    android:scaleType="fitCenter" 
    android:layout_width="wrap_content" 
    />

<TextView
    android:id="@+id/elementLista"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="Medium Text"
    android:textAppearance="?android:attr/textAppearanceMedium" 
    />

</LinearLayout>    

Abhi提供了帮助(请参阅上面的评论),但似乎我在SpannableString方面存在问题(请参阅回复)。谢谢您的回答! - FloIancu
不幸的是,这项任务需要使用BaseAdapter。而且,我计划在每个项目左侧添加一个图标,这不能使用ArrayAdapter完成。那么这个SpannableString怎么样? - FloIancu
你可以独立于使用哪种类型的适配器来构建列表项。我编辑了我的答案,添加了一个BaseAdapter版本和一个包含左侧图标的列表项... - gwvatieri
适配器是否会保留对象的副本或源的引用?@gwa - Sazzad Hissain Khan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接