91超碰碰碰碰久久久久久综合_超碰av人澡人澡人澡人澡人掠_国产黄大片在线观看画质优化_txt小说免费全本

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Flutter加載圖片流程之ImageProvider源碼分析

發布時間:2023-04-20 15:59:58 來源:億速云 閱讀:117 作者:iii 欄目:開發技術

本篇內容主要講解“Flutter加載圖片流程之ImageProvider源碼分析”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強。下面就讓小編來帶大家學習“Flutter加載圖片流程之ImageProvider源碼分析”吧!

    加載網絡圖片

    Image.network()是Flutter提供的一種從網絡上加載圖片的方法,它可以從指定的URL加載圖片,并在加載完成后將其顯示在應用程序中。

    ImageProvider

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

    ImageProvider類包含兩個核心方法: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;
    }

    根據文檔解釋,我們可以了解到以下幾點:

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

    2、這是 [ImageProvider] 類層次結構的公共入口點。

    3、子類應該實現 [obtainKey] 和 [load] 方法,這兩個方法將被該方法使用。 

    4、如果子類需要更改使用的 [ImageStream] 的實現,則應該重寫 [createStream] 方法。 

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

    閱讀resolve方法的實現。我們可以知道:

    1、它使用給定的configuration參數創建一個ImageStream對象(createStream)。然后調用_createErrorHandlerAndKey方法,該方法會異步獲取圖片的唯一標識符,并設置一個錯誤處理區域,以防圖片加載過程中發生錯誤。

    2、如果獲取唯一標識符的過程中出現異常,則會將錯誤信息封裝成一個_ErrorImageCompleter對象,并將其設置為ImageStreamcompleter屬性,表示圖片加載失敗。

    3、如果唯一標識符獲取成功,則會調用resolveStreamForKey方法來解析圖片,并將圖片數據存儲到ImageStream對象中,供后續使用。

    4、該方法是ImageProvider類層次結構的公共入口點,因為它是所有圖片提供器的解析方法。子類只需要實現obtainKeyload方法來獲取圖片的唯一標識符和加載圖片的數據,而不需要重寫resolve方法。

    5、如果子類需要更改使用的ImageStream的實現方式,則可以重寫createStream方法。如果子類需要管理實際的圖像分辨率,則可以重寫resolveStreamForKey方法。例如,AssetImage類中的createStream方法返回一個AssetBundleImageStreamCompleter對象,該對象用于從應用程序資源中加載圖片數據。而NetworkImage類中的resolveStreamForKey方法使用HTTP客戶端從網絡上加載圖片數據。

    6、這段代碼中還有一些調試信息,例如將圖片提供器、圖片配置和圖片唯一標識符添加到調試信息中,以便在出現錯誤時進行調試。

    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);

    這段注釋是關于obtainKey方法的說明。該方法是ImageProvider的子類應該實現的方法之一,用于將ImageProvider的設置及ImageConfiguration轉換為一個可以唯一標識圖片的key

    不同的ImageProvider根據相同的構造函數參數和ImageConfiguration對象應該返回相等的key,以便于后續加載和緩存圖片。key的類型由子類確定,它應該是一個值,可以唯一地標識出要加載的圖片(包括其縮放比例)。

    在實現obtainKey方法時,子類可以考慮使用自定義的類來表示key,并實現==方法以保證唯一性。

    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) {
        /// 關鍵是解析并設置ImageStreamCompleter對象
        stream.setCompleter(completer);
      }
    }

    官方文檔解釋:

    • 該方法是ImageProvider的子類應該實現的方法之一,用于根據key來解析圖片。

    • resolveStreamForKey方法是由resolve方法調用的,其參數包括ImageConfigurationImageStreamkeyerrorHandler。子類可以通過實現resolveStreamForKey方法來管理圖片的實際解析過程,同時也可以通過調用errorHandler來處理解析過程中可能發生的錯誤。

    • 實現resolveStreamForKey方法時,子類可以考慮使用keyImageCache交互,例如調用ImageCache.putIfAbsent方法,并向stream通知監聽器。默認實現已經使用keyImageCache交互,子類可以選擇調用super.resolveStreamForKey方法或不調用。

    從上面的源碼,我們可以知道以下幾點:

    • 1、如果 stream 對象已經有了 completer(即已經有了可以加載圖片的方式),則將 completer 添加到 ImageCache 中,實現緩存功能,并直接返回。

    • 2、如果 stream 對象還沒有 completer,則調用 loadBuffer 方法加載圖片,并將其返回的 ImageStreamCompleter 對象添加到 ImageCache 中,同時設置到 stream 對象的 completer 中。

    • 3、如果 loadBuffer 方法出現了異常,則會將異常交給 onError 回調處理,以便在異常處理時能夠提供詳細的錯誤信息。

    • 4、關鍵是解析并設置ImageStreamCompleter對象

    • 5、PaintingBinding.instance.imageCache.putIfAbsent方法在內部將ImageStreamListener對象添加到ImageStreamCompleter對象的_listeners數組中了。

       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方法即可。

    • 這個方法是ImageProvider的一個protected方法,用于從緩存中加載指定的圖片。

    • 它接受兩個參數:一個是唯一標識圖片的key,另一個是一個用于解碼圖片數據的回調函數decode。

    • 這個方法調用了load方法,然后返回一個ImageStreamCompleter對象,它表示加載過程中的一個數據流。

    • 在load方法中,使用傳入的decode回調函數從緩存或網絡中獲取圖片數據并解碼,然后將解碼后的圖片數據傳遞給ImageStreamCompleter對象,以便它可以生成一個帶有正確圖片數據的ImageInfo對象,這個ImageInfo對象可以被傳遞到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');
    }

    從注釋可知:

    這個方法被廢棄了,現在已經不再建議使用了。如果需要更快的圖像加載,請實現 [loadBuffer] 方法。在 [load] 和 [loadBuffer] 方法中只需要實現其中一個,而且 [loadBuffer] 更受推薦。

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

    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);
    }

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

    列表快速滑動,內存暴增時,可以用這個方法做些事情。

    困惑解答

    第一次加載圖片時,stream對象通常沒有completer。在第一次調用resolveStreamForKey時,會將stream對象的completer與對應的ImageCacheImageStreamCompleter進行綁定,并且completer會被設置為ImageStreamCompleter

    到此,相信大家對“Flutter加載圖片流程之ImageProvider源碼分析”有了更深的了解,不妨來實際操作一番吧!這里是億速云網站,更多相關內容可以進入相關頻道進行查詢,關注我們,繼續學習!

    向AI問一下細節

    免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

    AI

    托里县| 桐乡市| 灌阳县| 宁城县| 永修县| 社旗县| 江油市| 双牌县| 名山县| 汝州市| 武邑县| 墨脱县| 鄂托克旗| 年辖:市辖区| 云梦县| 荔浦县| 麟游县| 特克斯县| 阳城县| 宁化县| 岑溪市| 兴文县| 尼木县| 西乡县| 沙雅县| 斗六市| 三穗县| 恩平市| 建德市| 长治市| 平南县| 巨鹿县| 绥阳县| 黎川县| 区。| 莱芜市| 博乐市| 高密市| 富蕴县| 上饶市| 雅江县|