【大白菜源码】【1.80英雄合击手游源码】【家政上门服务app源码】dartfuture源码详解

来源:漳平源码开发

1.Flutter系统网络加载流程

dartfuture源码详解

Flutter系统网络加载流程

       Flutter原生支持在Image组件上显示网络,源码最简单的详解使用方式如下,调用Image的源码命名构造方法Image.network即可实现网络的下载显示。

Widgetimage=Image.network(imageUrl);

       那么,详解它内部是源码如何实现的呢?是否有做缓存处理或其他优化操作呢?带着疑问,我们一起来看下它的详解大白菜源码底层究竟是如何实现的。

一、源码从构造函数开始

       我们以最简单的详解调用方式举例,当我们使用Image.network(imageUrl)这种方式来显示时,源码Image组件内部image属性就会被赋值NetworkImage。详解

//此为简化过的源码Image组件类结构classImageextendsStatefulWidget{ Image.network(Stringsrc,):image=NetworkImage(src);//数据处理的基类finalImageProviderimage;}

       这里引出了一个类叫NetworkImage,它是详解ImageProvider的子类,专门实现网络的源码下载和解析逻辑。当然你直接点进去看到的详解其实是个抽象类,并不是源码真正实现下载逻辑的地方,真正实现网络下载解析的在'_network_image_io.dart’这个文件下。构造函数知道这些就够了。1.80英雄合击手游源码接下来就看Image是在何时触发网络的下载的。

二、下载入口

       Image是一个StatefulWidget,它又一个对应的State叫_ImageState。在这个_ImageState的生命周期中,控制着的下载过程。

       State的生命周期可以简单的分为:构造函数→initState→didChangeDependencies→build

       因此,我们顺着这个顺序找,很快看到一个可疑的地方,didChangeDependencies中的_resolveImage方法。而TickerMode则是用于控制动画的,在这里被用于判断是否禁用了动画。关于TickerMode的相关介绍,可以看下这篇文章

//完整源码@overridevoiddidChangeDependencies(){ _updateInvertColors();//处理的入口_resolveImage();//当动画被禁用时,也是无法显示的,这个if(TickerMode.of(context))//添加流处理的家政上门服务app源码监听_listenToStream();else_stopListeningToStream(keepStreamAlive:true);super.didChangeDependencies();}

       我们进入到_resolveImage方法中去。

void_resolveImage(){ //ScrollAwareImageProvider包装了我们的NetworkImagefinalScrollAwareImageProviderprovider=ScrollAwareImageProvider<Object>(context:_scrollAwareContext,imageProvider:widget.image,);//新建流finalImageStreamnewStream=provider.resolve(createLocalImageConfiguration(context,size:widget.width!=null&&widget.height!=null?Size(widget.width!,widget.height!):null,));assert(newStream!=null);//更新流_updateSourceStream(newStream);}

       _resolveImage方法就做了三件事。

       1、用ScrollAwareImageProvider包装了NetworkImage

       2、创建流对象ImageStream

       3、更新流

2.1、ScrollAwareImageProvider

       ScrollAwareImageProvider也是ImageProvider的子类,它的作用很简单,就是防止在快速滑动的时候加载,当存在快速滑动时,会将解析的工作放到下一帧处理。至于具体如何实现,我们放在后面再提。

2.2、ImageConfiguration

       ImageConfiguration由方法createLocalImageConfiguration创建,保存了的基本配置信息,如Bundle,臭宝专用傻鱼源码屏幕项目比devicePixelRatio,本地化local,尺寸size,平台platform等。

2.3、ImageStream

       表示一个流,可以添加观察者ImageStreamCompleter来监听是否处理完成。一个流可以添加多个观察者。

       ImageStream由provider的resolve方法调用后创建。通过源码可知,此处的provider就是ScrollAwareImageProvider对象。但是它内部并没有实现resolve方法,因此此处调用的是父类ImageProvider的resolve方法。

三、流和Key

       以下代码截取自ImageProvider,并且删减了无关代码。量友三王公式源码

ImageStreamresolve(ImageConfigurationconfiguration){ //创建流,这里直接调用了ImageStream的构造函数,并没有用到configurationfinalImageStreamstream=createStream(configuration);//关键在这里,这里会根据configuration创建一个唯一key_createErrorHandlerAndKey(configuration,//成功的回调(Tkey,ImageErrorListenererrorHandler){ resolveStreamForKey(configuration,stream,key,errorHandler);},//下面是错误回调,可以不关注(T?key,Objectexception,StackTrace?stack)async{ awaitnull;//waitaneventturnincasealistenerhasbeenaddedtotheimagestream.InformationCollector?collector;if(stream.completer==null){ stream.setCompleter(_ErrorImageCompleter());}stream.completer!.reportError(exception:exception,stack:stack,context:ErrorDescription('whileresolvinganimage'),silent:true,//couldbeanetworkerrororwhatnotinformationCollector:collector,);},);returnstream;}

       resolve方法的作用是创建流对象ImageStream,并根据传入的配置信息configuration,创建对应的Key,这个Key用于缓存。

       那么这个key到底是怎么创建的呢,我们进入到_createErrorHandlerAndKey方法中查看。关键代码如下,已删除无关代码。

Future<T>key;try{ key=obtainKey(configuration);}catch(error,stackTrace){ handleError(error,stackTrace);return;}key.then<void>((Tkey){ obtainedKey=key;try{ successCallback(key,handleError);}catch(error,stackTrace){ handleError(error,stackTrace);}}).catchError(handleError);

       可以看到方法实现中调用了ImageProvider的obtainKey方法,而这个方法在ImageProvider并没有具体实现,需要子类完成对应的实现。

Future<T>obtainKey(ImageConfigurationconfiguration);

       还记得上文的分析不,我们说传入的imageProvider实例是ScrollAwareImageProvider对象,因此对应的实现也要到这个类中去查找。很快,我们找到obtainKey方法的实现,可以看到它做了个透传,具体是由它包装的类也就是NetworkImage来实现的。

@overrideFuture<T>obtainKey(ImageConfigurationconfiguration)=>imageProvider.obtainKey(configuration);

       那么,我们就去NetworkImage找obtainKey。

       注意下真正的NetworkImage实现是在_network_image_io.dart文件下的。

Future<NetworkImage>obtainKey(image_provider.ImageConfigurationconfiguration){ returnSynchronousFuture<NetworkImage>(this);}

       到这,我们就知道了NetworkImage的key为SynchronousFuture。

       获取到key后的下一步就是调用_createErrorHandlerAndKey方法的successCallback回调。从而触发了下一个流程resolveStreamForKey。

_createErrorHandlerAndKey(configuration,(Tkey,ImageErrorListenererrorHandler){ //拿到Key之后的回调resolveStreamForKey(configuration,stream,key,errorHandler);})四、根据key来处理流

       还是回到子类ScrollAwareImageProvider中,它重写了父类的resolveStreamForKey方法,前文提到,ScrollAwareImageProvider是用来防止列表在快速滑动的时候来加载的,那么它是如何实现的?我们就从resolveStreamForKey这个方法中来一探究竟。

//此为简化过的Image组件类结构classImageextendsStatefulWidget{ Image.network(Stringsrc,):image=NetworkImage(src);//数据处理的基类finalImageProviderimage;}0

       Scrollable用于滑动组件,它有个方法叫recommendDeferredLoadingForContext,表示是否建议延迟加载。内部最终是根据滑动速度和当前设备的最大物理尺寸的边去比较,如果大于,表示速度过快,那么就建议延迟。具体逻辑在scroll_physics.dart文件下。这里不多做介绍。

       一旦当前应用处于滑动状态,并且速度过快,那么,的加载将会被推迟到下一帧再进行尝试。因此我们说,当处于快速滑动时,是无法加载的。

       当判断可以加载时,操作流将会被移交给被包装类imageProvider,这里是NetworkImage来处理。但是,NetworkImage没有实现resolveStreamForKey方法,因此最终还是跑到了ImageProvider类中的resolveStreamForKey方法下。

//此为简化过的Image组件类结构classImageextendsStatefulWidget{ Image.network(Stringsrc,):image=NetworkImage(src);//数据处理的基类finalImageProviderimage;}1

       当第一次加载网络图的时候,会直接走到下面这个逻辑中。这里涉及到一个很重要的类,ImageCache。它是做缓存用的。

//此为简化过的Image组件类结构classImageextendsStatefulWidget{ Image.network(Stringsrc,):image=NetworkImage(src);//数据处理的基类finalImageProviderimage;}.1、ImageCache

       缓存类,只做了内存缓存。它由PaintingBinding持有,是一个单利。它的内部通过三个Map来缓存。

//此为简化过的Image组件类结构classImageextendsStatefulWidget{ Image.network(Stringsrc,):image=NetworkImage(src);//数据处理的基类finalImageProviderimage;}3

       从缓存器中获取的逻辑集中在putIfAbsent方法中。以下代码已经去掉无关代码。

//此为简化过的Image组件类结构classImageextendsStatefulWidget{ Image.network(Stringsrc,):image=NetworkImage(src);//数据处理的基类finalImageProviderimage;}.2、load

       一旦在ImageCache中找不到缓存的,就会通过loader回调出来,走真正的下载流程。

//此为简化过的Image组件类结构classImageextendsStatefulWidget{ Image.network(Stringsrc,):image=NetworkImage(src);//数据处理的基类finalImageProviderimage;}5

       还是先看ScrollAwareImageProvider类,里面实现了load方法,并透传给了NetworkImage来实现。

//此为简化过的Image组件类结构classImageextendsStatefulWidget{ Image.network(Stringsrc,):image=NetworkImage(src);//数据处理的基类finalImageProviderimage;}6

       在NetworkImage下,可以找到对应的load方法实现。里面有个_loadAsync方法,它就是我们要找的下载核心代码。

//此为简化过的Image组件类结构classImageextendsStatefulWidget{ Image.network(Stringsrc,):image=NetworkImage(src);//数据处理的基类finalImageProviderimage;}7五、下载

       饶了一大圈,终于来到了下载的地方了。可以看到下载的逻辑很简单,创建一个下载的/post/

文章所属分类:休闲频道,点击进入>>