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

时间:2014-06-16 15:42:01

标签: android listview baseadapter

我尝试创建ListView。它包含由单个xml-template +一个视图创建的几个自定义视图,用于指示进度。 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,但它根本没有这样的方法

2 个答案:

答案 0 :(得分:0)

也许不要覆盖适配器的registerDataSetObserver方法。

其他一些提示:

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

对于Async的东西,最好使用AsyncTask,它更好地与Android系统集成,并且可以更轻松地在后台任务之前和之后在UI线程中运行东西。

答案 1 :(得分:-1)

尝试

mHotelsListAdapter.setNotifyOnChange(true);