notifyDataSetChanged 在具有自定义 BaseAdapter 的 ListView 中不起作用

问题描述 投票:0回答:3

我尝试创建ListView。它包含几个由单个 xml 模板创建的自定义视图 + 一个用于指示进度的视图。 ProgressView 必须始终位于我的自定义 ListView 的底部。 所以,这是代码:

public class SearchActivity extends Activity implements OnXMLDataGetterComplete {

    private ListView mMainLayout;
    private HotelsListAdapter mHotelsListAdapter;

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

        mHotelsListAdapter = new HotelsListAdapter(); //create my custom adapter
        mHotelsListAdapter.setLoading(true); //sets that my ListView will be show ProgressView at the bottom

        mMainLayout = (ListView) findViewById(R.id.search_activity_layout);
        mMainLayout.setAdapter(mHotelsListAdapter); //set adapter for my ListView

        getData(); //start to receive data from web
    }

    //this function runs after HTTP-query
    public void onGetData(final List data) { //receives list of some data
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                Iterator<XMLDataGetter.HotelListXMLParser.HotelListXMLEntry> it = data.iterator();
                while (it.hasNext()) {
                    XMLDataGetter.HotelListXMLParser.HotelListXMLEntry item = it.next();
                    mHotelsListAdapter.setLoading(data.size() != 0);
                    HotelItemView hotel = new HotelItemView(SearchActivity.this); //create some custom view by received data
                    ...
                    mHotelsListAdapter.addItem(hotel); //add this view to the adapter
                }
                mHotelsListAdapter.notifyDataSetChanged(); //THIS NOT WORKS
            }
        }
    }

    public class HotelsListAdapter extends BaseAdapter { //ny custom adapter

        private List<HotelItemView> mItems = new ArrayList<HotelItemView>(); //list, which contains all created custom views
        private boolean mIsLoading = false; //variable, which determines, whether ProgressView will be shown
        private RelativeLayout mLoadingView; //layout of activity

        public HotelsListAdapter() {
            LayoutInflater inflater = (LayoutInflater) ((Context) SearchActivity.this).getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            mLoadingView = (RelativeLayout) inflater.inflate(R.layout.hotel_list_loading, null); //inflate ProgressView
        }

        @Override
        public boolean areAllItemsEnabled() {
            return true;
        }

        @Override
        public boolean isEnabled(int position) {
            return true;
        }

        @Override
        public void registerDataSetObserver(DataSetObserver observer) {

        }

        @Override
        public void unregisterDataSetObserver(DataSetObserver observer) {

        }

        @Override
        public int getCount() {
            if (mIsLoading)
                return mItems.size() + 1; //custom adapter contains children vies + ProgressView
            else
                return mItems.size(); //custom adapter contains only children views
        }

        @Override
        public Object getItem(int position) {
            if (position > mItems.size() - 1)
                return mLoadingView; //return ProgressView
            else
                return mItems.get(position); //return child view
        }

        @Override
        public long getItemId(int position) {
            return position;
        }

        @Override
        public boolean hasStableIds() {
            return true;
        }

        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            return (View) getItem(position);
        }

        @Override
        public int getItemViewType(int position) {
            return 0;
        }

        @Override
        public int getViewTypeCount() {
            return 2;
        }

        @Override
        public boolean isEmpty() {
            return false;
        }

        public void addItem(HotelItemView item) {
            mItems.add(item);
        }

        public void clear() {
            mItems.clear();
        }

        public void setLoading(boolean loading) {
            mIsLoading = loading;
        }

        public boolean isLoading() {
            return mIsLoading;
        }
    }
}

这个带有 ProgressBarView 的示例,但我尝试删除有关它的引用:

    @Override
    public int getCount() {
        return mItems.size(); //custom adapter contains only children views
    }

    @Override
    public Object getItem(int position) {
        return mItems.get(position); //return child view
    }

notifyDataSetChanged() 无论如何都不起作用。我的问题是什么?我无法显示添加的视图。

我尝试在 otifyDataSetChanged() 之前添加 mMainLayout.invalidateViews() 。所以我看到了我的视图列表,但每隔三到五次我就会遇到异常“适配器的内容已更改但 ListView 未收到通知”。我该怎么办?

最主要的是我不需要清理我的适配器。添加子视图必须是增量的。我也尝试扩展ListAdapter,但它根本没有这样的方法

android listview baseadapter
3个回答
0
投票

也许不要重写Adapter的registerDataSetObserver方法。

其他一些提示:

如果没有理由不使用ArrayAdapter,我建议您使用它,因为它会为您节省一些基本配置并为您处理列表管理。 另外,不要将视图保存在要显示的列表中,而是保存保存数据的项目。 ListAdapters 可以为您回收视图,因此列表中的每一项都不是一个视图,而是每一项可见的项目都有一个视图。在 getView 方法中,如果 'convertView' 参数不为空,则该视图可以重复使用,因此只需填充其数据并返回即可。这将提高列表的性能并大大减少内存消耗。

对于异步内容,最好使用 AsyncTask,它与 Android 系统集成得更好,并且可以更轻松地执行诸如在后台任务之前和之后在 UI 线程中运行内容之类的操作。


0
投票

尝试

listview.setAdapter(adapter);
    if(state != null) {
       listview.onRestoreInstanceState(state);
    }

-1
投票

尝试

mHotelsListAdapter.setNotifyOnChange(true);
© www.soinside.com 2019 - 2024. All rights reserved.