• ListView的addHeaderView与setAdapter调用顺序

    顺序不当在低版本会报错
    服务器君一共花费 360.350 ms 进行了 3 次数据库查询,努力地为您提供了这个页面。
    广告很萌的
    1. Chapter: ListView 使用相关问题集
      1. 1. ListView的addHeaderView与setAdapter调用顺序

    ListView想要添加headerview的话,就要通过addHeaderView这个方法,然后想要为ListView设置数据的话,就要调用setAdapter方法了。但是,在调用addHeaderView和setAdapter的顺序上,有时候会报这样的一个异常:

    java.lang.IllegalStateException: Cannot add header view to list -- setAdapter has already been called.
    

    产生原因:addHeaderView()调用在setAdapter()之后,并且该代码运行在Android4.3之前的系统版本。就是因为我们在addHeaderView之前调用了setAdapter。

    比如下面的代码:

    mDataHelper = new RepliesDataHelper();
    mAdapter = new RepliesAdapter(this);
    mListView.setAdapter(mAdapter);
    mListView.setOnScrollListener(new PauseOnScrollListener(ImageLoader.getInstance(), true, true));
    
    if (getTopicData()) {
    	initTopicData();
    	getLoaderManager().initLoader(4, null, this);
    	getRepliesData();
    } else {
    	RequestManager.getInstance().getTopic(this, mTopicId, new Response.Listener<Topic>() {
    		@Override
    		public void onResponse(Topic response) {
    			initTopicData();
    			getLoaderManager().initLoader(4, null, TopicActivity.this);
    			getRepliesData();
    		}
    	}, new SimpleErrorListener(this));
    }
    

    在低版本 Android 系统会报以上的错。改成下面这样就没事了:

    mDataHelper = new RepliesDataHelper();
    mAdapter = new RepliesAdapter(this);
    
    if (getTopicData()) {
    	initTopicData();
    	getLoaderManager().initLoader(4, null, this);
    	getRepliesData();
    } else {
    	RequestManager.getInstance().getTopic(this, mTopicId, new Response.Listener<Topic>() {
    		@Override
    		public void onResponse(Topic response) {
    			initTopicData();
    			getLoaderManager().initLoader(4, null, TopicActivity.this);
    			getRepliesData();
    		}
    	}, new SimpleErrorListener(this));
    }
    
    mListView.setAdapter(mAdapter);
    mListView.setOnScrollListener(new PauseOnScrollListener(ImageLoader.getInstance(), true, true));
    

    initTopicData(); 里包含了 addHeaderView(headerView, null, false); 所以把它放在 setAdapter 之前,错误就不会发生。

    建议setAdapter需要在addHeaderView和addfooterView之后调用。这样就安全了。下面,我们来看看源码吧,看看究竟是什么原因造成的。下面看看 addHeaderView 在不同版本的代码。

    Android-17(4.2)的addHeaderView的源码:

    public void addHeaderView(View v, Object data, boolean isSelectable) {  
    	if (mAdapter != null && ! (mAdapter instanceof HeaderViewListAdapter)) {  
    		throw new IllegalStateException(  
    				"Cannot add header view to list -- setAdapter has already been called.");  
    	}  
    
    	FixedViewInfo info = new FixedViewInfo();  
    	info.view = v;  
    	info.data = data;  
    	info.isSelectable = isSelectable;  
    	mHeaderViewInfos.add(info);  
    
    	// in the case of re-adding a header view, or adding one later on,  
    	// we need to notify the observer  
    	if (mAdapter != null && mDataSetObserver != null) {  
    		mDataSetObserver.onChanged();  
    	}  
    } 
    

    Android-18(4.3)的addHeaderView源码:

    public void addHeaderView(View v, Object data, boolean isSelectable) {
    	final FixedViewInfo info = new FixedViewInfo();
    	info.view = v;
    	info.data = data;
    	info.isSelectable = isSelectable;
    	mHeaderViewInfos.add(info);
    
    	// Wrap the adapter if it wasn't already wrapped.
    	if (mAdapter != null) {
    		if (!(mAdapter instanceof HeaderViewListAdapter)) {
    			mAdapter = new HeaderViewListAdapter(mHeaderViewInfos, mFooterViewInfos, mAdapter);
    		}
    
    		// In the case of re-adding a header view, or adding one later on,
    		// we need to notify the observer.
    		if (mDataSetObserver != null) {
    			mDataSetObserver.onChanged();
    		}
    	}
    }
    

    在上面,我们可以对比出代码中的处理的不同。在17版本中,只要adapter不为空的话,那就直接会抛出异常,而这个异常恰好就是我们文章开头说到的异常。在18版本中,如果adapter不为空的话,则会新建一个adapter,这个adapter会包含了headerview和footerview以及我们传进来的原来的adapter。这是在18版本以后做的一个处理。虽然有了处理,但是建议大家还是按照上面说的调用顺序来使用addHeaderView,addFooterView和setAdapter吧。

更多 推荐条目

Welcome to NowaMagic Academy!

现代魔法 推荐于 2013-02-27 10:23   

本章最新发布
随机专题
  1. [移动开发] Android根基概念Context 8 个条目
  2. [C语言程序设计] 结构体基本知识 1 个条目
  3. [Python程序设计] Django 入门知识浅介 10 个条目
  4. [Python程序设计] urls.py设置技巧 8 个条目
  5. [PHP程序设计] 对输入文件类型的检测 1 个条目
  6. [Python程序设计] 标准库:urllib/urllib2 14 个条目
  7. [Python程序设计] Python语言概述 6 个条目
  8. [PHP程序设计] 声明式编程范式 12 个条目
  9. [智力开发与知识管理] 超越整体性学习 5 个条目
  10. [智力开发与知识管理] 整体性学习步骤 9 个条目
  11. [移动开发] Android 开发调试工具 ADB 3 个条目
  12. [移动开发] 刷机与root相关 2 个条目
窗口 -- [博客]