简介:
本文完整介绍了如何安装、配置、备份 Trac 0.12。但这篇教程仅为官方教程的一个子集,仅适用于使用以下特定平台、软件的环境,并且不能保证适用于高于的 Trac 0.12 版本:
- 操作系统:Ubuntu Linux
- 数据库:SQLite
- 版本控制:Subversion
- 服务器端:tracd (自带)
Trac 的 wiki、浏览代码变更、浏览及对比代码等等功能非常实用,可以大大提高开发效率,而且还具有众多第三方插件可以实现更多的功能。
简介:
本文完整介绍了如何安装、配置、备份 Trac 0.12。但这篇教程仅为官方教程的一个子集,仅适用于使用以下特定平台、软件的环境,并且不能保证适用于高于的 Trac 0.12 版本:
Trac 的 wiki、浏览代码变更、浏览及对比代码等等功能非常实用,可以大大提高开发效率,而且还具有众多第三方插件可以实现更多的功能。
Summary:
This post explains Bluetooth audio profile A2DP, and discuss audio quality of it in technical aspect.
Let's begin with Bluetooth core specification, the most popular and widely supported one is Bluetooth 2.0/2.1 + EDR, which can transmit at 2.1Mbit/s at most. High speed feature is introduced since Bluetooth 3.0, its speed can go up to 24Mbit/s when transfering data through WiFi. The devices support this feature would be marked Bluetooth 3.0 + HS. So those support Bluetooth 3.0 or even 4.0 but without the "HS" logo will remain the same as their Bluetooth 2.1 peers. As for Bluetooth 4.0, it contains 3 subsets that are called classic Bluetooth, high speed Bluetooth and low energy Bluetooth, which is actually equals to 2.1 plus 3.0 + HS and low energy Bluetooth.
A2DP(Advanced Audio Distribution Profile) is a Bluetooth profile, which is supported by almost all Bluetooth speakers and headphones. It is the key that defines audio data bandwidth and audio quality.
Summary:This post tells the theory of detecting SQLite database Cursor leak of your Android app, alongside some common mistake examples. Some leaks are hardly noticable in the code until memory errors happen. This sort of method can be applied to other kinds of resources leak as well.
Cursor leak means that you have opened a Cursor object, which is usually associated with a portion of memory, but fail to close it before you lost referece to it. If it do happens and is repeated several hundreds of times, you would finally be unable to query SQLite database, and exception like this would appear. The log says 866 Cursors are opened and memory allocation of 2MB is failed.
简介:
SQLite 内置函数比较有限,有时通过添加自定义函数(User-Defined Fuctions)的方式可以实现一些通过普通 SQL 操作无法实现或者实现很麻烦的功能;也可以替换 SQLite 原有的内置函数,使其符合我们的要求。本文侧重说明在 Android 环境下的做法。
现在假设我们现在要在 Android 系统的视频播放器增加一个按照文件扩展名排序的功能,如果不是用自定义函数,就需要先从多媒体数据库中查询出来视频的路径,然后取出视频文件的扩展名并进行排序,因为查询得到的 Cursor 对象不可写,所以需要生成一个 MatrixCursor,把排序后的数据写入,最后返回这个 MatrixCursor。伪代码表示如下:
public Cursor getSortedByFileExtensionCursor() {
Cursor rawCursor = queryVideoFileNameFromDb(); // 从数据库查询出 id 和路径
HashMap idAndExtensionMap = getVideoFileExtension(rawCursor); // 获取 id 和扩展名的 HashMap
Cursor result = sortAndCreateNewMatrixCursor(idAndExtensionMap); // 对扩展名进行排序,生成 MatrixCursor 作为结果
return result;
}
而如果我们能够向 SQLite 注册一个自定义函数,很多类似问题就要简单不少。
简介:
本文简单介绍了蓝牙无线音频技术 A2DP,并从技术角度探讨其最理想情况下的音质。
我们先从蓝牙核心规范说起,蓝牙 1.0 的音频传输带宽只有 64kbit/s,8kHz 采样率 8 位采样精度,仅适用于电话。后来进行了升级,目前支持最广泛的蓝牙 2.0/2.1 + EDR 连接速率为 3Mbit/s,实际可用数据传输速率为 2.1Mbit/s(A2DP 与文件传输共享)。蓝牙 3.0 引入了高速数据传输新特性,最高数据传输速率为 24Mbit/s,但是数据传输是通过 WiFi 进行的,支持该特性的设备会标记为“蓝牙 3.0 + HS”。市面上支持蓝牙 3.0 的设备,如果没有标记“蓝牙 3.0 + HS”,数据传输速率并不会提升,由于功耗限制耳机实际上不可能支持 WiFi 传输。最新的是蓝牙 4.0 是一个混合体,包括传统蓝牙,高速蓝牙与低功耗蓝牙三个子集,相当于 2.1 加上 3.0+HS 与低功耗蓝牙。低功耗蓝牙多用于可穿戴设备。
A2DP(Advanced Audio Distribution Profile) 是蓝牙的子协议,蓝牙耳机、音箱等都是通过此协议传输音频数据流的,蓝牙音频所能使用的数据带宽也是由此协议定义。
简介:
本文简单介绍了环绕声基础知识,还介绍了各种双声道虚拟环绕声(多声道)的技术。最近突然对虚拟环绕声感兴趣,整理了一下相关知识。
普通的立体声只能分清左右两个方向的声音,而环绕声还能让人声音的前后左右各个方位,更有空间感仿佛置身于现场。常见的环绕声主要有 5.1 声道与 7.1 声道两种,要重现环绕声也相应的需要 6 个或者 8 个音箱。
电影中最常见的环绕声格式是杜比数字和 DTS,两者是竞争对手关系,电影 DVD 中一般包含有其中一种或者两种音轨都有。此外,这两种格式也有多个不同的版本,这里就不作详细介绍。
除了这两种格式之外,部分蓝光光盘也提供 LPCM 格式的音轨,这是一种未经压缩的音频格式,体积最大。压缩后的音频解码成 PCM 格式才能播放,所以这种格式无需解码。理论上 LPCM 格式无压缩音质好,无需解码,是最理想的格式,但由于光盘容量是有限的,音频体积大会挤占视频的空间。可以计算 96kHz 采样率,24 位采样精度,7.1 声道的 LPCM 音轨每秒数据量是
在 Android 4.1,系统语言设置为中文,当使用如下 SQL 语句查询 SQLite 数据库时,排序结果与之前的 Android 版本不同。
SELECT file_path FROM table ORDER BY file_path COLLATE LOCALIZED
以上语句对查询结果进行了排序,并且排序是按照本地化的规则,就是说不仅对 ASCII 字符排序,也会考虑到汉字的排序规则。旧版的 Android 都是遵循英文在前面,中文排在后面的规则,但 4.1 中却是中文排在英文前面。
LOCALIZED 字符比较使用的是 icu 的多语言支持库,代码位于 Android 源码目录下的 external/icu4c 目录。经过一番研究后发现是 Android 4.1 把排序规则更改了(使用 icu 原始数据包排序正常),新增了两条汉字排序规则使汉字排在前面,规则文件位于 external/icu4c/data/coll/zh.txt
" [reorder Hani]" " [reorder Hani Bopo]" |
把 external/icu4c/data/coll/zh.txt 中新增那两句话去掉,重新生成 icudt48l-default.dat 数据文件,步骤说明在 external/icu4c/stubdata/readme.txt
具体步骤:首先设置 ANDROID_BUILD_TOP 环境变量为你 Android 源码目录,然后运行 icu_dat_generator.py 就会生成新的数据文件 icudt48l-default.dat。把新的文件 push 到 /system/usr/icu/icudt48l.dat,重启即可看到效果。
简介:
本文介绍如何使用 Android NDK(r7) 设置 Android 本地代码编译工具链,如何根据 Makefile 编写 Android.mk,并以 ffmpeg(0.8.5) 为例子介绍如何使用此工具链移植。使用编译出来的库文件,可以通过本地 C/C++ 程序调用 ffmpeg 解码库;也可以另外编写 JNI 接口,使用 Java 程序调用 ffmepg。
我们都知道编译软件的一般步骤为:
./configure |
当然还可以增加参数做些自定义,但大概的流程是这样。要移植一个已有的库到 Android 当中却有很大的不同,首先需要搭建一个交叉编译环境去运行 configure 脚本以便生成配置文件,然后还需要编写 Android.mk 才能编译。
拿 ffmpeg 作例子,运行 configure 会生成 config.mak、config.h 和 libavutil/avconfig.h 这几个文件,里面决定了 ffmpeg 编译哪些模块、是否开启某些特性等。当然如果足够熟悉的话也可以手动修改这几个文件,但是其中的依赖关系复杂,较容易出错。接着根据原来的 Makefile 手动编写 Android.mk 文件,就能编译了。以下是详细流程。
注意:不能直接在宿主系统上运行 configure 脚本,因为环境和目标系统(Android)是不同的,这需要建立交叉编译环境。
简介:
本文介绍如何在 Android 检测 Cursor 泄漏的原理以及使用方法,还指出几种常见的出错示例。有一些泄漏在代码中难以察觉,但程序长时间运行后必然会出现异常。同时该方法同样适合于其他需要检测资源泄露的情况。
最近发现某蔬菜手机连接程序在查询媒体存储(MediaProvider)数据库时出现严重 Cursor 泄漏现象,运行一段时间后会导致系统中所有使用到该数据库的程序无法使用。另外在工作中也常发现有些应用有 Cursor 泄漏现象,由于需要长时间运行才会出现异常,所以有的此类 bug 很长时间都没被发现。
但是一旦 Cursor 泄漏累计到一定数目(通常为数百个)必然会出现无法查询数据库的情况,只有等数据库服务所在进程死掉重启才能恢复正常。通常的出错信息如下,指出某 pid 的程序打开了 866 个 Cursor 没有关闭,导致了 exception:
3634 3644 E JavaBinder: *** Uncaught remote exception! (Exceptions are not yet supported across processes.) 3634 3644 E JavaBinder: android.database.CursorWindowAllocationException: Cursor window allocation of 2048 kb failed. # Open Cursors=866 (# cursors opened by pid 1565=866) 3634 3644 E JavaBinder: at android.database.CursorWindow. 3634 3644 E JavaBinder: at android.database.AbstractWindowedCursor.clearOrCreateWindow(AbstractWindowedCursor.java:198) 3634 3644 E JavaBinder: at android.database.sqlite.SQLiteCursor.fillWindow(SQLiteCursor.java:147) 3634 3644 E JavaBinder: at android.database.sqlite.SQLiteCursor.getCount(SQLiteCursor.java:141) 3634 3644 E JavaBinder: at android.database.CursorToBulkCursorAdaptor.getBulkCursorDescriptor(CursorToBulkCursorAdaptor.java:143) 3634 3644 E JavaBinder: at android.content.ContentProviderNative.onTransact(ContentProviderNative.java:118) 3634 3644 E JavaBinder: at android.os.Binder.execTransact(Binder.java:367) 3634 3644 E JavaBinder: at dalvik.system.NativeStart.run(Native Method) |
简介:
本文介绍如何在 shell 命令行中过滤 adb logcat 输出的几个小技巧。
开发当中经常看到别人的 log 如洪水般瞬间刷满了屏幕,对自己有用的信息都被淹没了,影响心情也影响效率。下面是几个我所知道的过滤方法。
最方便的当然是通过管道使用 grep 过滤了,这样可以使用 grep 强大的正则表达式匹配。简单的匹配一行当中的某个字符串,例如 MyApp:
adb logcat | grep MyApp adb logcat | grep -i myapp #忽略大小写。 adb logcat | grep --color=auto -i myapp #设置匹配字符串颜色。更多设置请查看 grep 帮助。 |
进阶一点可以使用 grep 的正则表达式匹配。例如上一个例子会匹配一行中任意位置的 MyApp,可以设置为仅匹配 tag。默认的 log 输出如下,如果修改过输出格式相应的表达式也要修改。
I/CacheService( 665): Preparing DiskCache for all thumbnails. |
可以看出 tag 是一行开头的第三个字符开始,根据这点写出表达式:
adb logcat | grep "^..MyApp" |
Summary: This post shows several useful tips of viewing adb logcat output in shell command line.
When debugging, I usually find my screen be flooded by useless logs printed by someone else, and the logs that are useful to me are washed out at the same time. It really sucks. So I want to share some tips that I know for filtering the logs.
Please read Android official documentation Reading and Writing Logs first, which introduce the usage of the build-in filter of adb. It can filter logs by tags and by priority. If you prefer GUI, please refer to Using DDMS, which also provides the same filter.
An alternative way of filtering logcat output is using grep, which is the method that I want to share in the following paragragh.
It's very easy to filter output by grep, and we can make use of the powerful regular expression matching function. An easy example is matching a string "MyApp" in any position of a log line:
adb logcat | grep MyApp adb logcat | grep -i myapp #Ignore case adb logcat | grep --color=auto -i myapp #Set color of matching string. See grep help for more details. |