只有在某些手机中,ListView才会在notifyDataSetChanged()

时间:2015-06-04 02:54:18

标签: android listview android-listview

这是因为它仅在某些手机中发生,因为它们的分辨率是FHD。

当显示UI时,一切似乎都可以。当我点击项目并调用notifyDataSetChanged()时,项目不会刷新它的样子。我需要再次点击ListView,项目将刷新布局到正确的外观。

如果列表视图改变大小(例如:搜索功能将重新设计整个布局),一切都会变好。

这是ListView代码:

public final class MyListView extends ListView implements AdapterView.OnItemClickListener
{

    ArrayList<SELECT_ITEM> selectList;
    ArrayList<ID_ITEM> idList;
    ShowItemAdapter showAdapter;

    public MyListView(Context context) 
    {
        selectList = new ArrayList<SELECT_ITEM>();
        idList = new ArrayList<ID_ITEM>();

        readIdList(mIdList);
        showAdapter = new ShowItemAdapter(context, idList, selectList);
        setAdapter(showAdapter);        

        ...
    }

    @Override
    protected void onFinishInflate() {
        setOnItemClickListener(this);
    }

    @Override
    public void onItemClick(AdapterView<?> parent, View view, int position, long ID) {
        boolean itemIsSelected = true;
        int size = selectList.size();

        // remove if click item in selectList
        for(int i=0 ; i<size ; i++) {
            int selectID = selectList.get(i).id;
            if (idList.get(position).id == selectID) {  
                itemIsSelected = false;
                selectList.remove(i);
                showAdapter.notifyDataSetChanged();
                break;
            }
        }

        if (itemIsSelected) {
            SELECT_ITEM item = new SELECT_ITEM();
            item.id = idList.get(position);
            selectList.add(item);
            // Here
            showAdapter.notifyDataSetChanged();
        }
    ...
    }

    ....
}

这是适配器代码,

    public final class ShowItemAdapter extends BaseAdapter{

    public ArrayList<ID_ITEM>   mIdList;
    public ArrayList<SELECT_ITEM>   mSelectList;

    public ShowItemAdapter(Context context,
        ArrayList<ID_ITEM> idList,
        ArrayList<SELECT_ITEM> selectList)
    {
        mIdList = idList;
        mSelectList = selectList;
    }

    @Override
    public int getCount() {
        int ret = mIdList.size();
        return ret;
    }

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

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

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {

        ...

        for(int i=0 ; i<size ; i++)
        {
            // is selected
            if (mIdList.get(position).id == 
                selectList.get(i).id)
            {
                mIsSelected = true;
                break;
            }
        }

        if (mIsSelected)
        {
            textView.setBackgroundColor(Color.red);
        }
        else
        {
            textView.setBackgroundColor(Color.white);
        }
    }
}

有人帮我一把吗?

我发现在getView()调试暂停时,这些手机正常工作会导致同样的问题。我认为..就像&#34;视图已经更新,因此它不会刷新视图。&#34;但是在调试期间更新视图会使ui实际上不刷新,然后它会以错误的方式工作。

我想这是关于令人耳目一新的观点。

8 个答案:

答案 0 :(得分:2)

我发现适配器的getView()和onItemClick()之间可能存在代码冲突和时序问题。

请允许我解释一下。在getView()中,有代码

if (mIdList.get(position).id == selectList.get(i).id)

注意:这会检查selectList的值,该值甚至不在此Adapter类中声明。我假设你的意思是mSelectList。但是,让我们继续......

在onItemClick()中,有代码

if (idList.get(position).id == selectID) {  
   ...
   selectList.remove(i);
   ...

注意:此代码从selectList中删除项目,而在getView()中,它正在检查同一个对象。我们无法知道哪些代码会先运行。但我有个主意...... getView()是一种虚拟回调方法,当 BaseAdapter需要显示行或项时, BaseAdapter可以触发方法。因此,当您从Listview中删除项目时,无论您在代码中执行什么操作,适配器都不会请求刷新。适配器ShowItemAdapter负责所有行/视图刷新。

建议:在getView()中放置相同的代码(用于删除/添加项目)以避免这些类型的代码冲突。

让我们知道这个奇怪的异常并祝你好运 Tommy Kwee

答案 1 :(得分:1)

您需要在super类的constructoronFinishInflate函数中调用MyListView方法。这可能导致了这个问题。

public MyListView(Context context) 
 {
    super(context);
    selectList = new ArrayList<SELECT_ITEM>();
    ..
    ..
}

    @Override
    protected void onFinishInflate() {
        super.onFinishInflate();
        setOnItemClickListener(this);
    }

答案 2 :(得分:1)

这是Android 4.0.3上的错误,notifyDataSetChanged无法使用onItemClickListener

所以解决方案是这样的:

  1. onItemClickListener分别设置为适配器中的每个视图
  2. 将它发送到您想要处理的地方
  3. 做你想做的事情并从那里打电话notifyDataSetChanged

答案 3 :(得分:1)

通常我会更新适配器上的数据,但我不会遇到这类问题,我相信它更加稳固。由于您正在更新Listview中的数据(selectList),我认为刷新/更新有点间接。我建议一开始尝试。

以下代码后的代码示例:

selectList.remove(i);
showAdapter.notifyDataSetChanged();

添加

  1. 无效()或
  2. invalidateViews()
  3. 注意:我注意到你调用onInit()的解决方案,我不知道它是什么。似乎涉及到计时问题,这意味着您不必在新的/单独的线程上运行代码。

答案 4 :(得分:1)

以下可能有所帮助。我在4.4.2中遇到了类似的问题,这有助于:

//clear the adapter    
showAdapter.clear();
//add all the data in your list to adapter again
showAdapter.addAll(selectList);

您无需调用notifyDataSetChanged,因为它将在addAll中执行此操作。 希望有所帮助。

答案 5 :(得分:1)

您应该同步更新ListView。

 public final class ShowItemAdapter extends BaseAdapter{

public ArrayList<ID_ITEM>   mIdList;
public ArrayList<SELECT_ITEM>   mSelectList;

public ShowItemAdapter(Context context,
    ArrayList<ID_ITEM> idList,
    ArrayList<SELECT_ITEM> selectList)
{
    mIdList = idList;
    mSelectList = selectList;
}

 public synchronized void refreshData(ArrayList<SELECT_ITEM> items) {
    this.mSelectList = items;
    notifyDataSetChanged();
}

每当您对列表进行更改时,请调用refreshData()方法

 selectList.remove(i);
 refreshData(selectList);

 selectList.add(i);
 refreshData(selectList);

这肯定会刷新用户列表视图以及更新的项目列表

答案 6 :(得分:0)

我找到了一个解决方案,虽然它仍然可以解决一些问题 我在Activity.onCreate()下面调用,只有onInit()MyListView才会被初始化:

    postDelayed(new Runnable()
    {
        public void run()
        {
            onInit(icicle); // initial ui
        }
    }, 100);

它使视图显示较慢但工作正常 如果延迟大约100毫秒,可能会导致那些精细的手机变得糟糕。 延迟大约350毫秒使两部手机都运行良好。 有更好的答案吗?

答案 7 :(得分:0)

不是使用showAdapter.notifyDataSetChanged();只更新数据源,而是指selectList并重新初始化您的适配器并将其附加到ListView。

替换此

selectList.remove(i);
showAdapter.notifyDataSetChanged();

selectList.add(item);
showAdapter.notifyDataSetChanged();

分别用

selectList.remove(i);
// or selectList.add(item);
  showAdapter = new ShowItemAdapter(context, idList, selectList);
        setAdapter(showAdapter);