标签 android 下的文章

尽管现在诞生的高级语言里边有了什么STM,协程,绿程的概念,但写代码总会遇到现实(商业级平台都不会用很新的东西)的多线程的问题。

比如有时候你需要同步的获取在另一个线程执行的代码的结果,在android里这种场景下ConditionVariable就非常好用了。

```java
if (Looper.myLooper() != Looper.getMainLooper()) {

final ConditionVariable completed = new ConditionVariable(); // 构造一个条件变量

view.runOnUiThread(new Runnable() {

@Override
public void run() {
try {
doSomeThingInUiThread(); // 将期望在另外线程做的事post出去
} finally { // finally很重要,防止运行时异常远跳转将ConditionVariable忘了open
completed.open(); // 事情办完了,notify到另外线程
}
}
});
completed.block(TIMEOUT_WAIT_UI); // 等着另外线程做的事完成,同时支持设置超时
} else {
doSomeThingInUiThread();
}
```

当然了以上是很简单的一个场景,使用ConditionVariable非常方便且够用。对于复杂的多线程之间的协同还是使用标准的条件变量结合lock + while 循环检查。

在一些新语言中有非常丰富的并发编程原语(future, delay, promise),特别是协程让我们用代码自主的确定代码流之间的协作关系而不是被动的作为OS调度器的奴隶,来支撑一些并行需求。

由Mozilla开源的崩溃统计项目Socorro非常适合针对客户端的崩溃闪退、日志/堆栈上报,服务端进行采集、处理、分析、报告。

客户端的工作由类库[Breakpad](https://wiki.mozilla.org/Breakpad)完成。

服务端的工作由[Socorro](https://github.com/mozilla/socorro/)完成。

代码托管在[github](https://github.com/mozilla/socorro).

看这个提交和发布的数目,迭代程度还是挺深的。

这样针对移动开发,就不必重复造轮子了。

最近遇到了一位很热心的用户,反映C208B011版本的Huawei X1(想想MediaPad系列本人几年前在华为也曾参与研发)上无法使用一个WebApp。debug后发现在该系统的WebView内的JS里无法使用console.log()导致严重的java-js之间的通信机制缺失。特意为其创建一个BridgePolicy类来维护之,若是该款机器,则切换至window.alert来实现java-js之间的通信,否则则使用console.log()。

测试发现该机器的C208B009版本的WebView并无此问题(且与硬件,基带是3G或4G均无关)。

第一次face to face面对我们的用户感触颇多,一个产品对于他们家里的人是如此重要,一个WebApp不能用又如此大程度的影响到他,因为存在这个问题甚至想换掉这部手机。

用户对于解决问题的意愿极强。他(40岁左右的大叔)多次上Huawei X1论坛与其他用户交流看法和规律,寻求解决方案,为此去了解该机器的CPU,基带,ROM版本......。

幸运的是,他们使用的是我们这个首屈一指的互联网公司的产品,遇到了我们这样的团队,得以面对面的反映他遇到的问题——没有抱怨,而是尽可能为我们提供他“调查”,“摸索”出来的规律。

android在Java层对 utf 编码是支持得很好了,非常全面;但当你从事一些c/c++工程的开发时可就没有这么幸运了。
笔者最近在使用v8 javascript 引擎时便碰到了一个问题:

有些用户在昵称中使用了 emoji 表情,v8 引擎内部默认会使用utf-16编码,通过 v8 API 取到这个值之后转为utf-8的字符串,进而通过 JNI 的 API JNIEnv->NewStringUTF 往 Java 传递时会被系统的 checkJNI 给拦截住而报错。原因在为了让字符串中不包含任何 null 字节,JNI 以及 Java VM 内部都是使用的Modified UTF-8格式来编码字符串。

后来找到一个办法可以通过将字符串转为 utf-16 编码后传递给 JNI API JNIEnv->NewString 解决之:

  1. 使用 v8 API 将 utf-8 的字符串转为 utf-16 编码

    size_t utf8_to_utf16(const char *src, const uint16_t **dest) {
     if (src == NULL || dest == NULL) {
         return 0;
     }
     Isolate::Scope scope(Isolate::GetCurrent());
     HandleScope handle_scope;
     Local<String> str = String::New(src);
     String::Value val(str); // String::Value的内部编码是 utf-16
     const size_t len = (val.length()) * sizeof(uint16_t);
     uint16_t* target = (uint16_t*)calloc(val.length() + 1, sizeof(uint16_t));
     if (target == NULL) {
         return 0;
     }
     memcpy(target, *val, len);
     *dest = target;
     return val.length();
    }
  2. 将生成的 utf-16 字符串通过 JNI 传递到 Java 层

    uint16_t *utf16_action = NULL;
    size_t len = utf8_to_utf16(action, &utf16_action);
    jstring jText = (*env)->NewString(env, utf16_action, len);
    if (utf16_action != NULL) {
     free(utf16_action);
    }
    if (len == 0) {
     jText = (*env)->NewStringUTF(env, ""); // 降级到使用NewStringUTF来创建一个""字符串
    }

另外一种解决方法是通过 byteArray 来将 utf-8 编码的字符串传送到java层,详情请参考这篇文章