facebooktwitteryoutube
Welcome! Research Projects Android Engineering Linux Engineering Trip Gallery About This Site
in Trip - 28 Nov, 2015
by lzq8272587 - no comments

11月6日,开完会以后终于有一天时间自由出行。 早上一大早洗漱之后前往关内车站,坐地铁前往秋叶原,东京的地铁乱七八糟的,各种乱七八糟的线路,要是没有Google Map肯定就迷路了。Get到新技能,如果不知道怎么买票就直接把售票员抓过来叫他帮你买票就行了。 1个多小时之后到达秋叶原。一出地铁站就发现一大堆人围着很多机器在晃。不知道他们在干吗。研究了半天之后发现这个就是传说中的扭蛋机!!!可以塞硬币进去,然后可以自己扭一个转盘,会弹出一个球来。每转一次价格在200-300不等,能转到的东西也是随机的。我转到了一个特别牛逼的拼装机器人。 出来之后找到了电器街,就是卖各种插线板充电器充电线的一条街。我们要去买剃须刀,相机,然后就Google到了一个Yo什么什么的名字记不住了的商场。进去以后就是各种卖平板手机的,有一种中关村的即视感。不过没有人拉拽你去进店买东西。 上二楼以后发现卖相机镜头的,然后我就走不动了。不过我发现我自己已经上年纪了,没有想买镜头的冲动了。而且我发现这边的镜头并没有比国内便宜多少,可能是因为实体店提高了价格。 上三楼去给鳑鲏鱼找耳机,店员都找不到ES700不知道什么鬼耳机,然后试听了一下森海的旗舰耳机,太牛逼了。 五楼有很多卖模型的,四驱车什么的都有,我买了一个四驱车一个越野车。还想买很多高达的模型,不过还好忍住了。貌似这个东西就是真的比国内便宜好多,本土特产,可以买。 中午去找鳗鱼饭!!!!!!走了好久的路,虽然Google Map说只有22分钟,但是我们走了40分钟,太不靠谱了。 找到了伊豆荣鳗鱼饭,很好吃但是贵的吓死人,3700一份,只有4块鳗鱼。听说鳗鱼马上就要被吃完了。 吃完饭之后去浅草寺,以为很牛逼东京最古老的寺庙。后来发现好弱啊。不过许了三个愿,希望有用。门口他们还有小吃一条街,卖各种小吃还有玩具。 差不多还可以。 然后我们就去银座了,因为以为那里就是王府井。可是太贵了!!!!!完全不是我们买得起的。好多中国大妈! 有一个叫supe什么什么的,据说炒得特别火,还挺好看的,不过叫我2000多人民币买一件卫衣我脑子就进水了。 出来了什么都没有买,晚上去吃了一个豪华版屯骨拉面。太牛逼了。除了拉面最牛逼的就是鳗鱼饭了。 接下来去东京塔。一顿暴走走过去之后发现只要80块钱人民币就可以上去了,相比广州塔350到顶简直太良心了,哎! 上去到中间之后景色很好!然后去顶端250米的观光台,电梯上去居然还要排队!上去以后下来也要排队。 看完了下来,发现中间有一层居然还有DJ在搞节目,可是已经结束了,就只能回去了。 赶回横滨的路上还偶遇到了一个本地码农,他们太疯狂了晚上10点半块11点了地铁上还是满的人。 回去之后就睡觉了。 第二天在横滨的Queen Square逛街,好多衣服·想买买不起 所以就买了个书包,然后就结束了 从哪里开始从哪里结束,最后回到了90块钱一个烤串的那家店,可是中午时间不提供,就吃了一个麻油拉面,然后就去赶飞机了!! 机场又在免税店买了几个吃的,买了好多巧克力,然后就上飞机了。 上图时间~先上证件照!  

in Trip - 26 Nov, 2015
by lzq8272587 - no comments

下雪啦! 难得下一次雪,我决定从寝室绕到二校门,然后再走到实验室去。   这个是我们寝室楼下,自行车都没地方塞了:                       走出寝室之后,第一个十字路口:   听涛食堂门口: 路边上的一条小路:       踩雪太爽了。。。。       其实很多树叶子现在都还没有掉光,但是就已经下了两场雪了:     这些树叶子都还是绿的,不过过几天估计就要掉光了:     西操场:     最喜欢这几张照片:     绕到二校门来了,可是全都是游客,随手拍一张好了:     绕过二校门,走到大道上来,往前走就是主楼了:     路上全部都是化掉的积雪,但是又结冰了,果然不能骑车:   这么冷的天还在训练!!

in Computer Engineering - 25 Nov, 2015
by lzq8272587 - no comments

回调的基本思路,创建一个回调接口,然后把这个回调接口以参数的形势在远程调用的时候传递过去。   例子:假如设定了 其中,E3RemoteService是远程Service暴露出的接口,而ICallBack是要传递给Service的接口参数   CallBack的定义:     在Service的接口中,创建函数,记住要把参数传递过去:   在Service里面,实现这两个方法 这样,Service就会回调ICallback里面的方法了。   所以,我们还需要在client里面实现这个方法:  

in Computer Engineering - 25 Nov, 2015
by lzq8272587 - no comments

首先实现基本数据类型的传递,这里我们将AIDL的双方成为client和server   1.在server上创建aidl文件 2.创建一个Service,然后实现这个接口   3.在Service的OnBind函数里面,暴露这个接口 其实就是将实现好的接口返回     4.在client端,在相同的包名下创建相同的aidl文件 5.在client端连接到service,利用bindService方法 创建一个ServiceConnection方法,在连接上之后就可以获得server暴露出的接口了   注意Android5.0之后Intent必须显示声明,在bindService的时候,不然会报错。所以这里 使用了一个转化Intent的方法:   不要忘记了在Service里面创建过滤器: 这样就可以使用默认数据类型进行传递了。      

in Computer Engineering - 24 Nov, 2015
by lzq8272587 - no comments
in Computer Engineering - 23 Nov, 2015
by lzq8272587 - no comments

最后,我们看一下这个回调的类是怎么处理回调请求的。 这个ExecutorDelivery里面有两个函数是经常使用的: 重点看一下第二个 这里的Poster是一个executor类, 他干的事情就是执行runnable里面的东西。 所以,postResponse做的事情,就是把request先标记一下,然后执行runnable的事情。好吧我们就看看runnable里面在干嘛 注意,这个runnable里面居然还有一个runnable,这个内嵌的runnable是执行完这个runnable之后执行的runnable。好绕口。 看代码就理解了: 所以,这里调用了request的deliverResponse函数!!!这个就是用户自己定义的了! 然后,如果这个request不是一个中间结果,就可以调用它的finish函数了,最后会把这个request从队列中清理掉。 至此,分析完了整个delivery类。

in Computer Engineering - 23 Nov, 2015
by lzq8272587 - no comments

接下来看看Network调度器都在干嘛。 这里就没有Cache队列的,就只有一个队列了 重点关注一下run函数里面干了什么。 同样的,有一个巨大的while循环,从network队列里面取出request进行处理 执行这个request,把结果拿回来 如果这个response根本就没有修改,或者已经交付了,那就不传递一个一样的response了 看看这个finish函数里面做了什么事情: 调用一个Request的finish,其实就是让RequestQueue把这个request删掉。 然后,要把接收到的response转化,并且如果需要的话应该更新cache 最后,依然是调用传递函数,把response返回给application,结束 至此,结束对网络调度器的分析

in Computer Engineering - 23 Nov, 2015
by lzq8272587 - no comments

下一步,我们分析一下缓存调度线程。   先看看这个调度器里面有什么,可以确定的是这个调度器是一个线程   里面有两个奇怪的队列,不知道是什么东西。他们的命名跟在RequestQueue里面一样,都是叫m什么队列。   还有一个回调的类,应该就是用来返回结果的。   结合RequestQueue里面的代码可知道,这里的缓存和网络队列,实际上就是通过start函数创建调度器的时候传过去的。也就是说,RequestQueue和这个调度器里面的队列其实就是一个队列。   看构造函数:     以及RequestQueue里面的start函数:   接下来看看Cache调度器里面都做了什么! 这里,初始化了Cache,我们之前的分析中知道,这里是在创建一个文件夹,以及把根目录下的每一个cache文件的CacheHeader读取出来,存到它的那个列表里面。   然后在一个巨大的while循环里面,从缓存队列里面取出request处理:     然后!尝试去Cache里面找key对应的内容。如果没找到,丢给网络队列里面去,添加一个cache-miss的标记,然后就不管了。   但是如果找到了,可是过期了,要调用setCacheEntry这个函数,把entry放到request里面去。注意,这里等于把一个过期了的entry装到了Request里面。最后又丢给了NetworkQueue   /** * True if the entry is expired. */ public boolean isExpired() { return this .ttl < System. currentTimeMillis() ; } /** * True if a refresh is needed from […]

in Computer Engineering - 23 Nov, 2015
by lzq8272587 - no comments

然后我们回到RequestQueue里面,看看一个Request被塞到这个队列之后,后续执行了哪些操作   Note that 在Volley这个类里面,创建了RequestQueue之后,会马上调用start函数,这里就会创建各个调度线程类了。   首先看看这个RequestQueue里面包含有哪些队列:   这个mCurrentRequests里面,号称是装有所有的正在处理的Request   mCache和mNetwork分别又是两个有优先级的队列。     此外,还定义了一系列的调度器,这些调度器会在start函数中被实例化   大致了解了有哪些参数之后,现在来看看add函数里面都做了什么事情   第一步,把这个request里面的队列设置成当前队列,添加一个奇怪的标记(可以调试的时候用),并且要把这个Request添加到全都有的那个Set里面。   如果这个Request是不需要cache的,那么就直接丢到网络队列中去,网络调度器会统一的调度这个Request   如果request是需要cache的,那么这里有一个waitingrequest,是一个链表,里面装的是还没有被处理的request。   这个东西的作用在于,如果疯狂的点击一个按钮,生成相同的request,那么只有第一个request会被丢给mCacheQueue处理,剩余的Request都会被丢到这个stagedRequest中去,并且插入到等待队列中。   注意:这里如果cacheble的request,是先丢到缓存调度线程中去了。在RequestQueue里面,并没有判断是否命中Cache!   所以是否命中这个问题,后面交给了mCacheQueue这个队列,也就是丢给了缓存调度线程处理。  

in Computer Engineering - 23 Nov, 2015
by lzq8272587 - no comments

首先看一下,Cache是在哪里定义的: 在RequestQueue的构造函数里面,我们可以找到Cache的定义   而这个构造函数是在Volley里面使用的,如下图所示:   所以,本质上来看,这个Cache就是一个DiskBasedCache。而从代码里面看,这里的CacheDir就是使用这个framework的应用自己的那个Cache空间。   接下来我们看看这个DiskBasedCache是个什么东西     可以看到它实现了Cache这个接口。这个接口中会定义一个内部类Entry,所以Cache的方法都是围绕着这个Entry来执行的。(get,put等等)   回到DiskBasedCache,看看这个里面做了什么。   Volley本身对Cache的一些参数的定义,比如最大的Cache大小,以及不知道的一个什么系数。   这个·里面所谓的Cache本质上就是一个个文件。   来看看Cache里面的一些函数。   这个里面所有的Entry组成一个列表。列表里面本质上就是一个LinkedHashMap,里面装了String和CacheHeader的对应。注意这里的Entry本质上就是一个个的CacheHeader。   这个里面String就是每一个Cache里面的Entry的key值。(对应到Request就是url?)     接下来看看DiskBasedCache是怎么样实现Cache的那些接口的:     get函数,先根据key值跑到那个LinkedHashMap中去找对应的CacheHeader。   如果key对应的Cache不为空的话,则会根据key去找到一个对应的File。这里由key对应到Cache文件name是由一个hash决定的: 找到了这个文件之后,就会把文件里面的二进制数据读取出来,然后再利用这些二进制数据,填充CacheHeader,生成一个真正的Entry,然后返回。   总结一下get的流程,根据key找到CacheHeader,找到key对应的文件,读取出文件,然后用二进制内容填充CacheHeader,返回Entry。   这个CacheHeader中包含的内容有:(就是一些元数据)   初始化函数initialize,首先如果cache的文件夹不存在,那么创建文件夹。   如果文件夹存在了,并且已经存在Cache的内容了,那就对每一个文件内容,首先读出它的头部信息,然后把这个CacheHeader放到列表中去。 在这个CacheHeader里面做的事情就是,把这些乱七八糟的信息一个一个读出来,然后返回CacheHeader:   invalidate,让一个entry无效化,就是把它的过期时间设置成0   put方法,把一个entry和对应的key值写入到disk上。   put中,根据Entry生成CacheHeader,然后把CacheHeader以及对应的data写到文件中去,最后还要调用putEntry函数把CacheHeader写入到那个列表中去。   最后如果失败了,还需要抛出异常,并且把cache文件清理掉。     以上就是大致的OnDiskCache的分析了。所以从这里可以看到,基本上所有的操作都是需要直接跟Disk进行交流的。