編輯:關於Android編程
與其他圖片加載庫相同,Glide除了可以加載網絡圖片之外,也可以加載本地圖片。甚至還可以從各種各樣奇葩的數據源中加載圖片。
加載網絡圖片
很多情況下,我們使用圖片加載庫就是為了加載網絡圖片。網絡操作是一個很復雜的東西。試想一下,如果沒有圖片加載庫,我們就要手動去下載圖片,緩存圖片,最後再從文件裡面讀取bitmap並設置到Imageview裡面。這還算好的,要是在Listview裡面你會更頭疼的。原因我就不說了,你懂的~~再加上各種各樣的Bitmap操作,保准你再也不想撸代碼了。而且Bitmap這東西還很占內存,伺候不好,很容易就會引發OOM,app吧唧就閃退了!!
圖片加載庫的優勢就在於此。簡簡單單一句話,下載,緩存,加載統統搞定。簡直就是美好一生的東西。而Glide就是這樣使人美好一生的東西之一。
說了這麼多,Glide如何加載網絡圖片?很簡單,就上次的三句話:
ImageView targetImageView = (ImageView) findViewById(R.id.imageView); String internetUrl = "http://i.imgur.com/idojSYm.png"; Glide .with(context) .load(internetUrl) .into(targetImageView);
木有什麼亂七八糟的東西,直接傳入要加載圖片的url就可以了。那麼圖片加載庫有很多,為什麼選擇Glide呢?很簡單,因為它流暢,不卡,尤其是在Listview中。嗯,就是醬~
加載本地圖片
下表是.load()可以傳入的參數及說明
參數
說明
.load(String string)
string可以為一個文件路徑、uri或者url
.load(Uri uri)
uri類型
.load(File file)
文件
.load(Integer resourceId)
資源Id,R.drawable.xxx或者R.mipmap.xxx
.load(byte[] model)
byte[]類型
.load(T model)
自定義類型
從上面可以看到Glide不僅可以加載網絡圖片,還可以加載本地圖片。可接受的參數有文件路徑,uri,文件,資源id等。基本上滿足了大部分的需求。雖然加載本地圖片不像網絡圖片那樣復雜,但我還是建議使用Glide來加載本地圖片。因為它是內存友好的,而且還會“偷偷地”幫我們做很多事情。比如內存緩存,Bitmap復用,修正照片方向等。當然為了滿足各種各樣的需求,僅僅加載圖片是不夠的,你還需要對圖片進行各種各樣的變換,也就是Transformation。後面我們會詳細了解的。
加載自定義數據源
前面的表格中有一個是我們不熟悉的,就是.load(T model),即自定義的數據源類型。那麼如何去實現呢?
實際上,加載自定義數據源主要是通過ModelLoader接口來實現的。由於沒有在實際項目中用到過,這方面的經驗比較少。
不過從官方Wiki上來看,設計ModelLoader接口的初衷用來加載不同尺寸的圖片的。眾所周知,Android設備屏幕分辨率千奇百怪,大到2K,小到320p。如果在低分辨率的手機上加載大圖,不僅損耗用戶流量,而且很容易造成OOM;在高分辨的手機上,加載小圖又會出現模糊的情況,用戶體驗極差。很多時候,為了省事,很多app都會選擇一個中間分辨率,然後自適應大小。當然這樣做無可厚非,但是有更好的辦法,我們為什麼不去嘗試呢?
那麼如何使用Glide來實現這一具體需求呢?首先你要實現自己的ModelLoader,比較簡單的方法是繼承BaseGlideUrlLoader。
public interface MyDataModel { public String buildUrl(int width, int height); } public class MyUrlLoader extends BaseGlideUrlLoader<MyDataModel> { @Override protected String getUrl(MyDataModel model, int width, int height) { // Construct the url for the correct size here. return model.buildUrl(width, height); } }
接下來我們可以這樣來加載圖片:
Glide.with(this) .using(new MyUrlLoader(this)) .load(new MyDataModel() { @Override public String buidUrl(int width, int height) { if (width >= 600) { return url1; } else { return url2; } } }) .into(imageView);
(1).using(new MyUrlLoader(this)):使用我們自己的ModeLoader;
(2).load(new MyDataModel()):加載我們自定義的數據源
這裡需要解釋下getUrl的三個參數:
(1)model:你加載的數據源
(2)width:你加載的圖片的寬度(px)
(3)height:你加載的圖片的高度(px)
這樣,我們在高分率的設備上加載大圖的url1,在低分辨率的設備上加載小圖url2。從而實現了根據不同手機上的像素值大小加載不同尺寸的圖片的需求。
當然如果你不想每次都是用.using(new MyUrlLoader()),就需要實現一個自定義的ModelLoaderFactory並在GlideModule中注冊。
public class MyGlideModule implements GlideModule { ... @Override public void registerComponents(Context context, Glide glide) { glide.register(MyDataModel.class, InputStream.class, new MyUrlLoader.Factory()); } }
同時也要在AndroidManifest.xml聲明
<meta-data android:name="com.mypackage.MyGlideModule" android:value="GlideModule" />
如果你有多個自定義的GlideModule類,那麼也要在AndroidManifest.xml中聲明多個GlideModule。
在服務端有下面的幾個可以加載的url:
URL
圖片大小
myserver.com/images/__w-200-400-600-800-1000__/session1.jpg
原始尺寸
myserver.com/images/w200/session1.jpg
200px
myserver.com/images/w400/session1.jpg
400px
myserver.com/images/w600/session1.jpg
600px
myserver.com/images/w800/session1.jpg
800px
myserver.com/images/w1000/session1.jpg
1000px
那麼客戶端如何根據不同的手機分辨率去加載不同的url呢?
Google是這樣做的,下面是核心代碼:
//定義正則表達式 private static final Pattern PATTERN = Pattern.compile("__w-((?:-?\\d+)+)__"); @Override protected String getUrl(String model, int width, int height) { Matcher m = PATTERN.matcher(model); int bestBucket = 0; if (m.find()) { String[] found = m.group(1).split("-");//拿到可以加載的尺寸數組 for (String bucketStr : found) { bestBucket = Integer.parseInt(bucketStr); if (bestBucket >= width) {//剛好大於要加載的尺寸,直接跳出循環 // the best bucket is the first immediately // bigger than the requested width break; } } if (bestBucket > 0) {//返回合適尺寸的url model = m.replaceFirst("w"+bestBucket); } } return model; }
大概的步驟如下:
1.根據服務端可加載的圖片url定義正則表達式
2.根據正則匹配,獲取到可以加載的圖片尺寸數組
3.根據要加載的Imageview的大小,選擇合適的尺寸的url
4.拼接url並返回
上面的例子中有200,400,600,800,1000是可以加載的,如果你要加載的Imageview的大小為600px,當遍歷數組到600時,就會直接跳出循環,返回600px大小圖片的url,Glide就會加載600px的圖片。
異常調試
在Glide加載圖片過程中出現異常時,默認是沒有log輸出的。但是Glide給開發者提供了兩種方法來查看或者響應這些異常。
1.調試
為了在異常發生時可以看到它們,你可以打開Glide中處理所有媒體加載響應的類GenericRequest的log開關。很簡單,在命令行運行下面的指令即可:
adb shell setprop log.tag.GenericRequest DEBUG
如果你將DEBUG替換為VERBOSE,還可以看到詳細的請求時間日志。
如果你想禁用log輸出,執行:
adb shell setprop log.tag.GenericRequest ERROR
2.調試工作流
為了查看Glide內部引擎是何時、如何加載圖片的,你可以啟用這些log:
adb shell setprop log.tag.Engine VERBOSE adb shell setprop log.tag.EngineJob VERBOSE adb shell setprop log.tag.DecodeJob VERBOSE
啟用這些log可以幫助你了解到為什麼某些資源沒有從內存中加載?為什麼從外部url加載要重新下載數據?同時這也有助於了解在磁盤緩存時哪些參數需要配置。啟用DecodeJob log還可以幫助你了解自定義變換/解碼器/編碼器等相關問題。
3.請求監聽器
雖然啟動調試日志很簡單,但前提是你可以訪問到設備。為了完善Glide已存在或更復雜的錯誤日志系統,你可以使用RequestListener類。當加載請求失敗時onException()方法就會被調用,並給出造成失敗的異常或者null(在解碼器無法從它獲取到的數據中解碼出任何有用的東西時)。你可以通過listener() API為每一個請求添加一個監聽器。
確保onException()方法的返回值為false,避免覆蓋Glide默認的錯誤處理(比如加載失敗的錯誤圖片占位)。
這裡有一個實現快速調試的列子:
// 示例: .listener(new LoggingListener<String, GlideDrawable>()) public class LoggingListener<T, R> implements RequestListener<T, R> { @Override public boolean onException(Exception e, Object model, Target target, boolean isFirstResource) { android.util.Log.d("GLIDE", String.format(Locale.ROOT, "onException(%s, %s, %s, %s)", e, model, target, isFirstResource), e); return false; } @Override public boolean onResourceReady(Object resource, Object model, Target target, boolean isFromMemoryCache, boolean isFirstResource) { android.util.Log.d("GLIDE", String.format(Locale.ROOT, "onResourceReady(%s, %s, %s, %s, %s)", resource, model, target, isFromMemoryCache, isFirstResource)); return false; } }
IN THIS DOCUMENTCreating an Activity 創建一個ActivityImplementing a user interface 實現用戶界面
推薦閱讀:淺析Android手機衛士自定義控件的屬性淺析Android手機衛士關閉自動更新詳解Android 手機衛士設置向導頁面一般的手機沒有root權限,進不去dat
由於我的版本最低是2.2,所以只有把源碼下下來自己改,如果你覺得太多了可自己編譯成jar引用,本人不才,對java不是很熟悉,如果此版本中有錯誤還請大家指出來,此圖顯示的
這篇文章將逐個講解每個模式的意義。這裡所講的各種模式,在大家理解了之後可以回過頭來看看setColorFilter(new PorterDuffColorFilter(C