AI+daggerai 怎样输出固定大小输

含泪的Tridagger 社区老党员参观济南战役纪念馆(图)
BAIJIA HOT
国际热搜词
Entertainment
互联网图片
互联网+图片
Technology您的位置:
→ 流星蝴蝶剑隐藏命令使用方法
流星蝴蝶剑隐藏命令使用方法
22:30:37 来源: 作者:wei (0)
隐藏命令的使用方法一篇,当然,我们首先得准备一个隐藏命令开启器,然后再根据下面的方法使用隐藏命令即可。流星蝴蝶剑隐藏命令开启器:
相关补丁下载:
游戏工具 - 24KB
使用方法:在游戏的时候按下“\”键,屏幕左上角会出现“Command:”或“输入命令:”的字样,然后输入以下命,令就可以达到不同的效果。【\AI *】AI为加机器人的命令,“*”代表Level文件夹中.pst文件的文件名。流星蝴蝶剑隐藏命令:1. \AI Stinger 小何·双刺2. \AI Dagger 冷燕·匕首3. \AI Sword 律香川·剑4. \AI Lance 高寄萍·长***5. \AI Blade 铁胡子·大刀6. \AI Hammer 破空·锤7. \AI SAMURAI 石群·乾坤刀8. \AI PUNCH 孙玉伯.指虎9. \AI KATANA 无名·忍刀10.\AI GUARD 孙玉伯·防御状态11.\AI UNGUARD 破空·站立状态。
相关游戏攻略
· · · · · · · ·
本站提供: 好玩的单机游戏,是大型基地网站Copyright &
.All Rights Reserved备案编号:湘ICP备号-1【贴中有大量暴力破坏电池实验的视频,请点击最下面的阅读原文查看】大家好,我是菜青虫,很多玩电子烟的人认识我说白了,喜欢各种玩,什么圈子都混过,手电,单反,耳机,外设,键盘,收音机等等,个人玩电池玩的比较多年,所以在这里开个帖子,回答一切关于18650电池有关的问题与电池无关的问题,一般不会来回复,这个看心情电池有关的问题,肯定会看到回复本帖随个人脑洞思维写的,想到什么就写什么,主要就是介绍与电池有关的各种知识所谓的18650电池,其实很简单,就是18mm直径,65mm的长度,后面的0代表电池外形是圆柱形,同理可以知道1 26650等电池是什么个情况了大家电子烟基本上用到18650的电池的概率是最大的,其实这个也是正规大厂生产的最大的型号,其他型号,很少看到。单独讲18650电池,其实最简单的分类就是容量型电池,动力型电池这个其实很好理解,容量型电池就是电池追求容量的最大化,尽可能的在这个小小体积里面,做到容量最大,在一切需要大容量的设备里面,就比较有优势,比方说充电宝,肯定喜欢同样体积,容量更大,还有一些户外手电筒,对电流要求不高,但是希望能在野外多用几天,几个小时。这类电池,一般放电电流不大,比方说3000mah的容量的18650电池,可能放电就只有3A电流。但是贵在容量大但是动力型电池,追求的就是另外一个方面了,就是输出电流要大。为了做到这一点,厂家是各种脑子都想过了,唯一要求就是电流大,必须做到电池内阻小,因为大电流的时候,如果内阻大,电池本身就很容易发热,影响电池安全。另外一个方面,也是因为只有低内阻,才能达到大电流放电。,但是呢,如果要做到低内阻,那电池容量必须下降,同样的空间,容量下降了,里面的密度就小了,自然内阻可以做的更低我们给一个大概的参数大家看看,一般容量型电池,内阻要求在60毫欧以内但是动力电池,比方说20A 30A稳定输出的,内阻都在20毫欧以内。如果是10A放电的,那属于小动力电池了,内阻也是在30毫欧以内的国内电池其实厂家很多,比方说力神,比克,长江,金刚等等,不过针对电子烟玩家,估计很少有人知道这些品牌,那么国产的就先扔一边,看看国际一线大厂有哪些目前生产18650电池的国际一线大厂有松下,三洋,LG,三星,sony,基本上就这几家,其中三星还稍微低一点点档次三洋这里说明一下,(目前被松下收购了,但是工厂还在生产,也打三洋的品牌。这个很好理解,沃尔沃被吉利收购了,沃尔沃还继续出汽车,出各种新型号汽车,一个道理,)好了,继续说,松下,三洋是传统的容量型电池厂家,松下的大家都很熟悉,其中有一个事情大家知道一下,特斯拉的电池,就是和松下合作,松下来提供的。一辆特斯拉汽车,里面有7000多节松下18650的容量电池,通过并联,串联组合起来,而且这些电池,连外皮都不需要的,直接电池进行组装的。因为18650电池,本身就是属于工业电池,是工厂对工厂来销售的,本身不对民用销售。所以这类大厂出的18650电池,一般上面就一个型号,没有容量说明,有的电池连正负极标识都没有LG,国内名称叫做乐金,大家知道一下即可。整个15年年底,16年的主旋律就是缺货。导致很多国内换皮电池,不得不从lg电池,换成用三星电池来换皮了。性价比较高,动力电池比较出色。sony,一直大家都说sony大法好,因为sony在18650电池领域一直比不过松下,三洋的。这个看看大家笔记本里面用的电池电芯就知道了,基本上sony的电芯就很少见,万一拆开看到了,估计也寿命差不多了。所以,容量型电池不行的情况下,sony就把所有精力放在动力电池领域了。然后就出了个sony VTC系列,从初代的VTC ,到现在的VTC4 VTC5动力电池,可以达到稳定放电30A。目前大家如果有进口手电钻的,进口吸尘器,比方说戴森手持吸尘器,博士手持充电钻,电动起子的,里面基本上是都是sony的vtc系列动力电池,而且基本上是初代vtc电池,也就是1300mah的那款。这个也是从一方面说明sony的动力电池,确实得到了专业公司的认可和大量采用。三星,韩国的,大家都知道,国内部分三星容量电池是力神代工的,就是天津力神公司代工。但是动力电池领域,比方说三星22PM(2200mah),25R(2500mah),30Q(3000mah)这类电池还基本上还是韩国自己生产的。说到30Q,不得不说另外一个电池型号,lg hg2电池,两款都是3000mah容量,放电电流方面,hg2是20A稳定放电,价格实惠。三星30Q是3000mah,15-20A放电。这两款电池,是目前国内很多电子烟电池3000mah,用的最多的换皮对象。最初都是LG HG2的电池的,正极是标准4气孔。到了15年10月份以后,LG是各种缺货,所以很多换皮厂家,就只能用三星30Q的电池来换外皮了,正极是三气孔样子。目前正规大厂就这么几家,美国,德国,意大利啊什么的,暂时没什么电池品牌。美国科技倒是不错,但是电池领域一般般,不然特斯拉也不会去找松下合作了。哈哈一般很多人问我,我抽电子烟的,我要用什么电池啊其实,这个选择电池,完全看你使用的功率。我们是根据使用的功率,选择对应的电池比方说抽口感的,一般13W左右的,那么这个时候,你选择一款输出电流能达到5A的电池,就足够了,比方说松下 18650B这款电池,内阻34毫欧左右,输出电流4.5A最大。算一下3.7*4.5=16.65W功率。那么就支持你13W使用了但是如果你说你要使用50W功率的,那么你就必须找一款电池可以达到20A放电的,这样,算下来,3.7*20=74W,才能满足你的使用这里给大家几个公式&&1:电压*电流=功率,比方说电池稳定持续放电20A的,电池电压默认按照3.7V计算,这个是锂电池的标称电压,也可以说是电池的平均电压2:电压/电阻=电流。比方你机械杆子,0.29欧姆电阻,那么3.7/0.29=12.A电流,正常工作就是13A的电流,那你根据这个电流,你选择一款电池,可以稳定输出13A以上的即可,比方说15A的,20A的都可以。在能达到你需要的前提下,选择容量大一点的电池,意味着你使用的续航时间会更长一些回答一些电子烟客户经常问到的问题:电子烟圈子确实是我玩电池以后,遇到的一个比较大的群体,当然了也是比较乱的群体,很多新手接触电子烟,基本上是被忽悠,被坑的节奏。这个从我接触的几个老手的聊天中也深有体会,现在的老手,当年也是被坑着走过来了。要说电子烟乱,烟油,盒子什么咱们就不说了,就当本人熟悉的电池来说,很多电子烟商家的电池都是价格翻倍,3倍以上的销售的。被人问及电池为什么这么贵的时候,就信誓旦旦的说自己才是进口正品,那些低价的都是假货。用假货是会爆炸一类的话去忽悠新人。而且,电子烟圈子里面很多品牌的各种电池,几乎都是拿lg的电池,或者国产山寨电池(比方说这类规格的,正规lg ,松下,三洋等大厂都没生产这个型号的,都是国内山寨小厂生产的)换外皮以后,把原来输出电流20A的,就敢标40A,60A放电。有的连个注册商标都没,就是利用的很多新人怕买到假货,弄个防伪标签上去,赤裸裸的忽悠新手。原价16元的LG HE2电池,换个外皮,贴个防伪标,就能标40A放电,就可以卖到40元一节,更不要说大名鼎鼎的sony VTC4的这类电池了,65元一节,88元一节都是常见的。& && &电子烟确实是个新兴的圈子,很多东西都不成熟,市场不规范。当当从购买电池方面,可以给大家一点参考。比方说你看到什么品牌的电池,你就整个淘宝搜索一下,看看都是哪些商家在销售,如果搜索出来只有电子烟的商家销售,其他类目商家没销售的,那么基本上这个电池就是换皮电池,不建议购买如果你搜索的电池,销售的商家有手电筒的商家,有手电钻的商家,有航模的商家,有专业做电池,充电器的商家,有户外运动的商家,那么,基本上这个电池就相对来说比较靠谱,剩下的就是挑选适合的商家来购买这个电池了。看看市场均价多少,太低的不要,评价不好的不要,价格太贵的也不适合选择。最后了解一下动力电池的几个特色:动力电池的特点就是可以瞬间大电流放电,那么要做到大电流放电,本身电池的内阻要小,内阻小了,电流才可以大电流输出,而且电池本身不会很发热。如果要做到内阻小,就需要容量降低,容量做的很高,里面就会很紧,分子结构靠紧的话就会引起内阻变大。所以,对于动力电池来说,测试一节电池的内阻高低,是一个比较重要的参数。& && & 其实道理很简单,如果一个电池,又有3000mah的容量,又能达到40A的放电,那么这个性能,应该是宇宙第一了。那么我想博世,戴森这种厂家,肯定来采购这类电池了,而不是使用sony的vtc系列电池。而早于电子烟圈子的,有航模的圈子,手电钻的圈子,他们也有很多玩家,估计这些玩家,早就用这种3000mah,40A的电池了。而不会一直继续使用sony的动力电池。好的产品,好的性能的产品,自己会做广告,只要需要到这类电池的,肯定玩家都知道了。不会说就只是在电子烟圈子里面图点名声了。关于电池的安全,也是很多人说到的话题,我先给一个总结正规的18650电池就算短路了,用手电钻钻孔了,用大锤砸扁,也不会发生爆炸事故之所以玩电子烟的经常听到爆炸,完全是因为使用了一些山寨电池有人不相信我说的短路,手电钻钻孔,大锤砸扁不会爆炸不要紧,我用视频来给大家看一下,看完就明白了首先上一个松下18650电池钻孔试验。想想也是蛮拼的,豁出去老命了(发现无法发视频,就上个链接吧)?【贴中有大量暴力破坏电池实验的视频,请点击最下面的阅读原文查看】通过上诉视频,大家应该明白了,正规的电池,是不会爆炸的因为正规的电池,就算电池短路,顶多因为短路引起电池发热,内部压力达到一定值的时候,电池内部泄压阀弹起,释放内部气压,同时因为泄压阀弹起,电池就断开输出了,电池测试电压也就变成0了。不建议大家自己去短路电池测试,因为虽然不爆炸,但是电池短路的时候,电流大,发热量也很大,不会因为爆炸伤到你,但是会因为发热,烫伤你的【贴中有大量暴力破坏电池实验的视频,请点击最下面的阅读原文查看】蒸汽部落17vape(ai17vape) 
 文章为作者独立观点,不代表微头条立场
的最新文章
克苏鲁绕线器 Pro 绕线器是由Cthulhu MOD和英国玩家 Pete. H 联合开发。 除了可以绕一般众测】克苏鲁 Pro 绕线器 招募试用 立即申请克苏鲁绕线器 Pro 绕线器是由Cthulhu MOD和英国又一款200W可以换面板的盒子,看了最近流行更换面板,用多种可以更换的面板来迎合玩家的不同风格爱好。但貌似单大家好,我是老K,一个电子烟老玩家,今天给大家带来一款新产品的介绍和评测,希望大家能够喜欢。今天为大家介绍的大D牌的 YURI,已经用了有一个多月了深圳出差20多天 回来就展会,忙得不亦乐乎早就想写个分享,无奈实在没大D牌的 YURI,已经用了有一个多月了深圳出差20多天 回来就展会,忙得不亦乐乎早就想写个分享,无奈实在没去了趟北京展会,这个COV 200W的评测耽误了几天,在展会上看到了COV的站台,一帮洋妞扭呀扭,倒是十足的论坛 微信群 QQ群这阵子经常引起一片热论的 就是 胡子兄弟出品的 武士道雾化器 之前我也没用过。。。胡子早有点标题党了。。。其实这个机身也不算很大很大。。。不过高度比较高 厚度比较大没办法 要塞进去2个 26650 ============故事正文=======2015年一个平淡无奇的下午,一位外表异常英俊的男子落寞的注今天的40L说电子唠叨一下半机械盒子以及机械杆子的功率计算问题:可以理解成我之前文章的补充部分【Mr.17G前言:写这篇教程的目的是给新手一个正确的操作方法少走弯路,直接找到雾化器的精髓所在。试了感觉不好那就真不好了YURI 尤里雾化器 专攻 口感滴油分类独特的侧面斜口进气 可以模拟出类似肯尼迪底部进气的浓郁口感同时还能满本帖最后由 布龙长九 于
18:45 编辑 发帖必有图,无图不丈夫!大家好,我是布龙,今电子烟的发展已经向前迈出了巨大的一步,而现在需要进一步提高公众的接受度。电子烟还完全可以帮助人们戒烟,目前已前两天还看到有玩家在询问这个Dagger 80W的盒子如何,其实这几天都在搞这个盒子。每次写完一个新评测,后各位帅哥美女晚上,我是tenfive,下面我要写一下抽完了时速系列之后的一些体验官方介绍:时速系列是针对滴油前言:以下纯属个人观点
同设计特点:两者一样为GENNY设计型底座在上,油仓在底,不会产生漏油问题同为双D3 不多介绍,大家都懂!连新手基本也都了解过这次要介绍的是D3S -D3的升级版,主要变化是增加了百醇模式这个变色雾化器 大家都很熟悉吧,看那个logo 应该晓得了limitless无极限雾化器也是他家参与设计的产SX MINI Q CLASS(Q200)双口感曲线使用方法前言:Q200是一个跨时代的产品,450J芯片比这个评测可能不会严谨内容可能会有错,因为我把玩theorem雾化器的几个配件2天了感觉还是不太明白双边进气那前言
千呼万唤,将近半年的等待……白驹过隙,时光荏苒。那一抹红,再次坐拥怀中。渐渐地,拥有亿海的产我是CoCo船长,很长时间没和朋友们见面了,今天给大家评测(放毒)一款小神器从我们开始接触电子烟都会有个信仰《视频请点击底部的阅读原文》首先祝大家五一快乐,你们享受这假期的快乐和家人团聚,我却沉浸在独在异乡为异客,每真挚的友谊来自于源源不断的自我介绍大家好我是72烟油归属地(USA)烟草口味的烟油我真不知道有多少朋友喜欢,最近可能赶上展会,不少新品上市,这不前几天收到腰子寄来的一台FEROBOX 65TC,单节18650 65W写在前面:请中奖的兄弟们直接发站内信给我 告诉我地址***收件人 邮费到付 最近好像各种店家都开始推出“可乐冰OK ~ 欢迎大家收看这一期【山鸡图文学堂】の真假美猴王!~呸呸呸、是辨别真假花冠。正文好啦~
开始这一期 大家好,我是徐州大烟雾,今天拿到了一款小盒子,觉得用着还不错,所以给大家做个评测! 打开包装盒就能看到一个大家对奶油和焦糖味道烟油的关注点都在是否健康上。哈佛之前一个学生(研究人员)发表的未被验证的论文里提到:烟油内容大部分在视频中需要看视频请点击底部的【阅读原文】看到这个帖子大家一定会很奇怪,为什么胡子会评个小杆子,提【导读】烟油正如我们日常饮食习惯及饮食追求一样,每一款烟油对每一个人味蕾的表现都略有不同,以下烟油纯属个人使【贴中有大量暴力破坏电池实验的视频,请点击最下面的阅读原文查看】大家好,我是菜青虫,很多玩电子烟的人认识我说
MCH发热组件 MCH heating componentsMCH是Metal Ceramic 很多朋友整天在纠结 什么雾化器不炸油,还有我的雾化器为啥炸油!最终找不到问题所在,就管他三期二十一,不是卖报告第一句我只想说:调压设备在经历了那么多年的改进终于难以察觉输出延迟了,我们还需要去妥协一个雾化器带来的延美产sonzz浆果
小草莓....我觉得这个油应该叫小清新....口感没有那么暴力..味道也挺明显的...同志们好,我是你们的蛋兄!这里是再次归来的二蛋推油时间,在我消失的这段时间里有没有想念我呢?(
王百万大牛角镇楼~
本人新人 入坑时间也就半年有余,最喜欢逛的坛子就是蒸汽部落了,本人菜鸟在坛子里属于静默学习型的,一直心水SX市售主流电池参数比较,详细参数回帖可见。方便大家选择电池性能。。。。。什么鬼?八爪鱼?电子烟电源盒子?你了解多少PS:小编刚收到这个稿子的时候,也没反应过来这个是什么东西,貌似跟OK~呐
做电子烟这么久 这是第一个评测帖子
希望能给坑友们带来一些建议和帮助今天我们拆的这款电子烟是咱这鲨鱼我之前改过510接口,要看的请看我以前发的贴子。/threaai17vape蒸汽部落电子烟论坛公众号,综合了玩家互动的论坛和低价正品的商城。17vape 一起vape热门文章最新文章ai17vape蒸汽部落电子烟论坛公众号,综合了玩家互动的论坛和低价正品的商城。17vape 一起vape带着疑惑走进Dagger2
Dagger2是一款最初由Square公司研发,后交由Google进行维护管理的依赖注入(Dependency Injection DI)框架。
我想之所以其越来越受欢迎,一是其自身的优异。二是当我们了解了对它的使用之后,就会发现它和Android现在盛行的MVP架构可以说是天生一对。
于是当我们看到越来越多的地方开始提及Dagger2这个东西,难免自己就会想要去尝试一下。那么,当我们看着一大堆的关于Dagger2的学习资料时:
难免就会被一些类似&Dagger2从入门到放弃&的关键词吸引,很显然这从一定程度上说明了:想要熟练的掌握Dagger2并不轻松;并且在学习过程中很可能会遇到无数的困惑。然而,对于&入门到放弃&这样的的观点,小弟只想说四个字:。。。。。。深!有!体!会。
所以,本文将试图站在一个&纯菜鸟&的视角上,介绍一些关于Dagger2的使用以及学习过程中遇到的疑惑。让我们开始吧!
简析依赖注入
我们前文已经说到Dagger2是一个依赖注入框架,所以在学习它的使用之前,我们显然有必要弄清楚依赖注入的概念。
老套的例子
看下面这样一个老套的例子:
上述代码试图还原的场景是:A类某个方法需要借助B类某个方法才能完成。于是很显然在A类当中需要持有B类的对象,这个时候就产生了所谓的依赖。
在这里B类对象的持有方式,是通过直接在A类中使用new来完成的。这肯定是最差的方式。因为,B类的构造函数一旦改动,A类将直接受到牵连。
为了避免这种情况发生,就衍生了所谓的依赖注入。逐步递进,现在,我们首先接着看一种比较&原始&的注入方式:
现在调整了代码,改为使用向构造函数传参来持有B类对象,这样A类和B类就完成了解耦。这时B类的构造器无论如何变动,至少A类代码不会再受影响。
但这种解耦其实也只是相对于&某种程度&上来说的。因为这个时候的耦合只是由A类转移到了第三方,即A类的调用者,比如说C类。看代码:
这个时候我们难免就会考虑,有没有一种方式可以更大程度完成解耦?&没有***就没有杀害&,那么现在有了***,于是也就出现了依赖注入框架。
进一步解耦,Dagger2的最基础使用
现在,我们通过一个简单的例子看一下怎么使用Dagger2对之前的代码进行解耦。在这个过程中,我们将学会两个常用的注解@Inject与@Component。
我们首先来看一下如何通过Dagger2来改造A类:
从上述的代码中可以看到,我们是分别对变量b以及A的构造函数加上了注解@Inject。这个注解可以说是Dagger2中最容易理解的一个:
对变量b加上注解意味着告诉Dagger2,A类依赖了B,但b对象需要你帮我注入到A类当中来,我就不管了。而对构造器声明该注解的意义暂且不提。
接着,是看一下B类是如何来改造的。同理,对B的构造函数加上@Inject的意义我们也暂且不提:
最后,是改造过后的C类的面目:
我们可以发现,这里就是对其需要的A类对象变量添加了注解@Inject。现在我们来回忆一下,就知道添加在A类与B类构造器上的@Inject注解的意义了。
之前我们说到在依赖的变量上添加@Inject的意义在于,告诉Dagger2这个变量的对象需要你负责帮我注入。那么,Dagger2怎么确定如何帮你注入呢?
我们可能会想,Dagger2你自己去找构造器啊?没错,如果你需要注入的类永远只有一个构造器,那么这样做看上去就是行得通的。但这显然不可能。
所以,我们还需要为所依赖的变量对象的类的构造器也添加上@Inject,这就等于告诉Dagger2,这里依赖的对象我希望你通过这种构造器来生成注入。
OK,那么通过Dagger2来设置依赖注入的工作是不是就完成了呢?实际上不难想到是还没有的。这样考虑:
为对象变量添加@Inject注解代表着这是依赖的需求方;而添加在依赖对象所属类的构造器上的@Inject代表这是依赖的提供方。从而不难看到:
现在,我们显然还需要一个&桥梁&把依赖方和提供方给联系起来。在Dagger2当中,这个桥梁就是@Component。所以我们还需要这样的东西:
也就是说,我们需要定义一个接口,然后为其添加上@Component注解,然后声明一个叫做inject()的方法,顾名思义,这个方法的意义很好理解。
可以这样认为:我们说过了component是桥梁,通过其调用inject()的意义就好比:现在要把提供(对象)注入给依赖(变量a)了,而注入的目的地,就是C。
OK,现在准备工作就完成了。重新编译一下项目,Dagger2会自动为我们生成一个刚才定义的Component的实际实现,其默认以Dagger开头。
于是,我们在C的构造器中添加以下一行代码,目的就是在构造C类的对象的时候就进行一系列相关的依赖注入工作:
现在,我们就完成了整个依赖注入工作了。现在我们可以写一个测试类来测试调用c的doSomething方法,看看会发生什么。
以上就是测试的日志输出结果,从中我们很容易简单的分析出整个依赖注入的过程:
首先,我们通过C类对象调用其实例方法doSomething,于是C类的构造器率先执行了。 而调用C的doSomething方法,由于其依赖A类,所以A类的构造器又执行了。 同理,A的doSomething方法又依赖于B类,所以B类的构造器又执行了。 这个时候,所有的对象就都注入完成了,于是正式调用B的doSomething方法,从而打印出对应内容。
好的,有可能这个时候,就会第一次冒出&从入门到放弃&的念头了。因为我们发现之前我们使用的很熟练的代码,加入Dagger2后,开始有点懵逼了!
其实这很正常,因为通常人都害怕&改变&。之前的代码我们写过无数,非常熟悉非常亲切。猛的一下换种方式难免会抗拒,何况这种方式看上去并不那么容易理解。所以这个时候,我们急需看到Dagger2带给我们的好处,抵消一下&哥想放弃&的怨念。想象一种情况:
现在因为需求的改变,B类需要依赖另一个新的类D了。那么如果以我们最初的方式,就会出现类似改动:
public B(D d){
Log.d(&Dagger2&,&Class B construct..&);
显然,这样做的话,就又会影响其他需要依赖B对象的地方。而因为我们使用了Dagger2,则可以使用如下改动:
由此我们可以发现,本次改动除了B类自身添加依赖,其它的A类,C类都不会受到任何的影响。
好吧,我们发现Dagger2让我们进一步进行了解耦。尝到了一点甜头,我们暂时决定放下&放弃&的念头。一起继续学习!
@Module与@Provides
不知道大家注意到没有,到目前为止,我们涉及到的依赖都有一个共同点,那就是其构造方式在我们控制范围内。现在试想一种新的情况:
如果我们依赖的某个类,来自于外部或者我们控制不了其构造,那么应该怎么办呢?于是现在就该@Module与@Provides上场了。
我们举个最简单的例子,在Android里面有一个我们熟悉的朋友:Context。那么,现在我们修改一下A类,变为了如下所示:
好的,现在我们看到的情况是A类的doSomeThing方法需要依赖于Context对象,所以我们可以通过如上图所示的方法来注入context。
但是,如果我们这里要统一为用Dagger2注入呢?应该如何去做?首先当然还是为依赖的Context对象变量添加@Inject注解:
接下来的工作就与之前有所不同了。因为,很显然我们不会去给Context类的构造器加上@Inject,现在意味着我们需要一种新的方式来提供Context的依赖。所以,我们需要新建一个下面这样的类:
如图所示,这里我们新建了一个叫做ClassAModule的类,加上了@Module注解。这意味着此类是一个专门用来为A类提供依赖的Module类。
接着,我们看到一个被@Provides注解的方法provideContext。顾名思义,它就是用来提供A类所依赖的Context对象的。那么,现在就又回到了熟悉的步骤,编写&桥梁&- Component:
从上图的代码中可以看到,与之前的不同之处在于,这次在@Component注解里声明了,本次向A类注入所需要的依赖的工作,不再是通过构造器,而是通过ClassAModule这个Module类来提供相关依赖对象。同样的,再次编译项目后就得到了对应的Component实际实现。当然调用也发生了轻微改变:
我们总结一下可以发现,通过@Module+@Provides与在构造器上设置@Inject的本质是相同的,都是用来提供依赖;差别只是提供方式不同而已。
分析一下这个过程也就是说:如果我们的某个类中依赖于某些类,同时这些类的构造方式又不是我们能控制的。那么,就可以新建一个@Module类用以提供这些依赖。而@Module类提供这些依赖的方式则是声明对应返回类型的provideXXX方法。但是:这个时候我就更想要&从入门到放弃&了!
因为回忆一下,之前说到@Inject的使用时,我们能很明显的体会到Dagger2带来的好处。但这里显然就不是了,我们对比一下两种注入方式:
我们可以看到这两处怎么看都是使用Dagger2过后写的代码更多一点。并且!使用Dagger2过后,我们还需要维护额外的Module与Component类。
试想现在A类又添加了新的依赖,那么两种方式同样都会涉及到A类和MainActivity的代码改动;而Dagger2还会涉及Module与Component的改动。
一脸懵逼的我想来想去,觉得似乎除了是要统一依赖注入的方式(Dagger2)之外;唯一能想到的好处似乎就是把类的依赖全部抽离到了单独的Module类中。当然,这只是个人看法,说不得正确,还希望有精通依赖注入和Dagger2的大腿能够指点迷津。
@Qulifier的使用
现在,我们接着考虑一种新的情况。假设现在有类A,B,C,类A和类B当中都依赖于C,但C有两种构造器,A和B分别是依赖于不同的构造器。那么,有了之前的使用基础,我们最初可能会简单的这样考虑:
那么,这里抛开Dagger2如何去区分类A,B到底是需要哪种构造器构造依赖对象不同。编译项目首先会遇到如下的错误:
很显然,编译器已经告诉你为C类定义了多个@Inject修饰的构造器,这是不合法的。这个时候该怎么办?我们想起了还有另一种提供依赖的方式:
但是这里就要注意了,回忆一下:之前说A类依赖于Context时,我们在Module类里通过provideContext方法来提供这个依赖。
但我们需要明白的是,这里的方法命名只是一种规范,而非规则。也就是说可以随意定义这个方法名,那么Dagger是如何确定这就是提供依赖的地方呢?
很显然,既然不是通过方法命名,自然就是通过返回类型了。但这里我们看到两个方法的返回类型都是C。显然我们还是没有完全解决我们的问题。
这个时候,就需要使用到Dagger2的另一个注解@Qulifier了。说白了这个注解就是用来起到一个标识的作用的。它的使用方式如下:
可以看到这个注解本身就是用来修饰注解的,我们这里定义了两个标示注解DefaultConstructor与ConstructorWithString。
之后的步骤我想大家都可以猜到怎么做了,没错,先分别给我们Module里的两个provide方法加上标示:
最后以A类为例,假设A类依赖的是C类无参的默认构造器,那么修改A类的代码:
最终经过调用,运行程序就得到了我们想要的日志打印信息:
最后,我们一起来看Dagger2中最难理解,最让人想要&从入门到放弃&的一个注解:@Scope的使用。我们首先看这样的代码:
然后是Activity的代码:
也就是说,这里我们在MainActivity中引用了两个A的对象a1和a2。在经过注入过后,我们打印这两个对象的信息,输出如图:
从输出结果我们可以看到,这里的分别构建了两个全新的对象。那么,有的时候我们希望控制某个对象的生命周期。比如说:
现在我们希望在当前Activity只存在唯一一个A类对象,并且其生命周期随Activity消亡而消亡。那么就需要借助@Scope来实现了:
有了之前@Qulifier的经验,我相信上面的代码并不难理解。之后的工作也很简单,我们分别在两处需要的地方加上这个注解就搞定了:
随后,我们再次运行程序,得到如下输出结果:
现在我们起码确定了A类的对象在MainActivity中是单例的,那么其生命周期究竟是否与Activity是保持一致的呢?我们进一步验证:
我们新建了一个SecondActivity,然后进行由MainActivity跳转到SecondActivity的操作,得到如下输出:
可以看到,Activity发生跳转后,就注入了新的A类对象。如果你是第一次接触@Scope,我相信你和我一样的疑惑。
因为我们好像就简单的通过@Scope定义了一个注解@ActivityScope,居然就实现了如此强悍的功能?但懵逼的是:
为什么这么轻易就实现了?似乎我们在使用@Scope注解时也没有指定任何有关于生命周期的信息啊?
不用着急,我们接着看。假设现在我们更进一步,想要在整个应用内,A类对象的依赖都是唯一的。也就是所谓的全局单例,那么又该怎么做?
首先,我们再定义一个@Scope注解,用来代表全局生命周期:
接着,新建一个用于注入全局依赖的@Component接口:
然后,当然是将其依赖的Module里的ProvideA()方法也设置Scope:
最后,当然自定义我们自己的Application类,并做相关设置:
可以看到,以上的大部分东西我们都是比较熟悉的,唯一的不同在于:
Component接口中没有再提供inject方法,相反是有一个返回类型为A的方法。 在MyApplication的onCreate方法中调用注入时,因为没有inject()方法,所以是直接通过build方法返回了定义的AppCompent对象。
我相信稍微机智的朋友到了这里就很容猜出出现这种不同的意义了,没错,核心就在于:我们通过MyApplication类里的appComponent对象调用getA方法,就可以返回Dagger2为我们注入到MyApplication的a了。也就是所谓的全局单例。那么,在Activity中我们就通过如下的方式去获取全局对象了:
但是细心一点的朋友可能会说,既然是Dagger2,对象还是通过@inject来注入好点吧!没错,那么现在我们怎么办呢?很简单,修改MainActivityComponent:
没错,这里我们看到原来Component也是可以进行依赖的,方式就是通过设置dependencies。现在Activity中就可以通过正规军的方式依赖A了:
好了,现在回归正题。我将结合自己的理解,试图以一种最简单易懂的方式来讲述@Scope注解为什么能实现这样的作用。我们分析一下:
不知道大家注意到没有,我们在AppComponent与ClassAModule中的provideA()方法上,添加的注解是@ApplicationScope。
然后,在MainActivityComponent上添加的注解时@ActivityScope注解。为什么这样做呢?我们可以测试一下:
假设,我们把AppComponent上的注解改为@ActivityScope,那么将受到如下异常:
其实异常信息描述的很清晰:为AppComponent设定的Scope与其自身依赖的Module中的provideA方法设定的Scope是不一致的。
所以请大家一定记住:@Component与其依赖的@Module的@Scope一定要是保持一致的。Dagger2实际就是通过这个来决定对象的生命周期的。
可以这样理解:当我们为Component设定了scope之后,当我们通过build()方法构建出这个&桥梁&后,它就进入了一段生命周期当中。同时:
与它关联的Module内,只要是同样设定了scope,那么它在这段生命周期范围内就是唯一的,并且生命周期将跟随scope。那么:
因为我们只在自定义的Application中build了一次AppComponent,自然的,设定了scope的依赖对象自然就成为了&全局唯一&的对象。
这样说可能仍然感觉很乱,我们通过一个例子能够更好的理解这个东西,修改MainActivity的代码:
上面的代码有了之前的基础,相信大家都能明白用意。现在再次运行程序,将收到如下的输出信息:
我们看到,这里得到了两个不同的对象。也就是说,现在虽然appComponent依旧是用所谓的@ApplicationScope进行注解的。
但是,上述代码中的对象a2现在的生命周期(域)实际上却是@ActivityScope,也就是与MainActivity相关联的了。
接着,假设我们做另一种尝试,把MainActivityComponent改为用注解@ApplicationScope。那么就将看到另一种异常出现:
有了之前的基础,这个异常就更容易理解了。简单的说就是:
MainActivityComponent的Scope设定与AppComponent冲突了,而它们本身就不属于同一个等级范围。
换句话说,MainActivityComponent的Scope设定,应该与它本身依赖的Module内的scope保持一致。
相信大家现在就明白了,所谓的@Scope并没有那么神奇。它的作用实际上就是统一管理Component和Module内提供依赖对象的方法。
当设定了Scope之后,Component被build出来后,这里面设定了Scope的依赖对象对于该Component注入的依赖来说就是唯一的。
@Singleton
最后,简单的说一下@Singleton。如果你能理解我之前的解释,那么理解@Singleton就将变得非常容易。举个例子:
我们之前用自己定义的@ApplicationScope来设定AppComponent和provideA方法。那么,我们直接使用@Singleton也是一样的。
因为所谓的@Singleton其实就只是一个@Scope的默认实现而已,一下就是@Singleton的:
到了这里,关于dagger2的使用就聊到这里。我只能再次感叹,学习这个东西的确容易让人懵逼和抓狂。希望本文能给您带来一点点的帮助。
(window.slotbydup=window.slotbydup || []).push({
id: '2467140',
container: s,
size: '1000,90',
display: 'inlay-fix'
(window.slotbydup=window.slotbydup || []).push({
id: '2467141',
container: s,
size: '1000,90',
display: 'inlay-fix'
(window.slotbydup=window.slotbydup || []).push({
id: '2467143',
container: s,
size: '1000,90',
display: 'inlay-fix'
(window.slotbydup=window.slotbydup || []).push({
id: '2467148',
container: s,
size: '1000,90',
display: 'inlay-fix'

参考资料

 

随机推荐