<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
Image.network()
是Flutter提供的一種從網路上載入圖片的方法,它可以從指定的URL載入圖片,並在載入完成後將其顯示在應用程式中。本節內容,我們從原始碼出發,探討下圖片的載入流程。
ImageProvider
是Flutter中一個抽象類,它定義了一種用於載入圖片的通用介面,可以用於載入本地圖片、網路圖片等各種型別的圖片。
ImageProvider
類包含兩個核心方法:obtainKey
和loadBuffer
。
/// 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
物件,並將其設定為ImageStream
的completer
屬性,表示圖片載入失敗。
3、如果唯一識別符號獲取成功,則會呼叫resolveStreamForKey
方法來解析圖片,並將圖片資料儲存到ImageStream
物件中,供後續使用。
4、該方法是ImageProvider
類層次結構的公共入口點,因為它是所有圖片提供器的解析方法。子類只需要實現obtainKey
和load
方法來獲取圖片的唯一識別符號和載入圖片的資料,而不需要重寫resolve
方法。
5、如果子類需要更改使用的ImageStream
的實現方式,則可以重寫createStream
方法。如果子類需要管理實際的影象解析度,則可以重寫resolveStreamForKey
方法。例如,AssetImage
類中的createStream
方法返回一個AssetBundleImageStreamCompleter
物件,該物件用於從應用程式資源中載入圖片資料。而NetworkImage
類中的resolveStreamForKey
方法使用HTTP使用者端從網路上載入圖片資料。
6、這段程式碼中還有一些偵錯資訊,例如將圖片提供器、圖片設定和圖片唯一識別符號新增到偵錯資訊中,以便在出現錯誤時進行偵錯。
/// 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<T> obtainKey(ImageConfiguration configuration);
這段註釋是關於obtainKey
方法的說明。該方法是ImageProvider
的子類應該實現的方法之一,用於將ImageProvider
的設定及ImageConfiguration
轉換為一個可以唯一標識圖片的key
。
不同的ImageProvider
根據相同的建構函式引數和ImageConfiguration
物件應該返回相等的key
,以便於後續載入和快取圖片。key
的型別由子類確定,它應該是一個值,可以唯一地標識出要載入的圖片(包括其縮放比例)。
在實現obtainKey
方法時,子類可以考慮使用自定義的類來表示key
,並實現==
方法以保證唯一性。
@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
方法呼叫的,其引數包括ImageConfiguration
、ImageStream
、key
和errorHandler
。子類可以通過實現resolveStreamForKey
方法來管理圖片的實際解析過程,同時也可以通過呼叫errorHandler
來處理解析過程中可能發生的錯誤。resolveStreamForKey
方法時,子類可以考慮使用key
與ImageCache
互動,例如呼叫ImageCache.putIfAbsent
方法,並向stream
通知監聽器。預設實現已經使用key
與ImageCache
互動,子類可以選擇呼叫super.resolveStreamForKey
方法或不呼叫。從上面的原始碼,我們可以知道以下幾點:
stream
物件已經有了 completer
(即已經有了可以載入圖片的方式),則將 completer
新增到 ImageCache
中,實現快取功能,並直接返回。stream
物件還沒有 completer
,則呼叫 loadBuffer
方法載入圖片,並將其返回的 ImageStreamCompleter
物件新增到 ImageCache
中,同時設定到 stream
物件的 completer
中。loadBuffer
方法出現了異常,則會將異常交給 onError
回撥處理,以便在例外處理時能夠提供詳細的錯誤資訊。ImageStreamCompleter
物件PaintingBinding.instance.imageCache.putIfAbsent
方法在內部將ImageStreamListener
物件新增到ImageStreamCompleter
物件的_listeners
陣列中了。PaintingBinding.instance.imageCache.putIfAbsent( key, () => loadBuffer(key, PaintingBinding.instance.instantiateImageCodecFromBuffer), onError: handleError, )
/// 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
方法即可。
/// 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] 回撥提供了獲取影象編解碼器的邏輯。
/// 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<void>((bool success) { /// if (success) { /// debugPrint('removed image!'); /// } /// }); /// } /// } /// ``` /// {@end-tool} Future<bool> evict({ ImageCache? cache, ImageConfiguration configuration = ImageConfiguration.empty }) async { cache ??= imageCache; final T key = await obtainKey(configuration); return cache.evict(key); }
這是一個名為evict
的非同步方法,它的作用是從影象快取中刪除給定設定下的圖片。它有兩個可選引數:cache
和configuration
。如果cache
引數為null,則預設使用全域性的imageCache
。configuration
引數是一個影象設定,它用於獲取將要從快取中刪除的圖片的鍵值。這個方法返回一個Future<bool>
物件,表示刪除是否成功。如果快取中沒有找到要刪除的圖片,則返回false
。
列表快速滑動,記憶體暴增時,可以用這個方法做些事情。
ImageProvider
是Flutter中一個用於提供影象資料的抽象類,它定義瞭如何從不同的資料來源(如檔案系統、網路、記憶體)中獲取影象資料,並將其轉換成ImageStreamCompleter
物件,以供Image
元件使用。
在Flutter中,使用Image
元件來載入和顯示影象,需要先提供一個ImageProvider
物件作為其image
屬性的值。ImageProvider
類包含了兩個關鍵的方法:obtainKey
和load
。
obtainKey
方法用於獲取一個用於唯一標識影象資料的ImageProvider
物件,這個物件可以用來快取影象資料,以便在需要重新載入影象時能夠快速獲取到它。例如,AssetImage
類使用圖片資源的路徑作為其ImageProvider
物件的識別符號,以便在需要重新載入該資源時能夠快速地從記憶體或磁碟快取中獲取到它。
load
方法用於獲取一個ImageStreamCompleter
物件,該物件包含了用於繪製影象的影象資料。在Flutter 2.5之前,load
方法是一個抽象方法,必須由子類實現。但是從Flutter 2.5開始,load
方法已被廢棄,取而代之的是resolve
方法。resolve
方法接受一個ImageConfiguration
引數,並返回一個Future<ImageStreamCompleter>
物件。它與load
方法的功能類似,都是用於獲取影象資料,並將其轉換成ImageStreamCompleter
物件,以供Image
元件使用。
使用ImageProvider
類載入和顯示影象的流程如下:
ImageProvider
物件,該物件提供了影象資料的來源和識別符號。ImageProvider
物件作為Image
元件的image
屬性的值。Image
元件會呼叫obtainKey
方法獲取一個用於唯一標識影象資料的ImageProvider
物件。Image
元件會呼叫resolve
方法獲取一個Future<ImageStreamCompleter>
物件。ImageStreamCompleter
物件會將其通知給Image
元件,Image
元件會將其渲染到螢幕上。總的來說,ImageProvider
類是Flutter中一個非常重要的類,它提供了一種方便的方式來載入和顯示影象。雖然load
方法已被廢棄,但是resolve
方法提供了更好的替代方案,可以用於獲取影象資料並將其轉換成ImageStreamCompleter
物件。
參考連結
第一次載入圖片時,stream
物件通常沒有completer
。在第一次呼叫resolveStreamForKey
時,會將stream
物件的completer
與對應的ImageCache
的ImageStreamCompleter
進行繫結,並且completer
會被設定為ImageStreamCompleter
。
以上就是Flutter載入圖片流程之ImageProvider原始碼範例解析的詳細內容,更多關於Flutter載入圖片ImageProvider的資料請關注it145.com其它相關文章!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45