【轉載】【Android】詳解7.0帶來的新工具類:DiffUtil

本文參考自:http://blog.csdn.net/zxt0601/article/details/52562770

(先說點題外話,這博主很不錯了,他的文章在hongyangAndroid (鴻洋)的公衆號的發佈過多次了,文章不僅有技術含量,而且文筆很細膩)


這次學習的是一個與RecyclerView有關的工具類——DiffUtil,具體的內容請看上文。我在這裏主要是就文章的一些點提出自己的見解:

1、在模擬刷新的onRefresh()方法中。有這麼一段代碼:

            mNewDatas = new ArrayList<>();
            for (TestBean bean : mDatas) {
                mNewDatas.add(bean.clone());//clone一遍舊數據 ,模擬刷新操作
            }
            //mNewDatas.addAll(mDatas); //++++++++++
            mNewDatas.add(new TestBean("趙子龍", "帥", R.drawable.pic6));//模擬新增數據
            mNewDatas.get(0).setDesc("Android+++++");
            mNewDatas.get(0).setPic(R.drawable.pic7);//模擬修改數據
            TestBean testBean = mNewDatas.get(1);//模擬數據位移
            mNewDatas.remove(testBean);
            mNewDatas.add(0,testBean);

在註釋裏有講解,clone一遍舊數據 ,模擬刷新操作,這裏需要注意,新的數據需要深度clone(生成一個新的與原來TestBean實例具有相同內容的成員變量的實例,如果不懂請看演示圖),否則mNewDatas與mDatas對於“一個相同的TestBean實例(成員變量的內容相同)”存在同一引用,從而導致改變mNewDatas的某一項的成員變量的內容,由於存在統一引用,mDatas中的那一項也會跟着改變,因此areContentsTheSame()是不起作用的, 大家也可以自己去嘗試一下,就像我註釋掉的那行代碼(把原來的操作註釋掉),雖然是new了一個新的mNewDatas,但是通過mNewDatas.addAll(mDatas)方法填充的數據,在未做其他操作的前提下,mNewDatas與mDatas中的每一項數據都具有相同的引用,說白了就是同一東東。(其實這一點在文章末尾也有提到,但具體的就是上面的意思)。(題外話:這裏是在用空間換效率)
這裏寫圖片描述

演示圖(第一張的爲正確的,第二張爲非正確的):
這裏寫圖片描述

這裏寫圖片描述

2、 在使用博主提供的Demo時,如果是按照文章的順序一步一步看下去的,則在第2步DiffUtil的簡單用法 時,想要運行demo體驗演示效果的話,需要把DiffCallBack.java中的getChangePayload(int oldItemPosition, int newItemPosition)方法與DiffAdapter中的onBindViewHolder(DiffVH holder, int position, List<Object> payloads)方法註釋掉,再去運行,因爲這是第3部分DiffUtil的高級用法的內容了。開始我就沒有注意到,就直接運行了,然後就沒有體驗到博主所說的“白光一閃”。(搞得我一直以爲是我眼花,看不出來#_#)
這裏寫圖片描述


番外篇:

在前面的文章中有提到過一個名詞“定向刷新”,如果對這個有疑惑的,可以看看這個:
【Android】 RecyclerView、ListView實現單選列表的優雅之路.

在這裏面,有用實際了代碼講解什麼是“定向刷新”。
值得注意的是在三 ListView 方案一覽:2 ListView裏尋找優雅之路:中,核心代碼如下(從考慮了HeaderView的情況 這裏就可以體現出作者的細膩):

                //如果 當前選中的View 在當前屏幕可見,且不是自己,要定向刷新一下之前的View的狀態
                if (position != mSelectedPos) {
                    int firstPos = mLv.getFirstVisiblePosition() - mLv.getHeaderViewsCount();//這裏考慮了HeaderView的情況
                    int lastPos = mLv.getLastVisiblePosition() - mLv.getHeaderViewsCount();
                    if (mSelectedPos >= firstPos && mSelectedPos <= lastPos) {
                        View lastSelectedView = mLv.getChildAt(mSelectedPos - firstPos);//取出選中的View
                        CouponVH lastVh = (CouponVH) lastSelectedView.getTag();
                        lastVh.ivSelect.setSelected(false);
                    }
                    //不管在屏幕是否可見,都需要改變之前的data
                    mDatas.get(mSelectedPos).setSelected(false);

                    //改變現在的點擊的這個View的選中狀態
                    couponVH.ivSelect.setSelected(true);
                    mDatas.get(position).setSelected(true);
                    mSelectedPos = position;
                }

在上面的代碼中,有View lastSelectedView = mLv.getChildAt(mSelectedPos - firstPos); ,這裏是爲了獲取先前被選中的view,這裏用到了ListView的getChildAt()方法,其作用就是取得在屏幕上可見的items中指定index的view,不過這裏index基數爲0,即第一個可見的item的index爲0,依次類推,而不是基於整個ListView的第一個item來說的,如下圖:
這裏寫圖片描述

另外,還需要注意一下末尾的評論,如果有出現評論中的狀況的:
這裏寫圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章