<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ??碼云GVP開源項目 12k star Uniapp+ElementUI 功能強大 支持多語言、二開方便! 廣告
                [TOC] # Glide使用 簡單使用: ```java @Override public void onCreate(Bundle savedInstanceState) { //... ImageView imageView = (ImageView) findViewById(R.id.my_image_view); Glide.with(this) .load("http://goo.gl/gEgYUd") .asBitmap() // 只允許加載靜態圖片,同理有asGif()方法 .placeholder(R.drawable.loading) // 占位圖 .error(R.drawable.error) // 異常占位圖 .override(100, 100) // 指定加載圖片的尺寸 .into(imageView); } ``` 其中,load方法有以下幾種重載: ```java // 從字節數組加載 public DrawableTypeRequest<byte[]> load(byte[] model) {} // 從File對象加載 public DrawableTypeRequest<File> load(File file) {} // 從資源文件加載 public DrawableTypeRequest<Integer> load(Integer resourceId) {} // 從File路徑或UriLoader構造的url、uri來加載 public DrawableTypeRequest<String> load(String string) {} // 從ModelLoaderFactory生成的model來加載 public <T> DrawableTypeRequest<T> load(T model) {} // 從UriLoader生成的Uri來加載 public DrawableTypeRequest<Uri> load(Uri uri) {} ``` # Glide源碼分析 ## with方法 with方法的主要作用有兩個,一是獲得一個RequestManager對象,二是確定Glide的生命周期,當傳入全局Application Context時,Glide生命周期等同于應用生命周期;當傳入Activity或Fragment時,Glide會向當前Activity中添加一個隱藏的Fragment,來確定自身的生命周期,比如加載圖片過程中Activity被銷毀了,隱藏的Fragment是可以感知的,這樣Glide的加載就可以同步終止。 with方法有以下幾個重載: ```java public static RequestManager with(Context context) {} public static RequestManager with(Activity activity) {} public static RequestManager with(FragmentActivity activity) {} public static RequestManager with(Fragment fragment) {} ``` 每一種方法都是根據入參獲取RequestManager: ```java public static RequestManager with(Context context) { RequestManagerRetriever retriever = RequestManagerRetriever.get(); return retriever.get(context); } ``` 下面看看retriever的get方法: ```java public RequestManager get(Context context) { if (context == null) { throw new IllegalArgumentException("You cannot start a load on a null Context"); } else if (Util.isOnMainThread() && !(context instanceof Application)) { if (context instanceof FragmentActivity) { return get((FragmentActivity) context); } else if (context instanceof Activity) { return get((Activity) context); } else if (context instanceof ContextWrapper) { return get(((ContextWrapper) context).getBaseContext()); } } return getApplicationManager(context); } ``` 可以看到,當前為主線程且Context非Application時是一種處理方式,其他是一種處理方式。當context為Application時,直接創建RequestManager對象: ```java private RequestManager getApplicationManager(Context context) { if (applicationManager == null) { synchronized (this) { if (applicationManager == null) { applicationManager = new RequestManager(context.getApplicationContext(), new ApplicationLifecycle(), new EmptyRequestManagerTreeNode()); } } } return applicationManager; } ``` 而當Context為Activity、Fragment、FragmentActivity時,處理如下: ```java public RequestManager get(FragmentActivity activity) { if (Util.isOnBackgroundThread()) { return get(activity.getApplicationContext()); } else { assertNotDestroyed(activity); FragmentManager fm = activity.getSupportFragmentManager(); return supportFragmentGet(activity, fm); } } ``` 可以看到,如果是在子線程的話,就按Context為Application來進行處理。否則調用supportFragmentGet方法來創建RequestManager: ```java RequestManager supportFragmentGet(Context context, FragmentManager fm) { SupportRequestManagerFragment current = getSupportRequestManagerFragment(fm); RequestManager requestManager = current.getRequestManager(); if (requestManager == null) { requestManager = new RequestManager(context, current.getLifecycle(), current.getRequestManagerTreeNode()); current.setRequestManager(requestManager); } return requestManager; } ``` 上面代碼中SupportRequestManagerFragment就是要添加的隱藏Fragment。 ## load方法 load方法是RequestManager中的方法,有多個重載,上文已經提到,下面我們看看其中的一個重載方法: ```java public DrawableTypeRequest<String> load(String string) { return (DrawableTypeRequest<String>) fromString().load(string); } ``` ```java public DrawableTypeRequest<String> fromString() { return loadGeneric(String.class); } ``` ```java private <T> DrawableTypeRequest<T> loadGeneric(Class<T> modelClass) { ModelLoader<T, InputStream> streamModelLoader = Glide.buildStreamModelLoader(modelClass, context); ModelLoader<T, ParcelFileDescriptor> fileDescriptorModelLoader = Glide.buildFileDescriptorModelLoader(modelClass, context); if (modelClass != null && streamModelLoader == null && fileDescriptorModelLoader == null) { throw new IllegalArgumentException("Unknown type " + modelClass + ". You must provide a Model of a type for" + " which there is a registered ModelLoader, if you are using a custom model, you must first call" + " Glide#register with a ModelLoaderFactory for your custom model class"); } return optionsApplier.apply( new DrawableTypeRequest<T>(modelClass, streamModelLoader, fileDescriptorModelLoader, context, glide, requestTracker, lifecycle, optionsApplier)); } ``` 在loadGeneric方法中,會生成ModelLoader對象,ModelLoader對象時用于加載圖片的,根據load方法傳入的參數不同,會得到不同的ModelLoader對象,剛剛傳入的是String.class對象,因此得到的是StreamStringLoader對象,實現了ModelLoader接口。 loadGeneric方法最后創建了一個DrawableTypeRequest對象,DrawableTypeRequest類主要是提供了asBitmap和asGif兩個方法,這兩個方法會返回BitmapTypeRequest和GifTypeRequest,當然不調用asBitmap和asGif的情況下,默認返回DrawableTypeRequest對象。 接下來看看fromString后的load方法,由于在DrawableTypeRequest類中沒有load方法,因此到其父類DrawableRequestBuilder中看看,在該類源碼中,可以看到load、placeholder、error、centerCrop等等方法,基本就是我們常用的那些。 ## into方法 into方法同樣是在DrawableRequestBuilder中定義的: ```java public Target<GlideDrawable> into(ImageView view) { return super.into(view); } ``` 調用了父類的方法: ```java public Target<TranscodeType> into(ImageView view) { //... return into(glide.buildImageViewTarget(view, transcodeClass)); } ``` 先是調用glide.buildImageViewTarget()方法構建出一個Target對象,Target對象是用來最終展示圖片用的。來看看是怎么構建出的: ```java <R> Target<R> buildImageViewTarget(ImageView imageView, Class<R> transcodedClass) { return imageViewTargetFactory.buildTarget(imageView, transcodedClass); } ``` ```java public <Z> Target<Z> buildTarget(ImageView view, Class<Z> clazz) { if (GlideDrawable.class.isAssignableFrom(clazz)) { return (Target<Z>) new GlideDrawableImageViewTarget(view); } else if (Bitmap.class.equals(clazz)) { return (Target<Z>) new BitmapImageViewTarget(view); } else if (Drawable.class.isAssignableFrom(clazz)) { return (Target<Z>) new DrawableImageViewTarget(view); } else { throw new IllegalArgumentException("Unhandled class: " + clazz + ", try .as*(Class).transcode(ResourceTranscoder)"); } } ``` 會根據傳入的class參數來構建不同的Target對象,我們在使用Glide加載圖片的時候調用了asBitmap()方法,那么這里就會構建出BitmapImageViewTarget對象,否則的話構建的都是GlideDrawableImageViewTarget對象。其中的DrawableImageViewTarget對象通常都是用不到的。 接下來回來看看拿到Target對象后調用的into方法: ```java public <Y extends Target<TranscodeType>> Y into(Y target) { //... Request request = buildRequest(target); target.setRequest(request); lifecycle.addListener(target); requestTracker.runRequest(request); return target; } ``` 首先調用buildRequest方法出那個鍵一個Request對象,然后再執行這個Request。Request在Glide中是用來發出加載圖片請求的,是一個非常關鍵的組件。先來看看Request是如何build出來的: ```java private Request buildRequest(Target<TranscodeType> target) { return buildRequestRecursive(target, null); } ``` ```java private Request buildRequestRecursive(Target<TranscodeType> target, ThumbnailRequestCoordinator parentCoordinator) { //前面省略處理縮略圖相關代碼 return obtainRequest(target, sizeMultiplier, priority, parentCoordinator); } ``` ```java private Request obtainRequest(Target<TranscodeType> target, float sizeMultiplier, Priority priority, RequestCoordinator requestCoordinator) { return GenericRequest.obtain( loadProvider, model, signature, context, priority, target, sizeMultiplier, placeholderDrawable, placeholderId, errorPlaceholder, errorId, fallbackDrawable, fallbackResource, requestListener, requestCoordinator, glide.getEngine(), transformation, transcodeClass, isCacheable, animationFactory, overrideWidth, overrideHeight, diskCacheStrategy); } ``` 這里調用了GenericRequest的obtain方法: ```java public static <A, T, Z, R> GenericRequest<A, T, Z, R> obtain( LoadProvider<A, T, Z, R> loadProvider, A model, Key signature, Context context, Priority priority, Target<R> target, float sizeMultiplier, Drawable placeholderDrawable, int placeholderResourceId, Drawable errorDrawable, int errorResourceId, Drawable fallbackDrawable, int fallbackResourceId, RequestListener<? super A, R> requestListener, RequestCoordinator requestCoordinator, Engine engine, Transformation<Z> transformation, Class<R> transcodeClass, boolean isMemoryCacheable, GlideAnimationFactory<R> animationFactory, int overrideWidth, int overrideHeight, DiskCacheStrategy diskCacheStrategy) { @SuppressWarnings("unchecked") GenericRequest<A, T, Z, R> request = (GenericRequest<A, T, Z, R>) REQUEST_POOL.poll(); if (request == null) { request = new GenericRequest<A, T, Z, R>(); } request.init(loadProvider, model, signature, context, priority, target, sizeMultiplier, placeholderDrawable, placeholderResourceId, errorDrawable, errorResourceId, fallbackDrawable, fallbackResourceId, requestListener, requestCoordinator, engine, transformation, transcodeClass, isMemoryCacheable, animationFactory, overrideWidth, overrideHeight, diskCacheStrategy); return request; } ``` 可以看到obtain方法實際就是獲得一個GenericRequest對象,同時對成員變量進行初始化。 拿到Request后,我們看看requestTracker.runRequest()方法中Request是怎么執行的: ```java public void runRequest(Request request) { requests.add(request); //... request.begin(); } ``` 下面看看GenericRequest的begin方法: ```java public void begin() { startTime = LogTime.getLogTime(); if (model == null) { onException(null); return; } status = Status.WAITING_FOR_SIZE; if (Util.isValidDimensions(overrideWidth, overrideHeight)) { onSizeReady(overrideWidth, overrideHeight); } else { target.getSize(this); } if (!isComplete() && !isFailed() && canNotifyStatusChanged()) { target.onLoadStarted(getPlaceholderDrawable()); } if (Log.isLoggable(TAG, Log.VERBOSE)) { logV("finished run method in " + LogTime.getElapsedMillis(startTime)); } } ``` 在begin方法中,我們主要關注以下幾行代碼: * onException(null); * onSizeReady(overrideWidth, overrideHeight); * target.getSize(this); * target.onLoadStarted(getPlaceholderDrawable()); 下面對這四個方法我們一個一個分析 1、onException(null); 可以看到,如果model等于null,也就是在load方法中傳入的圖片URL地址為空,會調用onException方法,onException方法中會調用setErrorPlaceholder方法: ```java public void onException(Exception e) { //... setErrorPlaceholder(e); } ``` ```java private void setErrorPlaceholder(Exception e) { Drawable error = model == null ? getFallbackDrawable() : null; if (error == null) { error = getErrorDrawable(); } if (error == null) { error = getPlaceholderDrawable(); } target.onLoadFailed(e, error); } ``` 會先去獲取一個error的占位圖,獲取不到的話會去獲取一個loading的占位圖,然后調用target.onLoadFailed方法并傳入占位圖: ```java public void onLoadFailed(Exception e, Drawable errorDrawable) { view.setImageDrawable(errorDrawable); } ``` 將占位圖設置到ImageView即可。 2、target.onLoadStarted(getPlaceholderDrawable()); ```java public void onLoadStarted(Drawable placeholder) { view.setImageDrawable(placeholder); } ``` 設置占位圖的代碼也很簡單 3、onSizeReady()和target.getSize() 當使用了override方法給圖片指定了固定寬高時,調用onSizeReady()方法;沒指定時,調用target.getSize()方法,target.getSize()方法的內部會根據ImageView的layout\_width和layout\_height值做一系列的計算,來算出圖片應該的寬高,然后再根據寬高調用onSizeReady()方法。那么來看看onSizeReady()方法: ```java ``` # Glide緩存原理 ## 緩存機制 Glide的緩存機制,主要分為2種緩存,一種是內存緩存,一種是磁盤緩存。 使用內存緩存的原因是:防止應用重復將圖片讀入到內存,造成內存資源浪費;使用磁盤緩存的原因是:防止應用重復的從網絡或者其他地方下載和讀取數據。正是因為有著這兩種緩存的結合,才構成了Glide極佳的緩存效果。 ## 緩存算法 1、LruCache最近最少使用算法,設定一個緩存大小,當緩存達到這個大小之后,會將最老的數據移除,避免圖片占用內存過大導致OOM。LruCache 內部用LinkHashMap存取數據,在雙向鏈表保證數據新舊順序的前提下,設置一個最大內存,往里面put數據的時候,當數據達到最大內存的時候,將最老的數據移除掉,保證內存不超過設定的最大值。 2、LinkHashMap繼承HashMap,在 HashMap的基礎上,新增了雙向鏈表結構,每次訪問數據的時候,會更新被訪問的數據的鏈表指針,具體就是先在鏈表中刪除該節點,然后添加到鏈表頭header之前,這樣就保證了鏈表頭header節點之前的數據都是最近訪問的(從鏈表中刪除并不是真的刪除數據,只是移動鏈表指針,數據本身在map中的位置是不變的)。 ### 三級緩存原理 1、讀取一張圖片的時候,獲取順序:Lru算法緩存-》弱引用緩存-》磁盤緩存(如果設置了的話)。 當我們的APP中想要加載某張圖片時: * 先去LruCache中尋找圖片,如果LruCache中有,則直接取出來使用,并將該圖片放入WeakReference中 * 如果LruCache中沒有,則去WeakReference中尋找,如果WeakReference中有,則從WeakReference中取出圖片使用 * 如果WeakReference中也沒有圖片,則從磁盤緩存/網絡中加載圖片 2、將圖片緩存的時候,寫入順序:弱引用緩存-》Lru算法緩存-》磁盤緩存中。 * 當圖片不存在的時候,先從網絡下載圖片,然后將圖片存入弱引用中,glide會采用一個acquired(int)變量用來記錄圖片被引用的次數, 當acquired變量大于0的時候,說明圖片正在使用中,也就是將圖片放到弱引用緩存當中; * 如果acquired變量等于0了,說明圖片已經不再被使用了,那么此時會調用方法來釋放資源,首先會將緩存圖片從弱引用中移除,然后再將它put到LruResourceCache當中 * 這樣也就實現了正在使用中的圖片使用弱引用來進行緩存,不在使用中的圖片使用LruCache來進行緩存的功能。 # 總結 1、Glide的with方法兩個作用,一是獲得RequestManager對象,二是確定Glide的生命周期。 # 其他 ## Bitmap的高效加載 1、圖片加載: Bitmap在Android中指的是一張圖片,BitmapFactory提供了四類方法:decodeFile、decodeResource、decodeStream和decodeByteArray,分別用于從文件系統、資源、輸入流以及字節數組中加載出一個Bitmap對象。其中decodeFile和decodeResource方法又簡介調用了decodeStream方法,最終調用native方法實現加載。 2、按需加載 高效加載Bitmap的核心思想是采用BitmapFactory.Options來按需加載相應尺寸的圖片。當原圖很大,需要展示圖片的ImageView很小時,通過BitmapFactory.Options按一定采樣率來加載縮小后的圖片到內存,再將其設置給ImageView,這樣可以降低內存占用,避免OOM,提高Bitmap的加載性能。 3、采樣率 采樣率inSampleSize的取值應該總是為2的指數,如不是系統會自動向下取整。 a、將BitmapFactory.Options的inJustDecodeBounds參數設置為true并加載圖片,此時只會解析圖片寬高,不會真正加載到內存 b、取出寬高信息,根據采樣率規則結合目標View的大小計算出采樣率inSampleSize c、將BitmapFactory.Options的inJustDecodeBounds參數設置為true,重新加載圖片 ## 內存泄漏問題 ## 大圖加載框架 # 參考文檔 [https://blog.csdn.net/guolin\_blog/article/details/53939176#commentBox](https://blog.csdn.net/guolin_blog/article/details/53939176#commentBox) [https://juejin.im/post/5dd766e1e51d45233c7e857f](https://juejin.im/post/5dd766e1e51d45233c7e857f) [https://juejin.im/post/5dbeda27e51d452a161e00c8](https://juejin.im/post/5dbeda27e51d452a161e00c8)
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看