Monthly Archives: November 2015

IETF横滨行

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块钱一个烤串的那家店,可是中午时间不提供,就吃了一个麻油拉面,然后就去赶飞机了!!

机场又在免税店买了几个吃的,买了好多巧克力,然后就上飞机了。

上图时间~先上证件照!

_DSC6324

_DSC6414

_DSC6401

_DSC6376

_DSC6375

_DSC6346

_DSC6344

_DSC6333

_DSC6332

_DSC6329

_DSC6328

 

下雪啦!

下雪啦!

难得下一次雪,我决定从寝室绕到二校门,然后再走到实验室去。

 

这个是我们寝室楼下,自行车都没地方塞了:
_DSC6468

 

 

 

 

 

 

 

 

 

 

 

走出寝室之后,第一个十字路口:

 

_DSC6469

听涛食堂门口:

_DSC6470

路边上的一条小路:

 

_DSC6472

 

 

踩雪太爽了。。。。

 

 

_DSC6473 _DSC6474 _DSC6475

 

其实很多树叶子现在都还没有掉光,但是就已经下了两场雪了:

 

_DSC6480

 

这些树叶子都还是绿的,不过过几天估计就要掉光了:

 

_DSC6481 _DSC6485 _DSC6486 _DSC6487

 

西操场:

 

_DSC6494

_DSC6501 _DSC6502 _DSC6503 _DSC6506

 

最喜欢这几张照片:

 

_DSC6510 _DSC6518 _DSC6522 _DSC6526 _DSC6528 _DSC6529 _DSC6530 _DSC6533 _DSC6537 _DSC6542

 

绕到二校门来了,可是全都是游客,随手拍一张好了:

 

_DSC6547

 

绕过二校门,走到大道上来,往前走就是主楼了:

 

_DSC6555 _DSC6557 _DSC6560

 

路上全部都是化掉的积雪,但是又结冰了,果然不能骑车:

_DSC6565 _DSC6567

 

这么冷的天还在训练!!

_DSC6574

Android AIDL研究,Service的回调

回调的基本思路,创建一个回调接口,然后把这个回调接口以参数的形势在远程调用的时候传递过去。

 

例子:假如设定了

其中,E3RemoteService是远程Service暴露出的接口,而ICallBack是要传递给Service的接口参数

 

CallBack的定义:

 

 

在Service的接口中,创建函数,记住要把参数传递过去:

 

在Service里面,实现这两个方法

这样,Service就会回调ICallback里面的方法了。

 

所以,我们还需要在client里面实现这个方法:

 

Android AIDL研究,基本AIDL步骤

首先实现基本数据类型的传递,这里我们将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里面创建过滤器:

这样就可以使用默认数据类型进行传递了。

 

 

 

Volley源码学习之回调类ExecutorDeliver和Delivery的分析

最后,我们看一下这个回调的类是怎么处理回调请求的。
这个ExecutorDelivery里面有两个函数是经常使用的:

重点看一下第二个
这里的Poster是一个executor类,

他干的事情就是执行runnable里面的东西。
所以,postResponse做的事情,就是把request先标记一下,然后执行runnable的事情。好吧我们就看看runnable里面在干嘛

注意,这个runnable里面居然还有一个runnable,这个内嵌的runnable是执行完这个runnable之后执行的runnable。好绕口。
看代码就理解了:

所以,这里调用了request的deliverResponse函数!!!这个就是用户自己定义的了!
然后,如果这个request不是一个中间结果,就可以调用它的finish函数了,最后会把这个request从队列中清理掉。
至此,分析完了整个delivery类。

Volley源码学习之关于NetworkDispatcher的分析

接下来看看Network调度器都在干嘛。
这里就没有Cache队列的,就只有一个队列了

重点关注一下run函数里面干了什么。
同样的,有一个巨大的while循环,从network队列里面取出request进行处理

执行这个request,把结果拿回来

如果这个response根本就没有修改,或者已经交付了,那就不传递一个一样的response了

看看这个finish函数里面做了什么事情:

调用一个Request的finish,其实就是让RequestQueue把这个request删掉。

然后,要把接收到的response转化,并且如果需要的话应该更新cache

最后,依然是调用传递函数,把response返回给application,结束

至此,结束对网络调度器的分析

Volley源码学习之关于CacheDispatcher的分析

下一步,我们分析一下缓存调度线程。

 

先看看这个调度器里面有什么,可以确定的是这个调度器是一个线程

 

里面有两个奇怪的队列,不知道是什么东西。他们的命名跟在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 the original data source.
*/
public boolean refreshNeeded() {

return this .softTtl < System. currentTimeMillis() ;

}

 

注意这里有一个硬性ttl和一个软ttl判断entry是否过期。

 

如果是两个判断都没有过期,就会直接把response丢给回调的那个类,让回调的类统一处理。

如果硬判断没过期,软判断过期,用了一个非常奇怪的方法处理,它一方面把response返回,另一方面还要把这个request丢给网络调度器。

 

(过期,刷新,这些都是HTTP里面的字段)

 

 

然后,刷新response的操作之后:

这个intermediate是说明这个response不是最新的,还有更新的会到达。

 

然后:

 

参考一下这个接口的说明:

 

所以,这里干的事情就是,把把response交还给应用,并且还要把request丢给network队列。

 

至此,Cache调度器分析完毕。

 

Volley源码学习之RequestQueue中核心函数add()的分析

然后我们回到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这个队列,也就是丢给了缓存调度线程处理。

 

Volley源码学习之关于Cache类,DiskBasedCache类的分析

首先看一下,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进行交流的。