雙RecyclerView 不一樣的聯(lián)動(dòng)方式

導(dǎo)讀

  • 問題描述
  • 代碼分析及修改
  • 性能測(cè)試

問題描述

數(shù)據(jù)2000多條,雙Recycleview聯(lián)動(dòng)滑動(dòng)伪朽,左右各一個(gè)轴咱,滑動(dòng)左邊的右邊也動(dòng),滑動(dòng)右邊左邊也動(dòng)烈涮;
先滑動(dòng)左邊的Recycleview-rcvLeft朴肺,兩個(gè)列表滑動(dòng)過程中(重點(diǎn)),去滑動(dòng)右邊的Recycleview-rcvRight
這時(shí)就會(huì)報(bào)錯(cuò)坚洽,堆內(nèi)存溢出8M (StackOverflowError)戈稿,同理先滑右過程中去滑左也是崩潰

首先看下下需求,設(shè)計(jì)稿如下圖

image

紅色部分左右滑動(dòng),藍(lán)色部分上下滑動(dòng)讶舰,所以紅色部分使用了HorizontalScrollView+RecyclerView鞍盗;綠色為兩個(gè)RecyclerView:

實(shí)際效果

image

代碼梳理

網(wǎng)上方式
mLeftScrollListener = new RecyclerView.OnScrollListener() {
            @Override
            public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) {
                super.onScrollStateChanged(recyclerView, newState);
        
            }

            @Override
            public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) {
                super.onScrolled(recyclerView, dx, dy);
                if (recyclerView.getScrollState() != RecyclerView.SCROLL_STATE_IDLE) {
                    rcvRight.scrollBy(dx, dy);
                }
            }
        };
        rcvLeft.addOnScrollListener(mLeftScrollListener);

        mRightScrollListener = new RecyclerView.OnScrollListener() {
            @Override
            public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) {
                super.onScrollStateChanged(recyclerView, newState);
              
            }

            @Override
            public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) {
                super.onScrolled(recyclerView, dx, dy);
                if (recyclerView.getScrollState() != RecyclerView.SCROLL_STATE_IDLE) {
            
                    rcvLeft.scrollBy(dx, dy);//報(bào)StackOverflowError
                }
            }
        };
        rcvRight.addOnScrollListener(mRightScrollListener);

網(wǎng)上上下聯(lián)動(dòng)都是這套代碼需了,可能數(shù)據(jù)量比較小,滑動(dòng)時(shí)都沒發(fā)現(xiàn)StackOverflowError這個(gè)異常般甲;
解決辦法:在滑動(dòng)rcvLeft時(shí)讓rcvRight的父布局去攔截rcvRight的觸摸事件肋乍,在滑動(dòng)rcvRight時(shí)讓rcvLeft的父布局去攔截rcvLeft的觸摸事件;
所以重寫了右邊的HorizontalScrollView和左邊父布局RelativeLayout敷存;

TouchHorizontalScrollView.java:
public class TouchHorizontalScrollView extends HorizontalScrollView {
    public TouchHorizontalScrollView(Context context) {
        super(context);
    }

    public TouchHorizontalScrollView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public TouchHorizontalScrollView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }


    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        if (intercept) {
            return true;
        }
        return super.onInterceptTouchEvent(ev);
    }

    /**
     * 是否攔截子View
     */
    private boolean intercept=false;

    public boolean isIntercept() {
        return intercept;
    }

    public void setIntercept(boolean intercept) {
        this.intercept = intercept;
    }
TouchRelativeLayout.java :
public class TouchRelativeLayout extends RelativeLayout {
    public TouchRelativeLayout(Context context) {
        super(context);
    }

    public TouchRelativeLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public TouchRelativeLayout(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }


    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        if (intercept) {
            return true;
        }
        return super.onInterceptTouchEvent(ev);
    }

    /**
     * 是否攔截子View
     */
    private boolean intercept=false;

    public boolean isIntercept() {
        return intercept;
    }

    public void setIntercept(boolean intercept) {
        this.intercept = intercept;
    }
}

處理后代碼:

mLeftScrollListener = new RecyclerView.OnScrollListener() {
            @Override
            public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) {
                super.onScrollStateChanged(recyclerView, newState);
                //newState 0:停止墓造,1、2表示滑動(dòng)锚烦,再滑動(dòng)時(shí)去攔截右側(cè)RecyclerView 的觸摸事件
               
                horizontalScrollview.setIntercept(newState != 0);
              
            }

            @Override
            public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) {
                super.onScrolled(recyclerView, dx, dy);
                if (recyclerView.getScrollState() != RecyclerView.SCROLL_STATE_IDLE) {
                    rcvRight.scrollBy(dx, dy);
                }
            }
        };
        rcvLeft.addOnScrollListener(mLeftScrollListener);

        mRightScrollListener = new RecyclerView.OnScrollListener() {
            @Override
            public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) {
                super.onScrollStateChanged(recyclerView, newState);
                    //newState 0:停止觅闽,1、2表示滑動(dòng)挽牢,在滑動(dòng)時(shí)去攔截左側(cè)RecyclerView 的觸摸事件
               
                    rl_left.setIntercept(newState != 0);
              
            }

            @Override
            public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) {
                super.onScrolled(recyclerView, dx, dy);
                if (recyclerView.getScrollState() != RecyclerView.SCROLL_STATE_IDLE) {
                
                    rcvLeft.scrollBy(dx, dy);//報(bào)StackOverflowError
                }
            }
        };
        rcvRight.addOnScrollListener(mRightScrollListener);

這樣處理完之后稍微有點(diǎn)小瑕疵:在滑動(dòng)左側(cè)后谱煤,滑動(dòng)右側(cè)是不生效的(因?yàn)橛|摸事件被攔截了),但是總比報(bào)StackOverflowError 崩潰強(qiáng)禽拔;

記得在onDestroy時(shí)移除滑動(dòng)事件監(jiān)聽,不然在滑動(dòng)時(shí)刘离,關(guān)閉頁面會(huì)報(bào)空指針

@Override
    protected void onDestroy() {
        try {
            if (rcvLeft != null) {
                rcvLeft.removeOnScrollListener(mLeftScrollListener);
            }
            if (rcvRight != null) {
                rcvRight.removeOnScrollListener(mRightScrollListener);
            }
            mLeftScrollListener=null;
            mRightScrollListener=null;
        }catch (Exception e){
           e.printStackTrace();
        }

        super.onDestroy();
    }

最后測(cè)試下這個(gè)滑動(dòng)的性能,看看有沒有掉幀的現(xiàn)象

打開https://perfdog.qq.com/,進(jìn)行測(cè)試,通過windows 客戶端 鏈接手機(jī)進(jìn)行數(shù)據(jù)收集,兩次之前的代碼測(cè)試,一次修改的代碼測(cè)試,選擇好進(jìn)行對(duì)比

image.png

藍(lán)色的線是我們修復(fù)代碼后的曲線
FPS


image

JANK


image
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市睹栖,隨后出現(xiàn)的幾起案子吻氧,更是在濱河造成了極大的恐慌河哑,老刑警劉巖丹墨,帶你破解...
    沈念sama閱讀 206,013評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件疾牲,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡曼氛,警方通過查閱死者的電腦和手機(jī)豁辉,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,205評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來舀患,“玉大人徽级,你說我怎么就攤上這事×那常” “怎么了餐抢?”我有些...
    開封第一講書人閱讀 152,370評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵,是天一觀的道長低匙。 經(jīng)常有香客問我旷痕,道長,這世上最難降的妖魔是什么顽冶? 我笑而不...
    開封第一講書人閱讀 55,168評(píng)論 1 278
  • 正文 為了忘掉前任欺抗,我火速辦了婚禮,結(jié)果婚禮上强重,老公的妹妹穿的比我還像新娘绞呈。我一直安慰自己团滥,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,153評(píng)論 5 371
  • 文/花漫 我一把揭開白布报强。 她就那樣靜靜地躺著,像睡著了一般拱燃。 火紅的嫁衣襯著肌膚如雪秉溉。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 48,954評(píng)論 1 283
  • 那天碗誉,我揣著相機(jī)與錄音召嘶,去河邊找鬼。 笑死哮缺,一個(gè)胖子當(dāng)著我的面吹牛弄跌,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播尝苇,決...
    沈念sama閱讀 38,271評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼铛只,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了糠溜?” 一聲冷哼從身側(cè)響起淳玩,我...
    開封第一講書人閱讀 36,916評(píng)論 0 259
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎非竿,沒想到半個(gè)月后蜕着,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,382評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡红柱,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,877評(píng)論 2 323
  • 正文 我和宋清朗相戀三年承匣,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片锤悄。...
    茶點(diǎn)故事閱讀 37,989評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡韧骗,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出铁蹈,到底是詐尸還是另有隱情宽闲,我是刑警寧澤,帶...
    沈念sama閱讀 33,624評(píng)論 4 322
  • 正文 年R本政府宣布握牧,位于F島的核電站容诬,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏沿腰。R本人自食惡果不足惜览徒,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,209評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望颂龙。 院中可真熱鬧习蓬,春花似錦纽什、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,199評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至枫慷,卻和暖如春让蕾,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背或听。 一陣腳步聲響...
    開封第一講書人閱讀 31,418評(píng)論 1 260
  • 我被黑心中介騙來泰國打工探孝, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人誉裆。 一個(gè)月前我還...
    沈念sama閱讀 45,401評(píng)論 2 352
  • 正文 我出身青樓顿颅,卻偏偏與公主長得像,于是被迫代替她去往敵國和親足丢。 傳聞我的和親對(duì)象是個(gè)殘疾皇子粱腻,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,700評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容