亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

Flutter加載圖片流程之ImageProvider源碼示例解析

 更新時(shí)間:2023年04月20日 11:38:13   作者:Nicholas68  
這篇文章主要為大家介紹了Flutter加載圖片流程之ImageProvider源碼示例解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪

加載網(wǎng)絡(luò)圖片

Image.network()是Flutter提供的一種從網(wǎng)絡(luò)上加載圖片的方法,它可以從指定的URL加載圖片,并在加載完成后將其顯示在應(yīng)用程序中。本節(jié)內(nèi)容,我們從源碼出發(fā),探討下圖片的加載流程。

ImageProvider

ImageProvider是Flutter中一個(gè)抽象類,它定義了一種用于加載圖片的通用接口,可以用于加載本地圖片、網(wǎng)絡(luò)圖片等各種類型的圖片。

ImageProvider類包含兩個(gè)核心方法:obtainKeyloadBuffer。

resolve

/// Resolves this image provider using the given `configuration`, returning
/// an [ImageStream].
///
/// This is the public entry-point of the [ImageProvider] class hierarchy.
///
/// Subclasses should implement [obtainKey] and [load], which are used by this
/// method. If they need to change the implementation of [ImageStream] used,
/// they should override [createStream]. If they need to manage the actual
/// resolution of the image, they should override [resolveStreamForKey].
///
/// See the Lifecycle documentation on [ImageProvider] for more information.
@nonVirtual
ImageStream resolve(ImageConfiguration configuration) {
  assert(configuration != null);
  final ImageStream stream = createStream(configuration);
  // Load the key (potentially asynchronously), set up an error handling zone,
  // and call resolveStreamForKey.
  _createErrorHandlerAndKey(
    configuration,
    (T key, ImageErrorListener errorHandler) {
      resolveStreamForKey(configuration, stream, key, errorHandler);
    },
    (T? key, Object exception, StackTrace? stack) async {
      await null; // wait an event turn in case a listener has been added to the image stream.
      InformationCollector? collector;
      assert(() {
        collector = () => <DiagnosticsNode>[          DiagnosticsProperty<ImageProvider>('Image provider', this),          DiagnosticsProperty<ImageConfiguration>('Image configuration', configuration),          DiagnosticsProperty<T>('Image key', key, defaultValue: null),        ];
        return true;
      }());
      if (stream.completer == null) {
        stream.setCompleter(_ErrorImageCompleter());
      }
      stream.completer!.reportError(
        exception: exception,
        stack: stack,
        context: ErrorDescription('while resolving an image'),
        silent: true, // could be a network error or whatnot
        informationCollector: collector,
      );
    },
  );
  return stream;
}

根據(jù)文檔解釋,我們可以了解到以下幾點(diǎn):

1、使用給定的`configuration`解析該圖片提供器,返回一個(gè) [ImageStream]。  

2、這是 [ImageProvider] 類層次結(jié)構(gòu)的公共入口點(diǎn)。

3、子類應(yīng)該實(shí)現(xiàn) [obtainKey] 和 [load] 方法,這兩個(gè)方法將被該方法使用。 

4、如果子類需要更改使用的 [ImageStream] 的實(shí)現(xiàn),則應(yīng)該重寫 [createStream] 方法。 

5、 如果子類需要管理實(shí)際的圖像分辨率,則應(yīng)該重寫 [resolveStreamForKey] 方法。 

閱讀resolve方法的實(shí)現(xiàn)。我們可以知道:

1、它使用給定的configuration參數(shù)創(chuàng)建一個(gè)ImageStream對(duì)象(createStream)。然后調(diào)用_createErrorHandlerAndKey方法,該方法會(huì)異步獲取圖片的唯一標(biāo)識(shí)符,并設(shè)置一個(gè)錯(cuò)誤處理區(qū)域,以防圖片加載過(guò)程中發(fā)生錯(cuò)誤。

2、如果獲取唯一標(biāo)識(shí)符的過(guò)程中出現(xiàn)異常,則會(huì)將錯(cuò)誤信息封裝成一個(gè)_ErrorImageCompleter對(duì)象,并將其設(shè)置為ImageStreamcompleter屬性,表示圖片加載失敗。

3、如果唯一標(biāo)識(shí)符獲取成功,則會(huì)調(diào)用resolveStreamForKey方法來(lái)解析圖片,并將圖片數(shù)據(jù)存儲(chǔ)到ImageStream對(duì)象中,供后續(xù)使用。

4、該方法是ImageProvider類層次結(jié)構(gòu)的公共入口點(diǎn),因?yàn)樗撬袌D片提供器的解析方法。子類只需要實(shí)現(xiàn)obtainKeyload方法來(lái)獲取圖片的唯一標(biāo)識(shí)符和加載圖片的數(shù)據(jù),而不需要重寫resolve方法。

5、如果子類需要更改使用的ImageStream的實(shí)現(xiàn)方式,則可以重寫createStream方法。如果子類需要管理實(shí)際的圖像分辨率,則可以重寫resolveStreamForKey方法。例如,AssetImage類中的createStream方法返回一個(gè)AssetBundleImageStreamCompleter對(duì)象,該對(duì)象用于從應(yīng)用程序資源中加載圖片數(shù)據(jù)。而NetworkImage類中的resolveStreamForKey方法使用HTTP客戶端從網(wǎng)絡(luò)上加載圖片數(shù)據(jù)。

6、這段代碼中還有一些調(diào)試信息,例如將圖片提供器、圖片配置和圖片唯一標(biāo)識(shí)符添加到調(diào)試信息中,以便在出現(xiàn)錯(cuò)誤時(shí)進(jìn)行調(diào)試。

obtainKey

/// Converts an ImageProvider's settings plus an ImageConfiguration to a key
/// that describes the precise image to load.
///
/// The type of the key is determined by the subclass. It is a value that
/// unambiguously identifies the image (_including its scale_) that the [load]
/// method will fetch. Different [ImageProvider]s given the same constructor
/// arguments and [ImageConfiguration] objects should return keys that are
/// '==' to each other (possibly by using a class for the key that itself
/// implements [==]).
Future&lt;T&gt; obtainKey(ImageConfiguration configuration);

這段注釋是關(guān)于obtainKey方法的說(shuō)明。該方法是ImageProvider的子類應(yīng)該實(shí)現(xiàn)的方法之一,用于將ImageProvider的設(shè)置及ImageConfiguration轉(zhuǎn)換為一個(gè)可以唯一標(biāo)識(shí)圖片的key

不同的ImageProvider根據(jù)相同的構(gòu)造函數(shù)參數(shù)和ImageConfiguration對(duì)象應(yīng)該返回相等的key,以便于后續(xù)加載和緩存圖片。key的類型由子類確定,它應(yīng)該是一個(gè)值,可以唯一地標(biāo)識(shí)出要加載的圖片(包括其縮放比例)。

在實(shí)現(xiàn)obtainKey方法時(shí),子類可以考慮使用自定義的類來(lái)表示key,并實(shí)現(xiàn)==方法以保證唯一性。

resolveStreamForKey

@protected
void resolveStreamForKey(ImageConfiguration configuration, ImageStream stream, T key, ImageErrorListener handleError) {
  // This is an unusual edge case where someone has told us that they found
  // the image we want before getting to this method. We should avoid calling
  // load again, but still update the image cache with LRU information.
  if (stream.completer != null) {
    final ImageStreamCompleter? completer = PaintingBinding.instance.imageCache.putIfAbsent(
      key,
      () => stream.completer!,
      onError: handleError,
    );
    assert(identical(completer, stream.completer));
    return;
  }
  final ImageStreamCompleter? completer = PaintingBinding.instance.imageCache.putIfAbsent(
    key,
    /// 加載
    () => loadBuffer(key, PaintingBinding.instance.instantiateImageCodecFromBuffer),
    onError: handleError,
  );
  if (completer != null) {
    /// 關(guān)鍵是解析并設(shè)置ImageStreamCompleter對(duì)象
    stream.setCompleter(completer);
  }
}

官方文檔解釋:

  • 該方法是ImageProvider的子類應(yīng)該實(shí)現(xiàn)的方法之一,用于根據(jù)key來(lái)解析圖片。
  • resolveStreamForKey方法是由resolve方法調(diào)用的,其參數(shù)包括ImageConfiguration、ImageStream、keyerrorHandler。子類可以通過(guò)實(shí)現(xiàn)resolveStreamForKey方法來(lái)管理圖片的實(shí)際解析過(guò)程,同時(shí)也可以通過(guò)調(diào)用errorHandler來(lái)處理解析過(guò)程中可能發(fā)生的錯(cuò)誤。
  • 實(shí)現(xiàn)resolveStreamForKey方法時(shí),子類可以考慮使用keyImageCache交互,例如調(diào)用ImageCache.putIfAbsent方法,并向stream通知監(jiān)聽(tīng)器。默認(rèn)實(shí)現(xiàn)已經(jīng)使用keyImageCache交互,子類可以選擇調(diào)用super.resolveStreamForKey方法或不調(diào)用。

從上面的源碼,我們可以知道以下幾點(diǎn):

  • 1、如果 stream 對(duì)象已經(jīng)有了 completer(即已經(jīng)有了可以加載圖片的方式),則將 completer 添加到 ImageCache 中,實(shí)現(xiàn)緩存功能,并直接返回。
  • 2、如果 stream 對(duì)象還沒(méi)有 completer,則調(diào)用 loadBuffer 方法加載圖片,并將其返回的 ImageStreamCompleter 對(duì)象添加到 ImageCache 中,同時(shí)設(shè)置到 stream 對(duì)象的 completer 中。
  • 3、如果 loadBuffer 方法出現(xiàn)了異常,則會(huì)將異常交給 onError 回調(diào)處理,以便在異常處理時(shí)能夠提供詳細(xì)的錯(cuò)誤信息。
  • 4、關(guān)鍵是解析并設(shè)置ImageStreamCompleter對(duì)象
  • 5、PaintingBinding.instance.imageCache.putIfAbsent方法在內(nèi)部將ImageStreamListener對(duì)象添加到ImageStreamCompleter對(duì)象的_listeners數(shù)組中了。
   PaintingBinding.instance.imageCache.putIfAbsent(
     key,
     () =&gt; loadBuffer(key, PaintingBinding.instance.instantiateImageCodecFromBuffer),
     onError: handleError,
   )

loadBuffer

/// Converts a key into an [ImageStreamCompleter], and begins fetching the
/// image.
///
/// For backwards-compatibility the default implementation of this method calls
/// through to [ImageProvider.load]. However, implementors of this interface should
/// only override this method and not [ImageProvider.load], which is deprecated.
///
/// The [decode] callback provides the logic to obtain the codec for the
/// image.
///
/// See also:
///
///  * [ResizeImage], for modifying the key to account for cache dimensions.
@protected
ImageStreamCompleter loadBuffer(T key, DecoderBufferCallback decode) {
  return load(key, PaintingBinding.instance.instantiateImageCodec);
}

從源碼我們知道, [ImageProvider.load], which is deprecated被廢棄了。子類只需要重寫loadBuffer方法即可。

  • 這個(gè)方法是ImageProvider的一個(gè)protected方法,用于從緩存中加載指定的圖片。
  • 它接受兩個(gè)參數(shù):一個(gè)是唯一標(biāo)識(shí)圖片的key,另一個(gè)是一個(gè)用于解碼圖片數(shù)據(jù)的回調(diào)函數(shù)decode。
  • 這個(gè)方法調(diào)用了load方法,然后返回一個(gè)ImageStreamCompleter對(duì)象,它表示加載過(guò)程中的一個(gè)數(shù)據(jù)流。
  • 在load方法中,使用傳入的decode回調(diào)函數(shù)從緩存或網(wǎng)絡(luò)中獲取圖片數(shù)據(jù)并解碼,然后將解碼后的圖片數(shù)據(jù)傳遞給ImageStreamCompleter對(duì)象,以便它可以生成一個(gè)帶有正確圖片數(shù)據(jù)的ImageInfo對(duì)象,這個(gè)ImageInfo對(duì)象可以被傳遞到Image widget中用于顯示圖片。

load(被廢棄)

/// Converts a key into an [ImageStreamCompleter], and begins fetching the
/// image.
///
/// This method is deprecated. Implement [loadBuffer] for faster image
/// loading. Only one of [load] and [loadBuffer] must be implemented, and
/// [loadBuffer] is preferred.
///
/// The [decode] callback provides the logic to obtain the codec for the
/// image.
///
/// See also:
///
///  * [ResizeImage], for modifying the key to account for cache dimensions.
@protected
@Deprecated(
  'Implement loadBuffer for faster image loading. '
  'This feature was deprecated after v2.13.0-1.0.pre.',
)
ImageStreamCompleter load(T key, DecoderCallback decode) {
  throw UnsupportedError('Implement loadBuffer for faster image loading');
}

從注釋可知:

這個(gè)方法被廢棄了,現(xiàn)在已經(jīng)不再建議使用了。如果需要更快的圖像加載,請(qǐng)實(shí)現(xiàn) [loadBuffer] 方法。在 [load] 和 [loadBuffer] 方法中只需要實(shí)現(xiàn)其中一個(gè),而且 [loadBuffer] 更受推薦。

[decode] 回調(diào)提供了獲取圖像編解碼器的邏輯。

evict

/// Evicts an entry from the image cache.
///
/// Returns a [Future] which indicates whether the value was successfully
/// removed.
///
/// The [ImageProvider] used does not need to be the same instance that was
/// passed to an [Image] widget, but it does need to create a key which is
/// equal to one.
///
/// The [cache] is optional and defaults to the global image cache.
///
/// The [configuration] is optional and defaults to
/// [ImageConfiguration.empty].
///
/// {@tool snippet}
///
/// The following sample code shows how an image loaded using the [Image]
/// widget can be evicted using a [NetworkImage] with a matching URL.
///
/// ```dart
/// class MyWidget extends StatelessWidget {
///   const MyWidget({
///     super.key,
///     this.url = ' ... ',
///   });
///
///   final String url;
///
///   @override
///   Widget build(BuildContext context) {
///     return Image.network(url);
///   }
///
///   void evictImage() {
///     final NetworkImage provider = NetworkImage(url);
///     provider.evict().then&lt;void&gt;((bool success) {
///       if (success) {
///         debugPrint('removed image!');
///       }
///     });
///   }
/// }
/// ```
/// {@end-tool}
Future&lt;bool&gt; evict({ ImageCache? cache, ImageConfiguration configuration = ImageConfiguration.empty }) async {
  cache ??= imageCache;
  final T key = await obtainKey(configuration);
  return cache.evict(key);
}

這是一個(gè)名為evict的異步方法,它的作用是從圖像緩存中刪除給定配置下的圖片。它有兩個(gè)可選參數(shù):cacheconfiguration。如果cache參數(shù)為null,則默認(rèn)使用全局的imageCacheconfiguration參數(shù)是一個(gè)圖像配置,它用于獲取將要從緩存中刪除的圖片的鍵值。這個(gè)方法返回一個(gè)Future<bool>對(duì)象,表示刪除是否成功。如果緩存中沒(méi)有找到要?jiǎng)h除的圖片,則返回false

列表快速滑動(dòng),內(nèi)存暴增時(shí),可以用這個(gè)方法做些事情。

總結(jié)

ImageProvider是Flutter中一個(gè)用于提供圖像數(shù)據(jù)的抽象類,它定義了如何從不同的數(shù)據(jù)源(如文件系統(tǒng)、網(wǎng)絡(luò)、內(nèi)存)中獲取圖像數(shù)據(jù),并將其轉(zhuǎn)換成ImageStreamCompleter對(duì)象,以供Image組件使用。

在Flutter中,使用Image組件來(lái)加載和顯示圖像,需要先提供一個(gè)ImageProvider對(duì)象作為其image屬性的值。ImageProvider類包含了兩個(gè)關(guān)鍵的方法:obtainKeyload。

obtainKey方法用于獲取一個(gè)用于唯一標(biāo)識(shí)圖像數(shù)據(jù)的ImageProvider對(duì)象,這個(gè)對(duì)象可以用來(lái)緩存圖像數(shù)據(jù),以便在需要重新加載圖像時(shí)能夠快速獲取到它。例如,AssetImage類使用圖片資源的路徑作為其ImageProvider對(duì)象的標(biāo)識(shí)符,以便在需要重新加載該資源時(shí)能夠快速地從內(nèi)存或磁盤緩存中獲取到它。

load方法用于獲取一個(gè)ImageStreamCompleter對(duì)象,該對(duì)象包含了用于繪制圖像的圖像數(shù)據(jù)。在Flutter 2.5之前,load方法是一個(gè)抽象方法,必須由子類實(shí)現(xiàn)。但是從Flutter 2.5開(kāi)始,load方法已被廢棄,取而代之的是resolve方法。resolve方法接受一個(gè)ImageConfiguration參數(shù),并返回一個(gè)Future<ImageStreamCompleter>對(duì)象。它與load方法的功能類似,都是用于獲取圖像數(shù)據(jù),并將其轉(zhuǎn)換成ImageStreamCompleter對(duì)象,以供Image組件使用。

使用ImageProvider類加載和顯示圖像的流程如下:

  • 創(chuàng)建一個(gè)ImageProvider對(duì)象,該對(duì)象提供了圖像數(shù)據(jù)的來(lái)源和標(biāo)識(shí)符。
  • 使用ImageProvider對(duì)象作為Image組件的image屬性的值。
  • Image組件會(huì)調(diào)用obtainKey方法獲取一個(gè)用于唯一標(biāo)識(shí)圖像數(shù)據(jù)的ImageProvider對(duì)象。
  • Image組件會(huì)調(diào)用resolve方法獲取一個(gè)Future<ImageStreamCompleter>對(duì)象。
  • 當(dāng)圖像數(shù)據(jù)加載完成后,ImageStreamCompleter對(duì)象會(huì)將其通知給Image組件,Image組件會(huì)將其渲染到屏幕上。

總的來(lái)說(shuō),ImageProvider類是Flutter中一個(gè)非常重要的類,它提供了一種方便的方式來(lái)加載和顯示圖像。雖然load方法已被廢棄,但是resolve方法提供了更好的替代方案,可以用于獲取圖像數(shù)據(jù)并將其轉(zhuǎn)換成ImageStreamCompleter對(duì)象。

參考鏈接

Flutter系統(tǒng)網(wǎng)絡(luò)圖片加載流程解析_Android

Flutter入門系列(四)---Flutter圖片緩存

Flutter | Image 源碼分析與優(yōu)化方式

困惑解答

第一次加載圖片時(shí),stream對(duì)象通常沒(méi)有completer。在第一次調(diào)用resolveStreamForKey時(shí),會(huì)將stream對(duì)象的completer與對(duì)應(yīng)的ImageCacheImageStreamCompleter進(jìn)行綁定,并且completer會(huì)被設(shè)置為ImageStreamCompleter。

以上就是Flutter加載圖片流程之ImageProvider源碼示例解析的詳細(xì)內(nèi)容,更多關(guān)于Flutter加載圖片ImageProvider的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Android開(kāi)發(fā)手冊(cè)Button按鈕實(shí)現(xiàn)點(diǎn)擊音效

    Android開(kāi)發(fā)手冊(cè)Button按鈕實(shí)現(xiàn)點(diǎn)擊音效

    這篇文章主要為大家介紹了Android開(kāi)發(fā)手冊(cè)Button按鈕實(shí)現(xiàn)點(diǎn)擊音效示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-06-06
  • Android App調(diào)用MediaRecorder實(shí)現(xiàn)錄音功能的實(shí)例

    Android App調(diào)用MediaRecorder實(shí)現(xiàn)錄音功能的實(shí)例

    這篇文章主要介紹了Android App調(diào)用MediaRecorder實(shí)現(xiàn)錄音功能的實(shí)例,MediaRecorder非常強(qiáng)大,不僅能夠用來(lái)錄制音頻還可以錄制視頻,需要的朋友可以參考下
    2016-04-04
  • Android中SwipeBack實(shí)現(xiàn)右滑返回效果

    Android中SwipeBack實(shí)現(xiàn)右滑返回效果

    這篇文章主要介紹了Android中SwipeBack實(shí)現(xiàn)右滑返回效果的相關(guān)資料,需要的朋友可以參考下
    2016-02-02
  • RecyclerView+PagerSnapHelper實(shí)現(xiàn)抖音首頁(yè)翻頁(yè)的Viewpager效果

    RecyclerView+PagerSnapHelper實(shí)現(xiàn)抖音首頁(yè)翻頁(yè)的Viewpager效果

    這篇文章主要為大家詳細(xì)介紹了RecyclerView+PagerSnapHelper實(shí)現(xiàn)抖音首頁(yè)翻頁(yè)的Viewpager效果,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2019-10-10
  • Android端權(quán)限隱私的合規(guī)化處理實(shí)戰(zhàn)記錄

    Android端權(quán)限隱私的合規(guī)化處理實(shí)戰(zhàn)記錄

    大家應(yīng)該都發(fā)現(xiàn)了,現(xiàn)在很多應(yīng)用市場(chǎng)都要求應(yīng)用上架需要用戶協(xié)議,這篇文章主要給大家介紹了關(guān)于Android端權(quán)限隱私合規(guī)化處理的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2021-08-08
  • Flutter中獲取屏幕及Widget的寬高示例代碼

    Flutter中獲取屏幕及Widget的寬高示例代碼

    這篇文章主要給大家介紹了關(guān)于Flutter中如何獲取屏幕及Widget的寬高的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者使用Flutter具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-03-03
  • 詳解Android布局加載流程源碼

    詳解Android布局加載流程源碼

    這篇文章主要介紹了詳解Android布局加載流程源碼,對(duì)布局感興趣的同學(xué)可以參考下
    2021-04-04
  • Android開(kāi)發(fā)Compose remember原理解析

    Android開(kāi)發(fā)Compose remember原理解析

    這篇文章主要為大家介紹了Android開(kāi)發(fā)Compose remember原理解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-07-07
  • Android仿手機(jī)QQ圖案解鎖功能

    Android仿手機(jī)QQ圖案解鎖功能

    這篇文章主要為大家詳細(xì)介紹了Android仿手機(jī)QQ圖案解鎖功能的相關(guān)資料,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-05-05
  • Android幀率監(jiān)測(cè)與優(yōu)化技巧

    Android幀率監(jiān)測(cè)與優(yōu)化技巧

    Android 應(yīng)用的性能優(yōu)化是開(kāi)發(fā)過(guò)程中至關(guān)重要的一環(huán),而幀率(Frame Rate)是評(píng)估應(yīng)用性能的一個(gè)關(guān)鍵指標(biāo),在本文中,我們將深入探討如何監(jiān)測(cè) Android 應(yīng)用的幀率,以及如何通過(guò)代碼示例來(lái)優(yōu)化應(yīng)用的性能,需要的朋友可以參考下
    2023-10-10

最新評(píng)論