<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom"><title type="text">博客园_谦虚的天下</title><subtitle type="text">深入探索android,多总结,多创新... ...</subtitle><id>http://feed.cnblogs.com/blog/u/35328/rss</id><updated>2012-05-29T10:59:24Z</updated><author><name>谦虚的天下</name><uri>http://www.cnblogs.com/qianxudetianxia/</uri></author><generator>feed.cnblogs.com</generator><link rel="alternate" type="text/html" href="http://www.cnblogs.com/qianxudetianxia/"/><link rel="self" type="application/atom+xml" href="http://feed.cnblogs.com/blog/u/35328/rss"/><entry><id>http://www.cnblogs.com/qianxudetianxia/archive/2012/05/27/2512447.html</id><title type="text">Android拓展系列(6)--CM9源码下载和编译</title><summary type="text">公司最近也开始基于android4.0 ICS修改框架了，公司的手机暂时不适合拿回家测试，也没有kernel的权限。从个人的角度看，我手上现在有两部手机，一部是Htc G9 Aria，一部是Samsung I9100 Galaxys2,Cyanogenmod的开源代码都提供了对这些手机的驱动支持，并且能方便的编译打包，并安装到手机。上一篇文章是android2.3的编译，已经过时，而且现在ubuntu已经升级到12.04，等等之类的，使我觉得非常有必要重新写一篇新的博客来展示最新的android怎么在最新的ubuntu上编译。基于以上几点，下面我将基于galaxys2来演示如何编译cm9的源码</summary><published>2012-05-27T05:25:00Z</published><updated>2012-05-27T05:25:00Z</updated><author><name>谦虚的天下</name><uri>http://www.cnblogs.com/qianxudetianxia/</uri></author><link rel="alternate" href="http://www.cnblogs.com/qianxudetianxia/archive/2012/05/27/2512447.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/qianxudetianxia/archive/2012/05/27/2512447.html"/><content type="html">&lt;p&gt;公司最近也开始基于android4.0 ICS修改框架了，公司的手机暂时不适合拿回家测试，也没有kernel的权限。&lt;br /&gt;从个人的角度看，我手上现在有两部手机，一部是Htc G9 Aria，一部是Samsung I9100 Galaxys2,Cyanogenmod的开源代码都提供了对这些手机的驱动支持，并且能方便的编译打包，并安装到手机。&lt;br /&gt;上一篇文章是android2.3的编译，已经过时，而且现在ubuntu已经升级到12.04，等等之类的，使我觉得非常有必要重新写一篇新的博客来展示最新的android怎么在最新的ubuntu上编译。&lt;br /&gt;基于以上几点，下面我将基于galaxys2来演示如何编译cm9的源码并打包zip安装到手机。下面是我的参考文章：&lt;br /&gt;&lt;a href="http://source.android.com/source/initializing.html"&gt;http://source.android.com/source/initializing.html&lt;/a&gt;&lt;br /&gt;&lt;a href="http://forum.xda-developers.com/showthread.php?t=1552090"&gt;http://forum.xda-developers.com/showthread.php?t=1552090&lt;/a&gt;&lt;br /&gt;&lt;a href="https://github.com/CyanogenMod/android"&gt;https://github.com/CyanogenMod/android&lt;br /&gt;&lt;/a&gt;这些链接或多或少会有一些问题，从这些这些东西我整理出最简单最有效的一条编译之路，也许会很上面这些文章很多步骤和说法上不一致。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;1.ubuntu12.04的选择&lt;/strong&gt;&lt;br /&gt;我第一次用x64的系统，发现配置环境的时候，会有很多种错误，后来我用32位的系统，安装这些必备的软件则一点都没有出错，所以在这里，如果用12.04系统编译cyanogenmod ics源码的话，我以个人经验推荐使用32位系统。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;2.内存和cpu&lt;/strong&gt;&lt;br /&gt;因为有些朋友在虚拟机上安装ubuntu，所以内存分配可能会容易偏小，建议尽量偏大，我1G内存的时候，编译中出现过错误，重启设置2G的内存就没问题。&lt;br /&gt;cpu太弱的话，编译的过程中进程也容易被kill掉，我出现过一次，重启后ok。所以cpu的水平要注意一下。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;3.java的选择&lt;/strong&gt;&lt;br /&gt;无论是android官方文档还是上面的那篇文章，java的安装都会找不到，他们的软件源有问题。需要手动安装。&lt;br /&gt;但是android ics的编译，官方文章中指出支持openjdk-6-jdk,所以可以直接安装openjdk6即可。&lt;br /&gt;注意:这里我要说明一下,CM9的编译脚本相对于官方源码的编译脚本忽略了或者说处理了一些可能出现的错误的地方，比如说这里java版本的检测，如果是open jdk的话，官方就编译不过，其实是一样的，只需要修改一下脚本(build/core/main.mk)，找到检测java版本的地方：&lt;/p&gt;&lt;div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;"&gt;# Check for the correct version of java&lt;br/&gt;java_version := $(shell java -version 2&amp;gt;&amp;amp;1 | head -n 1 | grep '^java .*[ "]1\.6[\. "$$]')&lt;br/&gt;ifneq ($(shell java -version 2&amp;gt;&amp;amp;1 | grep -i openjdk),)&lt;br/&gt;java_version :=&lt;br/&gt;endif&lt;br/&gt;ifeq ($(strip $(java_version)),)&lt;br/&gt;$(info ************************************************************)&lt;br/&gt;$(info You are attempting to build with the incorrect version)&lt;br/&gt;$(info of java.)&lt;br/&gt;$(info $(space))&lt;br/&gt;$(info Your version is: $(shell java -version 2&amp;gt;&amp;amp;1 | head -n 1).)&lt;br/&gt;$(info The correct version is: Java SE 1.6.)&lt;br/&gt;$(info $(space))&lt;br/&gt;$(info Please follow the machine setup instructions at)&lt;br/&gt;$(info $(space)$(space)$(space)$(space)http://source.android.com/source/download.html)&lt;br/&gt;$(info ************************************************************)&lt;br/&gt;#$(error stop) //如果确定已经安装正确的jdk的话，这句去掉，让编译继续&lt;br/&gt;endif&lt;br/&gt;&lt;/div&gt;&lt;p&gt;CM9的编译脚本直接就去掉了这句话，但是还是要注意一下安装正确的jdk版本。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;4.解决下载过程中googlesource访问不了的问题&lt;/strong&gt;&lt;br /&gt;你需要一个vpn帐号来翻墙。&lt;br /&gt;这个我使用我之前购买的一个VPN，也有免费的VPN，具体的免费VPN 和VPN的配置，大家参考下面两个链接：&lt;br /&gt;&lt;a href="http://173.252.215.172/server/query"&gt;http://173.252.215.172/server/query&lt;br /&gt;&lt;/a&gt;&lt;a href="http://173.252.215.172/setting/ubuntu.shtml"&gt;http://173.252.215.172/setting/ubuntu.shtml&lt;br /&gt;&lt;/a&gt;配置好了VPN，我们的Ubuntu就可以顺利的下载所有的CM9源码。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;5.环境配置&lt;/strong&gt;&lt;br /&gt;参考官方的Ubuntu 12.04(请注意官方文档，区分Ubutu11.10 x6和之前的系统)的要求，我们需要配置好如下环境：&lt;/p&gt;&lt;div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;"&gt;sudo apt-get install git-core gnupg flex bison gperf build-essential&lt;br/&gt;sudo apt-get install zip curl libc6-dev libncurses5-dev:i386 x11proto-core-dev&lt;br/&gt;sudo apt-get install libx11-dev:i386 libreadline6-dev:i386 libgl1-mesa-dev:i386&lt;br/&gt;sudo apt-get install g++-multilib mingw32 openjdk-6-jdk tofrodos python-markdown&lt;br/&gt;sudo apt-get install libxml2-utils xsltproc zlib1g-dev:i386&lt;br/&gt;&lt;/div&gt;&lt;p&gt;应该不会出什么问题。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;6.安装repo&lt;/strong&gt;&lt;/p&gt;&lt;div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;"&gt;cd&lt;br/&gt;mkdir bin&lt;br/&gt;curl https://dl-ssl.google.com/dl/googlesource/git-repo/repo &amp;gt; ~/bin/repo&lt;br/&gt;chmod a+x ~/bin/repo&lt;br/&gt;alias repo="~/bin/repo"&lt;br/&gt;&lt;/div&gt;&lt;p&gt;本来如此即可，但是我们需要随时都能运行repo的话，最好把repo配置到环境中去：&lt;/p&gt;&lt;div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;"&gt;vim ~/.bashrc&lt;br/&gt;#打开后，在文件最后面加上alias repo="~/bin/repo"，然后保存退出&lt;br/&gt;source ~/.bashrc&lt;br/&gt;&lt;/div&gt;&lt;p&gt;下次该用户环境下无论什么时候什么地方都可以repo了。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;7.下载CM9源码&lt;/strong&gt;&lt;br /&gt;列表文件是托管在Github上的：&lt;a href="https://github.com/CyanogenMod/android"&gt;https://github.com/CyanogenMod/android&lt;/a&gt;&lt;/p&gt;&lt;div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;"&gt;mkdir cm9&lt;br/&gt;cd cm9&lt;br/&gt;repo init -u git://github.com/CyanogenMod/android.git -b ics&lt;br/&gt;repo sync&lt;br/&gt;&lt;/div&gt;&lt;p&gt;ics分支就是CM9 ICS的分支了。&lt;br /&gt;慢慢的等待吧(如果下载过程中，不停的提示打不开googlesource的话，记得参考前面配置vpn翻墙，本人改host无效)。&lt;/p&gt;&lt;p&gt;8.配置USB&lt;br /&gt;这一步是为了后面要从你的手机拷贝系统属性文件，用户编译源码的。&lt;br /&gt;ubuntu下不需要装驱动才能连接的上你的手机，但是需要配置，可参考官方：&lt;a href="http://source.android.com/source/initializing.html"&gt;http://source.android.com/source/initializing.html&lt;/a&gt;&lt;br /&gt;我这里也简单的写下：&lt;/p&gt;&lt;div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;"&gt;sudo vim /etc/udev/rules.d/51-android.rules&lt;br/&gt;&lt;/div&gt;&lt;p&gt;然后，添加如下内容:&lt;/p&gt;&lt;div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;"&gt;#Samsung&lt;br/&gt;SUBSYSTEM=="usb", SYSFS{idVendor}==04e8, MODE=0666&lt;br/&gt;&lt;/div&gt;&lt;p&gt;这是三星手机的配置，其他手机通过lsusb命令查看相应的id，以上述格式添加到&lt;span&gt;/etc/udev/rules.d/51-android.rules文件里即可。&lt;br /&gt;配置好了后，拔掉手机再插上，基本上就可以了。如果还不可以，先kill-server，再用root用户连接。如果还不行，进入android-sdk/tools/,给你的adb这个命令文件"chmod +s adb",kill-server,再adb，多试几次。&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span&gt;&lt;strong&gt;9.下载设备专用工程&lt;/strong&gt;&lt;br /&gt;CM9现在和CM7在下载设备工程不一样，CM7是下载源码的时候就自动下载好了，CM9则没有，但是可以手动智能识别下载。&lt;br /&gt;比如我的手机是galaxys2，则使用如下命令：&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;&lt;div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;"&gt;brunch galaxys2&lt;br/&gt;&lt;/div&gt;&lt;p&gt;如果拼写正确的话，它会自动下载galaxys2的相关工程(在目录~/cm9/device/下多了以下目录samsung/galaxys2)。&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2012/31770/2012052918585672.png" alt="" data-pinit="registered" /&gt;&lt;/p&gt;&lt;p&gt;如果下载完成，进入编译的话，请停止编译，我们还需要进行下一步。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;10.获取手机系统属性文件&lt;/strong&gt;&lt;/p&gt;&lt;div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;"&gt;cd ~/cm9/device/samsung/galaxys2&lt;br/&gt;./extract-files.sh&lt;br/&gt;cd ~/cm9&lt;br/&gt;vendor/cm/get-prebuilts&lt;br/&gt;&lt;/div&gt;&lt;p&gt;这一步只需要执行一次就可以了。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;11.编译CM9源码&lt;/strong&gt;&lt;br /&gt;CM9的源码比编译Android官方源码相对出错情况会少很多。&lt;br /&gt;首先，初始化变量：&lt;/p&gt;&lt;div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;"&gt;cd cm9&lt;br/&gt;source build/envsetup.sh&lt;/div&gt;&lt;p&gt;直接使用命令：&lt;/p&gt;&lt;div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;"&gt;brunch galaxys2&lt;br/&gt;&lt;/div&gt;&lt;p&gt;然后慢慢的等待吧！&lt;br /&gt;如果是虚拟机的话，内存吃紧和cpu不足的话，随时都可能出错。&lt;br /&gt;如果出现错误的，注意分析一下错误的原因，我这里还比较顺利，中断了一次，重新编译一下又可以了。&lt;br /&gt;ps:如果是官方源码编译的话，我相信总有那么几个错误，CM9要好很多。&lt;br /&gt;编译完成后，会生成一个zip文件，放到手机里就可以刷机了。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;12.编译工程&lt;/strong&gt;&lt;br /&gt;到上面为止，我们已经搭建了一个健康的CM9的环境，但是我们的目地不是编译CM9 ROM，这个CM每天会出nightly版本，所以我们主要是使用这个CM9环境来编译framework，app等工程。&lt;br /&gt;比如第二天我们重新启动，如何编译framework-res.apk,framework.jar,Music.apk?我们需要用到这个环境:&lt;/p&gt;&lt;div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;"&gt;cd cm9&lt;br/&gt;source build/envsetup.sh&lt;br/&gt;//注意product名称，chooseproduct的时候，在之前galaxys2要加上cm-,不然找不到产品&lt;br/&gt;chooseproduct cm-galaxys2&lt;br/&gt;//下面进入到framework/base/core/res.编译framework-res.apk&lt;br/&gt;cd framework/base/core/res&lt;br/&gt;mm&lt;br/&gt;//也可以编译framework.jar&lt;br/&gt;cd ~/cm9/framework/base/core/java&lt;br/&gt;mm&lt;br/&gt;//还可以编译Music.apk&lt;br/&gt;cd ～/cm9/packages/apps/Music&lt;br/&gt;mm&lt;br/&gt;&lt;/div&gt;&lt;p&gt;如此就可以修改系统ROM，修改系统APP了。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;13.小结&lt;/strong&gt;&lt;br /&gt;搭建Android环境和编译Android源码是一个复杂，耗时，熬夜的过程，十分不容易。&lt;br /&gt;但是，释然回首，其实也很简单。&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;&lt;img src="http://www.cnblogs.com/qianxudetianxia/aggbug/2512447.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/qianxudetianxia/archive/2012/05/27/2512447.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/qianxudetianxia/archive/2012/05/14/2497073.html</id><title type="text">Android学习系列(29)--App调试的几个命令实践</title><summary type="text">在Android的应用开发中，我们会用到各种代码调试；其实在Android的开发之后，我们可能会碰到一些随机的问题，如cpu过高，内存泄露等，我们无法简单的进行代码调试，我们需要一个系统日志等等，下面我把握工作中碰到的几个常用命令和方法给大家演示实践一下。1.logcat命令这个命令最简单常用，可查看帮助，我不多说，如果需要打印时间，加参数-v timeadb logcat -v time 2.bugreport命令这个命令也非常简单，但是在实际应用中非常有用，会有从开机之后详细的dumpsys,dumpstate和logcat信息，是一份完整的日志记录。对分析用户行为，异常信息，系统状态有很</summary><published>2012-05-13T16:17:00Z</published><updated>2012-05-13T16:17:00Z</updated><author><name>谦虚的天下</name><uri>http://www.cnblogs.com/qianxudetianxia/</uri></author><link rel="alternate" href="http://www.cnblogs.com/qianxudetianxia/archive/2012/05/14/2497073.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/qianxudetianxia/archive/2012/05/14/2497073.html"/><content type="html">&lt;p&gt;在Android的应用开发中，我们会用到各种代码调试；其实在Android的开发之后，我们可能会碰到一些随机的问题，如cpu过高，内存泄露等，我们无法简单的进行代码调试，我们需要一个系统日志等等，下面我把握工作中碰到的几个常用命令和方法给大家演示实践一下。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;1.logcat命令&lt;/strong&gt;&lt;br /&gt;这个命令最简单常用，可查看帮助，我不多说，如果需要打印时间，加参数-v time&lt;/p&gt;&lt;div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;"&gt;adb logcat -v time &lt;/div&gt;&lt;p&gt;&lt;strong&gt;2.bugreport命令&lt;/strong&gt;&lt;br /&gt;这个命令也非常简单，但是在实际应用中非常有用，会有从开机之后详细的dumpsys,dumpstate和logcat信息，是一份完整的日志记录。对分析用户行为，异常信息，系统状态有很大的参考作用。一般我们会把bugreport导出到电脑上分析。&lt;/p&gt;&lt;div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;"&gt;adb bugreport &amp;gt; xxx.log&lt;br/&gt;&lt;/div&gt;&lt;p&gt;我再次强调，bugreport里面包含丰富的系统和用户信息，它是其他很多命令输出的结果的记录，非常有用。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;3.dumpsys命令&lt;/strong&gt;&lt;br /&gt;这个查看系统信息，用的还是比较多的.&lt;/p&gt;&lt;div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;"&gt;dumpsys [options]&lt;br/&gt;               meminfo 显示内存信息&lt;br/&gt;               cpuinfo 显示CPU信息&lt;br/&gt;               account 显示accounts信息&lt;br/&gt;               activity 显示所有的activities的信息&lt;br/&gt;               window 显示键盘，窗口和它们的关系&lt;br/&gt;               wifi 显示wifi信息&lt;br/&gt;&lt;/div&gt;&lt;p&gt;例如查看某个程序内存信息:&lt;/p&gt;&lt;div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;"&gt;#查看应用com.tianxia.test的内存使用情况&lt;br/&gt;adb shell dumpsys meminfo com.tianxia.test&lt;br/&gt;&lt;/div&gt;&lt;p&gt;效果图如下：&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2012/31770/2012051323235671.jpg" alt="" /&gt;&lt;/p&gt;&lt;p&gt;里面的信息很有价值，尤其对于分析内存泄露，内存溢出都有极大的作用。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;4.top命令&lt;/strong&gt;&lt;br /&gt;这个查看cpu信息太方便了。&lt;/p&gt;&lt;div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;"&gt;top -m 5 -t&lt;br/&gt;&lt;/div&gt;&lt;p&gt;我们看看效果图，其中按cpu大小列出5个进程列表。&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2012/31770/2012051323191491.jpg" alt="" /&gt;&lt;/p&gt;&lt;p&gt;com.tianxia.test的cpu过高，会导致手机发烫。同时利用这个信息，可以监控应用cpu的使用，以调整优化代码。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;5.配置文件local.prop&lt;/strong&gt;&lt;br /&gt;目前网上没有查到local.prop的配置使用，工作中本人只使用过如下：&lt;/p&gt;&lt;div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;"&gt;log.tag.SQLiteStatements=VERBOSE log.tag.SQLiteTime=VERBOSE&lt;br/&gt;&lt;/div&gt;&lt;p&gt;把上述文本加到/data/local.prop中，如果没有这个文件自行创建。然后重启手机，就能看到每个应用详细的查询数据库的sql语句信息，对于调试数据库，分析和优化数据库sql异常非常有用。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;6.分析手机发烫&lt;/strong&gt;&lt;br /&gt;下面我们来实践一个例子，手机发烫太厉害，怎么找出问题？&lt;br /&gt;首先我们写一个程序com.tianxia.test，死循环，核心代码如下：&lt;/p&gt;&lt;div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;"&gt;    @Override&lt;br/&gt;    public void onCreate(Bundle savedInstanceState) {&lt;br/&gt;        super.onCreate(savedInstanceState);&lt;br/&gt;        setContentView(R.layout.main);&lt;br/&gt;        while(true) {&lt;br/&gt;            System.currentTimeMillis();&lt;br/&gt;        }&lt;br/&gt;    }&lt;br/&gt;&lt;/div&gt;&lt;p&gt;这个应用打开后会一直获取系统时间，因为在主线程，肯定导致应用ANR，也会一直浪费系统cpu，手机发热，我们运行它。&lt;br /&gt;假设我们不知道上述代码，我们来找到这个问题：&lt;br /&gt;(1).找到发烫的应用。&lt;br /&gt;使用top命令：&lt;/p&gt;&lt;div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;"&gt;top -m 5 -t&lt;/div&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2012/31770/2012051323191491.jpg" alt="" /&gt;&lt;/p&gt;&lt;p&gt;一看是com.tianxia.test占用85%的cpu，原来是这家伙在捣鬼。进程ID是644，这个后面我们有用。&lt;br /&gt;(2).分析发烫的应用进程在干嘛&lt;br /&gt;需要用到linux下的strace命令，但是android是没有集成这个命令的，android版本的下载地址：&lt;br /&gt;&lt;a href="http://benno.id.au/android/strace"&gt;http://benno.id.au/android/strace&lt;br /&gt;&lt;/a&gt;下载完成后，上传到手机中：&lt;br /&gt;我们adb push strace /system/bin，在模拟器上是上传到/system/bin会报out of memory错误，我们也可以上传到/data目录下，如果没有执行权限，还需要chmod 777 strace.&lt;br /&gt;strace命令有很多参数，直接执行strace会显示使用说明:&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2012/31770/2012051323465333.png" alt="" /&gt;&lt;br /&gt;其中-p参数输入的就是进程号，第一步中我们找到com.tianxia.test的进程ID是644，我们看看这个应用占用这么高的cpu在干嘛？&lt;/p&gt;&lt;div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;"&gt;strace -p 644&lt;br/&gt;&lt;/div&gt;&lt;p&gt;输出如下：&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2012/31770/2012051323525058.png" alt="" /&gt;&lt;br /&gt;它的系统调用一直是gettimeofday,一直输出这个，显然哪里一定进入死循环了，而且是获取时间的死循环，然后结合logcat和代码，定位这段代码(就是前面我们给出的那段代码了)解决这个bug。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;7.采集手机的cpu运行情况.&lt;/strong&gt;&lt;br /&gt;有时使用日志我们很难针对性的获取我们想要的信息，我们可能需要写一些最简单的脚步放在手机里面执行。&lt;br /&gt;如监控cpu占用的记录cpu_log.sh:&lt;/p&gt;&lt;div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;"&gt;# !/system/bin/sh&lt;br/&gt;#这个脚步比较粗糙，是这么个意思&lt;br/&gt;file=/sdcard/cpu/cpu_info.log&lt;br/&gt;rm $file&lt;br/&gt;until [ 1 -gt 10000 ]&lt;br/&gt;do&lt;br/&gt;echo -e "\n\n\n\n\n---------------"&amp;gt;&amp;gt;$file&lt;br/&gt;date &amp;gt;&amp;gt; $file&lt;br/&gt;top -m 5 -n 1 &amp;gt;&amp;gt; $file&lt;br/&gt;sleep 3&lt;br/&gt;done&lt;br/&gt;&lt;/div&gt;&lt;p&gt;每隔3s中就会把手机的cpu的信息写到sdcard的cpu目录下的cpu_info.log文件中，方便我们后续分析。&lt;br /&gt;&amp;nbsp;ps:使用方法是 push到data目录下，赋予可执行权限,在shell下执行即可。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;8.采集某个应用的内存数据&lt;/strong&gt;&lt;br /&gt;这个实践和上面的脚本类似，只是命令不一样我另外单独列出来，因为这个有时候很有用。&lt;br /&gt;比如，我们要采集com.tianxia.test的内存使用情况，分析它是不是会内存泄露，脚步类似：&lt;/p&gt;&lt;div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;"&gt;# !/system/bin/sh&lt;br/&gt;#这个脚步比较粗糙，是这么个意思&lt;br/&gt;file=/sdcard/cpu/mem_info.log&lt;br/&gt;rm $file&lt;br/&gt;until [ 1 -gt 10000 ]&lt;br/&gt;do&lt;br/&gt;echo -e "\n\n\n\n\n---------------"&amp;gt;&amp;gt;$file&lt;br/&gt;date &amp;gt;&amp;gt; $file&lt;br/&gt;dumpsys meminfo com.tianxia.test &amp;gt;&amp;gt; $file&lt;br/&gt;sleep 3&lt;br/&gt;done&lt;br/&gt;&lt;/div&gt;&lt;p&gt;使用方法也是一样。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;9.小结&lt;/strong&gt;&lt;br /&gt;零零碎碎的一直没有时间整理，有常用的也有不常用的，算是一些小技巧，感觉网上这方面的分享比较少，有时和朋友们谈起这些调试方法，特别是龙哥，硬是要求我今天写出来与大家分享，只好献丑，说不定对于解决一些疑难杂症有奇效，呵呵，想到什么写什么吧，想到几个写几个，也是一个学习的记录。&lt;/p&gt;&lt;img src="http://www.cnblogs.com/qianxudetianxia/aggbug/2497073.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/qianxudetianxia/archive/2012/05/14/2497073.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/qianxudetianxia/archive/2012/04/05/2433669.html</id><title type="text">[Android应用]《花界》V1.0  正式版隆重发布！</title><summary type="text">1.软件说明(1).花界是一款看花软件：“看花，议花，说花，提高您的赏花素养！”。 (2).发布《花界》V1.0正式版，一是检验，综合，统一本博客技术分析，二是从理论到实践的转换。2. 应用下载下载地址：点击谷歌市场：点击3. 源码下载源码托管：传送门4. 业务简介(1).持续更新高清花朵的图片赏析；(2). 给花儿分门别类，教你区分不同的花；(3). 转载一些有关花的文章，扩展视野，汲取花的文化知识。5. 技术说明(1). 囊括本博客大部分总结的技术，是本博客技术上的一个实现；(2). 结合了一些项目所需的服务器端的配置，是本博客技术上的一个延伸；(3). 本应用是一个开放源代码项目，每次提</summary><published>2012-04-05T15:56:00Z</published><updated>2012-04-05T15:56:00Z</updated><author><name>谦虚的天下</name><uri>http://www.cnblogs.com/qianxudetianxia/</uri></author><link rel="alternate" href="http://www.cnblogs.com/qianxudetianxia/archive/2012/04/05/2433669.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/qianxudetianxia/archive/2012/04/05/2433669.html"/><content type="html">&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2012/31770/2012042522545948.png" alt="" /&gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;1.&amp;nbsp;&lt;/strong&gt;&lt;strong&gt;软件说明&lt;br /&gt;&lt;/strong&gt;(1).&amp;nbsp;&lt;strong&gt;花界&lt;/strong&gt;是一款看花软件：&amp;ldquo;看花，议花，说花，提高您的赏花素养！&amp;rdquo;。 &lt;br /&gt;(2).&amp;nbsp;发布《花界》V1.0正式版，一是检验，综合，统一本博客技术分析，二是从理论到实践的转换。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;2. 应用下载&lt;/strong&gt;&lt;br /&gt;下载地址：&lt;a href="http://www.kaiyuanxiangmu.com/floworld/data/download/floworld_v1.0(official).apk"&gt;点击&lt;br /&gt;&lt;/a&gt;谷歌市场：&lt;a href="https://play.google.com/store/apps/details?id=com.tianxia.app.floworld"&gt;点击&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;3. 源码下载&lt;/strong&gt;&lt;br /&gt;源码托管：&lt;a href="https://github.com/openproject/world"&gt;传送门&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;4. 业务简介&lt;/strong&gt;&lt;br /&gt;(1).&amp;nbsp;持续更新高清花朵的图片赏析；&lt;br /&gt;(2). 给花儿分门别类，教你区分不同的花；&lt;br /&gt;(3). 转载一些有关花的文章，扩展视野，汲取花的文化知识。&amp;nbsp;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;5. 技术说明&lt;/strong&gt;&lt;br /&gt;(1). 囊括本博客大部分总结的技术，是本博客技术上的一个实现；&lt;br /&gt;(2). 结合了一些项目所需的服务器端的配置，是本博客技术上的一个延伸；&lt;br /&gt;(3). 本应用是一个开放源代码项目，每次提交和上传代码都能查阅，是本博客交流的一个新平台。&amp;nbsp;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;6. 技术要点&lt;/strong&gt;&lt;br /&gt;(1). 工程运用Android Library&lt;br /&gt;(2). 通用主框架搭建&lt;br /&gt;(3). 软件升级技术(自动更新)&lt;br /&gt;(4). 圆角ListView&lt;br /&gt;(5). json数据传递&lt;br /&gt;(6).&amp;nbsp;缓存机制&lt;br /&gt;(7). 异步图片加载&lt;br /&gt;(8). 统计(暂且使用友盟)&lt;br /&gt;(9). 广告(暂且使用有米)&lt;br /&gt;(10). 在线支付(集成支付宝)&lt;br /&gt;(11). 异步图片加载&lt;br /&gt;(12).其他&lt;/p&gt;&lt;p&gt;欢迎有兴趣的同仁上github提交补丁。&lt;/p&gt;&lt;img src="http://www.cnblogs.com/qianxudetianxia/aggbug/2433669.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/qianxudetianxia/archive/2012/04/05/2433669.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/qianxudetianxia/archive/2012/04/04/2432406.html</id><title type="text">Android学习系列(28)--App集成支付宝</title><summary type="text">手机的在线支付，被认为是2012年最看好的功能，我个人认为这也是移动互联网较传统互联网将会大放光彩的一个功能。人人有手机，人人携带手机，花钱买东西，不再需要取钱付现，不再需要回家上网银，想买什么，扫描一下，或者搜索一下，然后下单，不找零，直接送到你家，这将是手机支付给我们带来的全新交易体验。谷歌刚推出了谷歌钱包，这必是我们后面要使用的主要手段，但是鉴于当前国情，我觉得有必要介绍一下android手机集成支付宝功能。1.下载官方架包和说明文档其实官方已经提供了安装指南,下载地址：https://mobiless.alipay.com/product/product_down_load.htm?c</summary><published>2012-04-04T14:51:00Z</published><updated>2012-04-04T14:51:00Z</updated><author><name>谦虚的天下</name><uri>http://www.cnblogs.com/qianxudetianxia/</uri></author><link rel="alternate" href="http://www.cnblogs.com/qianxudetianxia/archive/2012/04/04/2432406.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/qianxudetianxia/archive/2012/04/04/2432406.html"/><content type="html">&lt;p&gt;手机的在线支付，被认为是2012年最看好的功能，我个人认为这也是移动互联网较传统互联网将会大放光彩的一个功能。&lt;br /&gt;人人有手机，人人携带手机，花钱买东西，不再需要取钱付现，不再需要回家上网银，想买什么，扫描一下，或者搜索一下，然后下单，不找零，直接送到你家，这将是手机支付给我们带来的全新交易体验。&lt;br /&gt;谷歌刚推出了谷歌钱包，这必是我们后面要使用的主要手段，但是鉴于当前国情，我觉得有必要介绍一下android手机集成支付宝功能。&amp;nbsp;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;1.下载官方架包和说明文档&lt;/strong&gt;&lt;br /&gt;其实官方已经提供了安装指南,下载地址：&lt;br /&gt;&lt;a href="https://mobiless.alipay.com/product/product_down_load.htm?code=SECURITY_PAY"&gt;https://mobiless.alipay.com/product/product_down_load.htm?code=SECURITY_PAY&lt;/a&gt;&lt;br /&gt;里面有有个pdf，详细说明了说用指南，写的比较详细，可以重点参考。&lt;/p&gt;&lt;p&gt;&lt;img style="display: block; margin-left: auto; margin-right: auto;" src="http://pic002.cnblogs.com/images/2012/31770/2012040421054311.png" alt="" /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;下载下来，我们主要是用到Android(20120104)目录下的alipay_plugin.jar和AppDemo/assets下的alipay_plugin223_0309.apk，这两个文件是我们不能修改的支付宝api和安装包。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;2. 商户签约&lt;/strong&gt;&lt;br /&gt;现在的安全机制，都是这样，客户端需要先和服务端请求验证后才能进行进一步操作，oauth也是如此。&lt;br /&gt;打开https://ms.alipay.com/，登陆支付宝，点击签约入口，选择"应用类产品"，填写并等待审核，获取商户ID和账户ID。&lt;br /&gt;签约的时候还要向需要提供实名认证和上传应用，所以我建议先把应用做好了，最后再集成支付宝。&lt;/p&gt;&lt;p&gt;&lt;img style="display: block; margin-left: auto; margin-right: auto;" src="http://pic002.cnblogs.com/images/2012/31770/2012040421302878.png" alt="" /&gt;&lt;br /&gt;我大概等了1-2天审核，审核是失败的，回复是应用类型啥的应该是"虚拟货币"，我改成那个马上自动就审核通过了。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;3.密钥配置&lt;/strong&gt;&lt;br /&gt;解压openssl-0.9.8k_WIN32(RSA密钥生成工具).zip，打开cmd，命令行进入openssl-0.9.8k_WIN32(RSA密钥生成工具)\bin目录下，&lt;br /&gt;(1).执行&lt;/p&gt;&lt;div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;"&gt;openssl genrsa  -out rsa_private_key.pem 1024&lt;br/&gt;&lt;/div&gt;&lt;p&gt;生成rsa_private_key.pem文件。&lt;br /&gt;(2).再执行&lt;/p&gt;&lt;div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;"&gt;openssl rsa  -in rsa_private_key.pem  -pubout -out rsa_public_key.pem&lt;br/&gt;&lt;/div&gt;&lt;p&gt;生成rsa_public_key.pem 文件。&lt;br /&gt;(3).在执行&lt;/p&gt;&lt;div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;"&gt;openssl pkcs8  -topk8  -inform PEM  -in rsa_private_key.pem  -outform PEM  -nocrypt&lt;br/&gt;&lt;/div&gt;&lt;p&gt;将RSA私钥转换成 PKCS8 格式，去掉begin和end那两行，把里面的内容拷贝出来，保存到某个txt中，如rsa_private_pkcs8_key.txt中（我好像没用到这个）。&lt;br /&gt;打开rsa_public_key.pem,即商户的公钥，复制到一个新的TXT中，删除文件头&amp;rdquo;-----BEGIN PUBLIC KEY-----&amp;ldquo;与文件尾&amp;rdquo;-----END PUBLIC KEY-----&amp;ldquo;还有空格、换行，变成一行字符串并保存该 TXT 文件，然后在网站的&amp;ldquo;我的商家服务&amp;rdquo;切换卡下的右边点击&amp;ldquo;密钥管理&amp;rdquo;，然后有个"上传商户公钥(RSA)"项，选择上传刚才的TXT文件.&lt;br /&gt;好了，服务器配置OK，因为这一段之前没有截图，现在弄好了又不好截图，如果有不明白的地方请大家参考官方文档。&amp;nbsp;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;4.引用jar和包含安装包&lt;/strong&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; (1).新建android工程；&lt;br /&gt;&amp;nbsp; &amp;nbsp; (2).copy上面说的alipay_plugin.jar到工程的libs目录下，并在java build path中通过Add External JARs找到并引用该jar；&lt;br /&gt;&amp;nbsp; &amp;nbsp; (3).copy上面说的alipay_plugin223_0309.apk安装包到assets目录下，后面配置路径用到。&lt;/p&gt;&lt;p&gt;&lt;img style="display: block; margin-left: auto; margin-right: auto;" src="http://pic002.cnblogs.com/images/2012/31770/2012040421142141.png" alt="" /&gt;&lt;/p&gt;&lt;p&gt;如果libs和assets目录没有，手动建立者两个目录。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;5.调用代码整理&lt;/strong&gt;&lt;br /&gt;这里我们要严重的参考文档中AppDemo，我们建一个包com.tianxia.lib.baseworld.alipay，把AppDemo的com.alipay.android.appDemo4包下的源码全部copy到刚才我们自己的包下，还有res目录下的资源文件也合并到我们工程res下。&lt;br /&gt;其中AlixDemo.java,ProductListAdapter.java,Products.java是示例类，我们借鉴完后可以删除。&lt;br /&gt;PartnerConfig.java是配置类，配置商户的一些配置参数。&lt;br /&gt;其他的类是严重参考类，直接留下使用。&lt;br /&gt;PartnerConfig.java代码如下:&lt;/p&gt;&lt;div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;"&gt;public class PartnerConfig {&lt;br/&gt;//合作商户ID。用签约支付宝账号登录ms.alipay.com后，在账户信息页面获取。&lt;br/&gt;public static final String PARTNER = "xxx";&lt;br/&gt;//账户ID。用签约支付宝账号登录ms.alipay.com后，在账户信息页面获取。&lt;br/&gt;public static final String SELLER = "xxx";&lt;br/&gt;//商户（RSA）私钥 ,即rsa_private_key.pem中去掉首行，最后一行，空格和换行最后拼成一行的字符串&lt;br/&gt;public static final String RSA_PRIVATE = "xxx";&lt;br/&gt;//支付宝（RSA）公钥  用签约支付宝账号登录ms.alipay.com后，在密钥管理页面获取。&lt;br/&gt;public static final String RSA_ALIPAY_PUBLIC = "xxx";&lt;br/&gt;//下面的配置告诉应用去assets目录下找安装包&lt;br/&gt;public static final String ALIPAY_PLUGIN_NAME ="alipay_plugin223_0309.apk";&lt;br/&gt;}&lt;br/&gt;&lt;/div&gt;&lt;p&gt;AlixDemo中代码是最终的调用代码在onItemClick(AdapterView&amp;lt;?&amp;gt; arg0, View arg1, int arg2, long arg3) {}中，下面我们提取其中的核心代码。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;6.提取核心调用代码&lt;/strong&gt;&lt;br /&gt;在AlixDemo.java同目录下新建AlixPay.java,来提取AlixDemo.java的核心代码：&lt;/p&gt;&lt;div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;"&gt;package com.tianxia.lib.baseworld.alipay;&lt;br/&gt;&lt;br/&gt;import java.net.URLEncoder;&lt;br/&gt;import java.text.SimpleDateFormat;&lt;br/&gt;import java.util.Date;&lt;br/&gt;&lt;br/&gt;import com.tianxia.lib.baseworld.R;&lt;br/&gt;&lt;br/&gt;import android.app.Activity;&lt;br/&gt;import android.app.ProgressDialog;&lt;br/&gt;import android.content.DialogInterface;&lt;br/&gt;import android.os.Handler;&lt;br/&gt;import android.os.Message;&lt;br/&gt;import android.view.KeyEvent;&lt;br/&gt;import android.widget.Toast;&lt;br/&gt;&lt;br/&gt;public class AlixPay {&lt;br/&gt;&lt;br/&gt;    static String TAG = "AlixPay";&lt;br/&gt;&lt;br/&gt;    private Activity mActivity;&lt;br/&gt;    public AlixPay(Activity activity) {&lt;br/&gt;        mActivity = activity;&lt;br/&gt;    }&lt;br/&gt;&lt;br/&gt;    private ProgressDialog mProgress = null;&lt;br/&gt;&lt;br/&gt;    // the handler use to receive the pay result.&lt;br/&gt;    private Handler mHandler = new Handler() {&lt;br/&gt;        public void handleMessage(Message msg) {&lt;br/&gt;            try {&lt;br/&gt;                String strRet = (String) msg.obj;&lt;br/&gt;&lt;br/&gt;                switch (msg.what) {&lt;br/&gt;                case AlixId.RQF_PAY: {&lt;br/&gt;&lt;br/&gt;                    closeProgress();&lt;br/&gt;&lt;br/&gt;                    BaseHelper.log(TAG, strRet);&lt;br/&gt;&lt;br/&gt;                    try {&lt;br/&gt;                        String memo = "memo=";&lt;br/&gt;                        int imemoStart = strRet.indexOf("memo=");&lt;br/&gt;                        imemoStart += memo.length();&lt;br/&gt;                        int imemoEnd = strRet.indexOf(";result=");&lt;br/&gt;                        memo = strRet.substring(imemoStart, imemoEnd);&lt;br/&gt;&lt;br/&gt;                        ResultChecker resultChecker = new ResultChecker(strRet);&lt;br/&gt;&lt;br/&gt;                        int retVal = resultChecker.checkSign();&lt;br/&gt;                        if (retVal == ResultChecker.RESULT_CHECK_SIGN_FAILED) {&lt;br/&gt;                            BaseHelper.showDialog(&lt;br/&gt;                                    mActivity,&lt;br/&gt;                                    "提示",&lt;br/&gt;                                    mActivity.getResources().getString(&lt;br/&gt;                                            R.string.check_sign_failed),&lt;br/&gt;                                    android.R.drawable.ic_dialog_alert);&lt;br/&gt;                        } else {&lt;br/&gt;                            BaseHelper.showDialog(mActivity, "提示", memo,&lt;br/&gt;                                    R.drawable.infoicon);&lt;br/&gt;                        }&lt;br/&gt;                        &lt;br/&gt;                    } catch (Exception e) {&lt;br/&gt;                        e.printStackTrace();&lt;br/&gt;&lt;br/&gt;                        BaseHelper.showDialog(mActivity, "提示", strRet,&lt;br/&gt;                                R.drawable.infoicon);&lt;br/&gt;                    }&lt;br/&gt;                }&lt;br/&gt;                    break;&lt;br/&gt;                }&lt;br/&gt;&lt;br/&gt;                super.handleMessage(msg);&lt;br/&gt;            } catch (Exception e) {&lt;br/&gt;                e.printStackTrace();&lt;br/&gt;            }&lt;br/&gt;        }&lt;br/&gt;    };&lt;br/&gt;&lt;br/&gt;    // close the progress bar&lt;br/&gt;    void closeProgress() {&lt;br/&gt;        try {&lt;br/&gt;            if (mProgress != null) {&lt;br/&gt;                mProgress.dismiss();&lt;br/&gt;                mProgress = null;&lt;br/&gt;            }&lt;br/&gt;        } catch (Exception e) {&lt;br/&gt;            e.printStackTrace();&lt;br/&gt;        }&lt;br/&gt;    }&lt;br/&gt;&lt;br/&gt;    public void pay() {&lt;br/&gt;        MobileSecurePayHelper mspHelper = new MobileSecurePayHelper(mActivity);&lt;br/&gt;        boolean isMobile_spExist = mspHelper.detectMobile_sp();&lt;br/&gt;        if (!isMobile_spExist)&lt;br/&gt;            return;&lt;br/&gt;&lt;br/&gt;        if (!checkInfo()) {&lt;br/&gt;            BaseHelper.showDialog(mActivity, "提示",&lt;br/&gt;                    "缺少partner或者seller，", R.drawable.infoicon);&lt;br/&gt;            return;&lt;br/&gt;        }&lt;br/&gt;&lt;br/&gt;        try {&lt;br/&gt;            // prepare the order info.&lt;br/&gt;            String orderInfo = getOrderInfo();&lt;br/&gt;            String signType = getSignType();&lt;br/&gt;            String strsign = sign(signType, orderInfo);&lt;br/&gt;            strsign = URLEncoder.encode(strsign);&lt;br/&gt;            String info = orderInfo + "&amp;amp;sign=" + "\"" + strsign + "\"" + "&amp;amp;"&lt;br/&gt;                    + getSignType();&lt;br/&gt;            &lt;br/&gt;            // start the pay.&lt;br/&gt;            MobileSecurePayer msp = new MobileSecurePayer();&lt;br/&gt;            boolean bRet = msp.pay(info, mHandler, AlixId.RQF_PAY, mActivity);&lt;br/&gt;            &lt;br/&gt;            if (bRet) {&lt;br/&gt;                // show the progress bar to indicate that we have started paying.&lt;br/&gt;                closeProgress();&lt;br/&gt;                mProgress = BaseHelper.showProgress(mActivity, null, "正在支付", false,&lt;br/&gt;                        true);&lt;br/&gt;            } else&lt;br/&gt;                ;&lt;br/&gt;        } catch (Exception ex) {&lt;br/&gt;            Toast.makeText(mActivity, R.string.remote_call_failed,&lt;br/&gt;                    Toast.LENGTH_SHORT).show();&lt;br/&gt;        }&lt;br/&gt;        &lt;br/&gt;    }&lt;br/&gt;&lt;br/&gt;    private boolean checkInfo() {&lt;br/&gt;        String partner = PartnerConfig.PARTNER;&lt;br/&gt;        String seller = PartnerConfig.SELLER;&lt;br/&gt;        if (partner == null || partner.length() &amp;lt;= 0 || seller == null&lt;br/&gt;                || seller.length() &amp;lt;= 0)&lt;br/&gt;            return false;&lt;br/&gt;&lt;br/&gt;        return true;&lt;br/&gt;    }&lt;br/&gt;&lt;br/&gt;&lt;br/&gt;    // get the selected order info for pay.&lt;br/&gt;    String getOrderInfo() {&lt;br/&gt;        String strOrderInfo = "partner=" + "\"" + PartnerConfig.PARTNER + "\"";&lt;br/&gt;        strOrderInfo += "&amp;amp;";&lt;br/&gt;        strOrderInfo += "seller=" + "\"" + PartnerConfig.SELLER + "\"";&lt;br/&gt;        strOrderInfo += "&amp;amp;";&lt;br/&gt;        strOrderInfo += "out_trade_no=" + "\"" + getOutTradeNo() + "\"";&lt;br/&gt;        strOrderInfo += "&amp;amp;";&lt;br/&gt;        //这笔交易价钱&lt;br/&gt;        strOrderInfo += "subject=" + "\"" + mActivity.getString(R.string.donate_subject) + "\"";&lt;br/&gt;        strOrderInfo += "&amp;amp;";&lt;br/&gt;        //这笔交易内容&lt;br/&gt;        strOrderInfo += "body=" + "\"" + mActivity.getString(R.string.donate_body) + "\"";&lt;br/&gt;        strOrderInfo += "&amp;amp;";&lt;br/&gt;        //这笔交易价钱&lt;br/&gt;        strOrderInfo += "total_fee=" + "\"" + "10.00" + "\"";&lt;br/&gt;        strOrderInfo += "&amp;amp;";&lt;br/&gt;        strOrderInfo += "notify_url=" + "\""&lt;br/&gt;                + "http://notify.java.jpxx.org/index.jsp" + "\"";&lt;br/&gt;&lt;br/&gt;        return strOrderInfo;&lt;br/&gt;    }&lt;br/&gt;&lt;br/&gt;    // get the out_trade_no for an order.&lt;br/&gt;    String getOutTradeNo() {&lt;br/&gt;        SimpleDateFormat format = new SimpleDateFormat("MMddHHmmss");&lt;br/&gt;        Date date = new Date();&lt;br/&gt;        String strKey = format.format(date);&lt;br/&gt;&lt;br/&gt;        java.util.Random r = new java.util.Random();&lt;br/&gt;        strKey = strKey + r.nextInt();&lt;br/&gt;        strKey = strKey.substring(0, 15);&lt;br/&gt;        return strKey;&lt;br/&gt;    }&lt;br/&gt;&lt;br/&gt;    // get the sign type we use.&lt;br/&gt;    String getSignType() {&lt;br/&gt;        String getSignType = "sign_type=" + "\"" + "RSA" + "\"";&lt;br/&gt;        return getSignType;&lt;br/&gt;    }&lt;br/&gt;&lt;br/&gt;    // sign the order info.&lt;br/&gt;    String sign(String signType, String content) {&lt;br/&gt;        return Rsa.sign(content, PartnerConfig.RSA_PRIVATE);&lt;br/&gt;    }&lt;br/&gt;&lt;br/&gt;    // the OnCancelListener for lephone platform.&lt;br/&gt;    static class AlixOnCancelListener implements&lt;br/&gt;            DialogInterface.OnCancelListener {&lt;br/&gt;        Activity mcontext;&lt;br/&gt;&lt;br/&gt;        AlixOnCancelListener(Activity context) {&lt;br/&gt;            mcontext = context;&lt;br/&gt;        }&lt;br/&gt;&lt;br/&gt;        public void onCancel(DialogInterface dialog) {&lt;br/&gt;            mcontext.onKeyDown(KeyEvent.KEYCODE_BACK, null);&lt;br/&gt;        }&lt;br/&gt;    }&lt;br/&gt;}&lt;br/&gt;&lt;/div&gt;&lt;p&gt;这个类的pay方法就是支付的方法，最简单的不设置的话，调用方法如下：&lt;/p&gt;&lt;div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;"&gt;AlixPay alixPay = new AlixPay(SettingTabActivity.this);&lt;br/&gt;alixPay.pay();&lt;br/&gt;&lt;/div&gt;&lt;p&gt;如果没有安装支付宝，它会提示你安装，如果已经安装，它直接让你选择付款：&lt;/p&gt;&lt;p&gt;&lt;img style="display: block; margin-left: auto; margin-right: auto;" src="http://pic002.cnblogs.com/images/2012/31770/2012040422291258.png" alt="" /&gt;&lt;/p&gt;&lt;p&gt;这说明已经配置成功了。&lt;br /&gt;然后可以删掉那些示例java文件了：&amp;nbsp;AlixDemo.java,ProductListAdapter.java,Products.java。&amp;nbsp;&lt;br /&gt;你也可以通过调整参数来修改订单信息，如主题，价格等。&lt;br /&gt;另外在BaseHelper的94行：&lt;/p&gt;&lt;div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;"&gt;dialog.setOnCancelListener( new AlixDemo.AlixOnCancelListener( (Activity)context ) );&lt;/div&gt;&lt;p&gt;需要修改为：&lt;/p&gt;&lt;div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;"&gt;dialog.setOnCancelListener( new AlixPay.AlixOnCancelListener( (Activity)context ) );&lt;/div&gt;&lt;p&gt;&lt;strong&gt;7.注意&lt;/strong&gt;&lt;br /&gt;我在测试的时候，调用的activity是框在一个ActivityGroup里的（与tabhost类似，据说tabhost也有这个问题），导致MobileSecurePayer.java的pay方法中调用服务的两行代码：&lt;/p&gt;&lt;div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;"&gt;mActivity.bindService(new Intent(IAlixPay.class.getName()), mAlixPayConnection, Context.BIND_AUTO_CREATE);&lt;br/&gt;mActivity.unbindService(mAlixPayConnection);&lt;br/&gt;&lt;/div&gt;&lt;p&gt;需要修改为：&lt;/p&gt;&lt;div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;"&gt;mActivity.getApplicationContext().bindService(new Intent(IAlixPay.class.getName()), mAlixPayConnection, Context.BIND_AUTO_CREATE);&lt;br/&gt;mActivity.getApplicationContext().unbindService(mAlixPayConnection);&lt;br/&gt;&lt;/div&gt;&lt;p&gt;不然会报错java.lang.ClassCastException: android.os.BinderProxy cannot be cast to com.android.server.am.ActivityRecord$Token...&lt;/p&gt;&lt;p&gt;&lt;strong&gt;8.小结&lt;/strong&gt;&lt;br /&gt;支付宝的集成比我想象的要复杂一些，比较麻烦，首先需要审核，然后代码需要提取，所以写出来与大家分享。&amp;nbsp;&lt;br /&gt;在做集成配置的时候，一定要仔细认真，一个地方出错，可能要导致后面查错查很长时间。&lt;br /&gt;因为本人是先集成成功后才写的这篇文章，难免会漏掉一些重要的细节或者步骤，如有不对，请留言指正。&amp;nbsp;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;img src="http://www.cnblogs.com/qianxudetianxia/aggbug/2432406.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/qianxudetianxia/archive/2012/04/04/2432406.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/qianxudetianxia/archive/2012/03/02/2020355.html</id><title type="text">Android设计模式系列(10)--SDK源码之原型模式</title><summary type="text">CV一族，应该很容易理解原型模式的原理，复制，粘贴完后看具体情况是否修改，其实这就是原型模式。从java的角度看，一般使用原型模式有个明显的特点，就是实现cloneable的clone()方法。原型模式，能快速克隆出一个与已经存在对象类似的另外一个我们想要的新对象。1.意图用原型实例指定创建对象的种类，并且通过拷贝这些原型创建新的对象。热门词汇：克隆 深拷贝 浅拷贝2.结构图和代码它的结构图非常简单，我们以Intent为例子：Intent的clone方法非常简单： @Override public Object clone() { return new Intent(...</summary><published>2012-03-02T05:07:00Z</published><updated>2012-03-02T05:07:00Z</updated><author><name>谦虚的天下</name><uri>http://www.cnblogs.com/qianxudetianxia/</uri></author><link rel="alternate" href="http://www.cnblogs.com/qianxudetianxia/archive/2012/03/02/2020355.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/qianxudetianxia/archive/2012/03/02/2020355.html"/><content type="html">&lt;p&gt;CV一族，应该很容易理解原型模式的原理，复制，粘贴完后看具体情况是否修改，其实这就是原型模式。&lt;br /&gt;从java的角度看，一般使用原型模式有个明显的特点，就是实现cloneable的clone()方法。&lt;br /&gt;原型模式，能快速克隆出一个与已经存在对象类似的另外一个我们想要的新对象。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;1.意图&lt;/strong&gt;&lt;br /&gt;用原型实例指定创建对象的种类，并且通过拷贝这些原型创建新的对象。&lt;br /&gt;热门词汇：&lt;strong&gt;&lt;em&gt;克隆&lt;/em&gt;&lt;/strong&gt; &lt;strong&gt;&lt;em&gt;深拷贝&lt;/em&gt;&lt;/strong&gt; &lt;em&gt;&lt;strong&gt;浅拷贝&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;2.结构图和代码&lt;/strong&gt;&lt;br /&gt;它的结构图非常简单，我们以Intent为例子：&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2012/31770/2012030213005237.jpg" alt="" /&gt;&lt;br /&gt;Intent的clone方法非常简单：&lt;/p&gt;&lt;div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;"&gt;    @Override&lt;br/&gt;    public Object clone() {&lt;br/&gt;        return new Intent(this);&lt;br/&gt;    }&lt;br/&gt;&lt;/div&gt;&lt;p&gt;返回一个新的Intent对象。&lt;br /&gt;克隆操作分深拷贝和浅拷贝，浅拷贝说白了就是把原对象所有的值和引用直接赋给新对象。深拷贝则不仅把原对象的值赋给新对象，而且会把原对象的引用对象也重新创建一遍再赋给新对象。&lt;br /&gt;我们具体分析一下Intent是浅拷贝还是深拷贝吧：&lt;/p&gt;&lt;div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;"&gt;    public Intent(Intent o) {&lt;br/&gt;        this.mAction = o.mAction;&lt;br/&gt;        this.mData = o.mData;&lt;br/&gt;        this.mType = o.mType;&lt;br/&gt;        this.mPackage = o.mPackage;&lt;br/&gt;        this.mComponent = o.mComponent;&lt;br/&gt;        this.mFlags = o.mFlags;&lt;br/&gt;        //下面几个是引用对象被重新创建了，是深拷贝&lt;br/&gt;        if (o.mCategories != null) {&lt;br/&gt;            this.mCategories = new HashSet&amp;lt;String&amp;gt;(o.mCategories);&lt;br/&gt;        }&lt;br/&gt;        if (o.mExtras != null) {&lt;br/&gt;            this.mExtras = new Bundle(o.mExtras);&lt;br/&gt;        }&lt;br/&gt;        if (o.mSourceBounds != null) {&lt;br/&gt;            this.mSourceBounds = new Rect(o.mSourceBounds);&lt;br/&gt;        }&lt;br/&gt;    }&lt;br/&gt;&lt;/div&gt;&lt;p&gt;这里我们为什么Intent要重写Object的clone方法，就与深拷贝有关。&lt;br /&gt;其实我们查看Object的clone()方法源码和注释，默认的super.clone()用的就是浅拷贝：&lt;/p&gt;&lt;div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;"&gt;    /**&lt;br/&gt;     * Creates and returns a copy of this {@code Object}. The default&lt;br/&gt;     * implementation returns a so-called "shallow" copy: It creates a new&lt;br/&gt;     * instance of the same class and then copies the field values (including&lt;br/&gt;     * object references) from this instance to the new instance. A "deep" copy,&lt;br/&gt;     * in contrast, would also recursively clone nested objects. A subclass that&lt;br/&gt;     * needs to implement this kind of cloning should call {@code super.clone()}&lt;br/&gt;     * to create the new instance and then create deep copies of the nested,&lt;br/&gt;     * mutable objects.&lt;br/&gt;     */&lt;br/&gt;    protected Object clone() throws CloneNotSupportedException {&lt;br/&gt;        if (!(this instanceof Cloneable)) {&lt;br/&gt;            throw new CloneNotSupportedException("Class doesn't implement Cloneable");&lt;br/&gt;        }&lt;br/&gt;&lt;br/&gt;        return internalClone((Cloneable) this);&lt;br/&gt;    }&lt;br/&gt;&lt;/div&gt;&lt;p&gt;这种形式属于简单形式的原型模式，如果需要创建的原型数目不固定，可以创建一个原型管理器，在复制原型对象之前，客户端先在原型管理器中查看&lt;br /&gt;是否存在满足条件的原型对象，如果有，则直接使用，如果没有，克隆一个，这种称作登记形式的原型模式。&lt;br /&gt;适用原型模式可以对客户隐藏产品的具体类，因此减少了客户知道的名字的数目，此外是客户无需改变&lt;br /&gt;原型模式的缺陷是每个原型的子类都必须实现Cloneable接口，这个实现起来有时候比较困难。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;3. 效果&lt;/strong&gt;&lt;br /&gt;(1).创建型模式&lt;br /&gt;(2).运行时刻增加和删除产品&lt;br /&gt;(3).改变只以指定新对象（ctrl+v，然后修改）&lt;br /&gt;(4).改变结构以指定新对象。（类似2，实现不同而已）&lt;br /&gt;(5).减少子类的构造&lt;/p&gt;&lt;img src="http://www.cnblogs.com/qianxudetianxia/aggbug/2020355.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/qianxudetianxia/archive/2012/03/02/2020355.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/qianxudetianxia/archive/2012/02/27/2010965.html</id><title type="text">Android设计模式系列(9)--SDK源码之适配器模式</title><summary type="text">对于android开发者来说起，适配器模式简直太熟悉不过，有很多应用可以说是天天在直接或者间接的用到适配器模式，比如ListView。ListView用于显示列表数据，但是作为列表数据集合有很多形式，有Array，有Cursor，我们需要对应的适配器作为桥梁，处理相应的数据（并能形成ListView所需要的视图）。正是因为定义了这些适配器接口和适配器类，才能使我们的数据简单灵活而又正确的显示到了adapterview的实现类上。适配器模式，Adapter Pattern，勇敢的去适配，大量的资源可以重用。1.意图适配器模式，把一个类的接口变换成客户端所期待的另一种接口，从而使原本不匹配而无法在</summary><published>2012-02-27T15:05:00Z</published><updated>2012-02-27T15:05:00Z</updated><author><name>谦虚的天下</name><uri>http://www.cnblogs.com/qianxudetianxia/</uri></author><link rel="alternate" href="http://www.cnblogs.com/qianxudetianxia/archive/2012/02/27/2010965.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/qianxudetianxia/archive/2012/02/27/2010965.html"/><content type="html">&lt;p&gt;对于android开发者来说起，适配器模式简直太熟悉不过，有很多应用可以说是天天在直接或者间接的用到适配器模式，比如ListView。&lt;br /&gt;ListView用于显示列表数据，但是作为列表数据集合有很多形式，有Array，有Cursor，我们需要对应的适配器作为桥梁，处理相应的数据（并能形成ListView所需要的视图）。&lt;br /&gt;正是因为定义了这些适配器接口和适配器类，才能使我们的数据简单灵活而又正确的显示到了adapterview的实现类上。&lt;br /&gt;适配器模式，Adapter Pattern，勇敢的去适配，大量的资源可以重用。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;1.意图&lt;/strong&gt;&lt;br /&gt;适配器模式，把一个类的接口变换成客户端所期待的另一种接口，从而使原本不匹配而无法在一起工作的两个，类能够在一起工作。&lt;br /&gt;适配器模式分为类适配器模式和对象适配器模式。&lt;br /&gt;关于类适配器模式，因为java的单继承，如果继承一个类，另外的则只能是接口，需要手动实现相应的方法。&lt;br /&gt;热门词汇：&lt;strong&gt;&lt;em&gt;类的适配器模式&lt;/em&gt; &lt;em&gt;对象的适配器模式&lt;/em&gt;&lt;/strong&gt; &lt;em&gt;&lt;strong&gt;缺省适配器模式&lt;/strong&gt; &lt;strong&gt;源类&lt;/strong&gt; &lt;strong&gt;目标接口&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;2.结构图和代码&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2012/31770/2012022722350660.jpg" alt="" /&gt;&lt;/p&gt;&lt;p&gt;为了简明直接，我省略了相关的其他适配器 ，只以此两个适配器为例。&lt;br /&gt;ListViews做为client，他所需要的目标接口(target interface)就是ListAdapter，包含getCount(),getItem(),getView()等几个基本的方法，为了兼容List&amp;lt;T&amp;gt;,Cursor等数据类型作为数据源，我们专门定义两个适配器来适配他们：ArrayAdapter和CursorAdapter。这两个适配器，说白了，就是针对目标接口对数据源进行兼容修饰。&lt;br /&gt;这就是适配器模式。&lt;br /&gt;其中BaseAdapter实现了如isEmpty()方法,使子类在继承BaseAdapter后不需要再实现此方法，这就是缺省适配器，这也是缺省适配器的一个最明显的好处。&amp;nbsp;&lt;/p&gt;&lt;p&gt;我们以最简单的若干个方法举例如下，ListAdapter接口如下（，为了简单，我省略了继承自Adapter接口）：&lt;/p&gt;&lt;div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;"&gt;public interface ListAdapter {&lt;br/&gt;    public int getCount();&lt;br/&gt;    Object getItem(int position);&lt;br/&gt;    long getItemId(int position);&lt;br/&gt;    View getView(int position, View convertView, ViewGroup parent);&lt;br/&gt;    boolean isEmpty();&lt;br/&gt;}&lt;/div&gt;&lt;p&gt;抽象类BaseAdapter,我省略其他代码，只列出两个方法，以作示意:&lt;/p&gt;&lt;div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;"&gt;public abstract class BaseAdapter implements ListAdapter, SpinnerAdapter {&lt;br/&gt;    // ... ...&lt;br/&gt;    public View getDropDownView(int position, View convertView, ViewGroup parent) {&lt;br/&gt;        return getView(position, convertView, parent);&lt;br/&gt;    }&lt;br/&gt;    public boolean isEmpty() {&lt;br/&gt;        return getCount() == 0;&lt;br/&gt;    }&lt;br/&gt;}&lt;br/&gt;&lt;/div&gt;&lt;p&gt;ArrayAdapter对List&amp;lt;T&amp;gt;进行封装成ListAdapter的实现，满足ListView的调用：&lt;/p&gt;&lt;div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;"&gt;public class ArrayAdapter&amp;lt;T&amp;gt; extends BaseAdapter implements Filterable {&lt;br/&gt;    private List&amp;lt;T&amp;gt; mObjects;&lt;br/&gt;    //我只列出这一个构造函数，大家懂这个意思就行&lt;br/&gt;    public ArrayAdapter(Context context, int textViewResourceId, T[] objects) {&lt;br/&gt;        init(context, textViewResourceId, 0, Arrays.asList(objects));&lt;br/&gt;    }&lt;br/&gt;    private void init(Context context, int resource, int textViewResourceId, List&amp;lt;T&amp;gt; objects) {&lt;br/&gt;        mContext = context;&lt;br/&gt;        mInflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);&lt;br/&gt;        mResource = mDropDownResource = resource;&lt;br/&gt;        mObjects = objects; //引用对象，也是表达了组合优于继承的意思&lt;br/&gt;        mFieldId = textViewResourceId;&lt;br/&gt;    }&lt;br/&gt;    public int getCount() {&lt;br/&gt;        return mObjects.size();&lt;br/&gt;    }&lt;br/&gt;   public T getItem(int position) {&lt;br/&gt;        return mObjects.get(position);&lt;br/&gt;    }&lt;br/&gt;    public View getView(int position, View convertView, ViewGroup parent) {&lt;br/&gt;        return createViewFromResource(position, convertView, parent, mResource);&lt;br/&gt;    }&lt;br/&gt;    // ... ...&lt;br/&gt;}&lt;br/&gt;&lt;/div&gt;&lt;p&gt;　 我们就如此成功的把List&amp;lt;T&amp;gt;作为数据源以ListView想要的目标接口的样子传给了ListView，同理CursorAdapter也是一模一样的道理，就不写具体代码了。&lt;br /&gt;&amp;nbsp; &amp;nbsp; 适配器本身倒是不难，但是提供了解决不兼容问题的惯用模式。&amp;nbsp;&lt;br /&gt;&amp;nbsp; &amp;nbsp; 关于什么时候使用适配器模式,大概有三种情况：&lt;br /&gt;&amp;nbsp; &amp;nbsp; (1). 你想使用一个已经存在的类，而它的接口不符合你的需求，这个在处理旧系统时比较常见。&lt;br /&gt;&amp;nbsp; &amp;nbsp; (2). 你想创建一个可以复用的类，该类可以和其他不相关的类或不可预见的累协同工作，这就是我们android开发者经常碰到的情况：我们常常自定义一个新的Adapter。&lt;br /&gt;&amp;nbsp; &amp;nbsp; (3). 你想使用一些已经存在的子类，但是不可能对每一个都进行子类化以匹配他们的接口，对象适配器可以适配他的父类接口。&amp;nbsp;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;3.效果&lt;/strong&gt;&lt;br /&gt;1. 结构性模式&amp;nbsp;&lt;br /&gt;2. 上面论述的主要是对象适配器，关于类适配器除了实现目标端口外，还要实现你要兼容的源类，这样可以少写几行代码，但是从组合优于继承的角度看，它总则没有那么的干净。&lt;br /&gt;3. 对同一个适配器（即同一个对象）对同样的源进行双向甚至多向的适配，则能使其适用两个甚至多个客户调用。&lt;/p&gt;&lt;img src="http://www.cnblogs.com/qianxudetianxia/aggbug/2010965.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/qianxudetianxia/archive/2012/02/27/2010965.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/qianxudetianxia/archive/2012/02/20/2112128.html</id><title type="text">Android学习系列(27)--App缓存管理</title><summary type="text">无论大型或小型应用，灵活的缓存可以说不仅大大减轻了服务器的压力，而且因为更快速的用户体验而方便了用户。Android的apk可以说是作为小型应用，其中99%的应用并不是需要实时更新的，而且诟病于蜗牛般的移动网速，与服务器的数据交互是能少则少，这样用户体验才更好，这也是我们有时舍弃webview而采用json传输数据的原因之一。采用缓存，可以进一步大大缓解数据交互的压力，特此，我们简略列举一下缓存管理的适用环境：1. 提供网络服务的应用2. 数据更新不需要实时更新，但是哪怕是3-5分钟的延迟也是可以采用缓存机制。3. 缓存的过期时间是可以接受的(不会因为缓存带来的好处，导致某些数据因为更新不及时</summary><published>2012-02-20T15:07:00Z</published><updated>2012-02-20T15:07:00Z</updated><author><name>谦虚的天下</name><uri>http://www.cnblogs.com/qianxudetianxia/</uri></author><link rel="alternate" href="http://www.cnblogs.com/qianxudetianxia/archive/2012/02/20/2112128.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/qianxudetianxia/archive/2012/02/20/2112128.html"/><content type="html">&lt;p&gt;无论大型或小型应用，灵活的缓存可以说不仅大大减轻了服务器的压力，而且因为更快速的用户体验而方便了用户。&lt;br /&gt;Android的apk可以说是作为小型应用，其中99%的应用并不是需要实时更新的，而且诟病于蜗牛般的移动网速，与服务器的数据交互是能少则少，这样用户体验才更好，这也是我们有时舍弃webview而采用json传输数据的原因之一。&amp;nbsp;&lt;br /&gt;采用缓存，可以进一步大大缓解数据交互的压力，特此，我们简略列举一下缓存管理的适用环境：&lt;br /&gt;1. 提供网络服务的应用&lt;br /&gt;2. 数据更新不需要实时更新，但是哪怕是3-5分钟的延迟也是可以采用缓存机制。&amp;nbsp;&lt;br /&gt;3. 缓存的过期时间是可以接受的(不会因为缓存带来的好处，导致某些数据因为更新不及时而影响产品的形象等)&lt;br /&gt;带来的好处：&lt;br /&gt;1. 服务器的压力大大减小&lt;br /&gt;2. 客户端的响应速度大大变快(用户体验)&lt;br /&gt;3. 客户端的数据加载出错情况大大较少，大大提高了应有的稳定性(用户体验)&lt;br /&gt;4. 一定程度上可以支持离线浏览(或者说为离线浏览提供了技术支持)&lt;/p&gt;&lt;p&gt;&lt;strong&gt;一、缓存管理的方法&lt;/strong&gt;&lt;br /&gt;这里的缓存管理的原理很简：通过时间的设置来判断是否读取缓存还是重新下载。&lt;br /&gt;里面会有一些细节的处理，后面会详细阐述。&lt;br /&gt;基于这个原理，目前鄙人见过的两种比较常见的缓存管理方法是:数据库法和文件法。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;二、数据库法缓存管理&lt;/strong&gt;&lt;br /&gt;这种方法是在下载完数据文件后，把文件的相关信息如url，路经，下载时间，过期时间等存放到数据库，下次下载的时候根据url先从数据库中查询，如果查询到当前时间并未过期，就根据路径读取本地文件，从而实现缓存的效果。&lt;br /&gt;从实现上我们可以看到这种方法可以灵活存放文件的属性，进而提供了很大的扩展性，可以为其它的功能提供一定的支持；&lt;br /&gt;从操作上需要创建数据库，每次查询数据库，如果过期还需要更新数据库，清理缓存的时候还需要删除数据库数据，稍显麻烦，而数据库操作不当又容易出现一系列的性能，ANR问题，实现的时候要谨慎，具体作的话，但也只是增加一个工具类或方法的事情。&lt;br /&gt;还有一个问题，缓存的数据库是存放在/data/data/&amp;lt;package&amp;gt;/databases/目录下，是占用内存空间的，如果缓存累计，容易浪费内存，需要及时清理缓存。&lt;br /&gt;当然这种方法从目前一些应用的实用上看，我没有发现什么问题。&lt;br /&gt;本文我侧重强调第二种方法，第一种方法的实现，就此掠过。&amp;nbsp;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;三、文件法缓存管理&lt;/strong&gt;&lt;br /&gt;这种方法，使用File.lastModified()方法得到文件的最后修改时间，与当前时间判断是否过期，从而实现缓存效果。&lt;br /&gt;实现上只能使用这一个属性，没有为其它的功能提供技术支持的可能。&lt;br /&gt;操作上倒是简单，比较时间即可。本身处理也不容易带来其它问题，代价低廉。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;四、&lt;/strong&gt;&lt;strong&gt;文件法缓存管理的两点说明&lt;br /&gt;&lt;/strong&gt;&lt;span style="text-decoration: underline;"&gt;&lt;em&gt;1. 不同类型的文件的缓存时间不一样。&lt;/em&gt;&lt;/span&gt;&lt;br /&gt;笼统的说，不变文件的缓存时间是永久，变化文件的缓存时间是最大忍受不变时间。&lt;br /&gt;说白点，图片文件内容是不变的，直到清理，我们是可以永远读取缓存的。&lt;br /&gt;配置文件内容是可能更新的，需要设置一个可接受的缓存时间。&lt;br /&gt;&lt;span style="text-decoration: underline;"&gt;&lt;em&gt;2. 不同环境下的缓存时间标准不一样。&lt;/em&gt;&lt;/span&gt;&lt;br /&gt;无网络环境下，我们只能读取缓存文件，哪怕缓存早就过期。&lt;br /&gt;WiFi网络环境下，缓存时间可以设置短一点，一是网速较快，而是流量不要钱。&lt;br /&gt;移动数据流量环境下，缓存时间可以设置长一点，节省流量，就是节省金钱，而且用户体验也更好。&lt;br /&gt;举个例子吧，最近本人在做的一个应用在wifi环境下的缓存时间设置为5分钟，移动数据流量下的缓存时间设置为1小时。&lt;br /&gt;这个时间根据自己的实际情况来设置：数据的更新频率，数据的重要性等。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;五、何时刷新&lt;/strong&gt;&lt;br /&gt;开发者一方面希望尽量读取缓存，用户一方面希望实时刷新，但是响应速度越快越好，流量消耗越少越好，是一个矛盾。&lt;br /&gt;其实何时刷新我也不知道，这里我提供两点建议：&lt;br /&gt;&lt;em&gt;&lt;span style="text-decoration: underline;"&gt;1. 数据的最长多长时间不变，对应用无大的影响。&lt;/span&gt;&lt;/em&gt;&lt;br /&gt;比如，你的数据更新时间为1天，则缓存时间设置为4~8小时比较合适，一天他总会看到更新，如果你觉得你是资讯类应用，再减少，2~4小时，如果你觉得数据比较重要或者比较受欢迎，用户会经常把玩，再减少，1~2小时，依次类推。&lt;br /&gt;为了保险起见，你可能需要毫无理由的再次缩减一下。&lt;br /&gt;&lt;em&gt;&lt;span style="text-decoration: underline;"&gt;2. 提供刷新按钮。&lt;/span&gt;&lt;/em&gt;&lt;br /&gt;上面说的保险起见不一定保险，最保险的方法使在相关界面提供一个刷新按钮，为缓存，为加载失败提供一次重新来过的机会，有了这个刷新按钮，我们的心也才真的放下来。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;六、文件缓存法的具体实现&lt;/strong&gt;&lt;br /&gt;针对配置文件的缓存，我新建了一个类ConfigCache:&lt;/p&gt;&lt;div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;"&gt;import java.io.File;&lt;br/&gt;import java.io.IOException;&lt;br/&gt;&lt;br/&gt;import android.util.Log;&lt;br/&gt;&lt;br/&gt;import com.tianxia.app.floworld.AppApplication;&lt;br/&gt;import com.tianxia.app.floworld.utils.FileUtils;&lt;br/&gt;import com.tianxia.app.floworld.utils.NetworkUtils;&lt;br/&gt;&lt;br/&gt;public class ConfigCache {&lt;br/&gt;    private static final String TAG = ConfigCache.class.getName();&lt;br/&gt;&lt;br/&gt;    public static final int CONFIG_CACHE_MOBILE_TIMEOUT  = 3600000;  //1 hour&lt;br/&gt;    public static final int CONFIG_CACHE_WIFI_TIMEOUT    = 300000;   //5 minute&lt;br/&gt;&lt;br/&gt;    public static String getUrlCache(String url) {&lt;br/&gt;        if (url == null) {&lt;br/&gt;            return null;&lt;br/&gt;        }&lt;br/&gt;&lt;br/&gt;        String result = null;&lt;br/&gt;        File file = new File(AppApplication.mSdcardDataDir + "/" + getCacheDecodeString(url));&lt;br/&gt;        if (file.exists() &amp;amp;&amp;amp; file.isFile()) {&lt;br/&gt;            long expiredTime = System.currentTimeMillis() - file.lastModified();&lt;br/&gt;            Log.d(TAG, file.getAbsolutePath() + " expiredTime:" + expiredTime/60000 + "min");&lt;br/&gt;            //1. in case the system time is incorrect (the time is turn back long ago)&lt;br/&gt;            //2. when the network is invalid, you can only read the cache&lt;br/&gt;            if (AppApplication.mNetWorkState != NetworkUtils.NETWORN_NONE &amp;amp;&amp;amp; expiredTime &amp;lt; 0) {&lt;br/&gt;                return null;&lt;br/&gt;            }&lt;br/&gt;            if(AppApplication.mNetWorkState == NetworkUtils.NETWORN_WIFI&lt;br/&gt;                   &amp;amp;&amp;amp; expiredTime &amp;gt; CONFIG_CACHE_WIFI_TIMEOUT) {&lt;br/&gt;                return null;&lt;br/&gt;            } else if (AppApplication.mNetWorkState == NetworkUtils.NETWORN_MOBILE&lt;br/&gt;                   &amp;amp;&amp;amp; expiredTime &amp;gt; CONFIG_CACHE_MOBILE_TIMEOUT) {&lt;br/&gt;                return null;&lt;br/&gt;            }&lt;br/&gt;            try {&lt;br/&gt;                result = FileUtils.readTextFile(file);&lt;br/&gt;            } catch (IOException e) {&lt;br/&gt;                e.printStackTrace();&lt;br/&gt;            }&lt;br/&gt;        }&lt;br/&gt;        return result;&lt;br/&gt;    }&lt;br/&gt;&lt;br/&gt;    public static void setUrlCache(String data, String url) {&lt;br/&gt;        File file = new File(AppApplication.mSdcardDataDir + "/" + getCacheDecodeString(url));&lt;br/&gt;        try {&lt;br/&gt;            //创建缓存数据到磁盘，就是创建文件&lt;br/&gt;            FileUtils.writeTextFile(file, data);&lt;br/&gt;        } catch (IOException e) {&lt;br/&gt;            Log.d(TAG, "write " + file.getAbsolutePath() + " data failed!");&lt;br/&gt;            e.printStackTrace();&lt;br/&gt;        }&lt;br/&gt;    }&lt;br/&gt;&lt;br/&gt;    public static String getCacheDecodeString(String url) {&lt;br/&gt;        //1. 处理特殊字符&lt;br/&gt;        //2. 去除后缀名带来的文件浏览器的视图凌乱(特别是图片更需要如此类似处理，否则有的手机打开图库，全是我们的缓存图片)&lt;br/&gt;        if (url != null) {&lt;br/&gt;            return url.replaceAll("[.:/,%?&amp;amp;=]", "+").replaceAll("[+]+", "+");&lt;br/&gt;        }&lt;br/&gt;        return null;&lt;br/&gt;    }&lt;br/&gt;}&lt;br/&gt;&lt;/div&gt;&lt;p&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; 从实现上我们全面考虑了几个细节，注释已经说明，不再赘述。&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; 然后我们调用方法如下：&lt;/p&gt;&lt;div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;"&gt;void getConfig(){&lt;br/&gt;        //首先尝试读取缓存&lt;br/&gt;        String cacheConfigString = ConfigCache.getUrlCache(CONFIG_URL);&lt;br/&gt;        //根据结果判定是读取缓存，还是重新读取&lt;br/&gt;        if (cacheConfigString != null) {&lt;br/&gt;            showConfig(cacheConfigString);&lt;br/&gt;        } else {&lt;br/&gt;            //如果缓存结果是空，说明需要重新加载&lt;br/&gt;            //缓存为空的原因可能是1.无缓存;2. 缓存过期;3.读取缓存出错&lt;br/&gt;            AsyncHttpClient client = new AsyncHttpClient();&lt;br/&gt;            client.get(CONFIG_URL, new AsyncHttpResponseHandler(){&lt;br/&gt;&lt;br/&gt;                @Override&lt;br/&gt;                public void onSuccess(String result){&lt;br/&gt;                    //成功下载，则保存到本地作为后面缓存文件&lt;br/&gt;                    ConfigCache.setUrlCache(result,  CONFIG_URL);&lt;br/&gt;                    //后面可以是UI更新，仅供参考&lt;br/&gt;                    showConfig(result);&lt;br/&gt;                }&lt;br/&gt;&lt;br/&gt;                @Override&lt;br/&gt;                public void onFailure(Throwable arg0) {&lt;br/&gt;                    //根据失败原因，考虑是显示加载失败，还是再读取缓存&lt;br/&gt;                }&lt;br/&gt;&lt;br/&gt;            });&lt;br/&gt;        }&lt;br/&gt;    }&lt;br/&gt;&lt;/div&gt;&lt;p&gt;这样配置文件既能有效缓存，又能及时更新了，同时支持离线浏览。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;七、小结&lt;/strong&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp;智能手机的缓存管理应用非常的普遍和需要，是提高用户体验的有效手段之一。&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp;当然，缓存管理一些内容没有细说，如图片缓存，缓存清理等，这些处理起来比较简单。&amp;nbsp;&lt;/p&gt;&lt;img src="http://www.cnblogs.com/qianxudetianxia/aggbug/2112128.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/qianxudetianxia/archive/2012/02/20/2112128.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/qianxudetianxia/archive/2012/01/01/2309102.html</id><title type="text">Android学习系列(24)--App代码规范之使用CheckStyle</title><summary type="text">最近经常思考团队开发的一些东西，其中代码风格不统一是最常见的问题之一。按理说，大家协商和沟通一下，风格统一一下就可以了，其实不然，因为这是个个性张扬的时代！工作code review中用了CheckStyle小半年了，觉得很好很强大很方便，使用起来也很方便，大家写出来的代码就像一个人写出来的一样，值此辞旧迎新，特简做说明，与尔同飨。1.简介官方网站：http://checkstyle.sourceforge.net/CheckStyle提供了一个帮助JAVA开发人员遵守某些编码规范的工具。它能够自动化代码规范检查过程，从而使得开发人员从这项重要，但是枯燥的任务中解脱出来。CheckStyle检</summary><published>2012-01-01T15:45:00Z</published><updated>2012-01-01T15:45:00Z</updated><author><name>谦虚的天下</name><uri>http://www.cnblogs.com/qianxudetianxia/</uri></author><link rel="alternate" href="http://www.cnblogs.com/qianxudetianxia/archive/2012/01/01/2309102.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/qianxudetianxia/archive/2012/01/01/2309102.html"/><content type="html">&lt;p&gt;最近经常思考团队开发的一些东西，其中代码风格不统一是最常见的问题之一。按理说，大家协商和沟通一下，风格统一一下就可以了，其实不然，因为这是个个性张扬的时代！&lt;br /&gt;工作code review中用了CheckStyle小半年了，觉得很好很强大很方便，使用起来也很方便，大家写出来的代码就像一个人写出来的一样，值此辞旧迎新，特简做说明，与尔同飨。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;1.简介&lt;/strong&gt;&lt;br /&gt;官方网站：&lt;a href="http://checkstyle.sourceforge.net/"&gt;http://checkstyle.sourceforge.net/&lt;br /&gt;&lt;/a&gt;&lt;span&gt;CheckStyle提供了一个帮助JAVA开发人员遵守某些编码规范的工具。它能够自动化代码规范检查过程，从而使得开发人员从这项重要，但是枯燥的任务中解脱出来。&lt;br /&gt;&lt;/span&gt;CheckStyle检验的主要内容&lt;br /&gt;(1). Javadoc注释&lt;br /&gt;(2).&amp;nbsp;命名约定&lt;br /&gt;(3).&amp;nbsp;标题&lt;br /&gt;(4).&amp;nbsp;Import语句&lt;br /&gt;(5).&amp;nbsp;体积大小&lt;br /&gt;(6).&amp;nbsp;空白&lt;br /&gt;(7).&amp;nbsp;修饰符&lt;br /&gt;(8).&amp;nbsp;块&lt;br /&gt;(9).&amp;nbsp;代码问题&lt;br /&gt;(10).&amp;nbsp;类设计&lt;br /&gt;(11).&amp;nbsp;混合检查（包活一些有用的比如非必须的System.out和printstackTrace）&lt;/p&gt;&lt;p&gt;&lt;strong&gt;2.定制&lt;/strong&gt;&lt;br /&gt;官方提供的代码规范往往太过严格，在工作中使用不太现实，所以有必要根据具体情况来定制具体的代码规范，CheckStyle对代码规范的定制提供了很多大灵活性。&lt;br /&gt;下面我们来定义一些基本的规范，后续有增加我们再修改。&lt;br /&gt;(1). 不要tab键;&lt;br /&gt;(2).&amp;nbsp;&lt;span&gt;避免重复的import, 多余的import和import *&lt;/span&gt;&lt;br /&gt;(3).&amp;nbsp;常量全部大写字母(static final);&lt;br /&gt;(4).&amp;nbsp;成员变量以m开头;&lt;br /&gt;(5).&amp;nbsp;&lt;span&gt;当有多重修饰符时,修饰符采用以下顺序:(&lt;/span&gt;&lt;span&gt;public,&lt;/span&gt;&lt;span&gt;protected,&lt;/span&gt;&lt;span&gt;private,&lt;/span&gt;&lt;span&gt;abstract,&lt;/span&gt;&lt;span&gt;static,&lt;/span&gt;&lt;span&gt;final,&lt;/span&gt;&lt;span&gt;transient,&lt;/span&gt;&lt;span&gt;volatile,&lt;/span&gt;&lt;span&gt;synchronized,&lt;/span&gt;&lt;span&gt;native,&lt;/span&gt;&lt;span&gt;strictfp)&lt;br /&gt;&amp;nbsp;... ...&lt;br /&gt;其他的我们后面慢慢的修改。&amp;nbsp;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;3.配置文件&lt;/strong&gt;&lt;br /&gt;在运行checkstyle时，需要一个参数(注:我的ubuntu服务器上安装的checkstyle5.4版本，最新的是5.5版本)：&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2012/31770/2012010123012888.png" alt="" /&gt;&lt;br /&gt;这个配置文件就是用来定义你自己定制的代码规范，你可以参考官方说明：&lt;a href="http://checkstyle.sourceforge.net/availablechecks.html"&gt;http://checkstyle.sourceforge.net/availablechecks.html&lt;/a&gt;&lt;br /&gt;这里，我们根据上面说的，来写这样一个code_check.xml :&lt;/p&gt;&lt;div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;"&gt;&amp;lt;?xml version="1.0"?&amp;gt;&lt;br/&gt;&amp;lt;!DOCTYPE module PUBLIC&lt;br/&gt;    "-//Puppy Crawl//DTD Check Configuration 1.2//EN"&lt;br/&gt;    "http://www.puppycrawl.com/dtds/configuration_1_2.dtd"&amp;gt;&lt;br/&gt;&lt;br/&gt;&amp;lt;module name="Checker"&amp;gt;&lt;br/&gt;&lt;br/&gt;    &amp;lt;!-- 检查文件是否以一个新行结束--&amp;gt;&lt;br/&gt;    &amp;lt;module name="NewlineAtEndOfFile"/&amp;gt;&lt;br/&gt;    &lt;br/&gt;&amp;lt;!-- 检查文件中是否含有tab键--&amp;gt;&lt;br/&gt;&amp;lt;module name="FileTabCharacter"/&amp;gt;&lt;br/&gt;&lt;br/&gt;&amp;lt;module name="TreeWalker"&amp;gt;&lt;br/&gt;&lt;br/&gt;    &amp;lt;!-- 常量全部用大写--&amp;gt;&lt;br/&gt;    &amp;lt;module name="ConstantName"/&amp;gt;&lt;br/&gt;&lt;br/&gt;&amp;lt;!-- 避免.*,重复多余的和不使用的import--&amp;gt;&lt;br/&gt;&amp;lt;module name="AvoidStarImport"/&amp;gt;&lt;br/&gt;        &amp;lt;module name="RedundantImport"/&amp;gt;&lt;br/&gt;        &amp;lt;module name="UnusedImports"/&amp;gt;&lt;br/&gt;&lt;br/&gt;    &amp;lt;!-- 成员变量格式为:m+大写+字母--&amp;gt;&lt;br/&gt;&amp;lt;module name="MemberName"&amp;gt;&lt;br/&gt;&amp;lt;property name="format" value="^m[A-Z][a-zA-Z0-9]*$"/&amp;gt;&lt;br/&gt;&amp;lt;/module&amp;gt;&lt;br/&gt;&lt;br/&gt;&amp;lt;!-- 检查代码块:起始大括号和if等同行，不能有空的代码块，结束大括号另起一行--&amp;gt;&lt;br/&gt;&amp;lt;module name="LeftCurly"/&amp;gt;&lt;br/&gt;        &amp;lt;module name="NeedBraces"/&amp;gt;&lt;br/&gt;        &amp;lt;module name="RightCurly"/&amp;gt;&lt;br/&gt;        &amp;lt;!-- 当有多重修饰符时,修饰符采用以下顺序:&lt;br/&gt;             (public,protected,private,abstract,static,final,&lt;br/&gt;             transient,volatile,synchronized,native,strictfp) --&amp;gt;&lt;br/&gt;&amp;lt;module name="ModifierOrder"/&amp;gt;&lt;br/&gt;    &amp;lt;/module&amp;gt;&lt;br/&gt;&lt;br/&gt;&amp;lt;/module&amp;gt;&lt;/div&gt;&lt;p&gt;更多检查规范中文说明参考园子里地址： http://www.cnblogs.com/liugang/archive/2010/10/26/1860903.html&lt;/p&gt;&lt;p&gt;&lt;strong&gt;4.使用checkstyle&lt;/strong&gt;&lt;br /&gt;插件工具的使用我就不介绍了，我只想起个抛砖引玉的作用，checkstyle命令非常简单，这里我只说明3个参数：-c, -r, -o。&lt;/p&gt;&lt;div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;"&gt;/*******************&lt;br/&gt; ***CheckStyle Usage**&lt;br/&gt; ******************/&lt;br/&gt;/***&lt;br/&gt; *参数&lt;br/&gt; *1. -c  配置文件,并验证文件&lt;br/&gt; *2. -o 输出结果&lt;br/&gt; *3. -r  遍历目录&lt;br/&gt; **/&lt;br/&gt;&lt;br/&gt;//用我们定制的code_checks.xml检查文件&lt;br/&gt;$&amp;gt;checkstyle -c ~/GitProj/world/code_checks.xml &lt;br/&gt;  ~/GitProj/world/floworld/src/com/tianxia/app/floworld/appreciate/AppreciateLatestActivity.java&lt;br/&gt;&lt;br/&gt;//用我们定制的code_checks.xml检查目录下的所有源文件，并把结果输出到result.txt中&lt;br/&gt;$&amp;gt;checkstyle -c ~/GitProj/world/code_checks.xml  &lt;br/&gt;  -r ~/GitProj/world/floworld/src/com/tianxia/app/floworld/appreciate/&lt;br/&gt;&lt;/div&gt;&lt;p&gt;我们打开result.txt来看下输出结果：&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2012/31770/2012010123370275.png" alt="" /&gt;&lt;/p&gt;&lt;p&gt;又是tab又是命名不规范，非常的准确。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;5.与Git挂钩&lt;/strong&gt;&lt;br /&gt;快12点了，我先把文章发表出来，这部分随后我再补写。&lt;/p&gt;&lt;img src="http://www.cnblogs.com/qianxudetianxia/aggbug/2309102.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/qianxudetianxia/archive/2012/01/01/2309102.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/qianxudetianxia/archive/2011/12/11/2283794.html</id><title type="text">Android学习系列(17)--App列表之圆角ListView(续)</title><summary type="text">本来这篇文章想并到上篇Android学习系列(16)--App列表之圆角ListView中的，但是若是如此就让大家错过一篇新的好的文章，着实可惜。上篇中我们使用shape，corners，gradient实现了一个渐变的圆角效果，但是在完文之后的实践中，我发现有时效果不甚满意，选中和放手的事件监听没有去正确的判断，然后渐变效果也比较单一，性能也觉得不是很快，不如用图片来的惊艳和迅速，又懒的去改原来的，所以我又用图片来实现一个更完美的效果。1. 准备您可能需要参考我之前的两篇文章:(1).Android学习系列(16)--App列表之圆角ListView(2).Android学习系列(4)--A</summary><published>2011-12-11T03:47:00Z</published><updated>2011-12-11T03:47:00Z</updated><author><name>谦虚的天下</name><uri>http://www.cnblogs.com/qianxudetianxia/</uri></author><link rel="alternate" href="http://www.cnblogs.com/qianxudetianxia/archive/2011/12/11/2283794.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/qianxudetianxia/archive/2011/12/11/2283794.html"/><content type="html">&lt;p&gt;本来这篇文章想并到上篇&lt;a href="http://www.cnblogs.com/qianxudetianxia/archive/2011/09/19/2068760.html"&gt;Android学习系列(16)--App列表之圆角ListView&lt;/a&gt;中的，但是若是如此就让大家错过一篇新的好的文章，着实可惜。&lt;br /&gt;上篇中我们使用shape，corners，gradient实现了一个渐变的圆角效果，但是在完文之后的实践中，我发现有时效果不甚满意，选中和放手的事件监听没有去正确的判断，然后渐变效果也比较单一，性能也觉得不是很快，不如用图片来的惊艳和迅速，又懒的去改原来的，所以我又用图片来实现一个更完美的效果。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;1. 准备&lt;/strong&gt;&lt;br /&gt;您可能需要参考我之前的两篇文章:&lt;br /&gt;(1).&amp;nbsp;&lt;a href="http://www.cnblogs.com/qianxudetianxia/archive/2011/09/19/2068760.html"&gt;Android学习系列(16)--App列表之圆角ListView&lt;br /&gt;&lt;/a&gt;(2).&amp;nbsp;&lt;a id="homepage1_HomePageDays_DaysList_DayItem_3_DayList_3_TitleUrl_0" class="postTitle2" href="http://www.cnblogs.com/qianxudetianxia/archive/2011/04/17/2017591.html"&gt;Android学习系列(4)--App自适应draw9patch不失真背景&lt;br /&gt;&lt;/a&gt;了解圆角的基本实现原理和9patch图片的制作和注意事项。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;2. 效果图(我准备了3套皮肤)&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2011/31770/2011121110540598.png" alt="" width="360" height="600" /&gt;&amp;nbsp;&lt;img src="http://pic002.cnblogs.com/images/2011/31770/2011121110542816.png" alt="" width="360" height="600" /&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2011/31770/2011121110544738.png" alt="" width="360" height="600" /&gt;&amp;nbsp;&amp;nbsp;&lt;img src="http://pic002.cnblogs.com/images/2011/31770/2011121110550356.png" alt="" width="360" height="600" /&gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;3. 圆角类CornerListView的实现：&lt;/strong&gt;&lt;/p&gt;&lt;div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;"&gt;/**&lt;br/&gt; * 圆角ListView&lt;br/&gt; */&lt;br/&gt;public class CornerListView extends ListView {&lt;br/&gt;&lt;br/&gt;    public CornerListView(Context context) {&lt;br/&gt;        this(context, null);&lt;br/&gt;    }&lt;br/&gt;&lt;br/&gt;    public CornerListView(Context context, AttributeSet attrs) {&lt;br/&gt;        super(context, attrs);&lt;br/&gt;        //整个listview的圆角背景&lt;br/&gt;        this.setBackgroundResource(R.drawable.corner_list_bg);&lt;br/&gt;    }&lt;br/&gt;&lt;br/&gt;    @Override&lt;br/&gt;    public boolean onInterceptTouchEvent(MotionEvent ev) {&lt;br/&gt;        switch (ev.getAction()) {&lt;br/&gt;        case MotionEvent.ACTION_DOWN:&lt;br/&gt;                int x = (int) ev.getX();&lt;br/&gt;                int y = (int) ev.getY();&lt;br/&gt;                int itemnum = pointToPosition(x, y);&lt;br/&gt;&lt;br/&gt;                if (itemnum == AdapterView.INVALID_POSITION){&lt;br/&gt;                    break;&lt;br/&gt;                } else {&lt;br/&gt;                        if (itemnum == 0){&lt;br/&gt;                                if (itemnum == (getAdapter().getCount()-1)) {&lt;br/&gt;                                    //只有一项&lt;br/&gt;                                    setSelector(R.drawable.corner_list_single_item);&lt;br/&gt;                                } else {&lt;br/&gt;                                    //第一项&lt;br/&gt;                                    setSelector(R.drawable.corner_list_first_item);&lt;br/&gt;                                }&lt;br/&gt;                        } else if (itemnum==(getAdapter().getCount()-1)){&lt;br/&gt;                             //最后一项&lt;br/&gt;                            setSelector(R.drawable.corner_list_last_item);&lt;br/&gt;                        } else {&lt;br/&gt;                            //中间项&lt;br/&gt;                            setSelector(R.drawable.corner_list_item);&lt;br/&gt;                        }&lt;br/&gt;                }&lt;br/&gt;                break;&lt;br/&gt;        case MotionEvent.ACTION_UP:&lt;br/&gt;                break;&lt;br/&gt;        }&lt;br/&gt;        return super.onInterceptTouchEvent(ev);&lt;br/&gt;    }&lt;br/&gt;}&lt;br/&gt;&lt;/div&gt;&lt;p&gt;从上面看到，我们用到了一张ListView的背景图片和4个项选择器。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;4. 素材&lt;/strong&gt;&lt;br /&gt;一种5张图片素材：1张背景图片和4个项选择器对应的选中图片，都是9patch图片：&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2011/31770/2011121111121364.png" alt="" /&gt;&amp;nbsp;&lt;img src="http://pic002.cnblogs.com/images/2011/31770/2011121111122486.png" alt="" /&gt;&amp;nbsp;&lt;img src="http://pic002.cnblogs.com/images/2011/31770/2011121111123767.png" alt="" /&gt;&amp;nbsp;&lt;img src="http://pic002.cnblogs.com/images/2011/31770/2011121111125596.png" alt="" /&gt;&amp;nbsp;&lt;img src="http://pic002.cnblogs.com/images/2011/31770/2011121111130278.png" alt="" /&gt;&lt;/p&gt;&lt;p&gt;分别对应的是：&lt;br /&gt;R.drawable.corner_list_bg，&lt;br /&gt;R.drawable.corner_list_first_pressed，&lt;br /&gt;R.drawablecorner_list_last_pressed，&lt;br /&gt;R.drawablecorner_list_pressed，&lt;br /&gt;R.drawablecorner_list_single_pressed&lt;/p&gt;&lt;p&gt;&lt;strong&gt;5.选择器构造&lt;/strong&gt;&lt;br /&gt;根据前面的后4张图片我们来构造选中时的对应选择器：&lt;/p&gt;&lt;div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;"&gt;&amp;lt;!-- corner_list_first_item.xml --&amp;gt;&lt;br/&gt;&amp;lt;?xml version="1.0" encoding="utf-8"?&amp;gt;&lt;br/&gt;&amp;lt;selector xmlns:android="http://schemas.android.com/apk/res/android"&amp;gt;&lt;br/&gt;    &amp;lt;item android:state_enabled="true" android:state_selected="true" android:drawable="@drawable/corner_list_first_pressed" /&amp;gt;&lt;br/&gt;    &amp;lt;item android:state_enabled="true" android:state_pressed="true" android:drawable="@drawable/corner_list_first_pressed" /&amp;gt;&lt;br/&gt;&amp;lt;/selector&amp;gt;&lt;br/&gt;&lt;br/&gt;&amp;lt;!-- corner_list_last_item.xml --&amp;gt;&lt;br/&gt;&amp;lt;?xml version="1.0" encoding="utf-8"?&amp;gt;&lt;br/&gt;&amp;lt;selector xmlns:android="http://schemas.android.com/apk/res/android"&amp;gt;&lt;br/&gt;    &amp;lt;item android:state_enabled="true" android:state_selected="true" android:drawable="@drawable/corner_list_last_pressed" /&amp;gt;&lt;br/&gt;    &amp;lt;item android:state_enabled="true" android:state_pressed="true" android:drawable="@drawable/corner_list_last_pressed" /&amp;gt;&lt;br/&gt;&amp;lt;/selector&amp;gt;&lt;br/&gt;&lt;br/&gt;&amp;lt;!-- corner_list_item.xml --&amp;gt;&lt;br/&gt;&amp;lt;?xml version="1.0" encoding="utf-8"?&amp;gt;&lt;br/&gt;&amp;lt;selector xmlns:android="http://schemas.android.com/apk/res/android"&amp;gt;&lt;br/&gt;    &amp;lt;item android:state_enabled="true" android:state_selected="true" android:drawable="@drawable/corner_list_pressed" /&amp;gt;&lt;br/&gt;    &amp;lt;item android:state_enabled="true" android:state_pressed="true" android:drawable="@drawable/corner_list_pressed" /&amp;gt;&lt;br/&gt;&amp;lt;/selector&amp;gt;&lt;br/&gt;&lt;br/&gt;&amp;lt;!-- corner_list_single_item.xml --&amp;gt;&lt;br/&gt;&amp;lt;?xml version="1.0" encoding="utf-8"?&amp;gt;&lt;br/&gt;&amp;lt;selector xmlns:android="http://schemas.android.com/apk/res/android"&amp;gt;&lt;br/&gt;    &amp;lt;item android:state_enabled="true" android:state_selected="true" android:drawable="@drawable/corner_list_single_pressed" /&amp;gt;&lt;br/&gt;    &amp;lt;item android:state_enabled="true" android:state_pressed="true" android:drawable="@drawable/corner_list_single_pressed" /&amp;gt;&lt;br/&gt;&amp;lt;/selector&amp;gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;6. 应用&lt;/strong&gt;&lt;br /&gt;我直接把使用圆角的Activity代码贴出来：&lt;/p&gt;&lt;div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;"&gt;public class SettingTabActivity extends Activity{&lt;br/&gt;&lt;br/&gt;    private CornerListView cornerListView = null;&lt;br/&gt;&lt;br/&gt;    private List&amp;lt;Map&amp;lt;String,String&amp;gt;&amp;gt; listData = null;&lt;br/&gt;    private SimpleAdapter adapter = null;&lt;br/&gt;&lt;br/&gt;    @Override&lt;br/&gt;    protected void onCreate(Bundle savedInstanceState) {&lt;br/&gt;        super.onCreate(savedInstanceState);&lt;br/&gt;        setContentView(R.layout.main_tab_setting);&lt;br/&gt;&lt;br/&gt;        cornerListView = (CornerListView)findViewById(R.id.setting_list);&lt;br/&gt;        setListData();&lt;br/&gt;&lt;br/&gt;        adapter = new SimpleAdapter(getApplicationContext(), listData, R.layout.main_tab_setting_list_item , &lt;br/&gt;new String[]{"text"}, new int[]{R.id.setting_list_item_text});&lt;br/&gt;        cornerListView.setAdapter(adapter);&lt;br/&gt;    }&lt;br/&gt;    &lt;br/&gt;    /**&lt;br/&gt;     * 设置列表数据&lt;br/&gt;     */&lt;br/&gt;    private void setListData(){&lt;br/&gt;        listData = new ArrayList&amp;lt;Map&amp;lt;String,String&amp;gt;&amp;gt;();&lt;br/&gt;&lt;br/&gt;        Map&amp;lt;String,String&amp;gt; map = new HashMap&amp;lt;String, String&amp;gt;();&lt;br/&gt;        map.put("text", "图库更新");&lt;br/&gt;        listData.add(map);&lt;br/&gt;&lt;br/&gt;        map = new HashMap&amp;lt;String, String&amp;gt;();&lt;br/&gt;        map.put("text", "检查新版本");&lt;br/&gt;        listData.add(map);&lt;br/&gt;&lt;br/&gt;        map = new HashMap&amp;lt;String, String&amp;gt;();&lt;br/&gt;        map.put("text", "反馈意见");&lt;br/&gt;        listData.add(map);&lt;br/&gt;&lt;br/&gt;        map = new HashMap&amp;lt;String, String&amp;gt;();&lt;br/&gt;        map.put("text", "关于我们");&lt;br/&gt;        listData.add(map);&lt;br/&gt;&lt;br/&gt;        map = new HashMap&amp;lt;String, String&amp;gt;();&lt;br/&gt;        map.put("text", "支持我们，请点击这里的广告");&lt;br/&gt;        listData.add(map);&lt;br/&gt;    }&lt;br/&gt;}&lt;br/&gt;&lt;/div&gt;&lt;p&gt;ps：记得设置cacheColorHit属性为0或者"#00000000"！&lt;/p&gt;&lt;p&gt;&lt;strong&gt;7. 总结&lt;/strong&gt;&lt;br /&gt;在平时Android使用的过程中，发现很多设置界面的选项大量应用到了这种圆角效果，非常的漂亮，同时也发现很多应用，这个效果做的很不如意，包括一些大公司，要么没有选中效果，要么listview整个的背景是圆角，但是选中的第一项和最后一项的选中效果还是直角，要么干脆为圆角里设定一定像素的内边距等等，我对此总结，算是对这个问题有一个比较好的解决方案（我已经在网上搜过，未发现有人把这个效果分享过来），独乐乐不如众乐乐。&amp;nbsp;&lt;/p&gt;&lt;p&gt;ps：附上3套皮肤素材：&lt;a href="http://files.cnblogs.com/qianxudetianxia/cornerlist-skin.zip"&gt;/Files/qianxudetianxia/cornerlist-skin.zip&lt;/a&gt;&lt;/p&gt;&lt;img src="http://www.cnblogs.com/qianxudetianxia/aggbug/2283794.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/qianxudetianxia/archive/2011/12/11/2283794.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/qianxudetianxia/archive/2011/09/27/2193590.html</id><title type="text">Android拓展系列(5)--CyanogenMod源码下载和编译(Android ROM定制基础篇)</title><summary type="text">本来想下载Android官方源代码，没想到android.git.kernel.org维护，不能访问，非常遗憾，并因此还郁闷了几天。后来转投MIUI,没找到它的源码，不知道它的"超过40万人社区开发团队"是什么意思，求解具体开发人员几何，都是谁？后来一想，竟然忘记了CyanogenMod这茬，这可是的的确确的开源啊，我的手机一直也在用CyanogenMod系统的，感觉确实不错。1.准备我得环境如下，VirtualBox 4.1.2.r73507Ubuntu11.10 Beta2(32位)下载CyanogenMod的gingerbread分支Ubuntu的环境配置大家可以参考</summary><published>2011-09-27T14:19:00Z</published><updated>2011-09-27T14:19:00Z</updated><author><name>谦虚的天下</name><uri>http://www.cnblogs.com/qianxudetianxia/</uri></author><link rel="alternate" href="http://www.cnblogs.com/qianxudetianxia/archive/2011/09/27/2193590.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/qianxudetianxia/archive/2011/09/27/2193590.html"/><content type="html">&lt;p&gt;本来想下载Android官方源代码，没想到android.git.kernel.org维护，不能访问，非常遗憾，并因此还郁闷了几天。&amp;nbsp;&lt;br /&gt;后来转投MIUI,没找到它的源码，不知道它的"超过40万人社区开发团队"是什么意思，求解具体开发人员几何，都是谁？&lt;br /&gt;后来一想，竟然忘记了CyanogenMod这茬，这可是的的确确的开源啊，我的手机一直也在用CyanogenMod系统的，感觉确实不错。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;1.准备&lt;br /&gt;&lt;/strong&gt;我得环境如下，&lt;br /&gt;VirtualBox 4.1.2.r73507&lt;br /&gt;Ubuntu11.10 Beta2(32位)&lt;br /&gt;下载CyanogenMod的gingerbread分支&lt;br /&gt;Ubuntu的环境配置大家可以参考我前面写的《&lt;a href="http://www.cnblogs.com/qianxudetianxia/archive/2011/05/29/2060636.html"&gt;Android拓展系列(3)--Android源码下载&lt;/a&gt;》，也可以参考&lt;a href="http://source.android.com/"&gt;http://source.android.com/&lt;/a&gt;。&lt;br /&gt;这里着重说下Android 2.3以上需要借助JAVA6，安装Java6，我推荐如下安装：&lt;/p&gt;&lt;div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;"&gt;$ sudo add-apt-repository "deb http://archive.canonical.com/ lucid partner"&lt;br/&gt;$ sudo add-apt-repository "deb-src http://archive.canonical.com/ubuntu lucid partner"&lt;br/&gt;$ sudo apt-get update&lt;br/&gt;$ sudo apt-get install sun-java6-jdk&lt;br/&gt;&lt;/div&gt;&lt;p&gt;其中第二句可能会出错，不过没关系，跳过即可。&amp;nbsp;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;2.安装repo&lt;/strong&gt;&lt;br /&gt;因为android.git官方已经不能访问，所以我这里提供一个repo文件的下载地址，免的大家到处搜索：&lt;a href="http://115.com/file/cl15goo2#repo"&gt;http://115.com/file/cl15goo2#repo&lt;/a&gt;&amp;nbsp;&lt;br /&gt;把repo拷贝到ubuntu根目录下得bin下&lt;br /&gt;操作方法：&lt;/p&gt;&lt;div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;"&gt;$mkdir bin&lt;br/&gt;//下载的repo脚本拷贝本地bin文件夹下&lt;br/&gt;//设置本地repo的可执行权限&lt;br/&gt;$chmod a+x ~/bin/repo&lt;br/&gt;$alias repo="~/bin/repo"&lt;br/&gt;//这里我用特意用别名，大家也可以按常规方法把repo的路径添加到PATH中&lt;br/&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;3.ubuntu中环境的配置&lt;/strong&gt;&lt;br /&gt;JDK前面已经说了，其他的软件列表如下：&lt;/p&gt;&lt;div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;"&gt;$sudo apt-get install git-core gnupg flex bison gperf libsdl1.2-dev libesd0-dev libwxgtk2.6-dev squashfs-tools build-essential zip curl libncurses5-dev zlib1g-dev sun-java6-jdk pngcrush schedtool  &lt;br/&gt;&lt;/div&gt;&lt;p&gt;这些软件都安装好之后我们开始下载CyanogenMod源码。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;4.下载CyanogenMod源码&lt;/strong&gt;&lt;/p&gt;&lt;div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;"&gt;//从用户根目录下开始&lt;br/&gt;//创建CyanogenMod文件夹来放置后面所有的代码&lt;br/&gt;$mkdir CyanogenMod&lt;br/&gt;//获取gingerbread的分支源代码&lt;br/&gt;$repo init -u git://github.com/CyanogenMod/android.git -b gingerbread  &lt;br/&gt;//同步服务器代码到本地，-j16据网友反应是多开网络连接，从而能提高下载速度&lt;br/&gt;$repo sync -j16&lt;br/&gt;&lt;/div&gt;&lt;p&gt;这个过程非常的漫长，大家慢慢的等吧，本人是晚上睡觉的时候下载，第二天早上醒来就Done了。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;5.编译源码&lt;/strong&gt;&lt;br /&gt;在CyanogenMod/device目录下有很多款手机的对应版本：&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2011/31770/2011092720560175.png" alt="" style="display: block; margin-left: auto; margin-right: auto;" /&gt;&lt;br /&gt;里面有个htc，本人是htc G9，也就是Liberty，我们点击看看：&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2011/31770/2011092720563435.png" alt="" style="display: block; margin-left: auto; margin-right: auto;" /&gt;&lt;br /&gt;我的liberty静静的优雅的舒服的躺在那里。&lt;br /&gt;所以本人决定编译一个我手头上的liberty对应的系统版本，编译完成后我们直接刷机。&lt;br /&gt;&lt;em&gt;&lt;strong&gt;第一步：读取手机上的一些私有配置文件&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;&lt;div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;"&gt;$cd CyanogenMod/device/htc/liberty&lt;br/&gt;$./extract-files.sh&lt;br/&gt;&lt;/div&gt;&lt;p&gt;图示如下：&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2011/31770/2011092721025486.png" alt="" style="display: block; margin-left: auto; margin-right: auto;" /&gt;&lt;/p&gt;&lt;p&gt;&lt;em&gt;&lt;strong&gt;第二步：生成编译脚本文件&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;&lt;div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;"&gt;$cd ~/CyanogenMod/vendor/cyanogen  &lt;br/&gt;$./get-rommanager&lt;br/&gt;$./extract-google-files&lt;br/&gt;//复制编译脚本文件到CyanogenMod目录下，后面编译整个系统用的就是这个文件&lt;br/&gt;$cp ~/CyanogenMod/vendor/cyanogen/products/cyanogen_lieberty.mk  ~/CyanogenMod/buildspec.mk&lt;br/&gt;&lt;/div&gt;&lt;p&gt;贴上进行时图片：&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2011/31770/2011092721064981.png" alt="" style="display: block; margin-left: auto; margin-right: auto;" /&gt;&lt;/p&gt;&lt;p&gt;&lt;em&gt;&lt;strong&gt;第三步：编译脚本&lt;/strong&gt;&lt;/em&gt;&lt;br /&gt;回到CyanogenMod目录下，执行脚本。&lt;/p&gt;&lt;div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;"&gt;//初始化脚本，这个是后面的重要基础步骤&lt;br/&gt;$source build/envsetup.sh&lt;br/&gt;//选择编译的产品&lt;br/&gt;//这个命令需要一小会儿时间，但是又没提示，耐性等待一下&lt;br/&gt;$lunch cyanogen_liberty-eng&lt;br/&gt;//开始编译&lt;br/&gt;$make -j4 CYANOGEN_WITH_GOOGLE=true otapackage &lt;br/&gt;&lt;/div&gt;&lt;p&gt;这个过程也是相当的漫长，还好一般情况下我们只是第一次需要项目整个编译，后面只需要编译某个模块。&lt;br /&gt;可惜完成的时候我忘记截图了，可惜不能上图了。&lt;br /&gt;在编译的过程中，我们有一点要特别注意，虚拟机的内存不要太小，本人刚开始分配虚拟机512M内存，一会儿就出错，重新编译又一会儿出错，如此重复，而且还导致某个文件被破坏掉了（values-cs/strings.xml中某行少一个右尖括号，这个我百思不得其解），后来我把虚拟机内存调到1024M就一直编译通过了。&lt;/p&gt;&lt;p&gt;&lt;em&gt;&lt;strong&gt;第四步：生产刷机zip包。&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;&lt;div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;"&gt;./vendor/cyanogen/tools/squisher&lt;br/&gt;&lt;/div&gt;&lt;p&gt;有图为赏：&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2011/31770/2011092721195018.png" alt="" style="display: block; margin-left: auto; margin-right: auto;" /&gt;&lt;br /&gt;用这个zip包，我刷到我手机上，一切正常。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;6.定制ROM&lt;/strong&gt;&lt;br /&gt;有了以上的环境后，我们就可以大展手脚，深度定制ROM, 做自己的操作系统，自己的CyanogenMod，自己的MIUI，自己的Android系统。&lt;br /&gt;举个最简单的例子：&lt;br /&gt;我们换一下默认menu菜单的选中背景图，我们进入CyanogenMod/frameworks/base/core/res/res/mdpi目录下(因为htc liberty的分辨率是480x320)，找到图片highlight_pressed.png，替换为绿色的背景：&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2011/31770/2011092721295436.png" alt="" style="display: block; margin-left: auto; margin-right: auto;" /&gt;&lt;br /&gt;那么修改资源文件后，我们需要重新编译framework-res.apk:&lt;/p&gt;&lt;div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;"&gt;//回到根目录&lt;br/&gt;$cd&lt;br/&gt;//切换到管理员权限&lt;br/&gt;$sudo -s&lt;br/&gt;//进入CyanogenMod目录，并初始化脚本文件&lt;br/&gt;$cd CyanogenMod&lt;br/&gt;$source build/envsetup.h&lt;br/&gt;//选择产品&lt;br/&gt;$lunch cyanogen_liberty-eng&lt;br/&gt;//进入资源编译目录(或者它的子目录也可以)&lt;br/&gt;$cd frameworks/base/core/res&lt;br/&gt;//开始编译framework-res.apk&lt;br/&gt;$mm&lt;br/&gt;&lt;/div&gt;&lt;p&gt;编译完成，示意图如下：&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2011/31770/2011092721494456.png" alt="" style="display: block; margin-left: auto; margin-right: auto;" /&gt;&lt;/p&gt;&lt;p&gt;在CyanogenMod/out/target/product/liberty/system/framework目录下生成了一个framework-res.apk文件，就是我们修改Menu选中项图片后新打的资源包。&lt;br /&gt;现在我们需要把这个资源包更新到手机中。&lt;br /&gt;USB连上手机后，一切正常的话(adb当然也是事前要装好的哦)，打开终端：&lt;/p&gt;&lt;div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;"&gt;//使其可写&lt;br/&gt;$adb remount&lt;br/&gt;//替换手机中资源包&lt;br/&gt;$adb push ~/CyanogenMod/out/target/product/liberty/system/framework/framework-res.apk /system/framework/&lt;br/&gt;//重启手机后生效&lt;br/&gt;$adb reboot&lt;br/&gt;&lt;/div&gt;&lt;p&gt;重启后，进入桌面，我们点击Menu，选择一项：&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2011/31770/2011092721573548.png" alt="" style="display: block; margin-left: auto; margin-right: auto;" /&gt;&lt;/p&gt;&lt;p&gt;修改资源包，可以修改样式，显示图片，调整布局等等。&lt;br /&gt;你也可以直接修改framework代码，在framework/base/core/java目录下，修改对应的类，比如逻辑处理，样式重绘等等，然后同上面类似编译，把生成的framework.jar替换掉手机的/system/framework下的framework.jar，重启手机即可看到效果。&lt;br /&gt;你也可以添加系统应用，删除系统应用等等，这里特别提到一点，系统应用可以通过如下命令删除(具有root权限)：&lt;/p&gt;&lt;div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;"&gt;$adb remount&lt;br/&gt;$adb shell&lt;br/&gt;#cd system/app&lt;br/&gt;//用rm删除系统FM应用&lt;br/&gt;#rm FM.apk&lt;br/&gt;&lt;/div&gt;&lt;p&gt;有了这些基础知识，我相信我们后面的深度定制ROM一定非常精彩！&lt;/p&gt;&lt;p&gt;&lt;strong&gt;7.小结&lt;/strong&gt;&lt;br /&gt;本文以CyanogenMod源码编译总结了Android改造系统的一个基本环境，是我们之后ROM系统定制，优化的基础，是android深入学习的必会技能，特此分享，共勉！&amp;nbsp;&lt;/p&gt;&lt;img src="http://www.cnblogs.com/qianxudetianxia/aggbug/2193590.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/qianxudetianxia/archive/2011/09/27/2193590.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry></feed>
