SwipeRefreshLayout無法下拉刷新了

最開始採用SwipeRefreshLayout作爲下拉刷新控件,但是產品經理還沒來得及定義EmptyView頁長什麼樣就跑路了,所以這個問題就交給程序員自己解決了,那當然最簡單的方案就是在Empty頁中間放一個按鈕,請求失敗或者無網絡的時候分別提示用戶點擊重試或者設置網絡,這也是大多數APP的選擇。本着人人都是產品經理的理念,個人認爲即便請求失敗或者空數據的情況下,仍然採用下拉刷新的操作來進行retry,在交互上可以保證用戶習慣的一致性,而且滑動操作也比點擊操作有更好的體驗,也是交互和設計的趨勢所向。

當時第一版開發時間特別緊,所以關於這個EmptyView的實現方案特別挫。直接在xml裏包了兩個SwipeRefreshLayout,一個用來下拉刷新列表,一個用來下拉刷新EmptyView,然後在代碼裏控制二者的顯示與隱藏。方案雖然很挫,但也沒出什麼大問題,就這麼作爲臨時方案先用着。

第二版的時候把這個方案替換掉了,去掉了EmptyView外面包裹的SwipeRefreshLayout。

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fitsSystemWindows="true"
 >
<android.support.v4.widget.SwipeRefreshLayout 
       android:id="@+id/swipeLayout"
       android:layout_width="match_parent"
       android:layout_height="match_parent"
       android:orientation="vertical">
        <android.support.v7.widget.RecyclerView
          android:id="@+id/list_view"
          android:layout_width="match_parent"
          android:layout_height="match_parent"/>
</android.support.v4.widget.SwipeRefreshLayout>
   <TextView
        android:id="@+id/error_view"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:gravity="center"
        android:textColor="@color/subhead_text_color"
        android:textSize="@dimen/primary_tip_size"
        android:visibility="gone" />
</RelativeLayout>

直接這樣,EmptyView依然可以下拉刷新,這裏依賴的原理是點擊事件的穿透,即便當前顯示在上層的視圖是EmptyView,如果不給EmptyView添加任何事件,那麼事件會向下傳遞,傳遞給下面的SwipeRefreshLayout,有時候這種奇技淫巧還是挺有用的。

然後這個方案就一直延續着,直到開頭提到的QA妹紙發現無法下拉刷新的bug爲止,都沒有發現什麼問題。那這個bug到底是什麼原因引起的呢?我第一反應是,有人動我代碼了,於是我compare了當前節點與上次發版的節點,代碼一毛一樣,沒有人動我代碼,但是線上的就OK啊。剛開始我跟QA妹紙打包票,半個小時解決問題,而實際上最後和同事們花了近半天時間才解決。

問題走進了死衚衕,首先是看了半個小時代碼,無法準確定位問題。compare了兩個節點的代碼,依然無法定位,那還是隻能採用笨辦法了,排除法。上次發版距本次發版,這中間已經產生了幾十個commit,到底是哪次commit後出現了這個問題,這是第一個要定位的問題,於是乎一一checkout驗證,當然這也是有技巧的,雖然沒驗證過到底怎樣的查找方式會比較快,習慣性的在這幾十個commit中來了個二分查找。每次checkout編譯運行測試也是很耗時的,而且這個工作很枯燥,只能發動大家一塊來找茬啦。

找了好大一會,終於定位到了一個commit,這個commit 之前OK,而之後就悲劇了。那毫無疑問就是它搞得鬼,但這個commit毫不起眼,根本沒有什麼傷筋動骨的修改。那如果代碼上沒有大修改,就要注意下AndroidManifeset和gradle了。gradle中增加了些看似無關緊要的引用,肉眼也實在看不出有什麼問題,但如果把這些新增的引用包去掉,問題馬上就解決了。但新增的這些包與SwipeRefreshLayout可是八竿子打不着啊,但SwipeRefreshLayout是android.support.v4包裏的控件,會不會是support.v4包更換了新的版本?

展開External Libraries 發現果然有兩個support.v4包。


Paste_Image.png

難道是這兩個包裏的SwipeRefreshLayout實現不太一樣,或者有做改動?


Paste_Image.png

找到源碼一探究竟,拉出support.v4-23.0.1和support.v4-23.3.0裏的SwipeRefreshLayout源碼,一看行數都不一樣,前者1152行,後者1163行。我勒個去還真是做了修改,難道是升級的時候沒有向下兼容嗎?compare了下兩個版本的代碼,發現事件分發那裏確實做了些修改。


Paste_Image.png

猜想大概是這個原因,利用Click-Through來實現下來刷新不能奏效了。但是我仍然想用以前的方案,怎麼辦呢?
有兩個辦法,一個是指定使用老版本的support.v4包。二是把老版本的代碼copy出來放到自己工程裏。最後我們採用了比較優雅一點的方式,在gradle裏強制指定了版本。

configurations.all {
    resolutionStrategy {
        force 'com.android.support:support-v4:23.0.1'
    }
}

最後一個問題,爲什麼會有兩個support-v4包呢?剛開始的時候用recyclerview,SwipeRefreshLayout這些空間的時候導入了一個support-v4包,這個版本相對較低,是support-v4:23.0.1,後來一直沒有更新。隨着項目的進行,另外的同學在導入其他第三方包的時候,這個第三方包依賴了一個比較新的support-v4包,support.v4-23.3.0。所以這個時候SwipeRefreshLayout默認使用了比較新的額代碼,就導致了開頭所提到的那個bug。友情提示:更新引用包是有很大風險的,一定要多測試。有時間再說下另外一次更新包挖的坑。



文/尹star(簡書作者)
原文鏈接:http://www.jianshu.com/p/2a1897fdc041
著作權歸作者所有,轉載請聯繫作者獲得授權,並標註“簡書作者”。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章