groovy 给每个 String
和 bytes[]
增加 md5 方法
比如
"hello".md5()
new File("test.zip").getBytes().md5()
没错,就是我
groovy 给每个 String
和 bytes[]
增加 md5 方法
比如
"hello".md5()
new File("test.zip").getBytes().md5()
因为只有 iOS 13
才开始支持键盘的浮动模式。如果不开启浮动模式的话,其实也可以,前提你能忍,就是会像下图那样占用半个屏幕
这样其实也有一个问题,就是容易误触。
开启方法很简单,看到大键盘,两个手指捏一下即可
然后我们就可以用笔愉快的玩耍了
讯飞,百度,搜狗都对比过,输入体验最好的还是苹 原生体验最好,不信可以自己体验一下。
ipad是支持120帧率的,这个东西就是为了让你在用笔输入的时候准备的,这样你就看不到笔输入带来的延时,但是也因为使用了高帧率所以用电也增加了很多
手写是没有笔输入快的,这点是肯定的。
公司因为扩展业务,新建了一个 android 项目,但是这个安卓项目明明比我们的主项目代码量少那么多,但是编译时间却比我们主项目时间长非常多。让我每次编译的时候都思考人生。
我们主项目是一个 80M 大小的App,dex 包都有 30M
,更改一行代码的时间实际上只需要 30s
不到的时间,但是新项目 apk 大小都没有10M
编译时间却要 一分多钟,有时候还需要 3分钟。
在 gradle
4.3 版本之后,gradle
提供了一个新的方法去扫描编译过程,就是
buildScan
功能,简单一点讲就是这个东西会把task
运行过程很多东西记录下来,图形化展示这些数据,让你更好的发现问题所在。
七牛只是支持使用 qshell get
方法下载一张图片,如果想批量下载,必须配置域名。贫穷的我发了工单也没解决怎么配置域名,只能写个脚本下载所有的图片。
主要用到这两条命令
// 列出 bucket 中所有的
qshell listbucket
// 获取单张图片
qshell get
因为我不是很熟悉shell,只能用 groovy 写个脚本,脚本如下
package com.hangox.pocketmonery
def location = new File("/Users/hangox/Downloads/qn")
def cmd = "/Users/hangox/Downloads/qn/qshell "
"$cmd listbucket wordpress".execute().text.split("\n").each { line ->
line.split("\t")[0].find(".+(png|jpg|gif)")?.with {
println it
println "$cmd get wordpress $it".execute(null,location).text
}
}
其中 location 为 qshell 的地址
手段 | 全量构建 | Java增量构建 | 资源增量构建 |
---|---|---|---|
升级 android gradle tools 到3.0 | -15s(-25%) | -10(-38%) | -2.5(-16%) |
避免使用遗留的Multidex | -5.5s(-12%) | -8(53%) | same |
debug 环境关闭multi-APK | -4.8s(-12%) | -0.5s(-6%) | -3s(-26%) |
设置包含最少的资源 | -6s(-17%) | -1.5s(-24%) | -2s(21%) |
关闭 png crunching | -9s(-33%) | same | same |
使用Instance Run | +7s(+37%) | -3s(-54%) | -3s(-42%) |
避免不注意的改变 | - | - | - |
不要使用动态版本号 | - | - | - |
注意分配 gradle 内存 | - | - | - |
开启 Gradle Caching | -7s(-25%) | same | +0.5s(+12%) |
使用implementation 或者 api 代替 compile |
- | - | - |
以上优化方案基于android gradle tools 3.0-alpha
- 9 个模块,包括Wear
- 500 多个Java文件
- 1700 个XML 文件,3500张PNG
- Multi-dex
- 没有 annotation processors
- APK大小接近60MB
这个项目可以在Google Github 帐号中找到
启动模式分为4种,分别为
就是默认的模式,启动多少个就是多少个
SingleTop 需要这样理解,SingleOnTop,当栈顶是我的时候,就不再创建新的实例。
例如,ABCD,启动D,还是ABCD。如果是ABDC,启动D,最后就变成ABDCD。
SingleOnTask的意思,我在这个任务栈是唯一的。需要注意的是,这货启动是默认自带clearTop效果的,也就是会把在它之后的Activity都清楚掉。
例如,任务栈中有ABDC,启动D,将会变成ABD,C将会被自动推出。
这个可以看做是SingleTask加强版,使用这个属性的Activity,将会被单独放在一个任务栈中,然后这个Activity在进程中都是唯一个的
Bitmap.Config | |
---|---|
ALPHA_8 |
每个像素存储为单透明(alpha)通道。其实就是保存透明度而已 |
ARGB_4444 |
已经废弃的格式,推荐使用ARGB_8888 |
ARGB_8888 |
每个像素存储在4个Byte上,其实就是ARGB分别占用8bit的意思 |
HARDWARE |
特殊配置,当位图只存储在图形内存中。 |
RGBA_F16 |
每个像素存储在8个Byte上,这个我不太看得懂,就是RGBA 格式保存,每一个占用16bit,F并不知道是什么意思 |
RGBA_F16 |
每个像素存储在8个Byte上,这个我不太看得懂,就是RGBA 格式保存,每一个占用16bit,F并不知道是什么意思 |
RGB_565 |
每个像素存储在2个Byte上,只有RGB通道被编码:红色以5位精度(32个可能值)存储,绿色以6位精度存储(64个可能值),蓝色存储5位精确。 |
例:
选择的是ARGB_8888
分辨率为 100*100 的位图。
占用的内存应该是
100 * 100 * 4 = 40000 Byte = 39kB
只要记住符号上表示的是bit就很容易计算Bitmap在内存中占用的大小了
各大主机提供商不太一样,这段靠自己吧
执行以下bash
或者直接在命令行上敲
curl -o- -L https://gist.githubusercontent.com/hangox/a9b977a9c026629101c38d5e6a2b4e76/raw/d97e16123218c068c024a12019e1a403ef47981f/update-kernel-for-centos7.sh | bash
执行完成脚本之后将会重启系统,耐心等候重启就好了
participant 编辑器 as B
participant MetaWeblogApi as M
participant 博客Git地址 as A
participant 博客 as E
B->M: 发送Mardown格式的文本
note left of M: git pull
M->B: 返回BlogId确认提交成功
note right of M: 生成Hexo 的Markdown
M->A: 提交到
note right of M: 调用Hexo 生成
M->E: deploy 到博客地址
Metaweblog的实现主要是参考这个开源项目,这个源码写得很直白,非常好懂。简单一点解释Metaweblog Api(后面简称M),和M对接的url其实只有一个,然后把访问不同的方法名封装在一个XML里面,通过解析这个xml,我们就能够知道这个请求到底需要访问什么方法。这个和我们一般的Api都不太一样,我在这个地方迷茫了好久。知道这个之后剩下的就是xml解析的问题了
需要解析的xml
<?xml version="1.0"?>
<methodCall>
<methodName>blogger.getUsersBlogs</methodName>
<params>
<param>
<value>
<string></string>
</value>
</param>
<param>
<value>
<string>12</string>
</value>
</param>
<param>
<value>
<string>12</string>
</value>
</param>
</params>
</methodCall>
解析使用的groovy代码
methodCall = new XmlParser().parseText(text)
methodName = methodCall.methodName.text()
params = methodCall.params.param
mUserAccount = params[1].text()
mUserPassword = params[2].text()
使用groovy 解析的话就好像使用js一样,直接使用xml字段名就能获取到值,非常方便
JGit 是个Java实现的Git操作库,可以很方便的操作各种Git操作,我主要使用到以下几个方法
mGit = Git.cloneRepository()
.setURI(url)
.setDirectory(new File(mGitConfig.repositoryLocation))
.setTransportConfigCallback(mTransportConfigCallback)
.setBranch('master')
.setCloneSubmodules(true)
.setTimeout(30000)
.call()
def git = git()
git.pull().setTransportConfigCallback(mTransportConfigCallback).call()
git.submoduleUpdate().call()
//如果不是干净的就合并
if (!git.status().call().clean) {
git.add().addFilepattern('.').call()
git.commit().setMessage(buildCommitMessage(git.status().call())).call()
def pushResult = git().push()
.setPushAll()
.setTransportConfigCallback(mTransportConfigCallback)
.call()
因为使用的
git
url 提交,需要ssh
key ,需要在~/.ssh/
生成密钥
我重新拓展了groovy String 中的execute,使得每次执行命令都在博客的目录下
String.metaClass.execute {
if (new File(mConfigBean.repositoryLocation).exists()){
delegate.execute(null,new File(mConfigBean.repositoryLocation))
}else{
delegate.execute(null,new File('/'))
}
}
但是我不建议这样做,这样写是方便了,但是会造成在别的地方执行execute会失败。建议是重新拓展一个方法。
因为使用groovy,我就可以这样执行hexo
的命令了
初始化hexo
'npm install '.execute().text
生成和推送
'hexo generate -d'.execute()
Docker 这个过程最蛋疼!!
贴出构建Docker的Dockerfile
FROM java:8u111-jdk
MAINTAINER <Hangox,liang.hanguang93@gmail.com>
RUN apt-get update -y --no-install-recommends
RUN apt-get install -y --no-install-recommends git-core curl
RUN curl -sL https://deb.nodesource.com/setup_6.x | bash -
RUN apt-get install -y --no-install-recommends nodejs
RUN npm install hexo-cli -g
COPY . /app
WORKDIR /app
RUN ./gradlew assemble
RUN mv build/libs/MetaweblogApi-1.0.jar app.jar
ENV GIT_NAME HexoMetaApi
ENV GIT_EMAIL your@email.com
ENV ACCOUNT account
ENV PASSWORD password
ENV REPOSITORY ''
#
#VOLUME ["root/.ssh", "/hexo"]
#EXPOSE 9000
CMD java -jar app.jar \
--blog.account=$ACCOUNT \
--blog.password=$PASSWORD \
--git.repository=$REPOSITORY \
--git.name=$GIT_NAME \
--git.email=$GIT_EMAIL
SpringBoot 这个框架简化了很多SpringMVC的配置,搭配Groovy开发非常舒服。
Metaweblog api 的实现还在于很粗糙的程度,目前也只是实现了,newPost
和editPost
两个简单的操作,争取实现更多的操作。Docker构建的话,还是希望自己以后不要在智商掉线了。Docker的相关信息也是时候要总结一下了。
问题来源:two sum
给定一个整数数组,返回两个数字的索引,使它们相加到一个特定的目标。 您可以假设每个输入都只有一个解决方案, 而您可能不会使用相同的元素两次。
Example:
Given nums = [2, 7, 11, 15], target = 9,
Because nums[0] + nums[1] = 2 + 7 = 9,
return [0, 1].
直接遍历所有的组合,求出问题的解
public int[] twoSum(int[] nums, int target) {
for (int i = 0; i < nums.length; i++) {
for (int j = i + 1; j < nums.length; j++) {
if (target == nums[j] + nums[i]) {
return new int[] { i, j };
}
}
}
throw new IllegalArgumentException("No two sum solution");
}
分析:
这是最简单的解法。两个嵌套循环,时间复杂度为O(n2)。空间复杂度为O(1)
用目标减去加数1,得到加数2,再在数组中寻找。
public int[] twoSum(int[] nums, int target) {
for (int i = 0; i < nums.length; i++) {
for (int j = i + 1; j < nums.length; j++) {
if (target - nums[i] == nums[i]) {
return new int[] { i, j };
}
}
}
throw new IllegalArgumentException("No two sum solution");
}
分析
没错,就是和第一解法时间空间复杂度都是一样的😂。没事,我们可以优化一下的。
在实现一中,我们的瓶颈主要是在如何根据值去找到索引的问题上,所以这里我们使用Map去优化根据值去寻找位置的瓶颈
public int[] twoSum(int[] nums, int target) {
Map<Integer, Integer> map = new HashMap<>();
for (int i = 0; i < nums.length; i++) {
map.put(nums[i], i);
}
for (int i = 0; i < nums.length; i++) {
int complement = target - nums[i];
if (map.containsKey(complement) && map.get(complement) != i) {
return new int[] { i, map.get(complement) };
}
}
throw new IllegalArgumentException("No two sum solution");
}
分析:
我们使用一个循环把数据与位置建立索引,然后获取的时候直接从map中直接获取,这样就可以避免了两个嵌套的循环了,是的时间复杂度为O(n) ,空间复杂度为O(1).
note: 在算法中,我们不考虑map这些数据结构具体实现使用的时间
实现2中使用了两个循环,能不能把第一个循环也去掉呢?答案是可以的。一边循环,一边插入map,然后获取这个差值是否已经加入到map中。
public int[] twoSum(int[] nums, int target) {
Map<Integer, Integer> map = new HashMap<>();
for (int i = 0; i < nums.length; i++) {
int complement = target - nums[i];
if (map.containsKey(complement)) {
return new int[] { map.get(complement), i };
}
map.put(nums[i], i);
}
throw new IllegalArgumentException("No two sum solution");
}
分析:
这个复杂度和实现2是一样的,时间为O(n),空间为O(n),但细看还是有差别的,这个算法的实际上比实现2的快了1倍