序言
有些bug,來(lái)無(wú)影,去無(wú)蹤。你不知道它怎么產(chǎn)生的。比如下面這個(gè),描述一下癥狀,每次Fragment切換的時(shí)候,頁(yè)面都會(huì)自己滾動(dòng)一點(diǎn)好像要把自己對(duì)齊。
布局如下
XML實(shí)現(xiàn)如下:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<RelativeLayout
android:id="@+id/top_bar"
android:layout_width="match_parent"
android:layout_height="@dimen/TopBarHeight"
android:background="@color/colorPrimary">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:src="@drawable/ic_logo" />
</RelativeLayout>
<com.trs.library.widget.statusviewlayout.StatusViewLayout
android:id="@+id/status_layout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.scwang.smartrefresh.layout.SmartRefreshLayout
android:id="@+id/ptr"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:srlEnableHeaderTranslationContent="true"
app:srlEnableLoadmore="true">
<com.scwang.smartrefresh.layout.header.ClassicsHeader
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:srlClassicsSpinnerStyle="FixedBehind" />
<android.support.v7.widget.RecyclerView
android:id="@+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@android:color/white" />
<com.scwang.smartrefresh.layout.footer.ClassicsFooter
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</com.scwang.smartrefresh.layout.SmartRefreshLayout>
</com.trs.library.widget.statusviewlayout.StatusViewLayout>
</LinearLayout>
用的是最近比較火的SmartRefreshLayout。
分析
一開始我看到的是這樣的
1.自定義Layout出問(wèn)題
每一次切換回來(lái)最頂部的自定義Layout都顯示不全,也就是下面這個(gè),實(shí)現(xiàn)可以看我的上一篇博客三角形兼梯形布局
于是把這個(gè)控件替換成RelativeLayout高度固定,但是bug依然存在。因此排除此項(xiàng)。
2.SmartRefreshLayout的問(wèn)題
這個(gè)頁(yè)面使用的了SmartRefreshLayout,詳情見這里Android智能下拉刷新框架-SmartRefreshLayout
雖然是比較有名的第三方庫(kù),但是bug也是可能有的。所以開始閱讀他的源碼,但是在閱讀了他的源碼以后,發(fā)現(xiàn)沒(méi)什么問(wèn)題。通過(guò)打斷點(diǎn)發(fā)現(xiàn),在頁(yè)面發(fā)生滾動(dòng)的時(shí)候它的方法根本就沒(méi)有調(diào)用。
3.手機(jī)的bug
我懷疑是不是開啟了類屬于三星的眼動(dòng)功能,于是用了同事的小米進(jìn)行測(cè)試,排除。
4.RecyclerView的問(wèn)題
既然排除了所以可能性,那么最不可能的答案也是答案了。在RecyclerView中負(fù)責(zé)滾動(dòng)的是LayoutManger,于是我自定義了LayoutManger,發(fā)現(xiàn)確實(shí)有Log輸出
測(cè)試代碼如下:
@Override
protected RecyclerView.LayoutManager getLayoutManager() {
return new MyLayoutManger(getActivity());
}
private class MyLayoutManger extends LinearLayoutManager {
public MyLayoutManger(Context context) {
super(context);
}
@Override
public int scrollVerticallyBy(int dy, RecyclerView.Recycler recycler, RecyclerView.State state) {
Log.i("zzz", "MyLayoutManger scrollHorizontallyBy dy=" + dy);
return super.scrollVerticallyBy(dy, recycler, state);
}
}
每一次切換回來(lái)的Log輸出
10-13 16:29:53.968 6990-6990/com.trs.cqjb.gov I/zzz: MyLayoutManger scrollHorizontallyBy dy=53
10-13 16:29:53.988 6990-6990/com.trs.cqjb.gov I/zzz: MyLayoutManger scrollHorizontallyBy dy=63
10-13 16:29:53.998 6990-6990/com.trs.cqjb.gov I/zzz: MyLayoutManger scrollHorizontallyBy dy=53
10-13 16:29:54.018 6990-6990/com.trs.cqjb.gov I/zzz: MyLayoutManger scrollHorizontallyBy dy=39
10-13 16:29:54.038 6990-6990/com.trs.cqjb.gov I/zzz: MyLayoutManger scrollHorizontallyBy dy=36
10-13 16:29:54.048 6990-6990/com.trs.cqjb.gov I/zzz: MyLayoutManger scrollHorizontallyBy dy=26
10-13 16:29:54.068 6990-6990/com.trs.cqjb.gov I/zzz: MyLayoutManger scrollHorizontallyBy dy=21
10-13 16:29:54.088 6990-6990/com.trs.cqjb.gov I/zzz: MyLayoutManger scrollHorizontallyBy dy=16
10-13 16:29:54.108 6990-6990/com.trs.cqjb.gov I/zzz: MyLayoutManger scrollHorizontallyBy dy=12
10-13 16:29:54.118 6990-6990/com.trs.cqjb.gov I/zzz: MyLayoutManger scrollHorizontallyBy dy=8
10-13 16:29:54.138 6990-6990/com.trs.cqjb.gov I/zzz: MyLayoutManger scrollHorizontallyBy dy=7
10-13 16:29:54.158 6990-6990/com.trs.cqjb.gov I/zzz: MyLayoutManger scrollHorizontallyBy dy=5
10-13 16:29:54.168 6990-6990/com.trs.cqjb.gov I/zzz: MyLayoutManger scrollHorizontallyBy dy=3
10-13 16:29:54.188 6990-6990/com.trs.cqjb.gov I/zzz: MyLayoutManger scrollHorizontallyBy dy=1
10-13 16:29:54.208 6990-6990/com.trs.cqjb.gov I/zzz: MyLayoutManger scrollHorizontallyBy dy=2
10-13 16:29:54.238 6990-6990/com.trs.cqjb.gov I/zzz: MyLayoutManger scrollHorizontallyBy dy=1
調(diào)用鏈如下
可以看出來(lái)都是Framework層的調(diào)用,沒(méi)有我們自己的代碼。也沒(méi)有SmartRefreshLayout的代碼。既然找到問(wèn)題了,就去Google。果然這是RecyclerView嵌套的bug。
總結(jié)
在遇到bug的時(shí)候,一定要耐心仔細(xì),從最容易出錯(cuò)的地方找起,可以先從自己找齊,但是如果自身沒(méi)有問(wèn)題,也不能放過(guò)第三方庫(kù),認(rèn)為第三方庫(kù)就完美無(wú)缺。當(dāng)遇到第三方庫(kù)有問(wèn)題的時(shí)候首先可以去翻閱Github中的issues這樣會(huì)更快捷,但是如果還沒(méi)有人閱讀這類問(wèn)題,那么我還得去read the funk source code (我曾經(jīng)就通過(guò)跟蹤斷點(diǎn),找出張鴻洋一個(gè)庫(kù)里面代碼的邏輯問(wèn)題,然后去提了issues。)因此當(dāng)我們遇到bug時(shí)不要怕,要平心靜氣,理性分析,合理假設(shè),逐一排除。