1.Fresco引發(fā)的血案
前面寫過一篇關(guān)于Fresco分析的文章,沒想到?jīng)]過幾天就發(fā)生了一場血案。事情是這樣的快压,昨天另一個小哥跟我說他用Fresco加載gif不能顯示了幔睬,他也不知道為什么,也沒改什么東西续膳,讓我?guī)兔匆幌隆F鋵嵨覀冺椖坑肍resco已經(jīng)挺久的了,然后之前那個地方也沒有問題霍殴,但是不知道為什么就是不顯示了。于是今天就開始了折騰系吩。
2.解決過程
1.首先我懷疑是不是改了布局来庭,導(dǎo)致控件沒有顯示出來。帶著這樣的懷疑穿挨,我設(shè)置了控件的背景為鮮明的紅色月弛,發(fā)現(xiàn)是顯示出來的,并沒有什么問題科盛。當(dāng)然這個想法可能太簡單了點帽衙,但是這樣的原因也是很有可能的,所以當(dāng)一個控件不能顯示的時候贞绵,你一定要先確定改控件是不是Visible厉萝,如果是Visible那么再去找其他原因。
2.懷疑加載圖片的URI有問題榨崩,通過跟蹤AbstractDraweeController中的
submitRequest()方向作為入口谴垫,不斷跟蹤到如下圖的地方,發(fā)現(xiàn)URI正確母蛛,且正確調(diào)用的相應(yīng)的方法翩剪。
既然url沒有錯,那我看看submit中的回調(diào)吧彩郊,如下圖前弯,媽蛋居然調(diào)的是失敗舞肆,這我就懵逼了,這tm到底哪里出錯了呢博杖,就錯了也不是咱自己的錯吧椿胯,這鍋不得facebook來背嗎?但以我多年的職業(yè)經(jīng)驗來看這個事情不是那么簡單剃根,于是我繼續(xù)斷點反復(fù)查看哩盲。我們通過對Fresco的分析會發(fā)現(xiàn),最終在處理請求時都會調(diào)用Producer類中的的produceResults來消費請求狈醉,但是對于這個Producer我也不是很懂廉油,但是就憑他要調(diào)用的這個方法,我斷點逐行分析苗傅,發(fā)現(xiàn)并沒有什么問題抒线。最終個條路也只能到這里結(jié)束。
3.實在沒什么頭緒了渣慕,于是去查看Fresco的文檔http://www.fresco-cn.org/docs/getting-started.html,文檔中關(guān)于加載gif的描述如下:
Uri uri;
DraweeController controller = Fresco.newDraweeControllerBuilder()
.setUri(uri)
.setAutoPlayAnimations(true)
. // 其他設(shè)置(如果有的話)
.build();
mSimpleDraweeView.setController(controller);
這代碼這么簡單沒什么問題啊嘶炭。繼續(xù)看文檔,發(fā)現(xiàn)在問題處理中說可以啟動日志逊桦,既然沒有辦法那就啟動日志來看看唄眨猎。Fresco日志默認(rèn)是關(guān)閉的,啟動日志方法如下强经,在Fresco初始化時做如下配置:
Set<RequestListener> requestListeners = new HashSet<>();
requestListeners.add(new RequestLoggingListener());
ImagePipelineConfig config = ImagePipelineConfig.newBuilder(context)
// other setters
.setRequestListeners(requestListeners)
.build();
Fresco.initialize(context, config);
FLog.setMinimumLoggingLevel(FLog.VERBOSE);
查看日志方法如下:
adb logcat -v threadtime | grep -iE 'LoggingListener|AbstractDraweeController|BufferedDiskCache'
ok打開日志后睡陪,再次加載,看到如下日志:
什么意思呢匿情?大概就是在DecodeProducer中有一個空指針異常兰迫,調(diào)用了decodeGif在一個空引用上。于是查看DecodeProducer類找到doDecode方法炬称,發(fā)現(xiàn)其中調(diào)用了mImageDecoder.decodeImage汁果,繼續(xù)查看在decodeImage中調(diào)用到了我們要找的decodeGif方法,內(nèi)容如下:
根據(jù)這個方法再打斷點說的就是這個mAnimatedImageFactory是空指針转砖,那么這個AnimatedImageFactory是個什么鬼须鼎,從源碼我可以知道這個類就是用來解析動圖的鲸伴,目前可以解析gif和webP府蔗。 繼續(xù)查看調(diào)用可以看到這個factory是在ImagePipeline中創(chuàng)建的,如下:
就是在這里通過AnimatedFactoryProvider創(chuàng)建了一個AnimatedFactory汞窗,里面代碼如下:
通過反射來創(chuàng)建的姓赤,既然出現(xiàn)了空指針那就是這里創(chuàng)建的問題咯,那我們來看看這個兩個類仲吏,發(fā)現(xiàn)根本找不到不铆,所以問題就是這里咯蝌焚。同時發(fā)現(xiàn)在項目中存在兩個Fresco的包0.8.0和0.11.0,于是定位到可能是依賴沖突的原因誓斥。查看了0.8.0里面創(chuàng)建AnimatedFactory的代碼發(fā)現(xiàn)與0.11.0中的代碼還是有點區(qū)別的只洒,確認(rèn)是依賴包沖突的問題了。
通過在Android studio Terminal輸入如下命令gradlew -q app:dependencies查看當(dāng)前使用的依賴版本,發(fā)現(xiàn)雖然配置的是使用0.8.0但是實際使用的卻是0.11.0劳坑。所以解決辦法1就是恢復(fù)到0.8.0版本毕谴,至于11版本的為什么沒有那兩個類我們稍后再來看。
+--- com.facebook.fresco:fresco:0.8.0 -> 0.11.0
| +--- com.facebook.fresco:drawee:0.11.0
| | +--- com.android.support:support-v4:23.2.1 (*)
| | \--- com.facebook.fresco:fbcore:0.11.0
| +--- com.facebook.fresco:fbcore:0.11.0
| \--- com.facebook.fresco:imagepipeline:0.11.0
| +--- com.android.support:support-v4:23.2.1 (*)
| +--- com.facebook.fresco:fbcore:0.11.0
| +--- com.parse.bolts:bolts-tasks:1.4.0
| +--- com.nineoldandroids:library:2.4.0
| \--- com.facebook.fresco:imagepipeline-base:0.11.0
| +--- com.android.support:support-v4:23.2.1 (*)
| +--- com.facebook.fresco:fbcore:0.11.0
| +--- com.parse.bolts:bolts-tasks:1.4.0
| \--- com.nineoldandroids:library:2.4.0
+--- com.facebook.react:react-native:0.29.2
| +--- com.google.code.findbugs:jsr305:3.0.0
| +--- org.webkit:android-jsc:r174650
| +--- com.facebook.fresco:imagepipeline-okhttp3:0.11.0
| | +--- com.facebook.fresco:fbcore:0.11.0
| | +--- com.squareup.okhttp3:okhttp:3.0.1 -> 3.2.0
| | | \--- com.squareup.okio:okio:1.6.0 -> 1.8.0
| | \--- com.facebook.fresco:imagepipeline:0.11.0 (*)
| +--- com.squareup.okio:okio:1.8.0
| +--- com.fasterxml.jackson.core:jackson-core:2.2.3
| +--- com.squareup.okhttp3:okhttp:3.2.0 (*)
| +--- com.facebook.fresco:fresco:0.11.0 (*)
| +--- com.squareup.okhttp3:okhttp-ws:3.2.0
| | \--- com.squareup.okhttp3:okhttp:3.2.0 (*)
| +--- com.android.support:recyclerview-v7:23.0.1 (*)
| +--- com.squareup.okhttp3:okhttp-urlconnection:3.2.0
| | \--- com.squareup.okhttp3:okhttp:3.2.0 (*)
| \--- com.android.support:appcompat-v7:23.0.1 (*)
從上面的依賴關(guān)系可以看出我們自己依賴了fresco的0.8距芬,同時依賴了react涝开,但是react中依賴了fresco 0.11導(dǎo)致我們實際依賴的是搞版本的fresco,所以如果要使用低版本的框仔,按理說只需要把react中的fresco排除舀武,然后我們在導(dǎo)入自己需要的版本就行了,但是我按照這樣的思路在build.gradle進(jìn)行了如下配置离斩,結(jié)果還是使用11版本的银舱,最終沒有找到原因,你們也可以試一下跛梗,如果有發(fā)現(xiàn)什么問題的一定要告訴我纵朋。
compile 'com.facebook.fresco:fresco:0.8.0'
compile ('com.facebook.react:react-native:0.29.2') {
exclude module:'com.facebook.fresco:fresco'
}
接下來我們就來看看為什么使用11版本的就少了那兩個類呢?查閱各種資料茄袖,最終在一篇博客中發(fā)現(xiàn)了如下的內(nèi)容:
一定要導(dǎo)入下邊這個 compile 'com.facebook.fresco:animated-gif:0.12.0'操软,否則gif圖壓根不動
于是瞬間懂了,原來高版本的fresco把gif相關(guān)的內(nèi)容獨立到了另一個依賴?yán)锩嫦芟椋@樣如果不需要用到gif的項目就不需要導(dǎo)入聂薪,由于我們升級到了高版本,所以默認(rèn)是沒有g(shù)if相關(guān)的類的蝗羊,所以就缺少了那兩個類藏澳,導(dǎo)致gif不能顯示,于是導(dǎo)入后耀找,完美解決問題翔悠。
3.總結(jié)
解決問題的方法有兩種:
1.退回到低版本的fresco
2.使用高版本的,需要另外導(dǎo)入com.facebook.fresco:animated-gif這個依賴