facebooktwitteryoutube
Welcome! Research Projects Android Engineering Linux Engineering Trip Gallery About This Site
Android
in Computer Engineering - 27 May, 2016
by lzq8272587 - no comments

手机上现在修图的软件很多,其中滤镜这方面做得最好的,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,具体参考: SS使用方法 ios需要自己找VPN或者找个能穿的AP,现在ios9.0以上好像不支持SS。 Step 2: 登陆VSCO。     这里使用的账号密码: VSCO账号   PPFFFJ@SINA.COM   密码   12345678   科科!        

in Computer Engineering - 02 Dec, 2015
by lzq8272587 - no comments

我们都知道,在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    

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