成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

Fresco源碼分析之DraweeView

draveness / 811人閱讀

摘要:首先這是對(duì)的源碼分析,所以在看這篇文章之前你應(yīng)該要有使用的基礎(chǔ),如果沒(méi)有的強(qiáng)烈推薦看下官方文檔。在中統(tǒng)一由來(lái)替代。關(guān)于后續(xù)文章會(huì)詳細(xì)分析。在其內(nèi)部的,是用來(lái)記錄事件的傳遞,方便的調(diào)試。這次主要是分析了中的基本組件與它的子類。

Android中圖片加載的框架很多,例如:Fresco、Picasso、GlideImageloader。它們都有各自的優(yōu)點(diǎn),但總的來(lái)說(shuō),使用起來(lái)方便簡(jiǎn)單、可配置性高與提供良好的緩存機(jī)制。由于平常主要用的還是Fresco,所以這里有必要對(duì)Fresco的原理進(jìn)行深入研究。這樣對(duì)于以后的使用與理解將會(huì)得到巨大的幫助。

Fresco是專注于對(duì)圖片加載而設(shè)計(jì)的框架,所以對(duì)于以圖片為主的App強(qiáng)烈推薦使用。Fresco對(duì)于圖片的展示支持多種情況:backgroud image(背景圖)、placeholder image(占位圖)、actual image(加載的圖片)、progress bar image(進(jìn)度條)、retry image(重新加載的圖片)、failure image(失敗圖片)與overlay image(疊加圖)。Fresco既然支持這么多圖片展示情況,那么它對(duì)這次圖層的管理模式又是怎么樣的呢?Fresco對(duì)于這些圖層的管理都交給了Hierarchy,而這些圖層的數(shù)據(jù)都通過(guò)Controller來(lái)設(shè)置。先不分析這些,這些后續(xù)文章會(huì)詳細(xì)分析,今天先從Fresco的基本組件開(kāi)始。

SimpleDraweeView
首先這是對(duì)Fresco的源碼分析,所以在看這篇文章之前你應(yīng)該要有使用Fresco的基礎(chǔ),如果沒(méi)有的強(qiáng)烈推薦看下Fresco官方文檔。

我們使用Fresco進(jìn)行圖片加載,使用最多的還是已經(jīng)封裝好的SimpleDraweeView,而在SimpleDraweeView的構(gòu)造方法中會(huì)調(diào)用init()方法,它的源碼如下:

private void init(Context context, @Nullable AttributeSet attrs) {
    if (isInEditMode()) {
      return;
    }
    Preconditions.checkNotNull(
        sDraweeControllerBuilderSupplier,
        "SimpleDraweeView was not initialized!");
    mSimpleDraweeControllerBuilder = sDraweeControllerBuilderSupplier.get();
 
    if (attrs != null) {
      TypedArray gdhAttrs = context.obtainStyledAttributes(
          attrs,
          R.styleable.SimpleDraweeView);
      try {
        if (gdhAttrs.hasValue(R.styleable.SimpleDraweeView_actualImageUri)) {
          setImageURI(
              Uri.parse(gdhAttrs.getString(R.styleable.SimpleDraweeView_actualImageUri)),
              null);
        } else if (gdhAttrs.hasValue((R.styleable.SimpleDraweeView_actualImageResource))) {
          int resId = gdhAttrs.getResourceId(
              R.styleable.SimpleDraweeView_actualImageResource,
              NO_ID);
          if (resId != NO_ID) {
            setActualImageResource(resId);
          }
        }
      } finally {
        gdhAttrs.recycle();
      }
    }
  }

這個(gè)方法做的事情很簡(jiǎn)單,但我們要注意的是它會(huì)對(duì)sDraweeControllerBuilderSupplier進(jìn)行null判斷,如果為null將會(huì)拋出異常。sDraweeControllerBuilderSupplier 是供應(yīng)類,通過(guò)它的get方法來(lái)獲取DraweeControllerBuilder,這個(gè)是controller構(gòu)造器,這個(gè)以后的章節(jié)會(huì)詳細(xì)說(shuō)明??张袛嗟哪康木褪窃谑褂?b>SimpleDraweeView之前必須初始化sDraweeControllerBuilderSupplier。在SimpleDraweeView中我們能找到它的初始化方法

public static void initialize(
      Supplier draweeControllerBuilderSupplier) {
    sDraweeControllerBuilderSupplier = draweeControllerBuilderSupplier;
  }

它是一個(gè)static方法,在SimpleDraweeView初始化之前加載一次即可。這是SimpleDraweeView的關(guān)鍵。它還有一個(gè)關(guān)鍵方法

public void setImageURI(Uri uri, @Nullable Object callerContext) {
    //通過(guò)controller 來(lái)保存Uri 等相關(guān)信息
    DraweeController controller = mSimpleDraweeControllerBuilder
        .setCallerContext(callerContext)
        .setUri(uri)
        .setOldController(getController())
        .build();
    setController(controller);
  }

使用mSimpleDraweeControllerBuilder來(lái)構(gòu)建一個(gè)Controller,而Controller是由build模式所創(chuàng)建,這里我們能看到uri也交由Controller管理。其實(shí)最終uri會(huì)封裝成一個(gè)ImageRequestController真正持有的是uri的封裝體ImageRequest。在SimpleDraweeView中它會(huì)重寫(xiě)setImageURI方法,最終也就是將ImageView中的原生方法給覆蓋掉。還有其它的類似的setImageResourcesetImageBitmap等,Fresco都在這些方法上加了@Deprecated,意思就是說(shuō)不推薦使用,如果使用的話就跟直接使用ImageView沒(méi)什么區(qū)別,這就無(wú)法體驗(yàn)到Fresco的強(qiáng)大的特性。在Fresco中統(tǒng)一由setController來(lái)替代。

關(guān)于Controller后續(xù)文章會(huì)詳細(xì)分析。
Fresco

如果我們根據(jù)Fresco官方文檔的正常步驟來(lái)使用的話就無(wú)需擔(dān)心這一步,因?yàn)樵谖覀冊(cè)谑褂?b>Fresco之前都要先調(diào)用Fresco.initialize(context)

public static void initialize(
      Context context,
      @Nullable ImagePipelineConfig imagePipelineConfig,
      @Nullable DraweeConfig draweeConfig) {
    if (sIsInitialized) {
      FLog.w(
          TAG,
          "Fresco has already been initialized! `Fresco.initialize(...)` should only be called " +
            "1 single time to avoid memory leaks!");
    } else {
      sIsInitialized = true;
    }
    // we should always use the application context to avoid memory leaks
    context = context.getApplicationContext();
    if (imagePipelineConfig == null) {
      //初始化ImagePipeline工廠,包含ImagePipelineConfig 相關(guān)初始化配置信息
      // (三級(jí)緩存、圖片解碼/編碼、轉(zhuǎn)化、漸變、bitmap配置、四種executor 分別為 io、decode、background、lightweight background)等
      ImagePipelineFactory.initialize(context);
    } else {
       ImagePipelineFactory.initialize(imagePipelineConfig);
    }
    //初始化Drawee相關(guān)配置信息
    initializeDrawee(context, draweeConfig);
  }

除了初始化ImagePipeline之外,最后還會(huì)調(diào)用initializeDrawee (context, draweeConfig),我們來(lái)看下initializeDrawee做了什么

private static void initializeDrawee(
      Context context,
      @Nullable DraweeConfig draweeConfig) {
    //構(gòu)建PipelineDraweeControllerBuilderSupplier,
    //其中ImagePipeline、PipelineDraweeControllerFactory、ControllerListener set集合
    sDraweeControllerBuilderSupplier =
        new PipelineDraweeControllerBuilderSupplier(context, draweeConfig);
    //初始化SimpleDrawee
    //初始化時(shí)通過(guò)調(diào)用PipelineDraweeControllerBuilderSupplier實(shí)現(xiàn)的Supplier的get()方法
    // 返回配置信息的封裝體PipelineDraweeControllerBuilder implements SimpleDraweeControllerBuilder
     SimpleDraweeView.initialize(sDraweeControllerBuilderSupplier);
  }

在這里我們會(huì)看到之前所提到的sDraweeControllerBuilderSupplierSimpleDraweeView中必須優(yōu)先調(diào)用的initialize方法。相信現(xiàn)在應(yīng)該明白的為什么在使用Fresco之前必須調(diào)用它的initialize方法了。因?yàn)樗仨氁跏蓟恍┍匾呐渲眯畔?,其中就包括使用的控?b>SimpleDraweeView的配置信息。

GenericDraweeView

上面所說(shuō)的SimpleDraweeView的父類是GenericDraweeView,它做的事情很簡(jiǎn)單,處理xml相關(guān)的屬性。它會(huì)通過(guò)inflateHierarchy方法進(jìn)行初始化。

protected void inflateHierarchy(Context context, @Nullable AttributeSet attrs) {
    GenericDraweeHierarchyBuilder builder =
        GenericDraweeHierarchyInflater.inflateBuilder(context, attrs);
    setAspectRatio(builder.getDesiredAspectRatio());
    setHierarchy(builder.build());
  }

它是由GenericDraweeHierarchyBuilder來(lái)統(tǒng)一封裝這些屬性。最終通過(guò)build方法來(lái)構(gòu)建GenericDraweeHierarchy,這就是Fresco的圖層。然后通過(guò)setHierarchy將圖層傳遞給DraweeHolder。DraweeHolder是用來(lái)管理HierarchyController的。而DraweeHolder是在最底層的DraweeView中,這也是GenericDraweeView的父類。下面我們進(jìn)入DraweeView ,來(lái)看看它到底做了什么。

DraweeView

DraweeViewFresco最底層的控件,也是我們使用它展示圖片的基礎(chǔ),它繼承于ImageView,所以它能做的事也無(wú)非于在原生ImageView上做擴(kuò)展或者方法重寫(xiě),從而來(lái)實(shí)現(xiàn)自己的一套邏輯。先看下它的構(gòu)造方法

public DraweeView(Context context) {
    super(context);
    init(context);
  }

沒(méi)什么特別的邏輯,就一個(gè)init方法,那么就進(jìn)入init看看

/** This method is idempotent so it only has effect the first time it"s called */
  private void init(Context context) {
    if (mInitialised) {
      return;
    }
    mInitialised = true;
    mDraweeHolder = DraweeHolder.create(null, context);
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
      ColorStateList imageTintList = getImageTintList();
      if (imageTintList == null) {
        return;
      }
      setColorFilter(imageTintList.getDefaultColor());
    }
    // In Android N and above, visibility handling for Drawables has been changed, which breaks
    // activity transitions with DraweeViews.
    mLegacyVisibilityHandlingEnabled = sGlobalLegacyVisibilityHandlingEnabled &&
        context.getApplicationInfo().targetSdkVersion >= 24; //Build.VERSION_CODES.N
  }

我們可以看到它會(huì)通過(guò)mInitialised來(lái)判斷是否需要初始化,源碼注釋也說(shuō)明的該方法只會(huì)調(diào)用一次。這是因?yàn)閯?chuàng)建Hierarchy的代價(jià)太大,所以只會(huì)創(chuàng)建一次,以后都會(huì)使用同一個(gè)mDraweeHolder中的Hierarchy,所以會(huì)看到這里就必須初始化一個(gè)mDraweeHolder。在DraweeView中還有以下幾個(gè)主要方法:

void setHierarchy(DH hierarchy)設(shè)置Hierarchy,同時(shí)會(huì)將Hierarchy交由mDraweeHolder管理,最后還會(huì)調(diào)用super.setImageDrawable(mDraweeHolder.getTopLevelDrawable());來(lái)將Hierarchy中的圖層樹(shù)顯示出來(lái)。

Drawable getTopLevelDrawable()會(huì)通過(guò)mDraweeHolder中的Hierarchy來(lái)獲取圖層樹(shù)。

void setController(@Nullable DraweeController draweeController)設(shè)置Controller,同時(shí)也會(huì)將Hierarchy中的圖層樹(shù)顯示出來(lái)。

void onAttachedToWindow()、void onDetachedFromWindow()、void onStartTemporaryDetach()void onFinishTemporaryDetach()是來(lái)控制圖層的顯示與隱藏、綁定與解綁的回調(diào)函數(shù),它們都分別會(huì)調(diào)用mDraweeHolderonAttach()onDetach()。其實(shí)最終調(diào)用的還是Controller中的onAttach()onDetach()。

boolean onTouchEvent(MotionEvent event)控制控件的觸摸,如果Controller有效的話會(huì)調(diào)用Controller中的onTouchEvent。

void setAspectRatio(float aspectRatio)用來(lái)設(shè)置DraweeView顯示的寬高比例。

setImageDrawable、setImageBitmap、setImageResourcesetImageURI這些方法都是原生ImageView的方法,但在DraweeView中這些方法都被加上了@Deprecated標(biāo)記。標(biāo)明不推薦使用,如果一定使用的話,那么DraweeView將會(huì)退化成一個(gè)普通的ImageView。因?yàn)樵?b>DraweeView中都是通過(guò)Controller來(lái)體現(xiàn)它的緩存、加載機(jī)制等特性。

上面這些就是DraweeView的主要涉及到的方法與特性,不過(guò)在DraweeView中基本上每一個(gè)方法都涉及到了DraweeHolder,那它到底是干什么的呢?別急下面就輪到它了。

DraweeHolder
A holder class for Drawee controller and hierarchy.

上面的是官方注釋,說(shuō)明DraweeHolder是用來(lái)管理HierarchyController的,同時(shí)也是它們之間的聯(lián)系的橋梁。DraweeView以及它的子類都是通過(guò)它來(lái)間接操作ControllerHierarchy。

public static  DraweeHolder create(
      @Nullable DH hierarchy,
      Context context) {
    DraweeHolder holder = new DraweeHolder(hierarchy);
    holder.registerWithContext(context);
    return holder;
  }

它是通過(guò)公有的靜態(tài)方法來(lái)創(chuàng)建自身實(shí)例的。在上面的DraweeViewinit方法中會(huì)調(diào)用。在其內(nèi)部的DraweeEventTracker,是用來(lái)記錄事件的傳遞,方便dubug的調(diào)試。如果不需要的話,可以在Fresco.initialize()之前調(diào)用DraweeEventTracker.disable()。那么剩下的方法其實(shí)基本上在DraweeView中都說(shuō)過(guò)。

onAttach()onDetach(),都會(huì)調(diào)用attachOrDetachController(),根據(jù)情況分別調(diào)用attachController()detachController(),最終調(diào)用的就是ControlleronAttach()onDetach()

Drawable getTopLevelDrawable()調(diào)用mHierarchy.getTopLevelDrawable()獲取圖層樹(shù)。

void setController(@Nullable DraweeController draweeController)設(shè)置Controller,在設(shè)置之前會(huì)先判斷是否已經(jīng)wasAttached,如果是的話就先調(diào)用detachController(),然后清除老的Controller,再將Hierarchy設(shè)置到新的Controller中。最后再attachController()進(jìn)行綁定顯示圖層。

void setHierarchy(DH hierarchy)設(shè)置Hierarchy,如果Controller有效的話就與Hierarchy建立鏈接,將Hierarchy設(shè)置到Controller中。

以上就是DraweeHolder的主要方法,都跟ControllerHierarchy相關(guān)。而DraweeHolder又與DraweeView相連,所以最終還是要回到ControllerHierarchy中。

End

這次主要是分析了Fresco中的基本組件DraweeView與它的子類。如果你還想進(jìn)一步了解HierarchyController的原理,下篇文章將會(huì)詳細(xì)分析相關(guān)的原理,敬請(qǐng)期待!

Fresco源碼分析系列Github地址

關(guān)注

Recommend

Fresco源碼分析之Hierarchy
Android共享動(dòng)畫(huà)兼容實(shí)現(xiàn)
Kotlin最佳實(shí)踐
RecyclerView下拉刷新與上拉更多
Android高仿微信之mvp實(shí)現(xiàn)(四)
tensorflow-梯度下降,有這一篇就足夠了
博客

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/70713.html

相關(guān)文章

  • Fresco源碼分析Hierarchy

    摘要:最終的顯隱操作都會(huì)轉(zhuǎn)化為在方法中進(jìn)行操作。主要是通過(guò)與數(shù)組來(lái)控制數(shù)組中各個(gè)的值,即顯隱它繼承于,顧名思義通過(guò)矩陣來(lái)改變狀態(tài)。 上篇文章我們分析了Fresco中的DraweeView,對(duì)其中的一些原理以及方法進(jìn)行了解析。在這過(guò)程中我們了解到,DraweeView中是通過(guò)DraweeHolder來(lái)統(tǒng)一管理的。而DraweeHolder又是用來(lái)統(tǒng)一管理相關(guān)的Hierarchy與Control...

    jzzlee 評(píng)論0 收藏0
  • 圖片加載框架Fresco

    摘要:中設(shè)計(jì)有一個(gè)叫做模塊,它會(huì)在圖片加載完成前顯示占位圖,加載成功后自動(dòng)替換為目標(biāo)圖片。當(dāng)圖片不再顯示在屏幕上時(shí),它會(huì)及時(shí)地釋放內(nèi)存和空間占用。大的內(nèi)存占用勢(shì)必引發(fā)更加頻繁的。 Fresco圖片框架簡(jiǎn)介及使用 Fresco是FaceBook退出了一個(gè)Android開(kāi)源圖片管理框架,它提供了圖片下載、漸進(jìn)式加載、內(nèi)存管理等功能,很大程度上把程序員從繁瑣的圖片管理工作中解放了出來(lái),官網(wǎng)地址,F(xiàn)...

    lvzishen 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<