精华内容
下载资源
问答
  • 博立收银助手2016是一款小巧简单的收银管理软件,能有效解决中餐、快餐、火锅店、麻辣香锅、称重运用、水果店、奶茶店、连锁店、西餐、咖啡等业态。一键安装,自动备份,功能简单实用。 1、系统自带数据库,无需...
  • 集合【营业管理、库存管理、会员管理、连锁管理、排号管理】等功能,并对酒楼、西餐厅、咖啡厅、酒吧等类似经营模式的餐饮企业提供多种针对性的系统解决方案,能更有效的协助餐饮企业规范业务流程,提高经营效率,...
  • 2003年全国开展药品集中招标采购工作以来,各地药品集中招标采购工作积极开展,招标范围不断扩大,改变了原有的医院采购模式,药品价格的透明度逐步提高,遏制了药品价格上涨的势头,减轻了百姓医疗费用的负担。...
  • 2019年8月7日,在七夕这个温馨的日子里,水贝万山创新企业优宝库收到由中国(深圳)创新创业大赛主办方传来的捷报...在一参赛者中,优宝顺利通过技术水平、竞争优势、商业模式和可行性等各方面的重重考核,一路...

      2019年8月7日,在七夕这个温馨的日子里,水贝万山创新企业优宝库收到由中国(深圳)创新创业大赛主办方传来的捷报——优宝库同时成功晋级区赛和市赛,即第三届罗湖区大梧桐创新创业决赛和第十一届中国深圳创新创业大赛半决赛。

      本届大赛吸引了各大领域创新企业的高度关注和积极参与,赛场可谓是高手云集、群雄逐鹿。在一众参赛者中,优宝库顺利通过技术水平、竞争优势、商业模式和可行性等各方面的重重考核,一路过关斩将,在151个项目中脱颖而出,成功跻身10强,成为珠宝行业唯一一家入围罗湖区决赛和深圳市半决赛的企业。


    万山总经理向各级领导介绍优宝库项目

      众所周知,珠宝行业是一个传统而保守的行业,普遍存在重资产、同质化、获客难、从业人员素质不高等问题。随着人们生活和消费水平的提高,消费者越来越追求品质、时尚、认同感、专属感,传统珠宝店的现货模式越发难以满足顾客的个性化需求。

      顺应这一历史发展潮流,优宝库倡导并践行“人人都是珠宝设计师”理念,十年磨一剑,打造了珠宝3D定制系统、3D导购机、AR智能柜台、AR智能橱窗等一站式软硬件解决方案,并且通过整合供应链的30多万款式资源以及50多万粒钻石数据,全面满足各类市场需求,帮助商家打造VR智慧门店和轻资产新零售模式。

      优宝库的3D定制系统不仅能让用户720°无死角观看首饰,任意缩放不模糊,还可以虚拟试戴,随时随地体验佩戴效果,所见即所得,下单后通过优宝库合作的供应链就可以实现快速投产。

    虚拟试戴

      优宝库的“C2M+UGC”定制模式,开创了用户DIY首饰的先河,让客户完全参与到产品的设计、研发、生产过程中,给予消费者极大的参与感、专属感、优越感,在珠宝行业长达千年的历史上,首次真正做到了“我的首饰我做主”、“我就是设计师”。同时让传统的珠宝店拥有前所未有的定制服务能力,每个导购都可以像专业设计师一样提供顾问式服务,让珠宝店和客户产生更强的联系,增加顾客粘性,提高转化率和复购率。


    AR橱窗


      优宝库不仅是个互联网公司,更是珠宝行业少有的人工智能公司。2019年5月,优宝库在第十五届文博会上推出了行业内首个珠宝3D导购机器人,引得现场人气爆棚。


      优宝库通过大数据和AI技术,在覆盖客户个性化设计需求的同时,大幅降低传统模式下定制化的成本,并将传统定制的时间周期从45天压缩到7天,真正实现大众顾客“一人一版,一物一款”的个性需求。

      优宝库的解决方案一经推出便获得了广泛的认可和支持。目前合作的珠宝店多达400家,合作品牌多达63个,诸如老凤祥、周六福、中国珠宝等知名珠宝品牌皆是优宝库的客户。

      值得一提的是,优宝库的模式在2018年被央视CCTV-2重点报道,这次晋级深创赛,实至名归。

      具体报道请查看CCTV-2财经频道8月15日13:10分的回放。

    央视报道

      8月13号~15号,优宝库将代表珠宝行业受邀参展第五届华人华侨产业交易会。有兴趣的朋友可以到深圳会展中心一号馆1B16零距离接触“珠宝VR定制”,体验魔幻珠宝DIY定制的独特魅力。
     
      “让定制成为普通大众的生活方式”是优宝库的使命,未来,优宝库将不忘初心,不辍研发脚步,为珠宝行业的转型升级做出更多的贡献。

      第十一届中国深圳创新创业大赛罗湖区赛暨第三届罗湖区大梧桐创新创业大赛,是在深圳市罗湖区政府的大力支持下,为深入实施 “创新驱动发展”战略,推动深圳市罗湖区大梧桐新兴产业带建设,聚集新兴产业创新企业或创业团队的重要措施。旨在通过大赛聚集创投资本和优秀团队,吸引和引导优质企业和团队落地罗湖、扎根罗湖。

    展开全文
  • 纯Swift项目-序篇

    2019-01-18 07:07:53
    任何一门语言,从出现到被广泛使用,都离不开大量的基础框架,Swift也不会例外,为了深入思考,这些年我一直对三方保持克制,尽量自己从底层封装三方,以探索更为合理的开发模式。得益于Swift的强大扩展能力,...

    迟来的分享

    虽然iOS从火爆到冰点,人们的热情早已不在,但我还是决定,写一系列文章,来分享我这些年使用Swift开发的经验。

    任何一门语言,从出现到被广泛使用,都离不开大量的基础框架,Swift也不会例外,为了深入思考,这些年我一直对三方库保持克制,尽量自己从底层封装三方库,以探索更为合理的开发模式。得益于Swift的强大扩展能力,博采众家之长,我自己封装的库已经很好的在数个项目中运行。

    文章中的代码大多数都是使用我封装的基础库,但各位看官也不必担心,这些库我一直都是开源的,也会给出github链接,之前由于Swift版本升级的关系,总是有大幅度改版,但Swift即将迎来5.0稳定版,我觉得这些基础库也该稳定下来了。

    写作计划

    • 经验篇(各种小技巧)
    • 架构篇(开发模式探索)
    • 武器篇(基础库介绍)

    文章列表(计划)

    经验篇

    1. 纯Swift项目-Xib | StoryBoard 多人协作技巧(已完成)
    2. 纯Swift项目-Xib | StoryBoard 设备适配技巧(待完成......)
    3. 纯Swift项目-Xib | StoryBoard 约束使用技巧(待完成......)
    4. 纯Swift项目-网络异常统一处理技巧(待完成......)
    5. 纯Swift项目-下拉刷新上拉加载更多使用技巧(待完成......)

    架构篇

    1. 纯Swift项目-(不同于ObjC的)开发模式变化(待完成......)

    武器篇

    Basic.frameworks(基础库、通用库)

    1. 纯Swift项目-JSON(Basic.frameworks)(已完成)
    2. 纯Swift项目-HTTP(Basic.frameworks)(待完成......)
    3. 纯Swift项目-响应式开发(Basic.frameworks)(待完成......)
    4. 纯Swift项目-Protocol协议(Basic.frameworks)(待完成......)
    5. 纯Swift项目-File(Basic.frameworks)(待完成......)
    6. 纯Swift项目-Date(Basic.frameworks)(待完成......)
    7. 纯Swift项目-UserDefaults(Basic.frameworks)(待完成......)
    8. 纯Swift项目-Number(Basic.frameworks)(待完成......)
    9. 纯Swift项目-String(Basic.frameworks)(待完成......)
    10. 纯Swift项目-Cache(Basic.frameworks)(待完成......)
    11. 纯Swift项目-Operator(Basic.frameworks)(待完成......)

    RichText.frameworks(富文本)

    1. 纯Swift项目-富文本(RichText.frameworks)(待完成......)

    Toast.frameworks(交互框架)

    1. 纯Swift项目-交互视图(Toast.frameworks)(待完成......)

    DataBase.frameworks(数据库)

    1. 纯Swift项目-SQLite(DataBase.frameworks)(待完成......)
    展开全文
  • 本文来源:中欧创平台、国云数据 168大数据经国云数据创始人马晓东授权发布 数字化中台建设并不存在一个所谓的'正确模式',落地方式也会多种多样,在很大程度上并无统一成熟模式可循。企业应视中台战略为其...

    本文来源:中欧众创平台、国云数据

    168大数据经国云数据创始人马晓东授权发布

     

    数字化中台建设并不存在一个所谓的'正确模式',落地方式也会多种多样,在很大程度上并无统一成熟模式可循。企业应视中台战略为其数字化转型的重要组成部分,中台建设应与企业的商业模式、业务发展方向、组织结构、信息化发展程度等紧密结合。数字化中台不只是单一维度的技术概念,单纯认为中台是数据仓库、IT技术工具、大数据分析方法或某个特定应用都是对中台的不全面的错误理解。

     

    误区一:'管理系统和分析工具的叠加 = 数字化中台' 

    传统企业在经营管理过程中会根据业务或管理需求,不断添加和升级诸如OA、CRM等不同类别的管理系统。为了更好地响应前台的业务需求,有些企业成立了新的或扩大、加强了原有的技术部门,由这些技术部门负责利用各类分析工具将管理系统中的数据进行分析后,将分析结果反馈给各运营部门。

     

    这种方式仍然是企业前、后台的传统运营模式,并不是真正意义上的数字化中台。管理系统和分析工具的搭配治标不治本,因为这样的叠加没有将业务、技术、分析各部门的数据打通,没有将共同资源进行优化组合,无法为企业数字化转型提供全面、敏捷的平台化服务。

     

    误区二,'业务报表 = 数字化中台' 

    在企业日常运营中,成本报表、费用报表、财务预算、财务分析、进销存等一系列报表的产生对企业加强沟通、控制、决策制定、业绩考核等方面发挥着重要作用。但对绝大多数企业来说,业务报表仅限于对企业内部运营进行管理和监控,对企业外部用户的维护、需求的跟踪、业务和产品的更新等方面发挥作用有限。

     

    相比之下,数字化中台不仅对企业内部资源进行打通,实现资源共享和运营管理,还具有有力支撑企业外部持续产品创新、快速满足用户需求、以及提升企业竞争力等作用,业务报表只体现了数字化中台其中小部分的价值。

     

    误区三,'大数据 BI 分析工具 = 数字化中台' 

    大数据BI分析工具只是限于业务分析,为企业管理者决策制定和执行提供科学依据,相比数字化中台为企业在数据采集、数据治理、数据挖掘、模型建立、可视化分析、应用开发等不同方面的融合能力,其功能非常有限,只呈现了数字化中台的很小一部分功能。

     

    误区四,'某个特定应用=数字化中台' 

    伴随着移动互联网在日常工作和生活中的渗透,企业大量开发以提升客户体验为核心的应用App。而针对加强企业运营管理效率,提高企业竞争力的企业级应用也是层出不穷。各个行业和维度的应用百花齐放,满足不同用户的需求,但这并不意味着这些独立的应用就是数字化中台。

     

    典型的数字化中台的工作原理可简单描述如下:

    数据中台从业务中台的数据库中获取数据,进行清洗和分析之后得到的结果支撑到业务中台的智能化应用。这些智能化应用在用户使用后产生的新数据又流转到数据中台,从而形成闭环。

     

    可见,应用为数据中台提供研发数据,数据中台为业务创新或者应用完善提供更多支撑。

     

    误区五,'大数据集群=数据中台' 

    为了解决海量的结构化和非结构化数据的存储、恢复和高效运算,很多企业建立了分布式大数据集群。但大数据集群并不等同于数据中台,大数据集群仅仅是在建立数字化中台底层数据存储和运算时用到的一部分技术架构。数据中台是业务部门代表的前台和技术部门经过资源整合、能力沉淀后形成的。

     

    误区六,'数据仓库理论=数据中台' 

    有人认为,数字化中台中的数据中台只是一种数据仓库,这个观点是错误的。在中台构架中,数据中台本身没有数据,数据来源于其他的文件和各个业务系统的API。因为数据中台拥有这些数据源的适配器,所以数据中台相当于建立了通向不同数据源的互联管道。可见,数据仓库是数据中台的重要组成部分,也是元数据的重要来源,但数据仓库并不代表数据中台。

     

    另外,一些优质的软件产品在增设分析功能的基础上配备数据库,主要提供业务计算功能,但这样的数据库并不是数据中台。该类软件数据库中所用到的分析数据只是企业局部数据而非全域数据,无法挖掘全域数据的价值。

     

    误区七,'计算平台=技术中台' 

    计算平台的建设并不能产生应用,因为其没有强大的数据治理体系,数据无法实现联通、共享,只纯粹地搭建计算平台并不是技术中台。

     

    误区八,'数据工具箱=技术中台' 

    数据分析产品、分析工具、仓库工具等集合在一起的工具箱并不是技术中台。因为每款工具的功能既相互交叉,又有各自的独立性,工具之间无法协同一致。工具箱的架构只是数字化中台建设的某个环节或多个环节,只能发挥各个工具的效果。

     

    而数字化中台建设初始就要考虑到各个环节的无缝打通,来确保之后的数据维护和数据质量,因为一旦某个环节的数据产生变化,其他环节的数据没有及时地自动修正,会导致用户决策出错,造成巨大的损失和影响。

    展开全文
  • Android开源图片加载框架

    千次阅读 2015-05-08 11:17:56
     本文主要介绍了android现下流行的图片加载中的3个,通过读取源码,比较设计架构,来总结移动应用中图片加载的共同特点,同时比较这三个的设计模式,博取家之长,补己之短,第一篇文章,词法不好之处还请海涵...

    同事写的一篇文章,mark下。

    1. 开始

           本文主要介绍了android现下流行的图片加载库中的3个,通过读取源码,比较设计架构,来总结移动应用中图片加载的共同特点,同时比较这三个库的设计模式,博取众家之长,补己之短,第一篇文章,词法不好之处还请海涵,若有错误不到之处,还望指正!

    2. App图片加载的通用策略

           Android应用中使用的图片来源不外乎这几种:本地资源drawable/assets/content/file,网络资源https/http。单纯从文件加载来说,android系统原生sdk已经提供了读取和解码的方法,但是这些加载任务需要和UI主线程并存,共享有限的硬件资源,为保证页面流畅性,通常UI线程享有最高的优先级,工作者线程的优先级总是比UI线程要低,所以图片加载策略在这方面会考虑得很细致,同时图片加载要尽可能节省无线流量,一方面是为用户流量费用考虑,另一方面也是考虑到系统性能问题。
           基于上面的设计思路,图片加载策略都会包含这些技术实现:两级缓存(内存/磁盘)、一级网络请求、线程池、降采样解码、重复请求合并等,下面用这张图来说明通用的加载策略流程:

           

           在Android应用中,将处理当前UI操作的线程称为主线程(MainThread),主线程的流畅性直接决定了用户对一款应用的打分,频繁的界面卡顿或者ANR(Application Not Response)就是因为主线程的负担太重(磁盘操作)或者线程被阻塞(网络请求),所以必须把费时的任务(Task)从主线程移出,放到后台线程去处理,其中磁盘文件读取和网络请求就是两大典型的任务。
           从图片加载的实例来看,主线程要为ImageView加载一张可显示的图片,通常都会提供一个URI,目标资源可能在内存、磁盘或者远程服务器,三者的时间消耗就如颜色的警示:内存<<磁盘<<网络。Android为了线程安全,规定UI操作必须在主线程内执行,内存Cache查询属于高效的操作也可以在主线程中运行,除此之外的其他操作都应该异步化,放在Worker线程去执行,这是保证UI流畅性的必然策略!Worker线程通常放在线程池中做统一管理,完成任务后,通过Handler通知主线程更新UI。
           以上是Android应用开发中图片加载的通用策略介绍,本文剩余部分将按顺序介绍3个图片加载库的具体设计方案,这3个库都是面向接口编程的,具备很好的扩展性,每个库都按照架构图、流程图、类关系图以及核心类解析的顺序进行说明。
    1. Volley: https://android.googlesource.com/platform/frameworks/volley
    2. UIL:https://github.com/dodola/Android-Universal-Image-Loader
    3. Picasso:http://square.github.io/picasso/

    3. Volley

    3.1 简介

           Volley 是 Google 推出的 Android 异步网络请求框架和图片加载框架。在 Google I/O 2013 大会上发布。

    3.2 架构图

           

           Volley的设计架构非常清晰,以任务的不同阶段可以将Volley的设计框架分为以上四层,每个请求对象对应一项Task,Task通过全局单例RequestQueue对象加入调度线程的等待队列,调度线程从阻塞等待队列取得Request,根据目标数据的存储位置调用不同的请求数据接口,得到数据后通过实现ResponseDelivery接口的对象,把任务执行结果通知到主线程。

    3.3 流程图


           Volley的调用接口非常简单,同名的Volley类提供了静态方法newRequestQueue(),用于返回一个任务管理对象RequestQueue,并在这个方法内完成了RequestQueue对象的所有初始化操作。
           RequestQueue对象聚合了1个Set和3个队列,这四个对象构成Request对象生命周期的中转站,作用不言而喻:
    (1)mCurrentRuqests:保存当前正在进行或者等待的非重复请求(Uri不同);
    (2)mWaitingQueue:合并相同uri对应的请求,在此等候;
    (3)mCacheQueue:读取本地缓存的请求队列,缓存miss时将会加入mNetworkQueue;
    (4)mNetworkQueue:需要网络连接的请求队列,请求不能缓存时从主线程直接加入,请求可缓存但缓存未命中时,由CacheDispatcher线程加入。
           mWaitingQueue是一个Map对象,用于缓存相同的请求,在请求处理完成后,相同请求通过调用RequestQueue的finish()方法被回调,这是volley处理相同请求的方式。
           Volley的Request处理方式使用的是生产者-消费者模式,这一步Volley实现了通用设计框架的任务异步化。Worker线程包含一个读本地缓存的线程CacheDispatcher,4个网络请求线程NetWorkDispatcher(使用默认配置时),CacheDispatcher作为RequestQueue的一个成员对象,NetWorkDispatcher[n]作为RequestQueue的成员数组对象,并都持有mNetworkQueue阻塞队列,NetWorkDispatcher线程作为队列的消费者,在这里Volley并没有选择使用线程池管理Worker线程,这5个Worker线程在队列为空时会阻塞等待。
           需要指出的是默认情况下Volley并没有实现内存缓存,在构造ReuqestQueue的时候只添加了DiskBasedCache这个磁盘缓存,这个类实现了Cache接口,为了快速查询磁盘中缓存的文件,这个类定义了CacheHeader这个内部类,并且定义了Map<string, cacheheader> mEntries = new LinkedHashMap<string, cacheheader>(16, .75f, true);成员对象,用于在内存中缓存磁盘文件的描述信息,mEntries可以认为是磁盘文件在内存中的索引,占用空间很小,这个设计值得借鉴。LinkedHashMap的accessOrder入参为true,开启LRU排序,每次缓存新对象前都会调用pruneIfNeeded()方法,预留足够的空间,Volley在这个地方又做了一个小优化策略,每次裁剪后的缓存空间是最大缓存空间(默认5M)的HYSTERESIS_FACTOR倍(默认=0.9),这样避免了在缓存空间满的情况下,加入新对象时每次都要进行prune操作。
           Volley缓存的磁盘文件内容是原始HttpResponse的ByteStream,也就是保存原始的数据,并且在DiskBasedCache中自定义了缓存文件的格式。
           请求处理完成后通过ExecutorDelivery对象post到主线程,在RequestQueue的构造方法中需要一个ResponseDelivery对象,默认传入的ExecutorDelivery对象持有向主线程发送消息的Handler,new ExecutorDelivery(new Handler(Looper.getMainLooper())),这是Volley实现通用设计框架的最后一步。

    3.4 类关系图


           Volley的类关系图很简洁,所有的请求类都派生于Request类,默认提供了4个子类,数据请求都是面向接口编程(interface Cache / NetWork),Response的分发也是通过interface ResponseDelivery来定义,可以说是一个高度解耦的框架。

    3.5 核心类

           从类关系图可以看出Volley包含四个核心类:
           (1)Request:所有请求都必须继承的抽象类,约定了请求处理流程中用到的所有必备接口方法,同时这个抽象类实现了Comparable<request>接口,可以对Request的优先级进行排序。
           (2)RequestQueue:Volley的对象管理核心,聚合了4个请求队列、1个CacheDispatcher对象、1个NetWorkDispatcher对象数组、引用实现了Cache/Network/ResponseDelivery接口的对象。通过RequestQueue.add(Request)方法添加请求到阻塞队列,可以认为是生产者,加入队列中的请求由消费者线程取走。
           (3)CacheDispatcher:继承于Thread类,本身代表了一个Worker线程类,从RequestQueue.mCacheQueue队列获取Request对象,如果缓存命中,就在自己线程内处理完请求,否则将请求移交给网络请求队列RequestQueue.mNetworkQueue,相当于网络请求队列的生产者。
           (4)NetworkDispatcher:继承于Thread类,作为Worker线程类,在Volley中作为RequestQueue.mNetworkQueue队列的消费者,负责网络请求的具体实现。

    3.6 思考  

           (1)Volley面向接口编程,各个模块间高度解耦,代码组织上也很清晰,在此基础上用户可以很容易地将其定制为符合自己需要的lib
           (2)Volley能够加载任意的对象资源,不仅仅是图片,作为一个通用的框架,没有为图片加载过程的细节做太多的考虑,比如没有留图片预处理和后处理的操作接口、列表滚动时不能暂停网络请求、缺少图片的内存Cache、不能设置加载前的占位图,有这些需求要自己添加改造,所以使用Volley作为图片加载库的功能还不够完善。

    4. UIL

    4.1 简介

           UIL(Android Universal Image Loader)为App提供异步图片加载、缓存和显示的解决方案,支持Android2.0+。

    4.2 架构图

           

           UIL通过ImageLoader对外提供两个图片加载的调用方法,图片加载的请求根据是否命中MemeoryCache,被封装为两种任务(实现Rnnable接口),ImageLoader将任务提交给ImageLoaderEngine的线程池开始处理,封装好的任务流程调用数据请求接口,得到Bitmap对象后,通过Handler通知UI主线程。

    4.3 流程图




           UIL是专门下载图片的Lib,不提供下载其他数据的接口(不同于Volley),几乎支持所有的图片的来源,这是UIL代码中枚举出的可支持的图片来源scheme:HTTP("http"), HTTPS("https"), FILE("file"), CONTENT("content"), ASSETS("assets"), DRAWABLE("drawable"), UNKNOWN("")
           使用UIL需要通过ImageLoaderConfiguration对象对ImageLoader进行初始化,初始化项包括:内存Cache、磁盘Cache、ImageDownloader、ImageDecoder,3个后台线程池。最顶层的ImageLoader被设计为全局单例,通过init(ImageLoaderConfiguration)方法接收配置参数,同时在内部构造了ImageLoaderEngine对象。
           UIL为用户提供了两个图片加载方法:void displayImage(String uri, ImageView imageView, DisplayImageOptions options, ImageLoadingListener listener)是通用的图片加载方法,也就是上面主流程的入口,loadImage不接收ImageView入参,用于加载窗口小部件的图片,最终也是调用displayImage方法加载图片。图片加载过程的特定步骤可以通过入参ImageLoadingListener得到通知。
           UIL对图片加载可能用到的处理方法都预留了接口,预处理PreProcessor在加入内存缓存前执行,后处理PostProcessor在加入内存缓存后执行,所以如果要对图片做统一的处理,可以添加PreProcessor对象,特定处理可以添加PostProcessor对象(比如旋转、缩放)。磁盘中保存的是压缩后的原始图片,这些处理任务都是在工作者线程中完成的。
           实际任务的处理流程被封装为:ProcessAndDisplayImageTask和LoadAndDisplayImageTask这两个任务,第一个任务在内存Cache命中时处理PostPrecessor,再通过Handler.post(DisplayBitmapTask·)分发出去,任务很轻;第二个任务包含内存Cache Miss后的全部任务流程:调用Decoder从本地磁盘加载图片,失败时调用ImageDownloader从远程下载图片,处理PreProcessor和PostProcessor,写DiskCache和MemoryCache,回调ImageLoadingListener,最后把任务处理结果通过Handler.post(DisplayBitmapTask)分发出去。
           在Volley中我们说明了相同请求的处理方法,使用的是Map<string, queue<request<?>>> mWaitingQueue;这个结构,在UIL中使用的则是ReentranceLock锁,每个锁实例通过Map<string, reentrantlock> uriLocks与uri关联,相同的uri被映射到同一个锁实例,在第一个任务启动后,锁即被Lock,相同的uri只能阻塞等待,直到第一个任务将锁Unlock,等待锁的任务被唤醒后,会先查询一次MemoryCache,如果前一个任务成功写了MemoryCache,这个重复的任务可以直接命中MemoryCache。Uri不同的任务照常执行,这里抢占锁的几率比较低,所以使用锁的性能消耗不大。
           流程图的下半部分有多个红色的圆圈,这是LoadAndDisplayImageTask任务在执行过程中检查是否要取消当前任务的测试点,任务取消的来源可以是:(1) ImageView重用绑定了另一个uri;(2) 线程被interrupted中断。
           ImageLoaderEngine提供了resume ()和 pause ()方法来启动或暂停引擎任务,在LoadAndDisplayImageTask入口的地方同步了engine.paused对象,所以未启动的任务将被阻塞,已启动的任务继续执行。为此UIL还提供了PauseOnScrollListener接口,用于监听滚动列表的状态变化事件,在进入OnScrollListener.SCROLL_STATE_FLING状态时,调用pause()停止任务,在进入OnScrollListener.SCROLL_STATE_IDLE状态时,调用resume()启动任务。

    4.4 类关系图

    950
           UIL对图片加载流程的各个细节和步骤考虑得很细致,对应提供的类也比较多,所有被聚合的类成员对象都是通过接口定义的,从类关系图可以清晰地看到各个功能模块之间的依赖关系,通过接口定义将模块间的耦合度降到最低。

    4.5 核心类

           (1)ImageLoader:是universalimageloader.core包下的类,也是UIL最顶层的核心类,在整个应用上下文中是单例,对用户提供两个调用方法:void displayImage(String uri, ImageView imageView, DisplayImageOptions options, ImageLoadingListener listener)和void loadImage(String uri, ImageSize targetImageSize, DisplayImageOptions options, ImageLoadingListener listener),接口使用极其简单,内部组合了1个ImageLoaderEngine对象,负责执行实际的图片加载任务。
           (2)ImageLoaderConfiguration:为ImageLoader提供配置参数,配置项包括内存Cache、磁盘Cache、ImageDownloader、ImageDecoder和FileNameGenerator等核心模块,查看UIL提供的源码,应用启动时在UILApplication.onCreate()中通过建造者模式构造了这个对象,作为ImageLoader核心类的默认配置,从类关系图可以看到ImageLoaderConfiguration聚合的核心模块都是通过接口定义的,模块之间高度解耦,并且可定制。
           (3)ImageLoaderEngine:UIL的图片加载引擎,称之为引擎是因为这个类提供了3个完成Task任务的线程池对象。taskExecutor是负责从远程网络加载图片的线程池对象,默认大小为3;taskExecutorForCachedImages负责从本地缓存加载图片,默认大小也是3; taskDistributor是向taskExecutor和taskExecutorForCachedImages线程池分发Task任务的线程池,其工作线程不会阻塞,所以池的大小没有限制,其实用单线程来代替也是完全可以的。
           (4)LoadAndDisplayImageTask:定义具体图片加载任务的类,负责从磁盘缓存或远程网络加载图片数据,并写入MemCache和DiskCache,图片加载完成后通过handler.post(DisplayBitmapTask)通知主线程,使用到的加载工具对象都来源于内部持有的ImageLoaderConfiguration对象,与初始化ImageLoader的配置对象是同一个,具体的任务执行流程请看UIL流程图部分。
           (5)BaseImageDownloader的网络请求实现基于HttpUrlConnection,HttpClientImageDownloader继承于BaseImageDownloader,重写了基类的getStreamFromNetwork()方法,使用org.apache.http.client.HttpClient取而代之

    4.6 思考

           (1)UIL同样基于接口聚合各个功能模块,模块之间解耦可定制;
           (2)UIL从网络加载Bitmap到本地后,先根据压缩格式写入了磁盘,然后把这个Bitmap recycle()掉,接着又从磁盘decode出这个url对应的图片,所以UIL在从远程网络加载图片时多了一次从磁盘decode图片的操作。
           (我对于第二点的理解有偏差,请看14F笔歌的说明,下面第(3)点是根据笔歌的建议,避免误导他人,我重新纠正论述一下)
          (3)UIL从网络加载图片的动作可以分两步:第一步从网络加载图片时,进行的降采样decode实际上是根据全局配置对象ImageLoaderConfiguration 中设置的 maxImageWidthForDiscCache 和 maxImageHeightForDiscCache 这两个变量限制的,得到的图片压缩后存入磁盘;接着从磁盘再次decode图片时,是根据实际view的尺寸加载的,bitmap会小很多。所以对于同一个uri,在磁盘中只对应一张图片,并且这张图片在下载时会尽可能细致,而decode到内存时是按需加载,所以内存中会有这张图片不同size的版本,内存Cache的memoryCacheKey为了保存这些不同size的图片,会在key的末尾加后缀,格式为:" uri_WxH "如 " uri_128x256 "," uri_256x512 "。UIL这么设计是为了各个分辨率的图片能有最佳的显示效果,否则下载小图再放大质量就太差了。

    5. Picasso

    5.1 简介

           Picasso是Square公司的开源项目,是一款强大的图片加载和缓存库。

    5.2 架构图


           

           Picasso下载图片的参数使用Builder模式进行配置,所以写成一句话就可以完成图片加载;请求被封装为Action,并提供RequestHandler的实现类对不同Action进行处理;任务的调度使用Dispatcher对象进行调度,耗时的加载流程放在后台线程池执行;数据接口包含内存Cache、DownLoader,磁盘Cache使用Http缓存,完成任务时通过Handler通知UI主线程。

    5.3 流程图



           Picasso的图片加载流程可以根据任务所在的线程来区分不同阶段。
            首先是Picasso的初始化,调用Picasso.with(Context)即可,第一次调用会使用Picasso.Builder构造一个全局的单例对象,在构造过程new了一个Dispatcher对象,这个对象很重要,作为Picasso的任务调度器,将Action从UI主线程调度到Worker线程,任务完成后又从Worker线程调度回UI主线程。启动图片加载任务使用Picasso.with(ApplicationContext).load(imageUrl).centerCrop().into(ImageView); 一句话完成指定url图片的定制和加载,接口再简单不过了,详细使用方法请查看官网说明:http://square.github.io/picasso/
           这里需要重点说明Dispatcher对象的任务调度原理,Dispatcher对象内部持有一个线程类对象:class DispatcherThread extends HandlerThread,可以看到DispatcherHandler继承于Android系统的HandlerThread,因此可以利用这个线程的Handler把各种消息post到Looper上,Looper在收到消息时,又会主动回调Handler的handleMessage方法,根据消息ID区分不同的消息,这是Picasso任务调度的设计方案,显得非常优雅。从上面的流程图可以看到Dispatcher线程在UI主线程和Worker线程之间起到了桥接的作用。Volley和UIL直接使用生产者-消费者模式(PriorityBlockingQueue)将请求任务异步化。在任务执行完毕后,这三个框架都是使用主线程的Handler把处理结果post到主线程,这种做法也是Android异步线程和主线程通信的标准做法。
           Picasso有一些很好的细节设计,需要说明一下,请看流程图中红色①~⑤标记的位置:
           (1)DeferredRequestCreator是Request请求的延迟构造器,这个类实现了ViewTreeObserver.OnPreDrawListener接口,这个接口中的方法在Android对ViewTree调用完layout()之后调用,那这个类存在的意义显然和android的视图绘制机制有关。对于一个View,如果它的布局参数要依赖于其他View,那么系统在对视图树调用layout()之前,这个view的宽高是未知的。由于Picasso在图片加载时要对图片计算降采样率,View的宽高不确定,对于Picasso来说就是不知道应该加载什么样的图片最合适,所以有了这个延迟构造器。
           (2)在UIL中提到了PauseOnScrollListener接口,用于在滚动列表Fling时停止引擎的加载任务,Picasso同样提供了这个功能,请看流程图中②的位置,Tag标识的请求被暂停时,请求直接进入pauseActions等待,Picasso.resumeTag(Object)和Picasso.pauseTag(Object)就是用于唤醒和停止请求任务的API,这里的Object是全局唯一的应用上下文。源码的示例也提供了SampleScrollListener来演示这个功能。
           (3)在Volley和UIL中都提到了重复请求的处理方法:Volley使用mWaitingQueue,UIL使用了ReentranceLock,这里请看流程图中③的位置, Picasso策略和Volley相同:先使用Action的请求参数计算requestKey,作为Action的唯一标识,requestKey相同的Action将被放入BitmapHunter.actions列表中,在任务执行完毕后,一并得到回调通知,通知动作发生在流程图中⑥的位置。
           (4)流程图中④的位置对得到的bitmap进行了变换操作,这里会开辟新的内存用于缓存中间结果的图片,如果多个后台线程同时执行这一步,很可能导致应用OOM而挂掉,所以Picasso借鉴了Volley在解析图片时的保守策略(详见Volley的ImageRequest.parseNetworkResponse()方法),使用synchronized (DECODE_LOCK)同步了一个静态类成员,同一时刻只允许一个线程进行这个操作,避免潜在的OOM bug。这个设计来源在BitmapHunter.java类文件中DECODE_LOCK变量定义的位置是有注释说明的。
           (5)Picasso的任务处理结果是按批次分发出去的,这个动作发生在流程图中⑤的位置,操作流程是这样的:设置任务完成的Messag要延迟200ms(默认时长)后再发送出去,同时这个任务会被加入Dispatcher.batch的这个成员对象中,如果在接下去的200ms内有新完成的任务到达,也会被加入Dispatcher.batch成员对象中,等200ms延时到达时,将batch统一发送到主线程,然后清空batch,用于下一批的Message的容器。
           (6)Volley和UIL都对请求进行优先级排序,Picasso也有相同的功能实现,将BitmapHunter任务包装到PicassoFutureTask中,并实现Comparable接口,class PicassoFutureTask extends FutureTask implements Comparable。Picasso提供了LOW/NORMAL/HIGH三个任务优先级,线程池使用PriorityBlockingQueue,所以优先执行高优先级的任务。
            最后再说一下Picasso的磁盘缓存,Picasso使用OkHttpClient和HttpUrlConnection作为Downloader接口的实现,并且优先使用OkHttpClient,Picasso会默认开启Client的Response缓存,所以不像UIL那样专门提供了DiskCacheAware的磁盘缓存接口。

    5.4 类关系图



           Picasso的类设计大量使用了组合模式,总体架构设计得很巧妙,对于内存Cache和Downloader也是通过接口聚合,这一点和Volley/UIL是相同的。

    5.5 核心类

           (1)Picasso:与Lib同名的Picasso类作为最上层的管理类,聚合了lib运行时必须的功能模块,包括Dispatcher、内存Cache、RequestHandler列表等,同时对用户提供简洁的调用接口。
           (2)Dispatcher:Picasso的任务调度类,提供调度任务的接口,通过内部组合的DispatcherThread线程类对象在UI线程和Worker线程间传递任务,内部的调度流程对用户是透明的。
           (3)Action:包装Request请求的抽象类,同时提供请求处理成功或失败时使用的资源,子类必须实现complete()和error()抽象方法,作为任务处理结果的回调。
           (4)RequestHandler:处理异步图片加载任务的抽象类,子类必须实现canHandlerRequest(Request)和load(Request,int)两个抽象方法,前者判断这个RequestHandler能否处理入参Request,后者执行实际的Request请求。Picasso默认提供了7种RequestHandler,如果用户有其他类型的Handler,可以通过Picasso.Builder. addRequestHandler(RequestHandler)进行注册。新加入的RequestHandler从List requestHandlers的第1个下标位置开始放,Picasso遍历调用每个已注册的RequestHandler.canHandlerRequest()方法,找到第一个可以处理Request的RequestHandler即返回,所以能够优先使用用户自定义的RequestHandler。
           (5)BitmapHunter:封装异步任务的具体处理流程,该类实现了Runnable接口,每个BitmapHunter实例对应一个独立不重复的请求(指requestKey独立不相同),任务流程在Worker线程执行,负责从磁盘或远程网络加载图片。

    5.6 思考

           (1)Picasso写得很专业,每个功能都有详细的测试用例,理清Picasso的设计思路,其中的细节值得参考借鉴。

    6. 总结比较

      Volley UIL Picasso
    初始化 Volley.newRequestQueue() ImageLoader.getInstance().
    init(ImageLoaderConfiguration)
    Picasso.with(Context)
    调用接口 RequestQueue.add(Request<T>)

    ImageLoader.displayImage(Url, ImageView);
    ImageLoader.loadImage(Url, ImageLoadingListener);

    Picasso.with(Context).load(url)
    .placeHolder().
    error(R.drawable.error).into();          
    多类型请求 通过构造不同的Request子类实现 只支持图片资源:http, https, 
    file,content, assets, 
    drawable
    通过提供不同的Action子类和RequestHandler子类实现
    支持的资源 远程Json、Image、String 远程和本地的Image 远程和本地的Image
    重复请求 使用Map<String, Queue<Request<?>>>
    mWaitingQueue去重
    使用ReentranceLock去重 使用BitmapHunter类的List<Action> actions去重
    列表滚动停止加载 Volley本身不提供支持方法 ImageLoaderEngine提供
    resume()和pause()方法支持
    Picasso提供resumeTag(Object)和PauseTag(Object)方法支持
    降采样加载解码 完整读取远程图片的字节流,
    在本地进行降采样解码
    远程读取的图片尽可能清晰(见4.6(3)的说明)
    压缩后保存到本地,
    之后根据目标view降采样解码出不同size的图片
    远程和本地都支持降采样解码

           Volley是Google官方提供的通用IO框架,并不针对每个细节进行优化,但是总体的框架值得学习;UIL的设计针对客户端图片加载,对各类图片来源都支持,框架的各个模块通过接口定义,耦合度底,使用时对不需要的功能可以进行裁剪;Picasso也是针对客户端图片加载,框架设计的很巧妙,并且每个功能包含详细的测试用例,功能也很完善。要从这三个图片加载框架选择,还是推荐Picasso,这三个Lib只是学习用,当然还有其他的选择。

           注:Volley的架构图、类关系图和UIL的架构图绘制,参考了 http://codekk.com/open-source-project-analysis 上的两篇文章,这两篇文章对Volley和UIL进行了非常详细的介绍,细致到每个方法变量,可以对照源码细读。
    展开全文
  • GA005-181-05

    2020-11-18 22:25:20
    模式的目的是允许业务分析师、业务架构师或其他涉创建一个组织图,以表示特定时间点的组织结构。组织部门、角色或指定人员可以作为图表的一部分。 它通常在定义企业或业务体系结构时使用,并允许将角色包含在存储...
  • GA007-182-003

    2020-12-31 08:44:10
    小组作业06 学号 姓名 ...它通常在定义企业或业务体系结构时使用,并允许角色包含在存储的其他部分中,例如表示哪个角色、标题或人员负责...模式的目的是允许业务分析师、业务架构师或其他涉创建一个组织图,以
  • 我的d类文章索引

    2020-09-09 18:03:47
    亚当的动态 使用arsd.com d奇怪的容器类型 d模板元编程笔记05 d模板元编程笔记04 d模板元编程笔记03 d模板元编程笔记02 d模板元编程笔记01 d的静态模板,启动时初化 dmd一个小示例,不带运行时 dub的sdl配置文件中文...
  •  2013年集团新注册上海资合讯实业有限公司,主要从事工控自动化线下服务,深度挖掘客户潜在需求,打造B2B20的产业化商业模式。  2014年成立了工博士集团,公司现已形成集团化、产业化、信息化发展, 为了更好的...
  • 通过平台系统,用户可以轻松管理自己的微信各类信息,对微信公众账号进行维护;含有手机客户端APP。   佳易商城系统使用说明: 解压后将jiayi9文件夹下的所有文件上传到支持ASPJPEG和ASPUpload组件的ASP空间中...
  • 通过**台系统,用户可以轻松管理自己的微信各类信息,对微信公众账号进行维护;含有手机客户端APP。 佳易商城系统使用说明: 解压后将jiayi9文件夹下的所有文件上传到支持ASPJPEG和ASPUpload组件的ASP空间中...
  • 产品自身技术原理巧妙解决大多数安全软件资源占用问题,无病毒占用内存,无需每日频繁升级骚扰。  影子系统2008智冠天下特别版 特性: ┃0. 不支持windows 7/vista;支持XP,2003,2000,Nt。  ┃1. 增加对新双核...
  • 我们在开发过程中使用了一些第三方,这些的信息可以在 版权信息 中进行查看。 开源许可 This project is under the Apache 2.0 License. See the LICENSE file for the full license text. Copyright (C) 2015-...
  • 产品自身技术原理巧妙解决大多数安全软件资源占用问题,无病毒占用内存,无需每日频繁升  级骚扰。  提取影子系统企业版核心文件作为控制平台,更加稳定可靠 影子系统2008智冠天下特别版 特性:  0. 不支持...
  • 导医系统一般以触摸屏或网站的形式公示于,主要用于展示医院的各种特色、通常包括医院介绍、专家介绍、科室介绍、设备介绍、药品价格公示、收费项目公示、一日清单等;客户管理主要用于为每位病员建立档案,包括...
  • the1812/Bilibili-Evolved:强大的哔哩哔哩增强脚本: 下载视频, 音乐, 封面, 弹幕 / 简化直播间, 评论区, 首页 / 自定义顶栏, 删除广告, 夜间模式 / 触屏设备支持 其他: kuresaru/geetest-validator:geetest调试...
  • 于2015-12月,我将XXL-JOB发表到我司内部知识,并且得到内部同事认可。 于2016-01月,我司展开XXL-JOB的内部接入和定制工作,在此感谢袁某和尹某两位同事的贡献,同时也感谢内部其他给与关注与支持的同事。 于2017...
  • 逐浪CMS是一款基于dotNET技术构建的高端CMS,也是目前华文领域alexa排名第一的web建站产品,不同于国内一CMS只满足于生产“垃圾流量网站”,逐浪软件产品定位于服务企业级产品,集成电商、APP、微信、OA、办公流、...
  • 于2015-12月,我将XXL-JOB发表到我司内部知识,并且得到内部同事认可。 于2016-01月,我司展开XXL-JOB的内部接入和定制工作,在此感谢袁某和尹某两位同事的贡献,同时也感谢内部其他给与关注与支持的同事。 于2017...
  • 杭州房产知识扫盲 -- 图片来自网络,侵权删 -- 数据不保证完全准确,错误之处还望海涵,如需深入使用还望自己求证。 -- 买房有风险,投资需谨慎 ,资料内容不保证完全正确,使用需谨慎。 新增杭州学区房购房指南...
  • 千里马酒店前台管理系统V7使用手册

    热门讨论 2011-06-16 14:09:38
    所谓“模式决定优势”,软件产品的质量是设计开发出来的,而不是测试修补出来的。 V7.2前台系统的功能全面涵盖了酒店房口部门的功能,如下图所示: 2.3 运行环境 千里马V72是CLIENT/SERVER物理结构的软件系统...

空空如也

空空如也

1 2
收藏数 24
精华内容 9
关键字:

众库模式