Remove Verbose Log In Production

android.util.Log is a very useful class to help developer debug their application. But when in production release. Any verbose log (Log.v) should be removed properly to prevent annoying user or leak some information.

You can simply commented those Log.v out or Using a ProGuard to remove any verbose log statements directly from the bytecode of your compiled JAR executable. This method is described in Christopher’s answer in the StackOverflow post

The easiest way is to run your compiled JAR through ProGuard before deployment, with a config like:

1
2
3
-assumenosideeffects class android.util.Log {
public static int v(...);
}

That will — aside from all the other ProGuard optimisations — remove any verbose log statements directly from the bytecode.

Comments

自己改的Brackets用的Monokai主题,参考Webstorm配色

因为之前被人推荐过Brackets,自己也试用了一下,总体感觉还是不错的。虽然跟现在正在试用Webstorm比起来要弱一些,不过对于不太严重依赖IDE的人来说,作为前端开发编辑器来说还是很出色的。

由于Brackets基于webkit写成的,所以可以按照开发web的方法来编写插件。而Themes插件则利用CodeMirror来编写主题。 不过里面自带的Monokai过于鲜亮,加上Brackets在Mac下有字体渲染bug(后面会解释如何修复这个问题),所以我决定按照Webstorm的monokai主题配色方案来修改一个Brackets的monokai主题。

不过修改起来才发现,Brackets的功能还是略弱,比如不能按照语言来定义颜色,不能区分很具体的变量用法(比如未使用的局部变量),在修改配色的时候首先照顾javascript,然后才是css,所以css最后效果和正常的monokai差距较大,是个遗憾之处。

总的来说修改之后的monokai主题有以下优点:

  • 和默认的monokai-dark-soda相比,对比度降低了一些,不那么刺眼了,虽然还是优点略亮。
  • 此外还解决了mac下字体显示的问题

效果预览:

JS代码效果:

JS代码效果

HTML代码效果:

HTML代码效果

CSS代码效果:

CSS代码效果

下载地址:

https://gist.github.com/lordfriend/858e369f8e9f7cd9861c

欢迎试用与反馈bug

使用方法:

  • 安装Brackets的Themes扩展:https://github.com/MiguelCastillo/Brackets-Themes
  • 然后打开扩展的文件夹(Help菜单->show Extensions Folder),进入user/themes/theme,然后将下载的monokai-webstorm.css放到里面,重启Brackets,在Themes菜单里选择monokai-webstorm主题即可。

如何修复mac下字体显示问题

mac下字体显示问题是因为brackets自己加了一个 -webkit-font-smoothing: antialiased 属性导致的。 这个属性本来是为了让windows下字体显示更平滑,不过 antialiased 这个值在mac下却导致了字体显示变成点阵一样的效果。 解决办法就是使用 subpixel-antialiased 值来代替默认值。

如果你要定义自己的主题。那么在 .CodeMirror里加上这样一句就可以了:

1
2
3
.CodeMirror {
-webkit-font-smoothing: subpixel-antialiased;
}
Comments

nya-bootstrap-select也许应该完全重写了

就在不久前,我还对这个插件很乐观,不过在解决了最近的两个bug之后,我觉得同angularjs自带的directive作斗争是一件不愉快的事情。

由于nya-bootstrap-select依赖bootstra-select这个jQuery插件,而该插件需要使用select标签来定义下拉选框。但Angular内部已经把select标签作为了一个directive,并且定义了一些列特殊行为。这些行为导致了目前各种冲突,其中一个问题就是,当我们使用ng-options来生成选项的时候。select directive会先生成一个?值的option作为默认选项,一开始为了保持美观和一致性,我删除了这个选项,但我发现angular内部似乎会错误的引用位置,导致当select的值由无变成确定值时,删除后的第一个实际option被删除。 这带来了严重的问题,最后不得已,我只能保留那个?的option,但这样很难看。看起来避免使用select标签才是根本解决之道。

Comments

在Node.js中使用promise摆脱回调金字塔

在开始谈论正题之前,我们先来看看下面一段代码:

1
2
3
4
5
6
7
8
9
step1(function (value1) {
step2(value1, function(value2) {
step3(value2, function(value3) {
step4(value3, function(value4) {
// Do something with value4
});
});
});
});

是不是感觉很恐怖,随着嵌套的回调函数增加,结尾会有大量的花括号和圆括号 }); 出现。

Promise

在javascript中实现异步最简单的方式是Callback。遗憾的是,这种编程方式牺牲了控制流,同时你也不能throw new Error()并在外部捕获异常。 Promise的出现解决了这两个需求,又保持了javascript异步的优势,不同于Fiber这种多线程的实现方式,Promise只是一种编程方式的变化。而无须在底层改变。

CommonJS的规范提到了多种Promise,我们只介绍其中一种的实现q (https://github.com/kriskowal/q)

我们在这里不讲解抽象的Promise规范,这多半是实现者应该关心的,我们直接从示例入手,如果你有兴趣,可以参见Promise/A+

q的核心是一个promise对象的then方法,他接受两个回调方法,一个promise被定义之后有3种状态,pending(过渡状态),fullfilled(完成状态),rejected(错误状态)。一个promise只能是这三种状态种的一种,而无法是他们的混合状态。

  • pending状态可以理解为promise还没有获得确定值,就相当于一个任务还没有完成。
  • fullfilled状态可以理解为完成并返回结果。这时then(onFullfilled, onRejected)的onFullfilled方法会被调用。
  • rejected状态可以理解为错误,并结束。返回错误。这时then(onFullfilled, onRejected)的onRejected方法会被调用。

了解了核心思想后,我们来看一个例子,在这个例子中我们先读取一个json文本文件,然后将其解析成javascript对象,最后这个对象进行修改再保存回去。 按照传统的callback写法,有如下代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
fs.readFile('example.json', function(err, data){
if(err) {
console.log(err):
} else {
try {
var obj = JSON.parse(data);
obj.prop = 'something new';
fs.writeFile('example.json', JSON.stringify(obj), function(error){
if(err) {
console.log(error);
} else {
console.log('success');
}
});
} catch(e) {
console.log(e);
}

}
});

在这个例子中,控制流被切割成多个部分(每次异步都要处理一次错误),并且 JSON.parse 的错误必须在内部捕获,但却不能跑到外部。因为在异步回调中无法抛出异常。 现在当我们使用promise的时候,假设我们有个能够返回一个 promise 对象的 readFilewriteFile 方法。那么上面的代码就可以变成如下形式:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
var promise = readFile();
promise
.then(function(data){
// we don't need to catch error. in other words. we can throw error in this callback.
var obj = JSON.parse(data);
obj.prop = 'something new';
// return a promise. so we can chain the then() method.
return writeFile(JSON.stringify(obj));
})
.then(function(){
console.log('success');
}, function(err){
// all error will fall down here.
console.log(err);
});

上面的例子中,我们首先从 readFile() 方法里获得了一个返回的 promise 对象,然后使用这个对象的 then() 方法。在这里,我们只传入了一个 onFullfilled 回调方法,根据Promise/A+的文档。then() 一定会返回一个 promise 对象,所以我们又连接了一个 then() ,由于这个 then() 是最后一个,所以我们需要在这里提供一个 onRejected() 回调方法来处理所有的错误。在第一个 onFullfilled() 回调方法中,我们返回了一个 promise ,这个 promise 的处理结果将会在下一个 then()onFullfilled() 方法中取得。

这段代码执行的时候,当任意位置抛出异常的时候,最后一个then的 onRejected 回调会被执行。否则一切按照从上至下的顺序执行,整个控制流都十分简洁明了。

因为 then() 方法必须返回一个promise,实际上我们也可以结合同步方法返回一个已经fullfilled的promise 比如下面这个例子

1
2
3
4
5
6
7
8
9
10
11
var promise = readFile();
promise
.then(function(data){
return JSON.parse(data);
})
.then(function(obj){
obj.prop = 'something new';
console.log(obj);
},function(err){
console.log(err);
});

上面例子中第二个then会在第一个then返回之后被执行,因为第一个then返回的时候,由于JSON.parse是同步方法,所以返回了一个值,这个值会被包装成一个fullfilled的promise.

制作promise的API

上面例子中我们知道了如何使用promise提供的核心方法 then() 。但是对于平时使用的fs等异步的库我们要怎么才能利用promise呢。 在q的文档中介绍了q-io库,里面将常用的io方法都用promise的模式包装了一遍,在实际使用中,你可以使用那个库的方法。不过我们在这里简单的对fs进行包装,让其支持promise,这样以后遇到任何异步方法,你都可以将其转化。

首先定义改一个readFile方法,返回promise,这里利用了 Qdefer() 方法,创建一个 deferred 对象。这个对象有连个关键的方法 resolvereject() 。当resolve(value)执行之后,promise变成fullfilled状态,fullfilled的值就是value 当 reject(reason) 执行之后,promise变成了rejected状态,reason会被传递到onRejected()方法。

1
2
3
4
5
6
7
8
9
10
11
12
var Q = require('q');
function readFile(callback){
var deferred = Q.defer();
fs.readFile('example.json', function(err, data){
if(err){
deferred.reject(err);
} else {
deferred.resolve(data);
}
});
return deferred.promise.nodeify(callback);
}

注意到这里面我们依然提供了一个callback,用于提供一些需要callback的场合的兼容性,我们利用 promise 对象的nodeify方法来调用这个callback,这个callback可以为undefined。

另外一点需要注意的是,一个promise状态改变之后,不能再次改变,所以,你只能调用一次reject或resolve。

有了这个API,我们便可以像前面例子里那样,使用promise来执行读取文件的操作了。其他异步回调转化成返回promise的异步方法基本上都可以参照这个模式来做。

一次处理多个promise的

如果你有几个异步方法,他们都返回promise,并且当这些方法都处理完之后,你才能进行下一步,Q提供了一个all()方法来帮助你消化多个promise。

1
2
3
4
5
6
7
8
9
10
11
Q.all([
readFile('file1.json'),
readFile('file2.json')
])
.then(function(dataArray){
for(var i = 0; i < dataArray.length; i++){
console.log(dataArray[i]);
}
}, function(err){
console.log(err);
});

在这里例子里,我们将一个promise数组传给 all() all返回一个promise,当数组里面的所有promise都为fullfilled状态时,我们的then()方法才会被调用。这时fullfilled值是一个数组,每个元素对应前面promise的fullfilled值。 当任意一个promise变成rejected状态的时候,all的promise会立即reject而不等其他的完成。

利用promise改写你的项目

最佳的理解方法便是事件,你可以把一些nodejs的基本异步方法包装成promise,这样你就可以在整个程序的多个地方使用这些方法。并且让你的程序的异步代码看起来更整洁,更容易理解。 阅读 Q的文档 了解更多的API和方法。并在程序中使用这些方法,使你的代码更优美,逻辑更健壮。 阅读 Promise/A+ 。了解promise原理。

Comments

开始使用nya-bootstrap-select

好吧,这个post是个广告,如果你是一名web前端开发者,使用AngularJS,bootstrap和jquery。那么我在这里向你推荐我最近发布的一个开源项目:nya-bootstrap-select

nya-bootstrap-select 是一个对bootstrap-select的包装,让这个功能强大的jquery插件可以用angularjs特有的风格在angularjs程序中使用。

依赖: AngularJS 1.0+(这个是当然的) bootstrap-select 1.3+ bootstrap css (支持2.x和3.x)

安装: 推荐使用bower来安装,可以帮助你自动处理依赖关系。

1
bower install nya-bootstrap-select

将src/nya-bootstrap-select.js加入到你的页面里

1
<script src="bower_components/nya-bootstrap-select/src/nya-bootstrap-select.js"></script>

将 nya.bootstrap.select作为angular app的依赖

1
angular.module('yourApp', ['nya.bootstrap.select']);

现在可以开始使用了。本文就只列举一个例子,更多例子请参考文档 http://nya.io/nya-bootstrap-select/

在select标签里,加入class nya-selectpicker 也可以作为属性加入。 然后将你的scope变量绑定到ng-model上,这样你可以获取到选择的值。 假设你的$scope.myOptions就是选项的条件

1
2
3
<select class="nya-selectpicker" data-container="body" ng-model="myModel" ng-options="c.value for c in myOptions">

</select>

Comments
NEWER POSTS OLDER POSTS