blog of faywong

love coding, love life


  • 首页

  • 关于

  • 归档

  • 标签

fastjson for android名不副实

发表于 2017-06-03 |

今天在尝试优化json的序列化和反序列化。发现一个陷阱:
android自带的json比fastjson(fastjson-1.1.43)解析在9k(及以下)大小字符串输入下性能要高10倍,在解析19k大小字符串时性能高3倍。如下图所示:

三星Note 3:
note 3

一加1代:
note 3

详细数据如下:
json字符串体积: 6k,android终端:三星note3

09-22 11:42:55.234: D/faywong(7810): org.json.JSONObject consumes: 1ms to parse json
09-22 11:42:55.254: D/faywong(7810): com.alibaba.fastjson.JSONObject consumes: 15ms to parse json
json字符串体积: 9k,android终端:三星note3
09-22 11:11:45.944: D/faywong(26631): org.json.JSONObject consumes: 1ms to parse json
09-22 11:11:45.954: D/faywong(26631): com.alibaba.fastjson.JSONObject consumes: 15ms to parse json
json字符串体积: 19k,android终端:三星note3
09-22 11:48:15.844: D/faywong(11569): org.json.JSONObject consumes: 6ms to parse json
09-22 11:48:15.864: D/faywong(11569): com.alibaba.fastjson.JSONObject consumes: 19ms to parse json
json字符串体积: 6k,android终端:一加1代
09-22 11:39:55.304: D/faywong(12964): org.json.JSONObject consumes: 1ms to parse json
09-22 11:39:55.315: D/faywong(12964): com.alibaba.fastjson.JSONObject consumes: 11ms to parse json
json字符串体积: 9k,android终端:一加1代
09-22 11:30:06.378: D/faywong(11412): org.json.JSONObject consumes: 1ms to parse json
09-22 11:30:06.395: D/faywong(11412): com.alibaba.fastjson.JSONObject consumes: 17ms to parse json
json字符串体积: 19k,android终端:一加1代
09-22 11:53:30.551: D/faywong(14248): org.json.JSONObject consumes: 3ms to parse json
09-22 11:53:30.564: D/faywong(14248): com.alibaba.fastjson.JSONObject consumes: 13ms to parse json

总结下json序列化和反序列化的使用经验:
在能控制json序列化和反序列化的整个闭环中(比如服务端+客户端)使用fastjson之类的方案是有优势的;如果你只是在其中的一环,并不知道前边的json是谁以怎样的方式序列化/反序列化得来,建议你使用org.json版本,这样性能不至于很差。

Android L上webview crash的问题

发表于 2017-06-03 |

在android L上测试反馈使用WebApp时会出现如下crash:

F/libc ( 7555): Fatal signal 6 (SIGABRT) in tid 12577 (RenderThread)
I/DEBUG ( 182): *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
I/DEBUG ( 182): Build fingerprint: 'google/hammerhead/hammerhead:L/LPV79/1236599:user/release-keys'
I/DEBUG ( 182): Revision: '11'
I/DEBUG ( 182): pid: 7555, tid: 12577, name: RenderThread >>> com.eg.android.AlipayGphone <<<
I/DEBUG ( 182): signal 6 (SIGABRT), code 0 (SI_USER), fault addr --------

后来研究发现:

https://code.google.com/p/android-developer-preview/issues/detail?can=2&start=0&num=100&q=&colspec=ID%20Type%20Status%20Owner%20Summary&groupby=&sort=&id=950

上有人报告同一问题。

LPV79这个build为developer preview version.存在一些问题。

后来在正式版本中验证同一问题,不可复现。

让opengrok支持webservice

发表于 2017-06-03 |

最近需要使用opengrok作为webservice来提供代码交叉索引功能。

但是opengrok的release版本中还没有提供这个功能,原因在于这个提交没有被release。

所以只能自己编译最新的master分支代码并deploy。注意一点编译时需要1.8的jdk,tomcat server也需要1.8jdk来运行方能不出错。

在服务的url后边加上json?freetext=ThreadPoolExecutor之类的参数(其他参数请见我在Opengrok项目上的回复)便可查询到结果了。

针对这个问题本人贡献了一遍详细点的文档,请参阅。

浅谈NavigationBar高度的获取

发表于 2017-06-03 |

由于MEIZU手机的特殊性,对于NavigationBar的获取有特殊的讲究,有三个方面的因素:

1)MEIZU早期的系统(flyme os 5以下)存在smartbar,且可以设置智能隐藏;flyme os 5及以后smartbar被废弃,而使用android的NavigationBar

2)flymeos 5以下的系统有些存在系统dimen资源用于获取smartbar高度,有些则不再存在

3)是否智能隐藏SmartBar的开关并不与Android是否显示NavigationBar的开关为同一个

所以我今天研究了下,封装了一个方法:

public static int getNavigationBarHeight(Context context) {
final boolean isMeiZu = Build.MANUFACTURER.equals("Meizu");
final boolean autoHideSmartBar = Settings.System.getInt(context.getContentResolver(),
"mz_smartbar_auto_hide", 0) == 1;
if (isMeiZu) {
if (autoHideSmartBar) {
return 0;
} else {
try {
Class c = Class.forName("com.android.internal.R$dimen");
Object obj = c.newInstance();
Field field = c.getField("mz_action_button_min_height");
int height = Integer.parseInt(field.get(obj).toString());
return context.getResources().getDimensionPixelSize(height);
} catch (Throwable e) { // 不自动隐藏smartbar同时又没有smartbar高度字段供访问,取系统navigationbar的高度
return getNormalNavigationBarHeight(context);
}
}
} else {
return getNormalNavigationBarHeight(context);
}
}
protected static int getNormalNavigationBarHeight(final Context ctx) {
try {
final Resources res = ctx.getResources();
int rid = res.getIdentifier("config_showNavigationBar", "bool", "android");
if (rid > 0) {
boolean flag = res.getBoolean(rid);
if (flag) {
int resourceId = res.getIdentifier("navigation_bar_height", "dimen", "android");
if (resourceId > 0) {
return res.getDimensionPixelSize(resourceId);
}
}
}
} catch (Throwable e) {
LogCatLog.d("FBTools", "getNormalNavigationBarHeight() exception:" + e.getMessage());
}
return 0;
}

CheckBox on HM NOTE 1W,4.4.2,WIFI

发表于 2017-06-03 |

这台红米Note1W上会有系统资源(res/drawable/btn_check_holo_light.xml)找不到的问题。备忘下。

0x10800de
java.lang.NullPointerException
at android.graphics.drawable.DrawableContainer$DrawableContainerState.addChild(DrawableContainer.java:584)
at android.graphics.drawable.StateListDrawable$StateListState.addStateSet(StateListDrawable.java:291)
at android.graphics.drawable.StateListDrawable.inflate(StateListDrawable.java:189)
at android.graphics.drawable.Drawable.createFromXmlInner(Drawable.java:937)
at android.graphics.drawable.Drawable.createFromXml(Drawable.java:877)
at android.content.res.Resources.createFromXml(Resources.java:2821)
at android.content.res.Resources.loadDrawable(Resources.java:2191)
at android.content.res.Resources.loadDrawable(Resources.java:2103)
at android.content.res.TypedArray.getDrawable(TypedArray.java:602)
at android.widget.CompoundButton.<init>(CompoundButton.java:74)
at android.widget.CheckBox.<init>(CheckBox.java:68)
at android.widget.CheckBox.<init>(CheckBox.java:64)
at android.widget.CheckBox.<init>(CheckBox.java:60)

常见js引擎在Android上性能对比

发表于 2017-06-03 |

以如下裴波那契数列为测试代码:

function fibonacci(n)
{
if (n < 2) return n;
return fibonacci(n - 1) + fibonacci(n - 2);
}
print('fibonacci(20):' + fibonacci(20));

当输入为10时的结果(单位:ms):

27 12-09 14:13:04.371 4816 4816 E BirdNest: fibonacci(10):55

29 12-09 14:13:04.371 4816 4816 I faywong : benchmark(v8): 537

31 12-09 14:13:04.391 4816 4816 I BirdNest: fibonacci(10):55

32 12-09 14:13:04.391 4816 4816 I faywong : benchmark(duktape): 2336

当输入为20时的结果:

59 12-09 14:15:38.621 9196 9196 E BirdNest: fibonacci(20):6765

61 12-09 14:15:38.621 9196 9196 I faywong : benchmark(v8): 1583

63 12-09 14:15:38.841 9196 9196 I BirdNest: fibonacci(20):6765

64 12-09 14:15:38.841 9196 9196 I faywong : benchmark(duktape): 189211

大致汇总下:在输入为10时,v8性能是duktape的4倍;

在输入为20时,v8性能是duktape的119倍,jsc是duktape的接近100倍

Java JNI方法签名void类型

发表于 2017-06-03 |

在Java中经常会遇到通过外部语言扩展Java本身的需要,此时就需要使用到JNI这门技术(规范)。
在c/c++中,java层的数据类型需要转化成类型签名,如在google中被收录在最前边的官方文档中Table 3-2所示。

问题来了,那么void类型在c/c++用什么来映射呢。这份表格里边是没有的(对应java 7的JNI规范里边也没有)。今天在其他文档里边间接查到void类型的类型签名是V:

Type Chararacter
boolean Z
byte B
char C
double D
float F
int I
long J
object L
short S
void V
array [

比如Java方法:

public static void jsDebugDetachCallback(long udata)

的类型签名为(其中返回值类型V不可省略):

"(J)V"

在c中获取该方法id的方式为:

jsDebugDetachCallbackMethod = (*env)->GetStaticMethodID(env, someClz, "jsDebugDetachCallback", "(J)V");

Java JNI打印Java层异常

发表于 2017-06-03 |

在一些复杂的JNI调用中,比如JNI调用Java层的对象、Java层又调native方法,嵌套过多了,某一次调用产生的异常会在下一次调用JNI时被check出来,
这时候会产生如下日志:

01-13 21:22:43.247 24613-24613/com.somepkg A/art: art/runtime/check_jni.cc:65] JNI DETECTED ERROR IN APPLICATION: JNI NewByteArray called with pending exception 'java.lang.NullPointerException' thrown in unknown throw location
01-13 21:22:43.247 24613-24613/com.somepkg A/art: art/runtime/check_jni.cc:65] in call to NewByteArray

这种问题都是在Java代码中产生了异常,但是并不是所有case下都能一眼通过逻辑判断是哪行,这时候有个JNIEnv的方法能帮上我们大忙:

jthrowable thr = (*env)->ExceptionOccurred(env);
if (thr) {
(*env)->ExceptionDescribe(env);
(*env)->ExceptionClear(env);
}

c++版本:

void CheckException(JNIEnv* env) {
if (!HasException(env)) return;
// Exception has been found, might as well tell breakpad about it.
jthrowable java_throwable = env->ExceptionOccurred();
if (!java_throwable) {
// Do nothing but return false.
CHECK(false);
}
// Clear the pending exception, since a local reference is now held.
env->ExceptionDescribe();
env->ExceptionClear();
// Set the exception_string in BuildInfo so that breakpad can read it.
// RVO should avoid any extra copies of the exception string.
base::android::BuildInfo::GetInstance()->set_java_exception_info(
GetJavaExceptionInfo(env, java_throwable));
// Now, feel good about it and die.
CHECK(false);
}

在被checkjni侦测到异常的代码(比如上例中是NewByteArray)之前加上如上代码就可以将Java层的异常信息给优雅地打印出来,从而精准定位问题。

另一种定位此类问题的方式是打开Android设备的CheckJni功能。但是一般production设备上都不太容易实现。所以强力推荐以上方法。

那些年一起撸过的js引擎

发表于 2017-06-03 |

v8

支持jit,性能好,生态大,sdk 支持面向对象编程,上手容易,代码能够保持优雅;调试协议能被 chrome 支持;同时由于 JIT 会在运行时生成额外的代码段,在iOS平台上发布时容易受限

Duktape

性能一般,但代码体积小,使用标准c开发,方便集成和嵌入其他项目;支持ES5.1的标准,文档和社区不错,开发起来经常需要掰着手指在那里计算堆栈入了多少次,出了多少次,刚开始会有点折磨;其作者对于开发和维护非常积极,基本上要求的特性只要社区呼声较高,他都会考虑添加进去,个人开发能力极强

Duktape 使用方面的其他文章请见标签 Duktape

v7

v7 性能是 non-JIT 引擎中较好的,但是对于ES规范的覆盖上不够,成熟度一般

Rhino

rhino的爹是Mozilla,用java编写,可以在android上不用写JNI代码,容易集成,性能也不错,项目历史很悠久,成熟度很高(访问不了其官网的,请前往 Github),但是存在很多不适合在线上环境中使用的特点:

  • 在实际开发中,只要在java层bridge实现掉document、window之类对象后,这种对象的属性读写和方法调用都全部落到了java层,就在js域连document.xxx = yyy;这样的写法都不支持了,查完它的官方maillist都没办法实现。

  • 在js侧用toString, print, JSON.stringify之类的方法容易将java层所有的方法和字段给反射出来,会有安全隐患

没事为什么要撸那么多js引擎

移动互联网年代客户端开发最痛苦的在于动态性,需求总有要变的时候,这时候一门灵活、能通过网络下载到客户端就地执行的语言就很重要了。而目前最合适的那门语言便是javascript。

git pull --rebase

发表于 2017-06-03 |

有的同学在使用 git 时会不小心本地分支merge了远端的公共分支(通过 git pull ),我找了篇文章帮助大家学会 pull 的时候直接 rebase

http://gitready.com/advanced/2009/02/11/pull-with-rebase.html

其实很简单,对应的命令行是:

git pull --rebase <remote name> <branch name>

由于 merge 提交会湮灭掉一些原始 commit 导致 rebase 时带来混乱,同时 merge 提交的 commit message 本身没有什么额外有价值的信息,我个人关于 merge 提交的经验是:

如果你的角色是scm,代码集成者,多个分支隔离开发很长时间之后的合并建议使用merge;每天持续开发中的数量不多的提交都最好使用rebase,这样可以让提交记录尽量保持线性和整洁,进而方便代码的集成和追踪。

12345
faywong

faywong

blog of faywong, faywong

43 日志
16 标签
© 2017 faywong
由 Hexo 强力驱动
主题 - NexT.Muse