怎麼載入一張我前所未見的圖片路徑

語言: CN / TW / HK

“我正在參加「掘金·啟航計劃」” 我們日常開發中圖片載入都是基操,本地的,伺服器的,資原始檔裡的,記憶體的圖片都輕而易舉。我們常見的檔案路徑也就 "file://" , "http/https://" 這些路徑。但就是今天,在對接一款相機的SDK時,我遇到了一個前所未見的檔案路徑,我看著demo硬生生的把它裝進了ImageLoader去處理,它長這個樣子: tutk://fileHandle=20&fileName=G1E2_0018.JPG&fileSize=3280536&thumbnail;這我當時就懵了,我害怕極了,知識盲區啊,這什麼東西ImageLoader竟然能加載出來。我先是單純的想到可能這是什麼我沒見過的協議而已,不管,ImageLoader這麼low的東西能解析圖片,Glide更加手拿把掐,那我直接把地址丟給Glide解析。理想很豐滿,現實相當骨感:我堂堂Glide竟然不能load source。眉頭一皺,發現事情並不簡單。

一、發現華點

我百思不得其解,我還去百度tutk是什麼協議,是否需要建立什麼連線。搜到的知識少之又少還毫不相干。我在demo的幾千行程式碼裡反覆的扒拉,終於發現,demo竟然揹著我在不知名的角落重寫了ImageLoader的BaseImageDownloader。開啟它重寫的類看了下重寫的內容,那感覺就像是翻到了我掉垃圾桶裡的100克拉大鑽戒。其實問題就在於該圖片地址並不是真正的用於直接讀取的網路圖片地址,而是需要傳給SDK的介面,介面返回圖片的byte[],然後把byte[]轉換成BaseImageDownloader重寫需要返回的InputStream。當然舉一反三,ImageLoader可以,那Glide一樣也可以。下面我將就兩種方法去介紹怎麼把一個前所未見的圖片地址變為圖片載入到我們的ImageView上。

二、ImageLoader自定義圖片請求方式

ImageLoader自定義圖片請求方式就是繼承BaseImageDownloader類,並且重寫該類的getStreamFromOtherSource方法 public class ICatchtekImageDownloader extends BaseImageDownloader{ //***** @Override protected InputStream getStreamFromOtherSource(String imageUri, Object extra) throws IOException { //特殊路徑特殊處理,避免其它常規路徑特殊處理 if (TutkUriUtil.isTutkUri(imageUri)) { //自定義獲取圖片的方式,返回值是InputStream return getStreamFromTUTK(imageUri, extra); } return super.getStreamFromOtherSource(imageUri, extra); } //***** } 自定義完我們的下載類後,將我們的下載類配置到ImageLoader中,然後大功告成。 java ImageLoaderConfiguration.Builder config = new ImageLoaderConfiguration.Builder(context); //........其他配置 config.imageDownloader(imageDownloader); ImageLoader.getInstance().init(config.build());

三、Glide自定義圖片請求方式

Glide自定義圖片請求方式相對來說複雜一點,它需要實現三個介面。

3.1 DataFetcher

DataFetcher的泛型為我們重寫後圖片資料處理完後的型別,Glide支援ByteBuffer和InputStream型別的資料轉為圖片,我們以ByteBuffer為例子,如果你的圖片獲取轉InputStream方便些的話用InputStream也是一樣的。 ``` public class ICatchtekDataFetcher implements DataFetcher {

private String model;

ICatchtekDataFetcher(String model) { this.model = model; }

@Override public void loadData(Priority priority, DataCallback<? super ByteBuffer> callback) { //我們自己的實現,最終轉為轉為ByteBuffer byte[] data = getBufferFromTUTK(model); ByteBuffer byteBuffer = ByteBuffer.wrap(data); callback.onDataReady(byteBuffer); }

@Override public void cleanup() { // Intentionally empty only because we're not opening an InputStream or another I/O resource! }

@Override public void cancel() { // Intentionally empty. }

@NonNull @Override public Class getDataClass() { return ByteBuffer.class; }

@NonNull @Override public DataSource getDataSource() { return DataSource.LOCAL; } } ```

3.2、ModelLoader

String為我們的路徑,其實也可以是其它物件,ByteBuffer為解析後的圖片資料 ```java public final class ICatchtekModelLoader implements ModelLoader { private static final String DATA_URI_PREFIX = "tutk:";

@Nullable @Override public LoadData buildLoadData(String model, int width, int height, Options options) { return new LoadData<>(new ObjectKey(model), new ICatchtekDataFetcher(model)); }

@Override public boolean handles(String model) { //符合特殊路徑的才處理 表示是否交由該類處理 return model.startsWith(DATA_URI_PREFIX); } } ```

3.3、ModelLoaderFactory

String為我們的路徑,ByteBuffer為解析後的圖片資料 ``` public class ICatchtekModelLoaderFactory implements ModelLoaderFactory {

@Override public ModelLoader build(MultiModelLoaderFactory multiFactory) { return new ICatchtekModelLoader(); }

@Override public void teardown() { // Do nothing. } } ```

3.4、註冊元件

前面三步完成相當於自定義一個我們的元件,現在把我們的元件註冊到Glide @GlideModule public class MyAppGlideModule extends AppGlideModule { @Override public void registerComponents(Context context, Glide glide, Registry registry) { registry.prepend(String.class, ByteBuffer.class, new ICatchtekModelLoaderFactory()); } } 註解@GlideModule需要添加註解解析依賴 annotationProcessor 'com.github.bumptech.glide:compiler:4.11.0' 但是會存在找不到註解的問題,通過issues查到問題是 kotlin annotationProcessor需要換成kapt,大功告成。

四、總結

如果看到奇怪的圖片路徑出不來圖不要慌,首先排查圖片的路徑來源,是否需要特殊處理,以Glide的例子來說,它是將Base64路徑轉為圖片。其它的情況其實也是一樣的思路,不管資料是什麼,從哪裡來,只有最終能變成ByteBuffer或者InputStream就能載入圖片。Glide的ModelLoader不單單是下載的功能,還可以做其他自定義的功能元件,有興趣的可以看看它的官方元件。歡迎大家批評指正,交流指導。

參考連結:

https://muyangmin.github.io/glide-docs-cn/tut/custom-modelloader.html