天天看點

Android ViewPager的動态更新和Adapter的notifyDataSetChanged方法無效的問題

開門見山地說        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));
    }
}
           
Android ViewPager的動态更新和Adapter的notifyDataSetChanged方法無效的問題

        可以看到我标出了錯誤的做法和正确的做法兩個地方。可能是因為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

十分感謝你能看到這裡。我們的目标是星辰大海,加油!