Tag Archives: Android

VSCO滤镜分享

手机上现在修图的软件很多,其中滤镜这方面做得最好的,VSCO算一个。现在最新版本的VSCO集成了很多很好的滤镜。效果大概是这样的:

 

但是正版的VSCO购买这些滤镜的话很贵。(不过淘宝要便宜很多。)

下面分享一个免费使用滤镜的方法。

 

###############

2016-05-28最新更新:之前写的原有方法已经失效,现在提供最新的Android版本的更新方法

Step1: 下载TiBackup并且安装,7.3版本的钛备份:http://pan.baidu.com/s/1eS6WgWa

Step2: 下载包括了所有VSCO滤镜的备份文件,传送门:http://pan.baidu.com/s/1c1AhLSk

注意,这个里面有个Backup文件夹,里面有3个文件。

Step3: 将Backup文件夹放到手机的sdcard目录下

Step4:启动TiBackup,注意这里需要root权限。将备份目录设置为sdcard下的这个Backup文件夹。

Step5:重启钛备份,在备份,恢复一栏就可以看到备份文件了。点击,恢复即可。

记住恢复的时候,选择恢复App+Data。

Step6,:这时候你会发现VSCO已经安装进去了。选择照片,这个时候所有的滤镜就应该已经可以用了。

OK!

###############

 

#下面为2016-05-28之前的方法,现在已经失效#

Step 1:

让你的手机能够穿墙。Android可以使用SS,具体参考:

http://www.lzq8272587.cn/2016/05/27/ss%E4%BD%BF%E7%94%A8%E6%96%B9%E6%B3%95/

ios需要自己找VPN或者找个能穿的AP,现在ios9.0以上好像不支持SS。

Step 2:

登陆VSCO。

 

 

这里使用的账号密码: VSCO账号   PPFFFJ@SINA.COM   密码   12345678

 

科科!

 

 

 

 

Android 6.0新特性:新的Permission模型

我们都知道,在Android上的应用有”权限“这一说法。

具体而言,每次我们安装好一个应用之后,系统都会弹出一个框框,说这个应用将会访问以下权限,是不是要允许?

然后我们就点允许或者不允许,然后确定就是了。

在代码层面,这些权限是通过Manifest文件制定的。就像下面这样:

这些权限,称之为install permission,就是程序安装的时候设定的权限,之后会一直允许。

 

在Android 6.0中Google提出了新的授权模型,叫做real-time permission。简单来说,就是不仅要在安装的时候授权,还要在运行程序的时候,当app要使用某个权限的时候,弹出一个框框让用户自己去选择是否授权。

 

举例来说,比如要访问磁盘读写了,就会弹出一个框框,说现在要访问设备上的资料了,允不允许。

 

但是,并不是所有的permission都需要这样授权。有一些permission被称作危险的权限,例如读写磁盘,这类权限是需要运行时询问的;另一些权限,如Internet访问,被称作安全权限,只要安装的时候允许了就可以了。

对于危险权限的设定如下图:

另外要注意一点,如果对于一个ground的某个权限授权了,就意味着会对这个group里面所有的权限授权。

 

比如我们授权读,那么就顺便授予写权限了。

 

那么如何在代码里面实现这个功能?

我们需要在Activity里面动态的申请权限,并且在回调函数里面执行后续的工作。

例如我们写一个这个函数:

 

然后重写回调函数:

 

 

这样就会申请disk的读写操作,并且在写权限被授予之后,创建一个MyLogger,这个是我自定义的一个日志文件。

这样,运行的时候就会弹出一个框框,不过是在Android 6.0场景下:

参考:http://www.captechconsulting.com/blogs/runtime-permissions-best-practices-and-how-to-gracefully-handle-permission-removal

 

 

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进行交流的。