背景
开发一个App一般会生成内测版和正式版,甚至还会有不同渠道的版本,不同版本的配置可能会不一样,比如内测版会需要记录完整的日志。
Android手机对于同样的Application Id的App只能安装一个版本,如果我们需要同时安装内测版和正式版,就必须修改其中一个版本的Application Id。
解决方案
Gradle支持buildTypes和productFlavors两种定制方法,这里只介绍通过buildType的解决方案。通过productFlavors则可有效解决渠道包,arm,x86等分平台以及付费版和广告版的打包问题。
修改debug版的包名
配置如下:
android {
buildTypes {
release {
...
}
debug {
applicationIdSuffix '.debug'
...
}
}
}
问题背景
团队一起在开发一个Android项目,工程师有的使用Eclipse,有个使用Intellij IDEA,有的使用Android Studio。每个人安装的Android SDK build-tools可能都不一样,有的是19.0.3,有的是19.1.0,不同版本的build-tools对Gradle Plugin也有相应的要求,如19.0.3对应的是com.android.tools.build:gradle:0.10.+,19.1.0对应的是com.android.tools.build:gradle:0.12.+,下面是一个典型的build.gradle配置文件。
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath 'com.android.tools.build:gradle:0.10.+'
}
}
apply plugin: 'android-library'
android {
compileSdkVersion 19
buildToolsVersion 19.0.3
defaultConfig {
minSdkVersion 8
targetSdkVersion 19
}
}
Android的线程和内存模型
Android操作系统在boot后,会启动一个Zygote(受精卵)进程,Zygote进程负责创建大部分应用程序进程。Zygote进程启动加载核心程序库和数据结构到内存后会创建一个Dalvik虚拟机(DVM)进程--SystemServer,此进程会包含大部分的系统服务(包括管理Activity的服务ActivityManagerService),SystemServer初始化后,Zygote进程会侦听本地的socket端口, 等待进一步的指令。当新的app被启动时,Zygote会为这个app创建一个DVM—-直接fork出一个子进程,这种架构的好处是同时启动多个App时,多个App进程可以访问共享内存。

Android App的进程也是一个DVM,内部有许多线程在执行,比如,主UI线程(Main Thread),垃圾回收线程等。其中主UI线程负责执行我们写的应用代码。对于只做很少的I/O操作或耗时操作的App,单一线程开发模式问题不大,但是如果有大量IO或者CPU计算的任务,我们就必须在其他线程内完成了。
因为主UI线程需要根据硬件刷新率[^3]同步用户界面的重绘。手机应用体验流畅要求界面帧率[^3]达到每秒60,也就是说每16.67毫秒就需要重绘一帧,这意味着如果我们在主线程上执行的任务超过16毫秒,就会出现丢帧现象,也就是界面会开始变卡。。。
Android异步执行任务的方法有以下几种:
AsyncTask
AsyncTask是最常用的异步方法,功能结构设计的也很丰富,给使用者足够的控制,使用上主要是将异步执行的任务放在下面方法里。
查看日志 adb logcat
下面命令将只显示错误日志,和所有Tag=mytag的调试日志,-C 会用不同颜色区分不同级别的日志,但只有Android 4.3以后才支持。
adb logcat [-C] *:E <mytag>:D
远程调试 adb over TCP
首先在手机或Pad上执行以下命令(要求root)
su
setprop service.adb.tcp.port 5555
stop adbd
start adbd
再执行下面命令则可以看到手机的网络地址
有root权限
adb shell su -c cat /data/data/app.package.name/databases/application.sqlite | sed 's/\r$//' > application.sqlite
应用可调试的话
adb shell
run-as app.package.name \
cp /data/data/package.name/databases/application.sqlite /sdcard/
exit
adb pull /sdcard/application.sqlite ~/
使用备份方法
adb backup -f ~/data.ab -noapk app.package.name
dd if=data.ab bs=1 skip=24 | python -c "import zlib,sys;sys.stdout.write(zlib.decompress(sys.stdin.read()))" | tar -xvf -
夏普GP2Y1010AU0F灰尘传感器价格较便宜,能检测出室内空气中的灰尘和烟尘含量。另外还有韩国SYHITECH生产的DSM501A粉尘传感器也有类似功能。
检测原理
其原理如下图,传感器中心有个洞可以让空气自由流过,定向发射LED光,通过检测经过空气中灰尘折射过后的光线来判断灰尘的含量。

电路图


因为数据是通过pin 5的电压模拟信号输出的,而树莓派的引脚不支持模拟信号直接读取(需要增加数模转换芯片),所以先用Arduino来实验。
使用过新浪开放平台的朋友都知道用户对小应用(用户数较少的)的授权Token很容易过期,自动续期要求授权过的用户在过期前重新打开授权页。如果你想实现一个自动备份自己微博的App,就不得每天(周)自己去访问授权页(想死的心都有了吧?)。这里介绍一种通过脚本自动登录微博获取最新oAuth token的方法(需要微博登录名和密码),合适自己玩。将脚本部署在树莓派上后,我再也不用每周都去登录一次授权页了,只是收到报警消息后(经常是帐号被冻结了)需要手动处理一下。
Phantomjs

Phantomjs 是一个开源的,没有界面可运行在命令行,跨平台,基于WebKit的全功能浏览器,可以用来做网站自动化测试。从源代码编译比较费时间,可以直接下载二进制版本,树莓派的版本在这里可下载。Phantomjs下载好了后就一个可执行文件,依赖非常少,我很喜欢这种方式。
代码
以下代码使用提供的微博用户名和密码登录,获得Token后还会打开微博首页看帐号是否被冻结了。
var page = require('webpage').create(),
system = require('system'),
fs = require('fs'),
address;
var weibo_userid = system.args[1]
var weibo_passwd = system.args[2]
var startUrl = "https://api.weibo.com/oauth2/authorize?client_id=<your_app_key>&redirect_uri=<your_return_url>/&response_type=token";
var verify_weibo_freeze = false;
page.onResourceReceived = function (res,network) {
if (res.stage == "end") {
// console.log("\t<-" + res.url);
if (res.url.indexOf("authorize?client_id")>0) {
startUrl = res.url
}
if (res.url.indexOf("?access_token")>0) {
var pos1 = res.url.indexOf("access_token=")
var pos2 = res.url.indexOf("&")
var access_token = res.url.substring(pos1+"access_token=".length, pos2)
console.log(weibo_userid + " login OK, access_token is: " + access_token)
verify_weibo_freeze = true
}
if (verify_weibo_freeze && res.url != "http://weibo.com/" && res.url.indexOf("http://weibo.com/")>-1) {
var pos1 = res.url.indexOf("/",8)
var pos2 = res.url.indexOf("?")
var weibo_name = res.url.substring(pos1+1,pos2)
console.log(weibo_name+" status verified OK")
phantom.exit();
}
}
};
page.onLoadFinished = function() {
if (verify_weibo_freeze) {
page.open("http://weibo.com/", function() {
phantom.exit();
})
}
};
page.onConsoleMessage = function(msg) {
console.log(msg);
};
page.open(startUrl, function(status) {
if ( status === "success" ) {
page.includeJs("https://ajax.googleapis.com/ajax/libs/jquery/1.6.1/jquery.min.js", function() {
var offset = page.evaluate(function(a,b) {
$("#userId").val(a)
$("#passwd").val(b)
if ($('.WB_btn_login').hasClass("formbtn_01")) {
// console.log("Found button!")
return $('.WB_btn_login').offset()
}
return undefined
}, weibo_userid, weibo_passwd);
page.sendEvent('click', offset.left + 1, offset.top + 1);
});
}
})
除了SD卡上的存储,树莓派还可以使用U盘来做存储,有时候我们可能需要替换已有的U盘为更大容量的。在Mac上可以采用下面的方法:
备份已有的U盘,把U盘从树莓派上拔下来插在Mac上,找出U盘对应的盘符(下例为/dev/disk2
)
20:51:19 hugozhu-mac-mini ~ $ diskutil list
/dev/disk0
#: TYPE NAME SIZE IDENTIFIER
0: GUID_partition_scheme *500.1 GB disk0
1: EFI 209.7 MB disk0s1
2: Apple_HFS Macintosh HD 499.2 GB disk0s2
3: Apple_Boot Recovery HD 650.0 MB disk0s3
/dev/disk2
#: TYPE NAME SIZE IDENTIFIER
0: FDisk_partition_scheme *2.1 GB disk2
使用 dd 命令把U盘拷贝到raspberrypi.img

Sublime 是一个相当好用的文本编辑器,界面简洁,功能强大。最近Sublime 3 Beta 出来了, 体验了一下,发现启动速度比之前快了很多。
下载安装
下载地址: http://www.sublimetext.com/3
安装Package Control
Sublime 支持插件来丰富其功能,package control 本身也是一个插件,可以用来管理其他插件,所以我们要先安装Package Control,Sublime 3需要安装Pacakge Control Alpha.
cd "Library/Application Support/Sublime Text 3"
cd Packages/
git clone https://github.com/wbond/sublime_package_control.git "Package Control"
cd "Package Control"
git checkout python3