2010 年谢彦的 Android 笔记 1 系统配置...................................................................................................................................1 1.1 建立SDK开发环境...................................................................................................2 1.2 Android源码的编译 .................................................................................................6 1.3 编译在G1 上运行的android 2.1(eclair)代码 ...........................................................9 1.4 编译在G1 上运行的android 2.2(froyo)代码_旧方法............................................12 1.5 编译在G1 上运行的android 2.2(froyo)代码_新方法............................................15 1.6 编译在N1 上运行的android 2.3(GingerBread)代码..............................................18 1.7 系统结构.................................................................................................................21 1.8 模拟器调试与真机调试.........................................................................................22 1.9 安装和卸载应用程序(apk包)...........................................................................23 1.10 系统升级.................................................................................................................26 1.11 android系统支持app2sd(修改boot.img)...........................................................27 2 基本概念.................................................................................................................................30 2.1 Android组件 ...........................................................................................................31 2.1.1 基本组件.............................................................................................................31 2.1.2 组件间的通讯.....................................................................................................32 2.1.3 intent使用方法....................................................................................................33 2.2 界面开发.................................................................................................................35 2.2.1 界面元素.............................................................................................................35 2.2.2 布局的实现.........................................................................................................36 2.2.3 事件响应.............................................................................................................37 2.2.4 应用软件代码结构.............................................................................................38 2.2.5 国际化的支持(多语言).................................................................................39 2.2.6 常见问题及解决方法.........................................................................................40 2.2.7 android是重要的包.............................................................................................41 2.3 界面元素分析.........................................................................................................42 2.4 修改公共控件.........................................................................................................43 2.5 源码中常用于参考的代码.....................................................................................44 3 程序开发.................................................................................................................................45 3.1 相关工具介绍.........................................................................................................46 3.1.1 从c++到java(一)............................................................................................46 3.1.2 从c++到java(二)............................................................................................47 3.2 常用技术.................................................................................................................49 3.2.1 如何新建和使用控件.........................................................................................49 3.2.2 使用定时器Timer及消息处理 ...........................................................................51 3.2.3 操作调试数据库与ContentProvider详解...........................................................53 3.2.4 电源管理.............................................................................................................56 3.2.5 开发桌面小程序AppWidget ..............................................................................58 3.2.6 代码中运行二进制程序或脚本.........................................................................60 3.2.7 Android自带的md5 校验 ...................................................................................61 3.2.8 将数据打进apk包...............................................................................................63 3.2.9 如何改变窗口的标题栏的布局.........................................................................66 3.2.10 动态改变控件大小.............................................................................................67 3.2.11 缩放drawable......................................................................................................68 2 2010 年谢彦的 Android 笔记 3.2.12 解析apk包内容...................................................................................................69 3.3 Java对C库的调用...................................................................................................70 3.3.1 android中使用JNI...............................................................................................70 3.3.2 安装使用NDK....................................................................................................72 3.3.3 在源码中将库打进apk.......................................................................................73 3.3.4 简单的C库调试方法..........................................................................................75 3.4 典型应用.................................................................................................................76 3.4.1 语音合成.............................................................................................................76 3.4.2 语音识别简介.....................................................................................................79 3.4.3 语音识别方法一:使用intent调用语音识别程序............................................80 3.4.4 语音识别方法二:应用程序自己调用语音识别库.........................................82 3.4.5 语音识别方法三:使用Service调用语音识别程序.........................................84 3.4.6 人脸识别.............................................................................................................87 3.4.7 图像识别.............................................................................................................89 3.4.8 文字识别.............................................................................................................90 3.4.9 卫星定位.............................................................................................................91 3.4.10 多媒体播放.........................................................................................................95 3.4.11 访问网络.............................................................................................................97 3.4.12 博客客户端的实现.............................................................................................99 3.5 调试技术...............................................................................................................102 3.5.1 JDWP调试 ........................................................................................................102 3.5.2 运行dalvik测试程序.........................................................................................103 3.5.3 测试小程序.......................................................................................................104 3.5.4 dalvik提供的调试工具集.................................................................................107 3.5.5 c++程序的调试 ................................................................................................110 3.5.6 测试工具CTS ...................................................................................................113 3.5.7 解决eclipse无法识别API的问题 .....................................................................115 3.5.8 调试方法补充...................................................................................................116 3.6 换肤(theme) ..........................................................................................................118 3.6.1 当前的换肤方法(theme) ..................................................................................118 3.6.2 制作换肤包.......................................................................................................120 4 android架构层分析 ..............................................................................................................122 4.1 启动过程...............................................................................................................123 4.1.1 开机流程...........................................................................................................123 4.1.2 开机动画...........................................................................................................125 4.1.3 android应用的启动过程...................................................................................127 4.2 服务的原理与使用...............................................................................................128 4.3 键盘事件处理.......................................................................................................130 4.4 包管理...................................................................................................................131 4.5 传感器...................................................................................................................132 4.6 浅析dalvik虚拟机JIT技术的实现........................................................................133 4.7 应用程序的签名(Signature).................................................................................135 4.8 应用的权限...........................................................................................................138 4.9 屏幕密度Density ..................................................................................................140 3 2010 年谢彦的 Android 笔记 4 4.10 Prelink实现的源码分析 .......................................................................................142 4.11 适配硬件平台.......................................................................................................145 4.12 其他介绍...............................................................................................................147 4.12.1 手机保护Keyguard...........................................................................................147 4.12.2 空中升级Fota....................................................................................................148 4.12.3 Flash分区..........................................................................................................149 2010 年谢彦的 Android 笔记 1 系统配置 1 2010 年谢彦的 Android 笔记 1.1 建立SDK开发环境 1. 系统平台 Linux 系统:ubuntu 8.04,最好用 ubuntu 系统,否则可能遇到缺少库,编译器版本不 对等一系列问题,安装和使用详见文档《ubuntu 系统的使用》 2. 安装 JDK 1) 为什么使用 JDK 用以支持 Android 和 Eclipse:Android 中的应用都是 java 程序,所以想在 Linux 上建立开发 Android 环境,就需要安装 java 虚拟机 2) 安装方法 1:好处是方便 a) 使用 ubuntu 安装包 $ sudo apt-get install sun-java6-bin 3) 安装方法 2:好处是下载后拷给别人安,省去了下载时间,可以自己设定安装位 置 a) 下载 打开网页http://developers.sun.com.cn/download/java_se.html 下载jdk-6u10-linux-i586.bin b) 安装 $ ./jdk-6u10-linux-i586.bin $ mkdir /usr/java $ mv jdk1.6.0_10/ /usr/java/ c) 设置环境 $ export JAVA_HOME=/usr/java/jdk1.6.0_10 $ export CLASSPATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar $ export PATH=$JAVA_HOME/bin:$PATH 注意前后顺序 最好把环境变量的设置加入$USER/.bashrc 脚本中 4) 测试是否安装成功 $ java -version 3. 安装 Android SDK 为什么使用 Android SDK Android SDK 包含创建和运行 Android 应用程序所需的一切,包括设备仿真器和高 级调试工具,如果你只想看看 Android 运行起来什么样,那只安装它就可以 1) 安装 注意选择你所使用平台和硬件对应的版本 平台 windows, linux, mac 版本 1.0, 1.5, 1.6… a) 下载 打开网页http://code.google.com/android/download_list.html 下载android-sdk-linux_x86-1.0_r1.zip b) 安装 $ unzip ../recv/android-sdk-linux_x86-1.0_r1.zip 无需编译,解开就能运行 2) 运行 $ cd android-sdk-linux_x86-1.0_r1/tools 2 2010 年谢彦的 Android 笔记 $ ./emulator -datadir ../../ // datadir 是一个必须存在的目录,用来存放数据 耐心等待,特别特别的慢,看到主菜单大概要三四分钟,请注意,安装到这一步, android 就能在你的 Linux 系统中运行了 3) 设置路径 $ export PATH=$PATH:/exports/android/test/android-sdk-linux_x86-1.0_r1/tools 最好把环境变量的设置加入$USER/.bashrc 脚本中 4) 创建并使用模拟的 500M SD 卡 $ ./mksdcard -l SD500M 500M ../../sd500m.img 建立虚拟 SD 卡的映像文档 $ ./emulator -sdcard ../../sd500m.img -datadir ../../ 5) 缩放屏幕 0.5 倍 $ ./emulator -scale 0.5 -datadir ../../ 6) SDK 目录结构 a) Add-ons 扩展的第三方库所在目录(如现在所放的地图库) b) Docs,documention.html 本地和网上提供的 SDK 文档 c) Platforms 含 1.1 和 1.5 两种 SDK Samples 其中含示例代码 android.jar 为 java 打包文件,其中包含构建应用程序的所有 Android SDK 类 d) Tools 构建应用程序的命令行工具(adb, emulator…) e) Usb_driver Android(G1)设备连接计算机后所需的驱动程序,只有 Window 平台需要, Linux 平台可以自动识别 4. 安装 eclipse 1) 为什么使用 eclipse eclipse 是一个基于 java 的开发平台,它是一个框架,通过安装插件构建开发环境, java 就是它的插件,android 也是一组插件,我们利用它用发和调试运行在 android 上的程序安装 a) 下载 打开网页http://www.eclipse.org/downloads/ 下载Eclipse IDE for Java EE Developers b) 解压 tar xvzf ../download/eclipse-jee-ganymede-SR1-linux-gtk.tar.gz c) 运行 cd eclipse ./eclipse 使用默认的 workspace 就可以了 2) 安装 android 的 eclipse 插件 a) 在 eclipse 中点击菜单 Help->Software Updates…… b) 切换到 Available Software 标签,点 Add Site……按钮 c) 在弹出的对话框里输入https://dl-ssl.google.com/android/eclipse/,然后按OK d) 选项新出新的 Developer tools 然后点 Install…… 3 2010 年谢彦的 Android 笔记 i) Android Developer Tools ii) Android DDMS(Dalvik Debug Monitor Service) 查看线程,堆栈,内存占用,广播,虚拟 GPS 坐标等 e) 点 Next,然后 Finish f) 重新启动 Eclipse 后生效 3) 指定 Android SDK 对应的目录 a) 在 eclipse 中点击菜单 Window->Preferences b) 左侧选 Android,右侧选 Browse……,指定你 android SDK 的安装目录 c) 点击 Apply,然后点 OK 5. 配置 AV D(Android Virtual Device) 1) 用于配置一些模拟器的特性:模拟器影像大小/触摸屏/轨迹球/摄像头/屏幕分辨率/ 键盘/GSM /GPS/Audio 录放/SD 卡支持/缓存区大小等 2) 如果用 SDK1.5 可能出现提示让你建立 AVD Name:AVD1.5 Target: Android 1.5 - 1.5 SDCard: 64M 点 Create AVD 然后再点 finish 即可 6. 第一个 android 程序 1) 建立 project a) 在 eclipse 中点击菜单 File->New->Project…… b) 选择 Android Project 按 Next c) 填写 project 的各项内容如下 Project name: test_xy 目录名, 它位于你设定的 workspace 之下 Package name: com.android.test 打包名称 Activity name: TestXy 好像是类名(生成文件 TestXy.java) Application name: test_app_name 可执行程序名 然后点 Finish 按钮 2) 填写代码 这时可以看到代码界面了,从左边的树中打开代码 test_xy->src->com.android.testxy->TestXy.java->TestXy->onCreate 其中代码改写如下:(摘自 code.google.com) package com.android.testxy; // 打包名 import android.app.Activity; import android.os.Bundle; import android.widget.TextView; public class TestXy extends Activity { /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); TextView tv = new TextView(this); tv.setText("My name is xieyan"); 4 2010 年谢彦的 Android 笔记 setContentView(tv); } } 3) 运行 a) 在 eclipse 中点击菜单 Run->Run Configurations…… b) 双击左边的 Android Application,产生了一个 New Configuration,点开它填写 内容如下: Name: yan_config // 随便起一个 Project: test_xy // 刚才起的 project, 即目录名 点击 Apply,然后点 Run,多等一会儿就出来了 7. 参考 1) 十分详细的中文文档(带图) http://www.590103.idv.tw/blog/archives/1510 2) 模拟器使用细节说明 http://whereq.blogspot.com/2008/11/android-emulator-how-to.html 5 2010 年谢彦的 Android 笔记 1.2 Android源码的编译 1. 配置环境 1) 磁盘 需要 6G 以上剩余空间 2) Linux 系统 Ubuntu 6.06 以上版本,我用的是 buntu 8.04,具体请见下篇文档《ubuntu 系统的 使用》 3) Git 工具(Git 1.5.4 以上版本) 它是类似 CVS 的版本管理工具,如果你的代码不用从网上下载,而是从别人处复 制,则无需此工具 $ sudo apt-get install git-core gnupg 4) Java 环境(JDK 5.0 update12 以上版本) $ sudo apt-get install sun-java6-jdk 具体安装请见上篇文档《Android 环境的搭建》 5) Python (Python 2.4 以上版本) 从http://www.python.org/download/下载 2.4以上版本 $ tar xvzf python-2.4.5.tgz $ cd python-2.4.5/ $ ./configure $ make; make install 6) 依赖的deb包 $ sudo apt-get install flex bison gperf libsdl-dev libesd0-dev libwxgtk2.6-dev build-essential zip curl 其中flex bison build-essential zip curl可以从光盘安装 其余gperf libsdl-dev libesd0-dev libwxgtk2.6-dev需要从网上安装,它们还 依赖一些安装包,所以要用apt-get下载,不要直接下deb包安装 调试工具 $ sudo apt-get install valgrind 下载及编译运行android源码 下载安装脚本 $ wget http://android.git.kernel.org/repo $ chmod 777 repo $ cp repo /bin/ 用安装脚本下载源码 $ mkdir android_code $ cd android_code $ repo init -u git://android.git.kernel.org/platform/manifest.git $ repo sync 以上命令是下载最新版本,也可以下载其它版本 如我买的手机,在设置->关于手机->固件版本中看到是 1.5,所以下载 1.5 版本,方法如下 $ repo init -u git://android.git.kernel.org/platform/manifest.git -b android-1.5r3 $ repo sync // 此后会长时间下载 2. 编译 1) 正常编译 6 2010 年谢彦的 Android 笔记 a) 编译方法 映像编译成功后会在目录 android_code/src/out/target/product/generic 下产生一些 image 文件:ramdisk.img system.img userdata.img $ cd android_code $ make b) 可能出现的问题及解决方法 i) make 若提示找不到-lncurses,则需要做以下链接 ln –s /lib/libncurses.so.5 /lib/libncurses.so ii) make 若提示找不到 run-java-tool,则需要设置 java 的安装路径 $ export ANDROID_JAVA_HOME=$JAVA_HOME iii) 若提提示找不到 zlib.h, 则运行如下命令安装 zlib 开发包 $ sudo apt-get install zlib1g-dev iv) 下了一个最版本后显示说只能使用 java-1.5 版本,于是从 1.6 版本降回 1.5 $ sudo apt-get install sun-java5-jdk flex $ sudo update-java-alternatives -s java-1.5.0-sun v) 如果报错 "compression requires the missing zlib module" 可能是 python 找不到 zlib 库 这时需要先安装 zlib 库, 然后重编 python, 并取代当前版本 python $ sudo apt-get install zlib1g-dev $ python2.6 --version 可看到当前版本, 下载当前版本, 重新编译安装 $ tar xvzf python-2.6.2.tgz $ cd python-2.6.2/ $ ./configure --prefix=/usr/local $ make; make install 2) 编译 sdk a) 编译 $ make sdk 此时 SDK 产生于此目录下:android_code/out/host/linux-x86/sdk/ 此包如同下载的 sdk 包,可供 eclipse 使用,注意把它移动其它位置使用,否则 一编译其它应用,它就被删除掉了 b) 编译不同 Android 硬件平台对应版本 需要在 make 前先针对设备进行设置,形如: $ choosecombo 1 1 8 3 使用不同参数,编译结果存存储的目录不同 默认包生成目录:android_code/out/target/product/qsd8250_surf/system/app/*.apk 以上选项包生成目录: android_code/out/target/product/generic/system/app/*.apk 3. 运行 1) 运行普通的虚拟器 emulator emulator 的路径是: /home/xieyan/bin/android_code/out/host/linux-x86/bin/emulator 设置环境变量 export PATH=$PATH:android_src/out/host/linux-x86/bin $ . build/envsetup.sh 7 2010 年谢彦的 Android 笔记 $ partner_setup $ emulator 2) 指定 img 运行 $ export ANDROID_PRODUCT_OUT=/home/xieyan/bin/android_code/out/target/product/generic $ emulator -image system.img -data userdata.img -ramdisk ramdisk.img 4. 常用的源码文件 1) frameworks/base/core/java/android/widget/下边 Android 系统控件的实现 2) package/apps 普通应用程序的实现 3) out/target/product/generic/system/apps/*.apk 安装包生成的位置 5. 参考 官方网站的安装说明 http://source.android.com/download 8 2010 年谢彦的 Android 笔记 1.3 编译在G1 上运行的android 2.1(eclair)代码 1. 说明 1) 下载编译最基本的 android 源码,无法在真机上使用(不能生成 boot.img),只能 在模拟器上使用。这是因为没有编译相关机型的内核和硬件驱动。以下介绍的是 用 android 源码编译出对应 HTC G1 的版本,和烧写的过程。编译生成的版本除相 机不能用之外,其它绝大部分功能都能正常使用,在 G1 上运行 2.1 版的速度也不 错。 2) 本文主要参考日文文档G1/G2 烧机指南,感谢原文作者,原文地址: http://code.google.com/p/android-development-environment/wiki/EclaironADP1andA DP2 同时加入中文系统的支持和JIT支持(提高速度),以及相关文字解释。 3) 以下步骤都经过验证(只验证 G1 手机,G2 部分请参见日文文档),实验系统 ubuntu8.04,实验日期 2010 年 5 月 8 日 4) 关键字: android 2.1 eclair g1 源码编译 2. 编译 1) 建立 android 源码编译目录 $ export ANDROID=/exports/android/android_2.1_cn/ $ mkdir -p $ANDROID $ cd $ANDROID 2) 源码下载 $ repo init -u git://android.git.kernel.org/platform/manifest.git -b android-2.1_r2 #设定下 载 2.1 版代码 $ vi .repo/local_manifest.xml # 新建下载配置文件 编辑内容如下 9 2010 年谢彦的 Android 笔记 注意:其中 msm 是高通芯片组,path 指明下载到源码目录中的位置,name 指明 git 上的项目名 $ repo sync # 开始下载代码,此时需要等待较长时间 3) 打补丁以支持动态壁纸(此为步骤为可选) $ wget http://android-development-environment.googlecode.com/files/patch_devphone_eclair.tar.gz $ tar zxvf patch_devphone_eclair.tar.gz $ ./patch/eclair-build-patch.sh 4) 编译内核及无线网络驱动 $ cd $ANDROID/kernel $ make ARCH=arm CROSS_COMPILE=../prebuilt/linux-x86/toolchain/arm-eabi-4.4.0/bin/arm-eabi- msm_defconfig # 设定默认的 msm 配置 $ vi .config # 修改新生成的配置文件,以重新设置 CPU 最高频率,修改如下: 修改 CONFIG_MSM_CPU_FREQ_ONDEMAND_MAX 项为 CONFIG_MSM_CPU_FREQ_ONDEMAND_MAX=528000 $ make ARCH=arm CROSS_COMPILE=../prebuilt/linux-x86/toolchain/arm-eabi-4.4.0/bin/arm-eabi- #编译内核 $ cd $ANDROID/system/wlan/ti/sta_dk_4_0_4_32 $ make ARCH=arm CROSS_COMPILE=$ANDROID/prebuilt/linux-x86/toolchain/arm-eabi-4.4.0/bin/arm-eabi- KERNEL_DIR=$ANDROID/kerne l #编译无线网络驱动 $ cp $ANDROID/kernel/arch/arm/boot/zImage $ANDROID/vendor/htc/dream-open/kernel $ cp $ANDROID/system/wlan/ti/sta_dk_4_0_4_32/wlan.ko $ANDROID/vendor/htc/dream-open/wlan.ko 5) 编译android源码 在HTC网站http://developer.htc.com/adp.html 下载名为signed-dream_devphone_userdebug-ota-14721.zip 的包,并把它放在 $ANDROID目录下 $ cd $ANDROID $ source build/envsetup.sh $ lunch aosp_dream_us-eng # 指明机型 $ cd vendor/htc/dream-open $ ./unzip-files.sh # 解压htc相关驱动 $ cd $ANDROID $ vi buildspec.mk # 新建配置文件 加入如下内容 CUSTOM_LOCALES:=zh_CN # 设置编译为中文系统 WITH_JIT:=true # 加入JIT支持,使得运算速度加快 1-2 倍 $ make -j2 # 编译android源码,需要等待较长时间 3. 把编译好的软件烧写到手机 用 usb 线连接手机到电脑,按 home+power 键将手机启动到工程模式,按 back 键准备 烧写 $ export PATH=$PATH:$ANDROID/out/host/linux-x86/bin # 把烧写工具所在目录加上路径 $ cd out/target/product/dream-open/ 10 2010 年谢彦的 Android 笔记 $ fastboot flash system system.img $ fastboot flash boot boot.img $ fastboot reboot 烧写系统后第一次启动手机需要几分钟,请耐心等待 4. 参考 1) 刷写部分未详细描述,具体请参考文档 http://xy0811.spaces.live.com/blog/cns!F8AECD2A067A6B17!1452.entry 2) 源码编译部分未详细描述,具体请参考文档 http://xy0811.spaces.live.com/blog/cns!F8AECD2A067A6B17!1364.entry 11 2010 年谢彦的 Android 笔记 1.4 编译在G1 上运行的android 2.2(froyo)代码_旧方法 1. 说明 下载编译最基本的 android 源码,无法在真机上使用(不能生成 boot.img),只能在模 拟器上使用。这是因为没有编译相关机型的内核和硬件驱动。以下介绍的是用 android 源码编译出对应 HTC G1 的版本,和烧写的过程。编译生成的版本绝大部分功能都能 正常使用(电话,短信,上网,音乐,软件安装等正常使用,SD 卡还不能自动挂载, 正在修改之中),在 G1 上运行 2.2 版稳定性不错,也很顺畅。 1) 本文主要参考编译android 2.1 的日文文档G1/G2 烧机指南,感谢原文作者,原文 地址: http://code.google.com/p/android-development-environment/wiki/EclaironADP1andA DP2 同时加入中文系统的支持和 2.2 部分相关修改,以及相关文字解释。 2) 以下步骤都经过验证(只验证 G1 手机),实验系统 ubuntu8.04,实验日期 2010 年 7 月 2 日 3) 关键字: android 2.2 froyo g1 源码编译 2. 编译 1) 建立 android 源码编译目录 $ export ANDROID=/exports/android/android_2.2/ $ mkdir -p $ANDROID $ cd $ANDROID 2) 源码下载 $ repo init -u git://android.git.kernel.org/platform/manifest.git -b android-2.2_r1 #设定下 载 2.2 版代码 $ vi .repo/local_manifest.xml # 新建下载配置文件 编辑内容如下 12 2010 年谢彦的 Android 笔记 注意:其中 msm 是高通芯片组,path 指明下载到源码目录中的位置,name 指明 git 上的项目名 $ repo sync # 开始下载代码,此时需要等待较长时间 3) 编译内核及无线网络驱动 $ cd $ANDROID/kernel $ make ARCH=arm CROSS_COMPILE=../prebuilt/linux-x86/toolchain/arm-eabi-4.4.0/bin/arm-eabi- msm_defconfig # 设定默认的 msm 配置 $ make ARCH=arm CROSS_COMPILE=../prebuilt/linux-x86/toolchain/arm-eabi-4.4.0/bin/arm-eabi- #编译内核 $ cd $ANDROID/system/wlan/ti/sta_dk_4_0_4_32 $ make ARCH=arm CROSS_COMPILE=$ANDROID/prebuilt/linux-x86/toolchain/arm-eabi-4.4.0/bin/arm-eabi- KERNEL_DIR=$ANDROID/kerne l #编译无线网络驱动 $ cp $ANDROID/kernel/arch/arm/boot/zImage $ANDROID/vendor/htc/dream-open/kernel $ cp $ANDROID/system/wlan/ti/sta_dk_4_0_4_32/wlan.ko $ANDROID/vendor/htc/dream-open/wlan.ko 4) 编译android源码 在HTC网站http://developer.htc.com/adp.html 下载名为signed-dream_devphone_userdebug-ota-14721.zip 的包,并把它放在 $ANDROID目录下 $ cd $ANDROID $ source build/envsetup.sh $ lunch aosp_dream_us-eng # 指明机型 $ cd vendor/htc/dream-open $ ./unzip-files.sh # 解压htc相关驱动 $ cd $ANDROID $ vi buildspec.mk # 新建配置文件 加入如下内容 CUSTOM_LOCALES:=zh_CN # 设置编译为中文系统 $ vi build/core/prebuild.mk 注掉第 59 行($error No LOCAL_CERTIFICATE……),否则编不过,这是由于对硬件部分的一个 包的签名检测不过引起的(硬件部分的代码已经很久没更新了) $ vi device/htc/dream-sapphire/libsensors/Android.mk 将第 39 行,改为 LOCAL_MODULE:=sensor.trout1,否则编不过,这是由于硬件部分的模块名 与源码中自带的模块名冲突引起 $ vi hardware/msm7k/libaudio/Android.mk 在第 29 行(CLEAR_VARS之后),加入LOCAL_PRELINK_MODULE:=false,否则,系统无法运行, 启动时会报错“failed to link libandroid_servers.so” $ make -j4 # 编译android源码,需要等待较长时间 $ mmm -B $ANDROID/packages/apps/Luancher2/ snod # 编译桌面程序,否则桌面将无法启 动,系统总停在开机动画 $mmm -B $ANDROID/framework/base/packages/DefaultContainerService/ snod # 编译 13 2010 年谢彦的 Android 笔记 ContainerService,否则无法安装软件 3. 把编译好的软件烧写到手机 用 usb 线连接手机到电脑,按 home+power 键将手机启动到工程模式,按 back 键准备 烧写 $ export PATH=$PATH:$ANDROID/out/host/linux-x86/bin # 把烧写工具所在目录加上路径 $ cd out/target/product/dream-open/ $ fastboot flash system system.img $ fastboot flash boot boot.img $ fastboot reboot 烧写系统后第一次启动手机需要几分钟,请耐心等 4. 修改 1) 支持 SD 卡 $ adb remount $ adb push $ANDROID/system/core/rootdir/etc/vold.fstab /etc/ 烧写手机后 SD 卡没有挂载是由于没有找到配置文件,将挂载服务 vold 所需的配 置文件 vold.fstab 写入手机即可,然后重启即可. 注意,你的 SD 卡最好只含一个 fat 格式分区,如果之前自己配置过早期的 APP2SD, 分有 ext2 分区,可能出现卡不被识别的情况. 2) 支持GPRS上网 添加APN即可上网和发彩信,详见http://www.andbeta.com/Basics/678.html 3) 支持 APP2SD $ adb shell # pm setInstallLocation 2 重启之后,程序即被安装到 SD 卡上 5. 参考 1) 刷写部分未详细描述,具体请参考文档 http://xy0811.spaces.live.com/blog/cns!F8AECD2A067A6B17!1452.entry 2) 源码编译部分未详细描述,具体请参考文档 http://xy0811.spaces.live.com/blog/cns!F8AECD2A067A6B17!1364.entry 3) 注意:以上灰色标出的是与编译 éclair 不同的部分 14 2010 年谢彦的 Android 笔记 1.5 编译在G1 上运行的android 2.2(froyo)代码_新方法 1. 说明 1) 下载编译最基本的 android 源码,只能在模拟器上使用,无法在真机上使用(不能 生成 boot.img),。这是因为没有编译相关机型的内核和硬件驱动。以下介绍的是 用 android 源码编译出对应 HTC G1 的版本,和烧写的过程。编译生成的版本除相 机以外,其它功能均正常,稳定性不错,也很顺畅。 2) 以下步骤都经过验证(只验证 G1 手机),实验系统 ubuntu8.04,实验日期 2010 年 7 月 12 日 3) 关键字: android 2.2 froyo g1 源码编译 2. 编译 1) 建立 android 源码编译目录 $ export ANDROID=/exports/android/android_2.2/ $ mkdir -p $ANDROID $ cd $ANDROID 2) 源码下载 $ repo init -u git://android.git.kernel.org/platform/manifest.git -b android-2.2_r1 $ vi .repo/local_manifest.xml # 新建下载配置文件,用以下载内核,编辑内容如下 注意:其中 msm 是高通芯片组,path 指明下载到源码目录中的位置,name 指明 git 上的项目名 $ repo sync # 开始下载代码,此时需要等待较长时间 3) 编译内核及无线网络驱动 $ cd $ANDROID/kernel $ make ARCH=arm CROSS_COMPILE=../prebuilt/linux-x86/toolchain/arm-eabi-4.4.0/bin/arm-eabi- msm_defconfig # 设定默认的 msm 配置 $ make ARCH=arm CROSS_COMPILE=../prebuilt/linux-x86/toolchain/arm-eabi-4.4.0/bin/arm-eabi- #编译内核 $ cd $ANDROID/system/wlan/ti/sta_dk_4_0_4_32 $ make ARCH=arm CROSS_COMPILE=$ANDROID/prebuilt/linux-x86/toolchain/arm-eabi-4.4.0/bin/arm-eabi- KERNEL_DIR=$ANDROID/kerne l #编译无线网络驱动 cp $ANDROID/kernel/arch/arm/boot/zImage $ANDROID/device/htc/dream/kernel cp $ANDROID/system/wlan/ti/sta_dk_4_0_4_32/wlan.ko $ANDROID/device/htc/dream/wlan.ko 4) 配置编译选项 vi device/htc/dream/AndroidBoard.mk #若 kernel 存在,则不重新编译 kernel ifeq ($(TARGET_PREBUILT_KERNEL),) TARGET_PREBUILT_KERNEL := $(LOCAL_PATH)/kernel endif 15 2010 年谢彦的 Android 笔记 file := $(INSTALLED_KERNEL_TARGET) ALL_PREBUILT += $(file) $(file): $(TARGET_PREBUILT_KERNEL) | $(ACP) $(transform-prebuilt-to-target) 5) 编译 android 源码 $ cd $ANDROID $ vi buildspec.mk # 加入如下内容,以支持中文 CUSTOM_LOCALES:=zh_CN $ source build/envsetup.sh $ lunch full_dream-userdebug #指定编译机型 $ make -j2 6) 以打补丁的方式加入不提供源码的库 此时的系统可以被烧写,但电话音乐等基本功能均不正常,需要从系统或其它升 级包中提取出源码中不包含的库,以支持相应功能。 在HTC网站http://developer.htc.com/adp.html 下载名为signed-dream_devphone_userdebug-ota-14721.zip的包(一个普通的update 包),并把它放在$ANDROID目录下,并将其改名为dreaem_update.zip $ mv signed-dream_devphone_userdebug-ota-14721.zip dream_update.zip $ cd device/htc/dream $ ./unzip-files.sh # 此时会提示有几个库找不后,后面有对应解决办法 $ cd $ANDROID $ vi vendor/htc/dream/device_dream-vendor-blobs.mk 删除包含以下内容的行,这是由于在update.zip中找不到相应库,为编译通过,选去掉它们 libGLES_qcom.so liblvmxipc.so liboemcamera.so libstagefrighthw.so $ make $ cp device/htc/dream/wlan.ko out/target/product/dream/system/lib/modules/wlan.ko #网卡驱动 $ make snod # 重新生成system.img 3. 把编译好的软件烧写到手机 用 usb 线连接手机到电脑,按 home+power 键将手机启动到工程模式,按 back 键准备 烧写 $ export PATH=$PATH:$ANDROID/out/host/linux-x86/bin # 把烧写工具所在目录加上路径 $ cd out/target/product/dream/ $ fastboot flash system system.img $ fastboot flash boot boot.img $ fastboot reboot 烧写系统后第一次启动手机需要几分钟,请耐心等 4. 修改 1) 安装中文字体(可以在烧写前加入,加在此处用以说明在启动后修改系统的方法) $ adb shell # su 取得 root 权限 # mount -o remount,rw -t yaffs2 /dev/block/mtdblock3 /system 使 system 分区可写 16 2010 年谢彦的 Android 笔记 # chmod 777 /system/fonts 使某个目录有写权限 # exit # exit $ adb push frameworks/base/data/fonts/DroidSansFallback.ttf /system/fonts/ 加中文字体 $ adb reboot 2) 支持GPRS上网 添加APN即可上网和发彩信,详见http://www.andbeta.com/Basics/678.html 3) 设置帐户 添加帐户时,服务器填写 m.google.com 5. 参考 1) 刷写部分未详细描述,具体请参考文档 http://xy0811.spaces.live.com/blog/cns!F8AECD2A067A6B17!1452.entry 2) 源码编译部分未详细描述,具体请参考文档 http://xy0811.spaces.live.com/blog/cns!F8AECD2A067A6B17!1364.entry 17 2010 年谢彦的 Android 笔记 1.6 编译在N1 上运行的android 2.3(GingerBread)代码 1. 修改效果 1) 在 32 位系统上正常编译通过,N1 上能运行,带 root 权限 2) 带 N1 原始的四色 X 开机动画,默认语言为简体中文 3) 带 google market,文件管理器,百度中文手写输入法,金山词霸等常用软件 4) 打电话,收发短信,WIFI,移动网络,热点上网正常(APN 已设) 5) 音频,视频,照像,摄像,Gps,Sensor 使用正常 6) 目前未测到不正常的功能 2. 下载 android 2.2 或 2.3 的 sdk 刷机使用的 fastboot 和 adb 都需要从 sdk 中获得 3. 对 N1 的处理 1) Bootloader 解锁 a) 关机后,按 Power+音量减开机,按音量键选 fastboot,然后按 Power 进入 b) 在 PC 端运行解锁命令如下(fastboot 命令可从 SDK/tools 目录得到) # fastboot oem unlock c) 通过音量和 Power 键选 Yes,重新启动,此时看到屏幕下面有一个解决锁标志 2) 注意:解锁后手机里的用户数据全被清除了,所以解锁之前需要先备份 4. 刷带 nandroid 的 recovery recovery 用于系统升级,通常情况下即使刷坏了,也不影响手机正常使用。它只对 boot, system, userdata 三个分区做备份,有些版本的 recovery 带 nandroid 功能,它用于备份 和恢复当前手机系统 1) 普通使用 a) 关机后,按 Power+音量减开机,按音量键选 recovery,然后按 Power 进入,此 时看到叹号和小绿人 b) 按音量加减+Power 进入菜单,此模式可以使用 update.zip 升级,但不能备份当 前系统,强烈建议升级前备份原系统,因为原生的一般都比后烧的稳定 c) 按 Power+音量减+滚轮重启 2) 替换带 nandroid 的 recovery,以备份原有系统 a) 下载 recovery-RA-nexus-v1.7.0.img(见下面指定的地址) b) 关机后,按 Power+音量减开机,按音量键选 fastboot,然后按 Power 进入 c) 在 PC 端运行烧写命令如下 $ fastboot flash recovery recovery-RA-nexts-v1.7.0.img d) 在手机端菜单中选择进入 bootloader e) 在 bootloader 中选 recovery,就可看到 recovery 的新选项,用轨迹球可以操作 f) 备份数据和恢复选项 更新的 recovery 除正常备份外还可以备份 google 帐号数据,备份 app2sd 中扩 展的数据,和恢复到选定的版本(早期版本只支持恢复到最后备份的版本) 3) 注意 用以上方法烧写 recovery 分区,系统重启后 recovery 又会恢复,这是由于开机时 被/data/recovery.img 恢复了,如果不想被刷回,可将下载的 recovery.img 放到/data/ 下即可(需要 root 权限) 5. 编译 android 2.3(如不想编译请跳过此步,直接下载编好的 img 烧写) 18 2010 年谢彦的 Android 笔记 1) 安装 jdk android 之前的版本使用 jdk1.5 编译,而 android 2.3 默认要求使用 jdk1.6 a) 安装 jdk 1.6 $ sudo apt-get install sun-java6-jdk b) 在同一台机器上同时编译 android 2.2 和 android 2.3,用以下方法进行切换 $ sudo update-java-alternatives -s java-1.5.0-sun 2) 用 git 下载 2.3 源代码 配置 linux 环境,安装 git 及 repo 请参见相关文档 3) 解决只能在 64 位系统编译的问题 android 2.3 默认只能在 64 位系统中编译,为了不重装系统可以用以下方法在 32 系统上编译 a) 修改 main.mk $ vi build/core/main.mk 将 75 行左右判断 64 位的部分注释掉,或修改如下: ifneq (i686,$(findstring i686,$(build_arch))) b) 修改 clearsilver 中的编译选项,将下面四个文件中的-m64 改为-m32 external/clearsilver/cgi/Android.mk, external/clearsilver/java-jni/Android.mk, external/clearsilver/util/Android.mk, external/clearsilver/cs/Android.mk 4) 编译前的准备工作 a) 连接手机和电脑 b) 将手机中的没有源码的库补丁到源码中(我的 N1 系统为 android 2.2) $ cd device/htc/passion/ $ ./extract-files.sh 此处需要的 adb 命令从 SDK 中获取 c) 修改源码 解决照像摄像问题(android 2.3 支持了多摄像头之后接口改变),修改 frameworks/base/services/camera/libcameraservice/CameraService.cpp frameworks/base/media/libstagefright/omx/OMXNodeInstance.cpp frameworks/base/media/libstagefright/OMXCodec.cpp frameworks/base/media/libstagefright/CameraSource.cpp d) 解决进应用闪白问题,修改 frameworks/base/libs/ui/GraphicBuffer.cpp 5) 编译 $ . build/envsetup.sh $ lunch 3 # 此处选择硬件平台为 N1(Passion) $ choosecombo 1 1 full_passion 3 # 3 为指定编译工程模式,即带 root 权限 $ make –j6 6. 下载 img 1) 此版本为个人测试使用,在本人上周网购的自带android 2.2 的港版N1 上正常使用, 不能保证所有N1 都使用正常,烧机后果自负,建议大家自行编译。再次提醒:请 在烧写前先用recovery nandroid备份当前系统。以下为下载地址: http://iask.sina.com.cn/u/ish?retcode=0 (含md5, system, userdata, boot, recovery) 2) 下载后可通过 fastboot 烧写,方法如下 19 2010 年谢彦的 Android 笔记 $ fastboot flash system system.img $ fastboot flash boot boot.img $ fastboot flash userdata userdata.img 7. 参考 1) Android 2.3 使用的google market可从此处下载 http://blog.csdn.net/silenceburn/archive/2010/12/24/6096822.aspx 2) 设置apn的方法 http://mobile.yesky.com/447/9288447.shtml 3) Recovery的使用请参考 http://anriqing.blogbus.com/logs/77459519.html 20 2010 年谢彦的 Android 笔记 1.7 系统结构 1. 镜像文件 image 1) 如何得到镜像文件 a) 编译 android 源码之后,在 out/target/product/generic 产生 ramdisk.img、system.img、userdata.img b) SDK 的 platforms\android-*\images ramdisk.img、system.img、userdata.img 2) 各镜像文件的含义 a) system.img 是由 system 目录打包压缩得到的,以只读方式挂载。 b) userdata.img 是由 data 目录打包压缩得到的,以读写方式挂载,用于存放用户 数据,用户安装的软件包在被装在这里。 c) ramdisk.img 是模拟器的文件系统,把 ramdisk.img 解压出来可知道,ramdisk.img 里的文件和根文件夹的文件基本一样。 3) 镜像文件的挂载顺序 模拟器装载 ramdisk.img 并解压到内存,接着分别把 system.img 和 userdata.img 挂 载到 ramdisk 下的 system 和 data 目录。 4) 如何更改系统的镜像文件 a) 模拟器 运行模拟器时指明镜像文件名参数,可以使用新生成的镜像文件 b) 真机 通过烧写替换原有镜像文件 2. 系统目录说明 1) 应用程序安装目录 a) 系统应用程序所在目录 /system/app/*.apk b) 用户安装应用程序所在目录 /data/app/*.apk c) 注意: i) 在模拟器中,每重启一次,/system/app/下的应用都会被还原,有时/data/app 下也会被清除 ii) 若在/system/app 和/data/app 下有重名的应用,不一定会启动哪一个,尤其是 在 adb install 杀死正在运行的程序时,有时旧的就会被启动 2) 用户数据所在目录 /data/data/应用包名/shared_prefs 配置文件 /data/data/应用包名/databases/* 库文件所在目录 3) SD 卡对应目录 /sdcard/ 21 2010 年谢彦的 Android 笔记 1.8 模拟器调试与真机调试 1. 模拟器调试 运行源码或 SDK 中的 emulator,加参数 2. 真机调试 3. 用 usb 线连接 G1 硬件和 PC 4. 若是 windows 系统,则安装驱动 5. 用源码或 SDK 中的 adb 命令看硬件是否连接成功 $ adb devices 正常调试 6. 注意: 1) 在 Linux 连接真机时需使用 root 权限 2) 如果之前连接过模拟器,最好连接前先杀掉 adb 后台进程 $ killall adb 7. Eclipse 中调试 若连接真机,未打开模拟器时,直接连接真机调试 若未连接真机,已打开模拟器时,在当前模拟器中调试 若未连接真机,也未打开模拟器时,打开模拟器调试 若只开多个真机或多个模拟器时,同时有多个可连接的设备,弹出列表供用户选择 8. 命令行中使用 adb 工具调试 连接多个设备时,需要用命令行参数指示设备名或设备类型 $ adb –s 设备名 shell 设备名由 adb devices 列出 $ adb –d shell 与硬件设备相连 $ adb –e shell 与模拟器相连 22 2010 年谢彦的 Android 笔记 1.9 安装和卸载应用程序(apk包) 1. 安装 1) 安装第三方应用 $ adb install apk 文件名 2) 安装系统应用 $ adb remount $ adb push apk 文件名 /system/app // apk 文件名形如 testme.apk 2. 卸载 1) $ adb uninstall 包名 // 包名形如 com.android.testme 2) Home->设置->应用程序->管理应用程序->选择某应用程序->卸载 3. 相关文件 1) /system/app/apk 文件 系统应用 2) /data/app/包名.apk 第三方应用 3) /data/data/包名 此位置用于存储用户数据 4) /data/dalvik-cache/组合名.dex dex 文件是 Android 虚拟机 Dalvik 支持的字节码文件格式 5) /data/data/com.android.launcher/databases/launcher.db Launcher 是 Android 应用程序的启动器,launcher.db 是应用程序数据库。 若应用程序数据发生混乱,删掉数据库文件,并杀掉 com.android.launcher 进程, 再使 Launcher 重新启动并重新生成应用程序数据库,以恢复错误 $ adb shell $ cd /data/data/com.android.launcher/databases/ $ rm launcher.db $ ps // 找到 com.android.launcher 对应的进程号 $ killall 进程号 重新进入应用列表界面(Home),此时 launcher 自动被重启,数据库重新生成 4. apk 的格式 apk 文件将 AndroidManifest.xml 文件、应用程序代码(.dex 文件)、资源文件和其他文 件打成一个压缩包 $ mv testme.apk xx.zip $ mkdir tmp; cd tmp $ unzip ../xx.zip 此时可看到 apk 包中的内容 23 2010 年谢彦的 Android 笔记 常用工具 5. Log 1) logcat 不同级别的打印信息,级别如下 V Verbose D Debug I Info W Warn E Error F Fatal S Silent 2) 如何在 log 里打行号和时间 getFileName () getClassName () getMethodName () getLineNumber () 6. Adb 工具介绍 1) 把程序装手机里:一般程序装 apk 即可 a) 手机打开,边上 usb 线,直接连上电脑 b) 系统 ubuntu 8.04 sdk 包 android-sdk-linux_x86-1.5_r3/tools/adb shell 变 root 权限(因为连接真机,若边模拟器就无所谓哪个用户了) c) 使用命令 adb devices 看设备是否连上了 如果同时启了模拟器和连接了手机,adb 会让你选择与谁连接 d) 注意:如果你有多个 SDK,千万要使用匹配的 adb 命令,最好用绝对路径,否 则很容易得到提示说找不设备,如果说找不到 adb,请尝试以下方法 $ killall adb $ rmmod ehci_hcd $ ./adb kill-server $ ./adb start-server 2) adb 常用参数 a) adb devices 察看手机是否连接(手机需要打开 USB debug) b) adb pull A 为手机路径,B 为电脑路径,意思为:把文件从手机复制到电脑上 c) adb push A 为手机路径,B 为电脑路径,意思为:把文件从电脑复制到手机上 d) adb remount 得到手机的系统文件读写权 e) adb install 包名 安装 pc 中的 apk 软件到手机 f) adb shell 进入手机的超级终端 Terminal 3) adb shell a) 看当前 log 信息 24 2010 年谢彦的 Android 笔记 # logcat b) 在 adb shell 用普通 shell 命令 # busybox df # busybox ls c) android 上的网络调试 adb shell 支持以下命令 i) # ping 发出 ping 命令,查看 google.com 是否可用 ii) # ifconfig lo 是本地或 loopback 连接。 tiwlan0 是 WiFi 连接 d) 数据库使用与调试 i) 操作数据库 # cd /data/data/com.android.mails/databases/ # sqlite3 库名 sqlite > select * from 表名 Ctr+D 退出 程序中参见关键字: execSQL, rawQuery ii) 查看数据字典 sqlite > .sch 25 2010 年谢彦的 Android 笔记 1.10 系统升级 1. 说明 一般常用系统升级有两种方式 update.zip 和 fastboot, 下面介绍它们的区别和联系 2. update.zip 1) 使用方法 一般把 update.zip 放在 SD 卡上,按 home+power 重启到烧机模式,通过在菜单中 选择之后烧写 2) 编译源码时 update.zip 会生成在 out/target/product/xxxx/目录中(只有针对某硬件的 才能生成,虚拟机版本没有,因为里面包含内核所在的 boot.img,不针对硬件, 不编内核),它是对整个系统的升级 3) update.zip 可以更新整个系统,或更新系统的一部分,update.zip 通常包含一个 update-script 脚本,用以决定更新 zip 中的哪些部分到系统中,全部更换为更换 system, userdata, boot 个分区的全部内容,部分更新可以更新单个或多个系统中的 文件 3. fastboot 1) 使用方法 用数据线连接手机和电脑,按 camera+power 重启到工程模式,然后在 PC 端使用 android 开发包自带的 fastboot 命令烧写 2) 通常烧写 system.img, userdata.img,boot.img 三个包,编译源码时*.img 会生成在 out/target/product/xxxx/目录中,只有针对某硬件的编译才能生成 boot.img. 有时也烧写 recover.img,recover.img 是烧机模式使用的系统 4. 对比 1) 系统生成 update.zip 中的 system 目录对应 fastboot 方法中的 system.img 2) 系统生成 update.zip 中的 boot.img 对应 fastboot 目录中的 boot.img 3) update.zip 更灵活,fastboot 更稳定 26 2010 年谢彦的 Android 笔记 1.11 android系统支持app2sd(修改boot.img) 1. 说明 app2sd 就是把应用程序放在 SD 卡上。有些 android 手机的用户数据分区(userdata)比 较小(比如 G1 只有 76M),dalvik 和 cache 和用户数据就占了大半,使得安装了几个 软件后就没有空间了。为了安装更多软件,在 SD 卡上划出部分空间用于存在新软件 和数据,使我们的手机可以使用更多软. 2. froyo(android2.2)之前版本的 app2sd 1) 原理 froyo 之前版本不支持 app2sd,所以网友用修改源码的方式加入了该功能的支持。 一般情况下都 SD 卡都默认分成一个 windows 可识别的分区(FAT)。因为有 linux 系统的权限问题,为了让它可以存放软件,需要把 SD 卡的一部分划分成 Linux 的使用的 ext2 文件系统,然后在开机时把此分区挂载到某处,并通过链接的方法, 让系统从 SD 卡中读取软件。 2) 实现 a) SD 卡分区 i) 使用 Linux 系统中的工具 fdisk,它是命令行工具,很快很简单 ii) Windows下的图形化工具 具体步骤见: http://www.3haoweb.cn/a/digital/mobile/2010/0609/2273.html b) 修改 boot.img 使得新分区在启动时被自动挂载 i) 说明: ♦ 也可以从网上下载带 app2sd 功能的 update.zip 包,升级整个系统,但是 那样的话还要备份设置、数据、软件太麻烦,所以我选择修改我手机中 自带的 boot.img,以最小的修改来实现功能 ♦ 修改 boot.img 中的 initrc(系统启动时运行的脚本,自动挂载 SD 卡的 ext2 分区) ii) boot.img 是什么 boot.img 包括了 2K 的文件头,后面紧跟着是用 gzip 压缩过的内核,再后面 是一个 ramdisk 内存盘(系统基本目录结构的镜像档),然后紧跟着第二阶 段的载入器程序(这个载入器程序是可选的,在某些映像中或许没有这部分) iii) 修改本机的 boot.img 包 ♦ 使用 nandroid 备份数据 任何对系统的修改都要先备份系统数据 ♦ 从机器中取出当前的 boot.img $ export PATH=$PATH:$ANDROID_DIR/out/host/linux-x86/bin/ $ adb shell # cat /proc/mtd/ 查看 boot 对应的 mtdx,一般是 mtd2 # cat /dev/mtd/mtd2 > /sdcard/boot.img 假设 boot 对应 mtd2 # mkdir /system/sd1 建立目录以挂载分区 # exit $ adb pull /sdcard/boot.img ./ 复制到 PC 中 ♦ 解包 27 2010 年谢彦的 Android 笔记 下载工具split_boot.img.pl http://cid-f8aecd2a067a6b17.office.live.com/self.aspx/.Public/android/referen ce/split^_bootimg.zip $ ./split_boot.img.pl boot.img 解包,解出内核和ramdisk包两部分 $ mkdir ramdisk; cd ramdisk $ gzip -dc ../boot.img-ramdisk.gz |cpio -i ♦ 修改启动脚本 $ vi init.rc 如果是乱码,请使用 reset 命令恢复一下 在 mount 最后加入 mount ext2 /dev/block/mmcblk0p2 /system/sd1 rw ♦ 重新打包 $ cd ../ $ mkbootfs ramdisk |gzip > ramdisk-new.gz $ mkbooting --cmdline ‘no_console_suspend=1 console=null’ --kernel boot.img-kernel --ramdisk ramdisk-new.gz -o boot_new.img (mkbootfs,mkbootimg 可以 android 源码包中取得,和 adb 在一个目录) ♦ 烧写新包到手机 $ adb push boot_new.img /sdcard $ adb shell # cat /dev/zero > /dev/mtd/mtd2 (可能找错没空间,没关系) # flash_image boot /sdcard/boot_new.im ♦ 验证是否成功 然后重启手机即可,重启后用以下命令看一下是否分区是否被挂载 $ adb shell $ df 如果看到/system/sd1 项就成功了 c) 做链接,使系统从 SD 卡读取软件 建立只对软件安装目录做修改(/data/app),这样拨出 SD 后除了后来安装的软 件不能使用之外,不影响手机基本功能的使用 $ adb shell # mkdir /system/sd1/data/ # cd /system/sd1/data/ # busybox cp -a /data/app ./ 建议做 # busybox cp -a /data/app-private ./ 不建议做 # busybox cp -a /data/dalvik-cache ./ 不建议做 # busybox cp -a /data/data ./ 不建议做 # rm -r /data/app # ln -s /system/sd1/data/app /data/app …… 其它目录以此类推 然后重启手机即可 d) 注意 由于 launcher 数据库的关系,可能桌面上看不到原来的那些应用了,不过主菜 单里是有的,再建一遍快捷方式即可 3) 参考 28 2010 年谢彦的 Android 笔记 http://kb.cnblogs.com/a/1743704/ 3. froyo(android2.2)及之后版本的 app2sd 1) 原理 从 froyo 之后版本,android 自身支持了 app2sd 功能,它更合理和安全,使用简单 的设置即可开启此功能。 2) 实现 a) 更改应用的默认安装目录 # pm setInstallLocation 2 默认安装到 SD 卡 # pm setInstallLocation 0 默认安装到内存卡 参数 2 为外存,1 为内存,0 为自动 b) 在界面下使用移至 SD 卡 设置->应用程序->管理应用程序->已下载->点选应用->移至 SD 卡 c) 说明 SD 卡中的 apk 都在挂载的方式使用,SD 卡的都是加密的包 不是所有应用都在放在 SD 卡上,Services, IME, Live Folder/Wallpaper, Widget 等等都不能放上去 29 2010 年谢彦的 Android 笔记 2 基本概念 30 2010 年谢彦的 Android 笔记 2.1 Android组件 2.1.1 基本组件 1. 为什么使用 JDK 用以支持 Android 和 Eclipse:Android 中的应用都是 java 程序,所以想在 Linux 上建 立开发 Android 环境,就需要安装 java 虚拟机 2. Activity 应用程序中每个屏幕显示都通过继承和扩展基类 Activity 在一个应用程序中每个 Activity 都是独立的 3. Service Service 是没有可见的用户界面,但可以长时间在后台运行 4. Broadcast 用户接受广播通知的组件,广播是一种同时通知多个对象的事件通知机制 应用程序注册不同的 Broadcast Receiver,从而接收不同广播通知 不实现图形界面 5. Content Provider 应用程序彼此间需要共享资源,数据通讯时,采用 content provider 机制 它能将应用程序特写的数据提供给另一个应用程序使用 31 2010 年谢彦的 Android 笔记 2.1.2 组件间的通讯 1. ContentProvider 用于提供,ContentResolver 用于调用 2. Intent 用于在不同组件间传递消息:Activity, Service, Broadcast Intent 一般带有一个组件对另一组件的请求的动作名称,请求动作及相关数据 1) Activity 相互调用 Intent in = new Intent(ac01.this, pickup.class); startActivity(in); 2) Activity 与 Broadcast 相互调用 public class AlarmReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { ac01 app = ac01.getApp(); app.btEvent("from AlarmReceiver"); } } Intent intent = new Intent(ac01.this, AlarmReceiver.class); PendingIntent p_intent = PendingIntent.getBroadcast(ac01.this, 0, intent, 0); // We want the alarm to go off 30 seconds from now. long firstTime = SystemClock.elapsedRealtime(); firstTime += 800; // Schedule the alarm! AlarmManager am = (AlarmManager)getSystemService(ALARM_SERVICE); am.setRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP, firstTime, 800, p_intent); 3) Activity 与 Service 相互调用 public class NotifyService extends Service{ @Override protected void onCreate() { ac01 app = ac01.getApp(); app.btEvent("from NotifyService"); } @Override public IBinder onBind(Intent intent) { return null; } } context.startService(new Intent(context, NotifyService.class)); 32 2010 年谢彦的 Android 笔记 2.1.3 intent使用方法 1. 说明 Android 中提供了 Intent 机制来协助应用间或者应用程序内部的交互与通讯。 Intent 的两种基本用法:一种是显式的 Intent,即在构造 Intent 对象时就指定接收者, 这种方式与普通的函数调用类似;另一种是隐式的 Intent,即 Intent 的发送者在构造 Intent 对象时,并不知道接收者是谁,只是指出接收者的一些特性(比如说启动音乐 播放软件) 2. 使用方法 1) 启动服务 a) 关键函数 context.startService()或 context.bindService() b) 示例 Intent i = new Intent(this, MyTestService.class); this.startService(i); // 启动 service 2) 发送广播 a) 关键函数 context.sendBroadcast() b) 发送方 String msg = “test”; Intent i = new Intent(“com.test.bc”); i.pubExtra(“msg”, msg); this.sendBroadcase(i); c) 接收方 IntentFilter intentFilter = new IntentFilter(); intentFilter.addAction(Intent.ACTION_MEDIA_EJECT); registerReceiver(mReceiver.interFilter); 3) 启动应用程序 a) 关键函数 context.startActivity() b) 示例 Intent intent = new Intent(“com.android.browser“, “com.android.browser.BrowserActivity“); startActivity(intent); 3. Intent 的组成 Intent 的参数可多可少,系统根据不同的参数组合过滤出一个或多个适合规则的界面 1) 调用方:以下几个规则可以同时指定,也可以指定一部分或几部分 Component:指定包名类名来调用(见上例),它是晚绑定,不会在编译时报错 Action:指定做什么的规则(比如 ACTION_DIAL 指定拨号类型应用),以供过滤 Data:提供的重要数据,通常是 Uri,同时也提供数据的类型,以供过滤 Type:用于指定类型,以供过滤(比如 ACTION_VIEW 同时指定为 Type 为 Image, 则调出浏览图片的应用) Category:指定范围 Extras:通过 Bundle 类传参, 数据多,数据量大时用它传 Flags:标志位(比如 FLAG_ACTIVITY_NEW_TASK 指定新开一个任务) 33 2010 年谢彦的 Android 笔记 2) 被调用方 在 AndroidManifest.xml 中的中声明规则 例如: 一般程序都需要在 inter-filter 中加入 android.intent.category.LAUNCHER 的 声明, 以便被程序启动器(Launcher)识别, 即以点击图标的方式供用户运行 3) 示例 Intent intent = new Intent(); intent.setClassName(“com.android.browser“, “com.android.browser.BrowserActivity“); // 打开浏览器 Uri data = Uri.parse(“http://www.google.com“); intent.setData(data); // 打开某网页 intent.addFlag(Intent.FLAG_ACTIVITY_NEW_TASK); // 以新建任务方式打开 intent.setAction(Intent.ACTION_VIEW); // 以浏览方式打开 startActivity(intent); 4. Intent 的源码实现 1) Intent 解析,过滤规则对应出具体应用 frameworks/base/core/java/android/content/IntentFilter.java 2) Intent 定义,规定程序中的使用的 Define 与 xml 中字串的对应关系 frameworks/base/core/java/android/content/Intent.java 5. 参考 http://zhubin215130.javaeye.com/blog/614913 34 2010 年谢彦的 Android 笔记 2.2 界面开发 2.2.1 界面元素 1. 窗口:Activity 应用程序中每个屏幕显示都通过继承和扩展基类 Activity 实现 分类:基本 Activity,带内容的 Activity(如 ListActivity) 2. 对话框:Dialog 一种显示于 Activity 之上的界面元素,由 Activity 管理,用于显示一些临时信息和功 能,它比 Activity 开销小 1) 常用对话框: AlertDialog:信息对话框 DatePickerDialog,TimePickerDialog:时间日期选择对话框 ProgressDialog:进度对话框 还可以设置对话框内容为我们自定义的 View 2) 相关函数: onCreateDialog():创建对话框的实现 showDialog():需要显示的时候调用 onPrepareDialog():更改已有对话框时调用 3. 菜单:Menu 一种显示于 Activity 之上的界面元素,由 Activity 管理,用于提供用户一些额外的选 项和设置 1) 常用菜单: Options Menu:按 Menu 键时从屏幕底部滑出的菜单 Context Menu:用户通过在按件上长按调出它 Submenu:用于给菜单分类,可被添加到其它菜单上,不能添加到子菜单上 2) 相关函数: onCreateOptionMenu():创建菜单 (onCreateContextMenu…) onOptionsItemSelected():处理菜单项的单击事件 onPrepareOptionsMenu():动态更新 4. 可视化控件:View 1) View 是可视化控件的基类,Layout 容器的父类也是 View View->ViewGroup->xxLayout 2) 常用控件: TextView, ImageView Button, CheckBox, RadioButton, ImageButton, ToggleButton AnalogClock, DigitalClock EditText, List… 3) 数据绑定:adapter adapter 将控件(如 List, GridView)和复杂数据(如数据,键表)绑定起来 5. 其它界面元素 标题栏 35 2010 年谢彦的 Android 笔记 2.2.2 布局的实现 1. 设置控件在屏幕上如何排布 2. LinearLayout:线性的布局方式 最常用,上下或左右的添加控件 3. GridView:网格布局 控件按照顺序依次填到每个格子里就好了,使界面很整齐 4. TableLayout:表格布局 以行列形式管理子控件,每行为一个 TableRow,TableRow 可添加子控件 5. AbsoluteLayout:绝对坐标布局 可以让子元素指定准确的 x/y 坐标值,并显示在屏幕上。(0, 0)为左上角。 AbsoluteLayout 没有页边框,允许元素之间互相重叠(尽管不推荐)。 不推荐使用,因为其在不同的设备上可能不能很好地工作。 6. RelativeLayout:相对坐标布局 控件可指定他们相对于其它元素或父元素的位置(通过 ID 指定)。 可以以右对齐,或上下,或置于屏幕中央的形式来排列两个元素。 7. FrameLayout:单帧布局 所有的子元素将会固定在屏幕的左上角,后一个子元素将会直接在前一个子元素之上 进行覆盖填充 36 2010 年谢彦的 Android 笔记 2.2.3 事件响应 1. 用注册回调函数的方式响应事件 2. 如果没被任何一个 View 处理,则由 Activity 处理 3. 常用事件处理 1) onKeyDown() 2) onKeyUp() 3) onTrackballEvent() 4) onTouchEvent() 4. 由于容器控件的层层嵌套 37 2010 年谢彦的 Android 笔记 2.2.4 应用软件代码结构 1. res:资源 资源是在代码中使用到的并且在编译时被打包进您的应用程序的附加文件 在代码中通过 R 类调用(R 类自动生成,形如 R.string.title) 1) layout:存放布局用的 xml 文件 a) 布局就像容器,里面可以装下很多控件,每个控件又有布局,字体设定, 如字体大小在 layout 的 xml 里使用: Android:textAppearance=”?android:attr/textAppearanceSmall” b) 默认的布局文件 main.xml 2) drawable:存放图片图标 3) values:存放常量的 xml 文件(如字串) 2. src:代码 3. AndroidManifest.xml 包含应用程序的基本信息,有哪些组件,哪些资源 1) 应用程序的 java 包名 2) 应用程序中所含组件(Activity, Service, BroadcastReceiver, ContentProvider) 3) 应用程序调用其它程序时的权限 4) 应用程序被其它程序调用时对其它程序的权限要求 5) 使用 Android API 的最低版本 6) 应用程序依赖的库 38 2010 年谢彦的 Android 笔记 2.2.5 国际化的支持(多语言) 1. 在系统中如何设置本地语言 桌面->settings->Local & text->Select locale->Chinese(China) 2. 在程序中如何加入多语言支持 res/value 中是默认的字体 把它复制一份成为 res/value-zh-rCN 文件夹,然后把其中文字改为简体中文 3. 在不改变系统设置的前提前,测试当前应用对某一语言的支持 import java.util.Local; // 引入相关类 import android.util.DisplayMetrics; 在 OnCreate 函数中加入以下本地化设置 Resources res = getResources(); Configuration conf = res.getConfiguration(); conf.locale = Locale.SIMPLIFIED_CHINESE; // 设置为简体中文 DisplayMetrics dm = res.getDisplayMetrics(); res.updateConfiguration(conf,dm); 编译后再运行程序时,读取的字串就是 res/value-zh-rCN 目录中 strings.xml 里的文字 了 39 2010 年谢彦的 Android 笔记 2.2.6 常见问题及解决方法 1. android.app.Application 创建一个属于你自己的 android.app.Application 的子类,然后在 manifest 中申明一下 这个类,这是 android 就为此建立一个全局可用的实例,你可以在其他任何地方使用 Context.getApplicationContext()方法获取这个实例,进而获取其中的状态 2. 用别人写的 java 文件改出自己的,R.xx 报错 由于资源找不对,要把它的 res 文件和 AndroidManifest.xml 内容也做相应替换,注意 xml 里边要改成自己的类名 3. android 中可以使用 java 中的类吗 一般数据结构使用它,而界面使用 android 自带的界面元素 4. layout 中的控件与程序中控件的关系 平等的,layout 中的控件用 R.id.xxx 得到 5. 布局冲突 requestWindowFeature 与 setContentView 冲突 40 2010 年谢彦的 Android 笔记 2.2.7 android是重要的包 1. android.app :提供高层的程序模型、提供基本的运行环境 android.content :包含各种的对设备上的数据进行访问和发布的类 android.database :通过内容提供者浏览和操作数据库 android.graphics :底层的图形库,包含画布,颜色过滤,点,矩形,可以将他们直 接绘制到屏幕上. android.location :定位和相关服务的类 android.media :提供一些类管理多种音频、视频的媒体接口 android.net :提供帮助网络访问的类,超过通常的 java.net.* 接口 android.os :提供了系统服务、消息传输、IPC 机制 android.opengl :提供 OpenGL 的工具 android.provider :提供类访问 Android 的内容提供者 android.telephony :提供与拨打电话相关的 API 交互 android.view :提供基础的用户界面接口框架 android.util :涉及工具性的方法,例如时间日期的操作 android.webkit :默认浏览器操作接口 android.widget :包含各种 UI 元素(大部分是可见的)在应用程序的屏幕中使用 41 2010 年谢彦的 Android 笔记 2.3 界面元素分析 1. 重要元素 1) 普通控件 a) View 它是所有控件的基类,一个控件通常占用屏幕上的一个矩形区域,并负责绘图 及事件处理 b) ViewGroup ViewGroup 是一个特殊的控件类,它的父类是 View。它的功能就是装载和管理 下一层的 View 对象和 ViewGroup 对象 c) xxLayout FrameLayout, LinearLayout, TableLayout, RelativeLayout, AbsoluteLayout 它们的父类都是 ViewGroup,是 ViewGroup 的具体实现,它们都为容器,用于 设置屏幕布局 2) 控件控制 a) ViewParent ViewParent 是一个接口(interface),并未做具体实现,实现 ViewRoot 和 ViewGroup 时使用到它 b) ViewRoot 介于普通控件和窗口管理及绘图间的中间层 ViewRoot 事件处理, 由它把上层的控件画到 surface 上, 使用同一个 ViewRoot 的 View 画在同一个 surface 上 它实现了 View 间的事件处理和逻辑处理 3) 窗口相关 a) Activity 一个逻辑管理,实现了往 Window 里加 View, 它本身控制生命周期这些逻辑, 并不负责绘图 b) Dialog 对话框,它是在 Activity 内部处理的 c) Toast Toast 主要用来做用户提示,看起来和 Dialog 差不多,只是没有按钮,没有焦 点,显示一会,然后自动消失 d) Window 它是一个抽象类,是真正意义的窗口,控件的载体 e) WindowManager 衔接屏幕和控件,使用它可以越过 Activity 层,直接把控件画在屏幕上 它维护多个 ViewRoot f) Display 4) 底层绘图 a) Surface b) Layer 2. 如何看基类 http://www.4feets.com/android1.5_ref/docs/reference/android/widget/ListView.html 42 2010 年谢彦的 Android 笔记 2.4 修改公共控件 1. 位置 公共控件的代码在源码目录 android/frameworks/base/core/java/android/中 后台服务的代码在源码目录 android/frameworks/base/services/java/android/server 中 2. 修改 修改其中代码并执行 mm 编译 形如: $ cd frameworks/base/services/java/com/android/server/ $ vi IntentResolver.java $ mm 3. 替换 编译后用生成的包替换手机上/system/framework/中相应的包 编译后生成的文件见提示 形如: $ cd out/target/product/general/system/framework/ $ adb push services.jar /system/framework/ 4. 使新的包生效 1) 方法 1: 重启手机后生效 2) 方法 2: 杀死 system_server 进程,使系统重新启动,这种方法速度快 $ ps 找到 system_server 对应的 pid, 假设它为 1219 $ kill 1219 5. 注意 1) 绝大多数情况下都能成功,不过最好在替换前备份原有 jar 包 2) 如果替换重要的包使机器不能启动到桌面了,可以通过重新打包 system.img,然 后重新烧写(fastboot)到系统中解决此问题,注意 system.img 的大小 $ ./out/host/linux-x86/bin/mkyaffs2image -f out/target/product/generic/system out/target/product/generic/obj/PACKAGING/systemimage_unopt_intermediates/system.img $ out/host/linux-x86/bin/acp -fpt out/target/product/generic/obj/PACKAGING/systemimage_unopt_intermediates/system.img out/target product/generic/system.img $ fastboot flash system system.img 此时用 fastboot 烧写方式重启手机 43 2010 年谢彦的 Android 笔记 2.5 源码中常用于参考的代码 1. 说明 在应用开发时,常遇到有些功能不知是否能实现,不知如何实现的问题,在网上资料 又不多的情况下,可以用参考已有源码的方式来解决这些问题,经常参考的目录如下 2. 系统控件的实现 了解有什么控件,控件的功能,功能如何实现 frameworks/base/core/java/android/* 3. 应用程序的实现 Android 系统中所有的应用程序都在这里实现,了解它们如何实现 package/apps/* 4. 系统提供的例程 各种类型程序的实现范例 development/samples/* 44 2010 年谢彦的 Android 笔记 3 程序开发 45 2010 年谢彦的 Android 笔记 3.1 相关工具介绍 3.1.1 从c++到java(一) 1. 目的 由于之前都用 C/C++写程序,现在改用 JAVA 写 android 程序,有些相关的认识和积 累,记录下来,自已保存资料,也供大家参考,帮助您在和我遇到同样问题的时候, 可以快速解决。 我遇到的问题基本分以下几类: 1) 不了解程序的流程:编译,执行,如何代码组织 2) 看不懂别人写的程序:重要的关键字不认识 3) JAVA 的特性和习惯用法:不明白什么意思 4) 某些功能不知如何实现:找不到 JAVA 对应的语法 2. 流程 1) 组织代码 a) 以类组织 整个 JAVA 语言建立在类的逻辑结构上,任何想法都必须封装在类中,也就是 说不允许函数,变量定义在类以外。 b) 程序入口 既然所有函数都必须封装在类中,主函数(main)也不例外,哪个类是入口, 就把 main 放在该类里边。对其它类和方法的调用可以写在 main 中,形如: public class HelloWorld { public static void main(String args[]) { System.out.println("Hello World!"); } } c) 文件类型 i) *.java 源程序代码文件 一般一个类写在一个.java 文件中,也可以把两个类写在一个 java 文件中, 编译出来成两个.class public 的类因于供他人调,所以要单写一个 java 文件,文件的名字和类名一 致 ii) *.class 编译后生成的字节码文件 iii) *.jar JAVA 程序的打包文件(类似 ZIP 包,可用 WINRAR 等工具打开) 2) 编译 编译单个文件 $ javac xxx.java 编译多个文件 $ javac *.java 46 2010 年谢彦的 Android 笔记 3.1.2 从c++到java(二) 1. JAVA 特性和习惯用法 1) 指针 JAVA 中没有指针,用以下方法使用 Test a = new Test(); a.t(); 2) 地址传递和值传递 原始类型是值传递 对象 (非原始)类型是地址传递 3) 手动回收资源 一般情况下,只要 new,系统会自动释放,但更严谨地做法是手动回收,如下: Employee e1 = new Employee( "Susan", "Baker" ); …… e1 = null; System.gc(); // garbage collection 此时析构函数 protected void finalize()会被调用 4) 内嵌类(一个类中声明另一个类) a) 内嵌类可以放在类中的任意一个位置,程序都可以找到它 b) 内嵌类的好处 内嵌类可以使用所属类的私有变量和方法 内嵌类的作用域只在所属类内部,其它类是不可见的,从而减少混乱 节约资源 5) 匿名内嵌类(anonymouse inner class) a) 没有具体名字的内嵌类,因为只使用一次,所有一般不命名 b) 写法 fancyButton.addActionListener ( new ActionListener() // ActionListener 是一个 interface, 含一个方法 {// anonymous inner class public void actionPerformed( ActionEvent event ) { JOptionPane.showMessageDialog( null, "You pressed: " + event.getActionCommand() ); } } ); 它返回的是一个实例,只处理从这个 handler 来的信息 c) 运行时生成内嵌类的 class 文件,形如 xxx$1.class 6) 事件处理 a) 引入 java.awt:事件处理包 b) 需要设置 listener 和 handler c) 任何一个对象都可以被监听(addListener), 当它 listen 的事件发生时就调 add 时指定的 handler 处理 7) 多线程 47 2010 年谢彦的 Android 笔记 a) 继承 Thead 类 b) 关键的方法 start(),sleep(),destroy(),resume(),stop(),getName() c) 线程执行优先级 1-10 d) 在外部使用它 PrintThread thread1 = new PrintThread( "thread1" ); thread1.start(); // 此时进入 ready 状态,等待资源 8) 界面 a) 引入 java.swing;JFC (用于在 java 中开发界面) b) 由于基类原因,控件即可以 draw 也可以做为 contrainer 2. JAVA 对应语法 1) 类的引入 a) 在某一类(文件)中想使用其它类时(如同 C 语言中的包含头文件) b) 使用 import 关键字,形如 import java.io.* 2) 工具函数的写法 C++中有些工具函数,可能被多处调用,本身又不属于某个类,在 JAVA 中可以专 写一个 Utility.java,里边的函数都是 static 的,直接用里边的函数,不用实例化 3) 枚举 近似类的写法,形如: public enum FolderType { HOLDS_FILDERS, HOLDS_MESSAGES } FolderType.HOLDS_FILDERS 4) 宏定义 在类中 public static final int IOERROR = 1; 5) ifdef 没有 ifdef 类似的功能可以使用,只能用常量或变量的判断来选择执行代码的不同 部分 48 2010 年谢彦的 Android 笔记 3.2 常用技术 3.2.1 如何新建和使用控件 1. 知识点 如何在 layout(xml)中使用自定义的控件 2. 示例 1) 功能:实现一个新的浏览器控件,使点击浏览器中任何位置都能打印 Log 信息 2) 步骤: a) 建立 project i) 在 eclipse 中点击菜单 File->New->Project…… ii) 选择 Android Project 按 Next iii) 填写 project 的各项内容如下 Project name: test_xy // 目录名, 它位于你设定的 workspace 之下 Package name: com.android.test //打包名称 Activity name: .TestXy // 类名(生成文件 TestXy.java) Application name: test_xy // 可执行程序名 然后点 Finish 按钮 b) 继承一个已有控件,加入新的属性和方法 i) eclipse 左侧:test_xy->src->com.android.test 点右键 New->class ii) 建立新控件:Name: MyWebView,其它使用默认选项 MyWebView.java 内容如下: package com.android.test; import android.view.MotionEvent; import android.webkit.WebView; import android.content.Context; import android.util.AttributeSet; import android.util.Log; public class MyWebView extends WebView { public MyWebView(Context context) { this(context, null); } public MyWebView(Context context, AttributeSet attrs){ this(context, attrs, 0); } public MyWebView(Context context, AttributeSet attrs,int defStyle) { super(context, attrs, defStyle); } // 注意实现带三个参数的构造函数 public boolean onTouchEvent(MotionEvent ev) { // 加入新功能 int action = ev.getAction(); Log.d("XY_TEST", "now recv key: " + action); return super.onTouchEvent(ev); 49 2010 年谢彦的 Android 笔记 } } c) 修改 xml 文件 i) eclipse左侧:test_xy->res->layout->main.xml修改其中内容如下 注意使用全名, 即com.android.test.MyWebView, 否则找不到新控件 d) 运行 i) 在 eclipse 中点击菜单 Run->Run Configurations…… ii) 双击左边的 Android Application,产生了一个 New Configuration,点开它填 写内容如下: Name: yan_config // 随便起一个 Project: test_xy // 刚才起的 project, 即目录名 iii) 点击 Apply,然后点 Run,多等一会儿就出来了 iv) 此时点击右上的 DDMS,可看到 Log 信息,在触摸 WebView 控件时,可看 到刚才加入的 Log 信息 50 2010 年谢彦的 Android 笔记 3.2.2 使用定时器Timer及消息处理 1. 知识点 1) 如何使用 handler 和 message 2) 如何延时调用 a) 使用延迟发消息的方式 b) 也可以使用android.util.Timer与handler相结合的方式 见 http://hi.baidu.com/iammuyue/blog/item/20ef6b10bbc92377cb80c467.html 2. 示例 1) 功能:实现一个应用界面,在用户长按触模屏两秒后,打出 Log 信息 2) 步骤: a) 建立 project i) 在 eclipse 中点击菜单 File->New->Project…… ii) 选择 Android Project 按 Next iii) 填写 project 的各项内容如下 Project name: test_xy // 目录名, 它位于你设定的 workspace 之下 Package name: com.android.test //打包名称 Activity name: .TestXy // 类名(生成文件 TestXy.java) Application name: test_xy // 可执行程序名 然后点 Finish 按钮 b) 修改 TestXy.java 代码如下 package com.android.test; import android.app.Activity; import android.os.Bundle; import android.view.MotionEvent; import android.os.Handler; import android.os.Message; import android.util.Log; public class TextXy extends Activity { /** Called when the activity is first created. */ static final int MESSAGE_LONG_PRESS = 1; // 定义长按事件 ID static final int LONG_PRESS_TIMEOUT = 2000; // 定义长按为 2 秒 final Handler mHandler = new LongPressHandler(); // 定义 handler class LongPressHandler extends Handler { // handler 类的实现 public void handleMessage(Message msg) { // 事件处理函数 switch (msg.what) { case MESSAGE_LONG_PRESS: // 选择事件 ID Log.d("TEST_XY", "now long press!"); break; } } 51 2010 年谢彦的 Android 笔记 } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); } public boolean onTouchEvent(MotionEvent ev) { // 处理触屏事件 int action = ev.getAction(); // 得到触屏动作 if (action == MotionEvent.ACTION_DOWN) { // 手指按下 mHandler.sendMessageDelayed(mHandler .obtainMessage(MESSAGE_LONG_PRESS), ONG_PRESS_TIMEOUT); // 延时 2 秒后发送事件 } else if (action == MotionEvent.ACTION_UP) { // 手指抬起 mHandler.removeMessages(MESSAGE_LONG_PRESS); // 取消延时事件 } return false; } } c) 运行 i) 在 eclipse 中点击菜单 Run->Run Configurations…… ii) 双击左边的 Android Application,产生了一个 New Configuration,点开它填 写内容如下: Name: yan_config // 随便起一个 Project: test_xy // 刚才起的 project, 即目录名 iii) 点击 Apply,然后点 Run,多等一会儿就出来了 iv) 此时点击右上的 DDMS,可看到 Log 信息,在长按屏幕两秒后,可看到刚 才加入的 Log 信息 52 2010 年谢彦的 Android 笔记 3.2.3 操作调试数据库与ContentProvider详解 1. 知识点 1) Android 中操作数据库——SQLiteOpenHelper 用于操作数据库 利用它实现在数据库不存在时新建,被访问的数据与当前版本不一致时的更新, 用它提供访问的句柄 2) Android 不同应用中共享数据——ContentProvider 某个应用把某个操作数据的类和一个 URI 对应起来,ContentProvider 的子类,必 须实现查询,插入,删除,更新等抽象方法,以备外界公共接口访问数据 外部应用通过这个 URI 和一些公共接口得到该应用提供的数据 3) 使用数据库的注意事项 a) 加 try cache 2. 示例 1) 操作数据库与提供 ContentProvider public class DataProvider extends ContentProvider { private static final String DATABASE_NAME = "path.db"; // 数据库名 private static final int DATABASE_VERSION = 2; // 数据库版本号 private static final String TABLE_NAME = "PathTable"; // 数据表名 private static class DatabaseHelper extends SQLiteOpenHelper { // 用于操作数据库的类 DatabaseHelper(Context context) { super(context, DATABASE_NAME, null, DATABASE_VERSION); } @Override public void onCreate(SQLiteDatabase db) { // 当数据库不存在时调用此函数 db.execSQL("CREATE TABLE " + TABLE_NAME + " (" + "timestr" + " TEXT," + "duration" + " TEXT," + "distance" + " TEXT," + "time" + " TEXT" + ");"); // 建立数据库 String sql_1 = "insert into " + TABLE_NAME + " (timestr, duration, distance, time) " + "values('2009/10/29', '10:29', '800', '1111111');"; // 插入数据 try { db.execSQL(sql_1); } catch (SQLException e) { Log.e("ERROR", e.toString()); } } @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { } } private DatabaseHelper mOpenHelper; // 声明操作数据库类的变量,以便使用 53 2010 年谢彦的 Android 笔记 @Override public boolean onCreate() { // 使用该 ContentProvider 时被调用 mOpenHelper = new DatabaseHelper(getContext()); return true; } @Override public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { // 查询功能的实现 SQLiteDatabase db = mOpenHelper.getReadableDatabase(); Cursor c = db.query(TABLE_NAME, projection, null, null, null, null, null); return c; } @Override public Uri insert(Uri uri, ContentValues initialValues) { // 插入功能的实现 String timestr = initialValues.get("timestr").toString(); String duration = initialValues.get("duration").toString(); String distance = initialValues.get("distance").toString(); String time = initialValues.get("time").toString(); SQLiteDatabase db = mOpenHelper.getWritableDatabase(); String sql_1 = "insert into "+ TABLE_NAME + " (timestr, duration, distance, time) values('" + timestr + "', '" + duration + "', " + distance + "', '" + time + "');"; try { db.execSQL(sql_1); } catch (SQLException e) { Log.e("ERROR", e.toString()); } return uri; } @Override public int delete(Uri uri, String where, String[] whereArgs) { // 删除功能的实现 SQLiteDatabase db = mOpenHelper.getWritableDatabase(); if (whereArgs == null) db.delete(where, null, null); else db.delete(where, whereArgs[0] + "='" + whereArgs[1] + "'", null); return 0; } @Override public int update(Uri uri, ContentValues values, String where, String[] whereArgs) { // 实现抽象函数 return 0; 54 2010 年谢彦的 Android 笔记 } @Override public String getType(Uri uri) { // 实现抽象函数 return null; } } 2) 调用 ContentProvider public static final String AUTHORITY = "com.xytest.provider.SQ01"; // 调用 URI 名 public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/PathTable"); // URI 加数据表名 private static final String[] PROJECTION = new String[] { "timestr", "duration", "distance", "time" }; // 定义要查询的字段 void search() { // 遍历数据库,打印数据库内容 Cursor cur = getContentResolver().query(CONTENT_URI, PROJECTION, null, null, null);// 查询 if (cur != null) { cur.moveToFirst(); // 游标移到查询结果第一项 while (!cur.isAfterLast()) { // 判断是否游标已移到查询结果最后一项 Log.d("XIEYAN", "item: " + cur.getString(0) // 打印游标当前项查询结果 + " " + cur.getString(1) + " " + cur.getString(2) ); cur.moveToNext(); // 游标移到查询结果下一项 } } } 3) AndroidManifest.xml 文件修改 // 通过这里声明,把类与 URI 联系起来,以便其它应用调用 3. 数据库调试 $ adb shell // 连接手机设备,进行手机 shell # cd /data/data/com.android.xytest/databases // 进入应用所对应的数据库目录 # sqlite3 path.db // 打开数据库 sqlite> .sch // 查看库中所有的表结构 sqlite> select * from PathTable; // 使用 sql 命令,查看数据表 PathTable 中的数据 55 2010 年谢彦的 Android 笔记 3.2.4 电源管理 1. 知识点 1) 相关概念 a) 出于节电的需要,一般应用在用户一段时间无操作的情况下屏幕变暗,然后进 后休眠状态 b) 用户只能在”设置->声音和显示”中设置所有应用默认的屏幕亮度和进行待机的 时间 c) 电源管理的实现分内核应用两部分,通过下面介绍的接口,我们可以设置应用 程序的电源管理,以控制与其休眠相关的状态(是否需要进入休眠,调整 cpu 频率,键盘灯的开关,屏幕的亮暗等) 2) 设置电源管理常用的几种状态 PARTIAL_WAKE_LOCK 屏幕关,键盘灯关,不休眠 SCREEN_MID_WAKE_LOCK 屏幕灰,键盘灯关,不休眠 SCREEN_BRIGHT_WEEK_LOCK 屏幕亮,键盘灯关,不休眠 FULL_WAKE_LOCK 屏幕亮,键盘灯亮,不休眠 3) 使用电源管理注意事项 a) 可在 onCreate 时设置该界面的电源管理,在 onDestroy 时取消设置 b) 可在 onResume 时设置该界面的电源管理,在 onPause 时取消设置 c) 注意设置是以 Activity 为单位,不是以应用为单位 d) 注意在 AndroidManifest.xml 中声明该应用有设置电源管理的权限 e) 注意加锁解锁要成对出现 f) 注意多个用途最好用多个锁,不要一锁多用,以免出错 g) 注意对运行在后台和异常时对锁的处理 h) 注意在网络连接或传输时最好加锁,以免传输被中断 i) 注意加锁以保证程序逻辑 2. 示例 1) 源码修改 a) 引入电源管理包,以使用相关类 import android.os.PowerManager; b) 类中加入变量 PowerManager.WakeLock mWakeLock; c) 修改 onCreate public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE); mWakeLock = pm.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK, "XYTEST"); mWakeLock.acquire(); } d) 修改 onDestroy public void onDestroy() { super.onDestroy(); 56 2010 年谢彦的 Android 笔记 mWakeLock.release(); } 2) AndroidManifest.xml 文件修改 57 2010 年谢彦的 Android 笔记 3.2.5 开发桌面小程序AppWidget 1. 什么是 AppWidget Android 系统允许某个应用把它自己的控件嵌入到其它的应用之中,这些被嵌入的控 件就是”widget”,发布控件的应用是”:appwidget providers”,而合成控件并显示的应用 是”AppWidget host”. widget 常被译作小应用,小控件,小部件。最常见的 widget 是显示在桌面上时钟, 日历,搜索,相框,音乐等,使用户不用进入应用,就可以方便地使用某种功能。桌 面也是一个应用程序(packages/apps/Launcher),代码中实现了”AppWidget host”,而 时钟,日历是分别实现了不同功能的”appwidget provider”(packages/apps/Calendar) 2. 建立第一个 AppWidget 长篇大论不如立竿见影地看到效果,用以下方法,建立你的第一个 widget $ cd $ANDROID_SRC/development $ cp $ANDROID_SRC/frameworks/base/tests/appwidgets/AppWidgetProviderTest MyWidget -R $ cd MyWidget $ mm $ adb install $ANDROID_SRC/out/target/product/qsd8250_surf/system/app/AppWidgetProvider.apk 注意: 1) android 2.1 因为加载 widget 时需要提供的图标和文字,而此例中没有,所以会在 加载小控件时报错,需要修改 AndroidManifest.xml 如下: 把改为 并在 drawable 下放 icon.png,作为出现在小控件列表中的图标 2) 不能全部 ANDROID 代码一起编,否则会因为类重名而报错 只编此项目没有问题,把文件名,目录名,类名等都改成你定义的名字即可全编 3. 代码分析 1) AndroidManifest.xml 主要描述由哪个 AppWidgetProvider 提供 Widget,最好在其中加入图标和名字,以 免 android 2.0 以上系统中出问题 2) Android.mk 编译规则 3) src/com/android/tests/appwidgetprovider/TestAppWidgetProvider.java 实现 AppWidgetProvider(继承自 BroadcastReceiver)或 BroadcastReceiver,在 AppWidget 应用 update, enable, disable 和 deleted 时接受通知。其中 onUpdate()(或 onReceive()中的 UPDATE 部分)最重要的方法,由它接受通知并更新,一般实现 如下: ComponentName thisWidget = new ComponentName(context, MyProvider.class); AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context); RemoteView views = new RemoteViews(context.getPackageNmae(), R.layout.provider) // 设定布局; appWidgetManager.updateAppWidget(thisWidget, views); // 请求 widgethost 刷新 真正的刷新在 widgethost 所在应用中实现 (AppWidgetHostView.updateAppWidget()),即在 widgetprovider 中只做描述,而在 widgethost 中把描述的资源 inflate 成为真正控件。 4) res/xml/appwidget_info.xml AppWidgetProviderInfo: 描述 AppWidget 的大小,更新频率和初始界面等信息,注 58 2010 年谢彦的 Android 笔记 意 Android 1.6 版本对更新频率支持有问题。 5) res/layout/xxxx.xml widget 的布局文件 6) res/values/strings.xml widget 中使用到的字串 4. 说明 1) 设置界面 有时需要设置界面(configure activity)在第一次运行前被调出,用于设置 AppWidget,它在 res/xml/xxx.xml 中设定,示例代码见: $ANDROID_SRC/development/samples/ApiDemos/src/com/example/android/apis/app widget/ 5. 参考代码 1) 从market下了几个电量显示控件,觉得不是太大就是太小,太难看,要不就是更 新有问题……,于是做了一个Widget,截取了iphone的电池控件图标,大小与icon 一致,仅供学习参考,代码及apk下载地址: http://cid-f8aecd2a067a6b17.skydrive.live.com/self.aspx/.Public/android/widget^_dem o.zip 59 2010 年谢彦的 Android 笔记 3.2.6 代码中运行二进制程序或脚本 1. 知识点 在程序中执行 shell 脚本或程序(线程中执行),并显示进度条 2. 示例 1) 功能 实现在程序中运行命令”sleep 3”,在线程中进行,并显示进度条 2) 代码 …… String commands = "sleep 3"; sendshell(commands); …… public void sendshell(final String commands) { String mymsg = "run " + commands; patience = ProgressDialog.show(this, "please wait", mymsg, true); Thread t = new Thread() { public void run() { try { Process process = Runtime.getRuntime().exec(commands); process.waitFor(); } catch (Exception e) { e.printStackTrace(); } patience.dismiss(); } }; t.start(); } 60 2010 年谢彦的 Android 笔记 3.2.7 Android自带的md5 校验 1. 说明 android 自带的 MD5 校验类 2. 例程 1) 功能 对文件/init.rc 做 MD5 计算,并以字串的方式显示 2) 可从此处下载可独立运行的代码 http://download.csdn.net/source/2660824 3) 使用 linux 命令得到 MD5 值 $ md5sum init.rc 4) 核心代码及说明 import java.security.MessageDigest; import java.io.FileInputStream; import java.io.InputStream; public class MD5 { private static final char HEX_DIGITS[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; public static void main(String[] args) { System.out.println(md5sum("/init.rc")); } public static String toHexString(byte[] b) { StringBuilder sb = new StringBuilder(b.length * 2); for (int i = 0; i < b.length; i++) { sb.append(HEX_DIGITS[(b[i] & 0xf0) >>> 4]); sb.append(HEX_DIGITS[b[i] & 0x0f]); } return sb.toString(); } public static String md5sum(String filename) { InputStream fis; byte[] buffer = new byte[1024]; int numRead = 0; MessageDigest md5; try{ fis = new FileInputStream(filename); md5 = MessageDigest.getInstance("MD5"); while((numRead=fis.read(buffer)) > 0) { md5.update(buffer,0,numRead); } 61 2010 年谢彦的 Android 笔记 fis.close(); return toHexString(md5.digest()); } catch (Exception e) { System.out.println("error"); return null; } } } 62 2010 年谢彦的 Android 笔记 3.2.8 将数据打进apk包 1. 介绍 需要安装一些资源到系统中,比如多媒体文件,配置文件或者某种数据文件,可以把 它打包放在资源 raw 目录中,然后在程序中读取解包,并安装在指定目录下 2. android 框架对多媒体的支持 apk 包中的数据一般都放在 res/raw 目录下,只有它的拥有者能通过 openRawResourceFd 的方式访问,如果不在 java 层访问,或者要将其安装在其它位置, 就需要在 java 程序中对其进行处理 3. 例程 1) 功能 把多媒体及数据文件打在 zip 包放在 res/raw 下,并将其打在安装包 apk 中,在程 序中点击按钮时将其安装在指定目录下 2) 可从此处下载可独立运行的代码 http://download.csdn.net/source/2841538 3) 核心代码及说明 package com.android.mydata; import android.app.Activity; import android.os.Bundle; import android.widget.Button; import android.widget.TextView; import android.content.res.AssetFileDescriptor; import android.content.res.Resources; import android.view.View.OnClickListener; import android.view.View; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.util.zip.ZipEntry; import java.util.zip.ZipInputStream; public class MyDataActivity extends Activity { String rootDirectory = "/data/data/com.android.mydata/data/"; // 安装的目录 TextView status; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); Button btn = (Button) findViewById(R.id.button); status = (TextView) findViewById(R.id.status); btn.setText("install"); // 点击此按钮开始安装 63 2010 年谢彦的 Android 笔记 status.setText("wait..."); btn.setOnClickListener(new OnClickListener() { public void onClick(View v) { unpack(); status.setText("okey..."); } }); } boolean unpack() { FileOutputStream out; byte buf[] = new byte[16384]; try { Resources res = getResources(); // 获得资源句柄 AssetFileDescriptor fd = res.openRawResourceFd(R.raw.test); // 压缩文件为 test.zip InputStream stream = fd.createInputStream(); ZipInputStream zis = new ZipInputStream(stream); ZipEntry entry = zis.getNextEntry(); while (entry != null) { if (entry.isDirectory()) { // 对文件夹处理 File newDir = new File(rootDirectory + entry.getName()); newDir.mkdir(); } else { // 对文件处理 String name = entry.getName(); File outputFile = new File(rootDirectory + name); String outputPath = outputFile.getCanonicalPath(); name = outputPath .substring(outputPath.lastIndexOf("/") + 1); outputPath = outputPath.substring(0, outputPath .lastIndexOf("/")); File outputDir = new File(outputPath); outputDir.mkdirs(); outputFile = new File(outputPath, name); outputFile.createNewFile(); out = new FileOutputStream(outputFile); int numread = 0; do { numread = zis.read(buf); if (numread <= 0) { break; } else { out.write(buf, 0, numread); } 64 2010 年谢彦的 Android 笔记 } while (true); out.close(); } entry = zis.getNextEntry(); } return true; } catch (IOException e) { e.printStackTrace(); return false; } } } 4) 注意:打包数据不能太小,否则会出错。数据打包使用如下命令 zip -r ../test.zip * 4. 参考 源代码语音合成external/svox/picolanginstaller对语音数据的安装 http://cnmsdn.com/html/201010/1287296527ID8341.html 65 2010 年谢彦的 Android 笔记 3.2.9 如何改变窗口的标题栏的布局 1. 知识点 一般应用的 Title 都是建立应用时在 AndroidManifest.xml 中配置的,或是用 setTitle 设置的简单字符串,要是想加入按钮,图片等多个复杂的布局,使用以下方法: 在窗口建立时,可以把一个 xml 布局设置成该应用的 Title 2. 示例 1) 功能:把 title 设置成为一个字串和一个按钮的组合 2) 修改 xxActivity.java 代码 public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); requestWindowFeature(Window.FEATURE_CUSTOM_TITLE); // 注意顺序 setContentView(R.layout.main); // 注意顺序 getWindow().setFeatureInt(Window.FEATURE_CUSTOM_TITLE, // 注意顺序 R.layout.title); } 3) 填加title.xml代码
还剩151页未读

继续阅读

pdf贡献者

ggl123eee

贡献于2012-07-26

下载需要 15 金币 [金币充值 ]
亲,您也可以通过 分享原创pdf 来获得金币奖励!