Android ViewPager的动态更新和Adapter的notifyDataSetChanged方法无效的问题

本文探讨了ViewPager在动态更新内容时的两种情况,特别是当只改变列表中元素的值而不改变位置和数量时,为何notifyDataSetChanged方法无效。通过一个示例展示了如何正确更新当前索引子项的组件值,强调了直接修改子项而不是替换整个列表的重要性。同时,提到了源码中notifyDataSetChanged的触发条件,并提供了相关文章链接以深入理解。
摘要由CSDN通过智能技术生成

开门见山地说        ViewPager的动态更新分为以下两种情况:

                1.只改变渲染的List中某些元素的某个值,不改变位置和数量的

                2.改变位置和数量的

        而Adapter的notifyDataSetChanged方法恰好就是在第一种情况中无效的。

        先讨论第一种情况。

        可能有一些跟我一样的初学者会有一样的疑问,为什么里面的元素都更改了,他的这个方法不触发呢,别急,导致notifyDataSetChanged方法哑火的情况有很多,我先只列出这种情况,你先看看是不是你的菜。

        我使用ViewPager+List<View>+ViewPagerAdapter构建了一个简易的切换页面,点击上方按钮,就可以更新下面的viewpager里面的当前索引的子项的某个组件的值(背景色),这里只大概解释原理和运行规则,MainActivity的代码如下,其他部分的代码我就不贴出来了,想必各位读者都是真才实学的高手,这点代码难不倒你们的。

       

public class MainActivity extends AppCompatActivity {

    private TextView mTextView;
    private ViewPager mViewPager;
    private MViewPagerAdapter mAdapter;
    private List<View> itemList;
    private LayoutInflater mInflater;
    private int mIndex;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mViewPager = findViewById(R.id.viewPager);
        mTextView = findViewById(R.id.textView);
        itemList = new ArrayList<>();
        mInflater = getLayoutInflater();
        //添加两个初始子项
        itemList.add(generateItem(R.color.pink));
        itemList.add(generateItem(R.color.teal_200));
        mAdapter = new MViewPagerAdapter(this,itemList);
        mViewPager.setAdapter(mAdapter);
        //给viewpager添加切换事件监听,滑动时可以切换索引
        mViewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
            @Override
            public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
                mIndex = position;
            }

            @Override
            public void onPageSelected(int position) {

            }

            @Override
            public void onPageScrollStateChanged(int state) {

            }
        });
        mTextView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                changeCurrentColor(mIndex,R.color.red);
            }
        });
    }

    /**
     * 用于插入一个ViewPager的子项
     * @param id 颜色的id,可以指定生成什么颜色的子项
     * @return 返回一个子项的view,直接插入itemList
     */
    public View generateItem(int id){
        View item = mInflater.inflate(R.layout.viewpager_item, null);
        TextView vpTextView = item.findViewById(R.id.vp_textView);
        vpTextView.setBackgroundColor(getResources().getColor(id));
        return item;
    }

    /**
     * 根据索引改变当前位置的子项中组件的背景色
     * @param index 索引
     * @param id 颜色的id
     */
    public void changeCurrentColor(int index,int id){
        //错误的做法
        /*View view = generateItem(id);
        itemList.set(index,view);
        mAdapter.notifyDataSetChanged();*/
        
        //正确的做法
        View view = itemList.get(index);
        TextView tv = view.findViewById(R.id.vp_textView);
        tv.setBackgroundColor(getResources().getColor(id));
    }
}

        可以看到我标出了错误的做法和正确的做法两个地方。可能是因为java基础不好,我很多时候是拒绝查看源码的,这是一个不好的习惯,也是导致这个问题我也是查了资料才解决的。

        源码中notifyDataSetChanged()的触发条件有二:

        1). 当前对象发生过位置改变

        2). 绑定的List的长度发生变化

具体源码的话我还是不太看得懂,详情见这篇

https://www.jianshu.com/p/863297e782c3?nomobile=yes

        也就是说,在错误案例中的

        View view = generateItem(id);
        itemList.set(index,view);
        mAdapter.notifyDataSetChanged();

 这样的操作完全没有碰到notifyDataSetChanged()方法的触发条件,这样用是错误的。

在更新List时的,删除子项或插入子项,调用这个方法没问题,但如果只是维护某索引的某个子项中的某个值的话,建议直接去修改它就好。

因此notifyDataSetChanged的这种情况的结论简单来说就是: 删除或插入可以,简单的更新不行。

当然notifyDataSetChanged失效的原因还有一点,viewpager-adapter-list三者之一不指向绑定时的地址了,换句话说就是,有内鬼!

具体的原因这篇文章讲的还不错,嘻嘻。

https://blog.csdn.net/whitley_gong/article/details/50562634

十分感谢你能看到这里。我们的目标是星辰大海,加油!

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值