安卓Adapter去item重複使用的方案!

關於adapter去重複的問題其實是個很簡單的問題,很多人沒有理解到list,grid以及recyclerview重複利用item以及使用viewholder的原理,所以在去重的道路上走得很坎坷,在這裏小羽帶着大家去好好的學習和總結一下item的知識,然後使用十分簡潔的方案去有效的解決重複使用item帶來的問題。

1.認識item的重複使用和viewholder的出現

item的重複使用目的是爲了解決大量的list數據消耗大量的視圖空間,而viewholder的出現是系統在解決數據顯示的時候做的一種方案。

而這種方案主要針對的是重複的item但是數據不同。通過tag去綁定在item上然後再取得使用。

保證了每個已經創建的item上一定有個viewholder,所以每次刷新item的時候都必須要把數據和各種狀態綁定一遍,否則滑動的時候就會有重複顯示的問題。

2.從系統原理上去去重複

上面我們講了item通過viewholder去解決數據重複的方案,雖然有點繁瑣,但是有效可行。
有人要問:“如果我想改變某個item的屬性又不想重複使用導致其他item屬性也改變,什麼辦法好用呢?”。
這個問題最近的項目裏我也遇到了。而且是一個item裏面有兩個子item,這兩個子item也要一摸一樣,但是不能同時干擾。
需要做屬性動畫去改變樣式!!(是不是很蛋疼?畢竟公司想要炫酷,那我們就按需設計唄!)。
既然item重複利用,那麼item的子控件都會是同一個對象。
所以小羽滋生了一種想法,既然控件是一樣的,那麼我可以記錄一個當前選中的item或者它的一個控件,如果是當前item並且對應的position也是一樣的,那麼肯定是當前的item可以做改變,當滑動到重複利用的item時,雖然也是當前的item但是position卻不一樣,所以這時候就做默認的設置。
當滑回來的時候滿足前面的條件所以又會繼續改變。爲什麼可以這麼自信的使用這種方案?原因很簡單。
系統在重複利用item的時候是做過處理的,重複利用的這個item不可能和上個item同時出現在屏幕上。
所以我們不需要像viewholder一樣把每種狀態都做改變,因爲即使此刻的上一個item的屬性會隨着當前item屬性改變而改變,放心你是看不見的,所以我們不必擔心這種方案的不可行!

3.源碼分析

//recyclerview的adapter開始BindViewHolder
    @Override
    public void onBindViewHolder(RecViewHolder holder, final int position) {
        if(!Utils.listIsEmpty(mTopPaymentTypes) && mTopPaymentTypes.size() > position){
            PaymentType topPaymentType = mTopPaymentTypes.get(position);
            initPayBtnResource(holder.topPayViewItem, position, topPaymentType);
        }

        if(!Utils.listIsEmpty(mBottomPaymentTypes) && mBottomPaymentTypes.size() > position){
            PaymentType bottomPaymentType = mBottomPaymentTypes.get(position);
            initPayBtnResource(holder.bottomPayViewItem, position,bottomPaymentType);
        }
    }

    //設置item數據
    private void initPayBtnResource(View itemView, int position, PaymentType paymentType) {
        TextView payTypeName = (TextView) itemView.findViewById(R.id.payview_item_name);
        ImageView payTypeImage = (ImageView) itemView.findViewById(R.id.payview_item_image);
        View payTypeLight = itemView.findViewById(R.id.payview_item_light);
        PayTypeSource paySource = mPaySources.get(paymentType);
        if (paySource != null) {
            payTypeName.setText(paySource.getPayTypeName());
            //viewholder綁定item數據
            bindItemData(View itemView, int position, PaymentType paymentType);

            //下面這段語句就是解決item重複使用修改屬性導致其他item出現問題的方案。
            if (mCheckedPayType == paymentType) {
                startLightAnimator();
                mAnimPayLight = payTypeLight;
            } else {
                if (mAnimPayLight == payTypeLight) {
                    endLightAnimator();
                }
            }
        }

        if (isSinglePay) {
            itemView.setOnClickListener(null);
            itemView.setBackgroundResource(R.drawable.pay_item_uncheck);
        } else {
            itemView.setOnClickListener(mClick);
            itemView.setTag(paymentType);
            itemView.setBackgroundResource(R.drawable.pay_item_can_change);
        }
    }

4.總結該方案!

這個方案只在單個item重複使用的時候纔會被調用做改變,不需要每個item都去改變屬性來保持平衡,非常簡單直觀的解決的重複利用的問題,從代碼的簡潔和系統執行的效率上說,都比較優,缺點就是多佔了一個引用的內存,性價比上來說非常的靠譜。
有人肯定要問後面的endLightAnimator();只結束了動畫但是屬性還是變了。
這裏小羽不得不吐槽一句了:“每個人的項目需求不一樣,我這裏是浮光效果,不選中的時候我可以直接把浮光隱藏掉就行了,至於這個屬性在那個位置都不重要了”。
那麼如果是一定要顯示的去改變屬性呢?這個小羽在3裏面就說了,默認屬性,就是比如你貼了一個機器人,要把他變成瘦機器人,那麼這裏end的時候直接賦值一個原來的機器人.方案是對的,問題是解決問題的需求不一樣大家要按照自己的需求去實現。
原諒小羽不能貼出所有代碼(雖然代碼是自己寫的,但是作爲公司商業化產品,部分保密還是需要的)。

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