二十七:Maven编译开源二维码扫描项目zxing

最后更新于:2022-04-01 06:43:07

拥有自己的手机软件工具箱是件非常有意义的事情。就目前国内Android的生态环境来说,混乱的不能再乱了。由于我们登录不了官网App商店,下软件就只好在国内五花八门的软件市场下载。由于这些市场的监管不力,什么样的软件都有,就拿二维码扫描软件来说,好多都带那种狗皮膏药一样的广告插件,真是特别讨厌。  在开源世界中有很多优秀的软件,其中zxing就是非常好的Android扫碼工具软件。我们可以拿来即用还可以学习内部机制,然后做些定制化个性化。既可以自己享用,又可以跟大家分享。真是不错。 zxing在github:[https://github.com/zxing/zxing](https://github.com/zxing/zxing) ~~~ zxing-master$ ls android android-integration AUTHORS CONTRIBUTING.md core javase pom.xml src zxingorg android-core androidtest CHANGES COPYING glass NOTICE README.md zxing.appspot.com ~~~ 源码很多,里面的pom.xml告诉我们需要用maven编译。可惜这个构建工具我用的并熟练,一切都要摸索着来。 Maven官网:[https://maven.apache.org](https://maven.apache.org/)  在ubuntu下的安装是很简单的,下载[apache-maven-3.3.1-bin.zip](http://mirror.bit.edu.cn/apache/maven/maven-3/3.3.1/binaries/apache-maven-3.3.1-bin.zip)解压(unzip)到你喜欢的目录下如/opt/apache-maven-3.3.1/ 。并将环境变量设置好,~/.bashrc下填入下面内容: ~~~ #Maven export PATH="$PATH:/opt/apache-maven-3.3.1/bin" export MAVEN_OPTS="-Xms256m -Xmx512m" ~~~ 前提是你的java7环境已经配好。请参考[Android实战技巧之八:Ubuntu下切换JDK版本](http://blog.csdn.net/lincyang/article/details/42024565) 下面是我的mvn环境: ~~~ $ mvn -v Apache Maven 3.3.1 (cab6659f9874fa96462afef40fcf6bc033d58c1c; 2015-03-14T04:10:27+08:00) Maven home: /opt/apache-maven-3.3.1 Java version: 1.7.0_71, vendor: Oracle Corporation Java home: /opt/jdk/jdk1.7.0_71/jre Default locale: en_US, platform encoding: UTF-8 OS name: "linux", version: "3.13.0-49-generic", arch: "amd64", family: "unix" ~~~ 对于zxing的编译,我没有找到相关的文档,所以都是我这个maven新人不断的摸索,虽然不是特别正规,但是达到我的目的是真的。 先在zxing根目录下执行mvn compile,好家伙,一个劲的下载依赖包,都说这第一次编译需要下载大量的包,如果我没有做代理或库的更改,那么需要漫长的等待。 我晚上跑步将近一个小时,以为回来就编译好了。可是令我大失所望,虽然包下完了,但是编译有问题。再次执行,这次编译没有报错,但是我搜遍目录没有找到jar包。这是有问题的,我还是按照自己的节奏来工作吧。 android目录是一个eclipse项目,我直接转换为AS工程然后编译发现少了好多zxing的类。 android-core下的pom是这样的: ~~~ <artifactId>android-core</artifactId> <version>3.2.1-SNAPSHOT</version> <packaging>jar</packaging> ~~~ 没有其他依赖,直接编译成jar。我执行mvn package,漫长的等待后jar包编译出来了。 ~~~ $ ls android-core/target/ android-core-3.2.1-SNAPSHOT.jar ~~~ 我引入这个jar,发现里面只有一个类com.google.zxing.client.android.camera.CameraConfigurationUtils  这显然还不够。  core目录才是重点,同样mvn package再等待,如果中途遇到依赖其他目录的jar就去编译之。 ~~~ $ ls core/target/ core-3.2.1-SNAPSHOT.jar ~~~ 再将其引入android工程,编译成功!
';

二十六:persistableMode与Activity的持久化

最后更新于:2022-04-01 06:43:04

API 21为Activity增加了一个新的属性,只要将其设置成persistAcrossReboots,activity就有了持久化的能力,另外需要配合一个新的bundle才行,那就是PersistableBundle。  这里的持久化与传统意义的不同,它的具体实现在Activity重载的onSaveInstanceState、onRestoreInstanceState和onCreate方法。 ~~~ public void onSaveInstanceState(Bundle outState, PersistableBundle outPersistentState) public void onRestoreInstanceState(Bundle savedInstanceState, PersistableBundle persistentState) public void onCreate(Bundle savedInstanceState, PersistableBundle persistentState) ~~~ onSaveInstanceState和onRestoreInstanceState方法是一对拯救灾难的方法,它们不在“正常“的Activity生命周期中,只有一些突发异常情况才会触发它们,比如横竖屏切换、按Home键等。当API 21后增加了PersistableBundle参数,令这些方法有了系统关机重启后数据恢复的能力。 网友们评价不一,但是无论如何这都为我们提供了一种便利。而它应用的场景是异常的状况,不会影响我们正常的数据持久化办法。比如在pause方法中做一些操作Preferences,文件I/O,SQLite数据库,ContentProvider等常规办法。 如何实践呢?  只需在Manifest中的activity设置属性: ~~~ android:persistableMode="persistAcrossReboots" ~~~ 然后在activity中直接用上述的三个方法即可。  另外注意API版本是21及以上。 验证是个难题。因为我没有5.0及以上系统的设备,求助与模拟器吧,各种问题都来了。无论是Genymotion还是自带的模拟器,在关机的过程中模拟器都会卡死。虽然我在log里看到了程序已经走过了onSaveInstanceState(Bundle,PersistableBundle)。就差模拟器关机后开启看效果。我这边是没有成功,如果哪位大虾看到了效果,请告诉我。
';

二十五:模拟器如何重启?试试Genymotion!

最后更新于:2022-04-01 06:43:02

需要测试Android 5.1系统重启后的一个功能,我手里的设备都没有这么高的版本,那么只好向模拟器求助了。就像大多网友一样,我遇到了一个大问题,如何将Android模拟器重启?  我有几个想法:  * 长按模拟器的power kay,调出重启键。可惜的是系统默认只有poweroff一项。  * adb reboot或者adb shell进入模拟器再执行reboot。尝试了几个模拟器,都没有成功,只听见我本子的cpu风扇在飞速的运转着。  * 自己写一个重启的小应用做重启这件事。这是几年前我就想写的程序了,可惜Android并没有放开接口。普通应用做不到。 就这样,几个点子都点不亮,怎么办呢?那就试试第三方的模拟器Genymotion吧!下面就是我抱着试试看的态度,一步一步走下去,没想到有个完美的结局。 Genymotion是一个口碑非常好的第三方Android模拟器,不过要使用高级的功能是要包月花钱的,如果只是基本的测试要求,免费的个人版也能帮上忙。官网是[https://www.genymotion.com/](https://www.genymotion.com/),下载和使用需要先注册帐号。 起初我以为口碑这么好的工具,安装应该事件非常easy的事,但没想到我安装遇到了很多问题。 需要先安装virtualbox.这个当然是越新越好,我之前安装的4.3.26足够用。版本过低是无法使用或效率有问题。ubuntu下用dpkg安装deb包即可。 注册帐号,并下载相应的bin包。(这个bin包当时我还真不清楚如何处理,最后问网友才知道是可执行的)  我的系统是ubuntu14.04,下载后执行: ~~~ $ ./genymotion-2.4.0_x64.bin ~~~ 生成genymotion文件夹,里面的内容如下: ~~~ $ ls genymotion crypto lib64OpenglRender.so libQtWebKit.so.4 device-upgrade libavutil.so.51 libQtXml.so.4 genymotion libcrypto.so libssl.so genymotion-shell libprotobuf.so.7 libswscale.so.2 genymotion-tool libqca.so.2 player genyshell libQtCore.so.4 plugins icons libQtGui.so.4 sqldrivers imageformats libQtNetwork.so.4 tools lib64EGL_translator.so libQtScript.so.4 translations lib64GLES_CM_translator.so libQtSql.so.4 lib64GLES_V2_translator.so libQtSvg.so.4 ~~~ 执行 ~~~ genymotion$ ./genymotion ~~~ 报错说virtualbox engine not load.  解决如下: ~~~ $ /etc/init.d/vboxdrv status VirtualBox kernel module is not loaded. $ sudo /etc/init.d/vboxdrv setup [sudo] password for linc: Stopping VirtualBox kernel modules ...done. Recompiling VirtualBox kernel modules ...done. Starting VirtualBox kernel modules ...done. $ /etc/init.d/vboxdrv status VirtualBox kernel modules (vboxdrv, vboxnetflt, vboxnetadp, vboxpci) are loaded. ~~~ 这次再执行./genymotion就会正常启动了。  ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-01-01_5685d198d3de2.jpg)  然后进入到添加设备阶段,需要登录,就遇到“genymotion unknown generic error“了。真是够不幸的,一天时间就要这么浪费下去吗?我还能否顺利的使用你呢?  也许是网络的问题,官网都非常慢。想登录一下也没有反显,用户体验真是不太好。  这个错误并不是网上说的那样需要设置vitualbox里设置虚拟机的网络配置,因为现在我们还没有任何虚拟机。这只是一个普通的网络原因造成的连接中断,多尝试几次没准就登录上去了。我试了超过5次才行。  登录后会出现可以下载的设备列表,我选择了6儿子,系统信息如下图:  ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-01-01_5685d198e78ff.jpg)  接下来就是下载的过程,个人感觉速度还可以。  ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-01-01_5685d1990a2a1.jpg)  那么启动这个模拟器看看吧!速度真是没得说,十分迅速!  ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-01-01_5685d19919e0c.jpg)  右侧是一些功能列表,但好多功能只有付费才能用。  现在咱们再看看virtualbox里是否也有这个虚拟机呢?如下图:  ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-01-01_5685d1992dfd0.jpg) 终于成功的启动期待的模拟器了,赶快尝试一下reboot十分好用。当然是用命令行来了,adb reboot和adb shell后执行reboot都可以成功的将模拟器重启。  漂亮!下面就可以用它来测试我要的功能了!
';

二十四:横竖屏切换

最后更新于:2022-04-01 06:43:00

这几年一直在做手机上和电视盒的App,几乎没有考虑过横竖屏切换的问题。电视盒好说,横屏不变,你要是给它设计个竖屏人家也没机会使;而手机上的应用就不好说了,有些界面你设计了横竖屏兼容可能是为了表示你的功能强大。但是按照惯例,或许也是设计师图省事,我们只是做一个方案。就像目前主流的App都只有竖屏一个模式,比如微信、京东和招商银行。我截了几张图表示一下。  ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-01-01_5685d19885676.jpg)  ![jd](http://img.blog.csdn.net/20150418221803905) ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-01-01_5685d19892817.jpg)  但是像地图之类的应用,也许横屏会显示的更友好一些。请看腾讯地图的设计如下:  ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-01-01_5685d198a6f73.jpg)  ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-01-01_5685d198c136f.jpg)  细心的你会发现,地图的横竖屏的样式几乎是一样的布局,调整起来还是比较容易的。我一直也这样认为,横竖屏切换就是一件十分Easy的事儿,但现在我不这样认为了。 因为我可是思考在Android平板上的界面设计了。屏幕大了,横竖屏可以提供不同的表现形式。这是平板与手机的区别。但这样一来,事情就会变得不那么简单了。尤其是大量信息录入的界面,后台有线程工作的时候,都是很难办的事儿。下面是我的一些探索,希望大家多提意见。 ## 生命周期的故事 横竖屏切换的过程,会经历onDestroy和onCreate。通俗点说,就是这个activity关闭了,有新起来一个activity。那么,前一个activity的数据肯定都不存在了。虽然这样的切换,你的EditText上输入的内容还在,但是一定要记得,成员变量都是空的啦。数据保存成了一个问题。 ## 保存整个activity的方案 在Manifest里对于的activity加上这个配置就不会重走销毁和创建了,如下: ~~~ android:configChanges="orientation|keyboardHidden|screenSize" ~~~ 不要高兴的太早,除非你不需要改变横竖屏的布局,否则这个方案仍然要有很多工作要做。 ## 还是乖乖的保存数据吧 onRetainNonConfigurationInstance()被弃用了,我们还是用onSaveInstanceState吧。针对横竖屏不同的布局,我们只需在创建一个layout-land文件夹,里面放同名的布局文件,onCreate时会自动加载相对应的横竖屏布局。  在横竖屏切换的过程中会经历onSaveInstanceState,给你一个保存数据的机会: ~~~ @Override public void onSaveInstanceState(Bundle outState) { Log.i("linc", "onSaveInstanceState(Bundle)"); super.onSaveInstanceState(outState); outState.putString(TEXT_ONE, ""+editText1.getTag(R.id.tag_first));//avoid null point // outState.putSerializable();//object } ~~~ 在onCreate中把数据取出来: ~~~ @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_land_port_switch); Log.e("linc","oncreate"); editText1 = (EditText)findViewById(R.id.txt1); // Restore saved state. if (savedInstanceState != null) { editText1.setTag(R.id.tag_first,savedInstanceState.getString(TEXT_ONE)); } } ~~~ ## github上的一个进度条例子 请看这个例子吧,横竖屏切换可以有自己的布局,切换过程中不会打断进度条的工作,用到了Fragment。详情请见这里:  [https://github.com/alexjlockwood/worker-fragments](https://github.com/alexjlockwood/worker-fragments)
';

二十三:Android Studio的NDK开发

最后更新于:2022-04-01 06:42:58

较新的NDK版本是r10b,Android Studio对NDK开发的支持还处于构思阶段,所以很多工作比如用javah生成头文件等工作还要自己做。今天用一个例子来演示AS中的NDK开发。 ## 新建一个项目SecondNdkTest 在此项目中新建一个Module叫ndklibrary,作为so库单独划出来。在library中新建一个java类SecondLib,内容如下: ~~~ package com.linc.ndklibrary; /** * Created by linc on 15-3-29. */ public class SecondLib { // Native implementation static { System.loadLibrary("SecondLib"); } //int array public static native int[] intMethod(); //string array public static native String[] stringMethod(); } ~~~ Build—>Make Module’ndklibrary’,这样SecondLib就编译完成了,通过SecondLib.class,用javah生成C的头文件,如下: ~~~ AndroidStudioProjects/SecondNdkTest/ndklibrary/src/main$ javah -d jni -classpath ../../build/intermediates/classes/debug com.linc.ndklibrary.SecondLib AndroidStudioProjects/SecondNdkTest/ndklibrary/src/main$ ls AndroidManifest.xml java jni res AndroidStudioProjects/SecondNdkTest/ndklibrary/src/main$ ls jni/ com_linc_ndklibrary_SecondLib.h ~~~ 头文件内容如下: ~~~ /* DO NOT EDIT THIS FILE - it is machine generated */ #include <jni.h> /* Header for class com_linc_ndklibrary_SecondLib */ #ifndef _Included_com_linc_ndklibrary_SecondLib #define _Included_com_linc_ndklibrary_SecondLib #ifdef __cplusplus extern "C" { #endif /* * Class: com_linc_ndklibrary_SecondLib * Method: intMethod * Signature: ()[I */ JNIEXPORT jintArray JNICALL Java_com_linc_ndklibrary_SecondLib_intMethod (JNIEnv *, jclass); /* * Class: com_linc_ndklibrary_SecondLib * Method: stringMethod * Signature: ()[Ljava/lang/String; */ JNIEXPORT jobjectArray JNICALL Java_com_linc_ndklibrary_SecondLib_stringMethod (JNIEnv *, jclass); #ifdef __cplusplus } #endif #endif ~~~ ## Native代码实现 在jni目录中新建c文件SecondLib.c与头文件对应,分别实现上述两个方法,内容如下: ~~~ #include "com_linc_ndklibrary_SecondLib.h" const static int length=10; //int array JNIEXPORT jintArray JNICALL Java_com_linc_ndklibrary_SecondLib_intMethod (JNIEnv *env, jclass obj) { jintArray array; array=(*env)->NewIntArray(env,10); int i=1; for(;i<=10;++i) { (*env)->SetIntArrayRegion(env,array,i-1,1,&i); } //get array length int len=(*env)->GetArrayLength(env,array); //array content jint* elems=(*env)->GetIntArrayElements(env,array,0); return array; } //string array JNIEXPORT jobjectArray JNICALL Java_com_linc_ndklibrary_SecondLib_stringMethod (JNIEnv *env, jclass obj) { jclass class=(*env)->FindClass(env,"java/lang/String"); jobjectArray string=(*env)->NewObjectArray(env,(jsize)length, class,0); jstring jstr; char* _char[]={"my ","name ","is ", "linc!!","正在","学习", "JNI","和","NDK","技术!" }; int i=0; for(;i<length;++i) { jstr=(*env)->NewStringUTF(env,_char[i]); (*env)->SetObjectArrayElement(env,string,i,jstr); } return string; } ~~~ ## 编译 在local.properties中加入ndk路径: ~~~ ndk.dir=/opt/ndk/android-ndk-r10b ~~~ 然后在ndklibrary的build.gradle中defaultConfig中加入ndk定义,如下: ~~~ defaultConfig { minSdkVersion 15 targetSdkVersion 22 versionCode 1 versionName "1.0" ndk{ moduleName "SecondLib" } } ~~~ 这样就可以直接编译了,不用自己编写make文件了。  Build—>Make Module’ndklibrary’,生成的so如下: ~~~ AndroidStudioProjects/SecondNdkTest$ find -name *.so ./ndklibrary/build/intermediates/ndk/debug/lib/armeabi/libSecondLib.so ./ndklibrary/build/intermediates/ndk/debug/lib/armeabi-v7a/libSecondLib.so ./ndklibrary/build/intermediates/ndk/debug/lib/mips/libSecondLib.so ./ndklibrary/build/intermediates/ndk/debug/lib/x86/libSecondLib.so ./ndklibrary/build/intermediates/ndk/debug/obj/local/armeabi/libSecondLib.so ./ndklibrary/build/intermediates/ndk/debug/obj/local/armeabi-v7a/libSecondLib.so ./ndklibrary/build/intermediates/ndk/debug/obj/local/mips/libSecondLib.so ./ndklibrary/build/intermediates/ndk/debug/obj/local/x86/libSecondLib.so ~~~ 注:  至于直接在Activity中用native的方法请参考下面的前两个链接。我遇到了问题没有得到解决: ~~~ $ javah -d jni -classpath /opt/sdk/platforms/android-5.1/android.jar;../../build/intermediates/classes/debug com.linc.secondndktest.MainActivity Error: no classes specified bash: ../../build/intermediates/classes/debug/: Is a directory ~~~ 参考:  [http://blog.csdn.net/rznice/article/details/42295215](http://blog.csdn.net/rznice/article/details/42295215)  [http://blog.csdn.net/sodino/article/details/41946607](http://blog.csdn.net/sodino/article/details/41946607)  [http://stackoverflow.com/questions/10483959/javah-error-android-app-activity-not-found](http://stackoverflow.com/questions/10483959/javah-error-android-app-activity-not-found)  [http://blog.csdn.net/lincyang/article/details/6705143](http://blog.csdn.net/lincyang/article/details/6705143)
';

二十二:Android 5.1 SDK下载与配置

最后更新于:2022-04-01 06:42:55

## 重要文件下载地址: (1)[http://dl-ssl.google.com/android/repository/sources-22_r01.zip](http://dl-ssl.google.com/android/repository/sources-22_r01.zip)  (2)[http://dl-ssl.google.com/android/repository/tools_r24.1.2-windows.zip](http://dl-ssl.google.com/android/repository/tools_r24.1.2-windows.zip)  (3)[http://dl-ssl.google.com/android/repository/android-22_r01.zip](http://dl-ssl.google.com/android/repository/android-22_r01.zip)  (4)[http://dl-ssl.google.com/android/repository/samples-22_r05.zip](http://dl-ssl.google.com/android/repository/samples-22_r05.zip)  (5)[http://dl-ssl.google.com/android/repository/build-tools_r21.1.2-windows.zip](http://dl-ssl.google.com/android/repository/build-tools_r21.1.2-windows.zip)  (6)[http://dl-ssl.google.com/android/repository/build-tools_r22-windows.zip](http://dl-ssl.google.com/android/repository/build-tools_r22-windows.zip)  (7)[http://dl-ssl.google.com/android/repository/build-tools_r22.0.1-windows.zip](http://dl-ssl.google.com/android/repository/build-tools_r22.0.1-windows.zip)  (8)[http://dl-ssl.google.com/android/repository/docs-22_r01.zip](http://dl-ssl.google.com/android/repository/docs-22_r01.zip)  (9)[http://dl-ssl.google.com/android/repository/sysimg_x86-22_r01.zip](http://dl-ssl.google.com/android/repository/sysimg_x86-22_r01.zip)  (10)[http://dl-ssl.google.com/android/repository/sysimg_x86_64-22_r01.zip](http://dl-ssl.google.com/android/repository/sysimg_x86_64-22_r01.zip)  (11)[http://dl-ssl.google.com/android/repository/sysimg_arm-22_r01.zip](http://dl-ssl.google.com/android/repository/sysimg_arm-22_r01.zip)  (12)[http://dl-ssl.google.com/android/repository/haxm-windows_r05.3.zip](http://dl-ssl.google.com/android/repository/haxm-windows_r05.3.zip) 按照惯例,linux版本的只需将上述地址中的windows换成linux即可。 ## SDK目录结构 ~~~ :/opt/sdk$ ls add-ons build-tools docs extras platforms platform-tools samples sources system-images temp tmp tools ~~~ **1.docs**  只需将原来的docs目录重命名,如docs-21,将最新的docs-22解压即可。文档是学习Android新feature的重要途径,一定要重视。  **2.sources**  API源码,另一个重要的学习资料。将其解压到sources目录下,最好将其api号标好,比如我这里: ~~~ $ ls sources/ android-14 android-15 android-16 android-17 android-18 android-19 android-21 android-22 ~~~ **3.samples**  例子是学习的第三个途径。将其放入samples目录下即可,如下: ~~~ $ ls samples/ android-10 android-15 android-16 android-17 android-18 android-19 android-5.1 ~~~ **4.platform**  这是sdk中的核心。将sources-22_r01.zip解压到platforms目录,如下: ~~~ $ ls platforms/ android-10 android-14 android-15 android-16 android-17 android-18 android-19 android-21 android-5.1 android-L ~~~ **5.编译工具**  tools_r24.1.2、build-tools_r22.0.1分别放到tools和build-tools下。  **6.sysimg**  有了5.1的platform我们就可以开发5.1的应用了,但是我们还缺少一个模拟器。这是sysimg要做的事情。  将sysimg_arm-22_r01.zip解压到platform-tools目录下。 ## 第一个Android5.1例子 build.gradle如下: ~~~ apply plugin: 'com.android.application' android { compileSdkVersion 22 buildToolsVersion "21.1.2" defaultConfig { applicationId "com.linc.testapi22" minSdkVersion 15 targetSdkVersion 22 versionCode 1 versionName "1.0" } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } } dependencies { compile fileTree(dir: 'libs', include: ['*.jar']) compile 'com.android.support:appcompat-v7:22.+' } ~~~ 演示如下图:  ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-01-01_5685d198068eb.jpg)  ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-01-01_5685d1981cb2c.jpg)  ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-01-01_5685d19833f50.jpg)  ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-01-01_5685d1985154f.jpg)  ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-01-01_5685d1986e553.jpg) 参考:  [http://www.cnblogs.com/warnier-zhang/p/4369647.html](http://www.cnblogs.com/warnier-zhang/p/4369647.html)  [http://www.cnblogs.com/yaotong/archive/2011/01/25/1943615.html](http://www.cnblogs.com/yaotong/archive/2011/01/25/1943615.html)
';

二十一:Android原型设计工具探索

最后更新于:2022-04-01 06:42:53

移动开发者、移动产品经理和交互设计师在有了产品的想法后会做出一系列的草图,然后反复推敲改进,直到自己满意。这个草图就是原型设计,是产品设计初期很重要的工作,它是产品的雏形,之后会以此为原型进行开发。 当移动互联网热度增加后,一些主打移动原型设计的工具如雨后春笋般冒了出来。在我看来,一个好的工具对产品还是帮助很大的,但遗憾的是,绝大多数的工具都是收费的。  下面列出我试用的工具。  1.[fluidui](https://www.fluidui.com/)  ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-01-01_5685d197b217c.jpg)  界面还是很炫的,用户体验确实不错。免费用户的限制是只能创建一个项目并且只有10个屏幕。收费版还是很贵的说,Lite版12刀一个月,pro版49刀一个月。  2.[justinmind](https://www.justinmind.com/)  产品也很好,只不过桌面版没有Linux的,真不好意思。  3.pencil  几年前这个开源工具还很火,13年后就没有更新了,更遗憾的是源代码放在code.google上管理。我很想得到这个工具,因为这是免费的工具,功能也足够我用。  4.[mockplus](https://www.mockplus.cn/)  摩客,一个国产软件。界面风格不错。免费版的局限是你的设计是公开的,这对于大部分用户来说是不可接受的。所以,付费版是必须。  ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-01-01_5685d197ca31f.jpg)  5.[modao](https://modao.io/)  墨刀,另一个国产软件。用户体验不错,缺点同上。  ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-01-01_5685d197dfcaf.jpg) 总结  鉴于自己的需求不高,觉得还是没有必要每个月花钱购置收费版。手绘是个不错的选择!当时就是这样!
';

二十:两个开源的图表/报表控件

最后更新于:2022-04-01 06:42:51

项目中要用饼图和折线图表示数据,重造轮子不是咱风格,先了解一下时下比较流行的开源图表控件吧。调查发现有三个口碑不错的开源项目,它们是MPAndroidChart、AChartEngine、HoloGraphLibrary。由于AChartEngine源码放在code.google上,遂先放弃它,主要研究其他两个在github上的项目。 ## HoloGraphLibrary 项目地址:[https://github.com/Androguide/HoloGraphLibrary](https://github.com/Androguide/HoloGraphLibrary)  简介:这是一个十分简单的图表控件,源码量在3千行左右。使用简单,项目自带sample作为使用指导。示意图如下:  ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-01-01_5685d1978c1c4.jpg) # MPAndroidChart 项目地址:[https://github.com/PhilJay/MPAndroidChart](https://github.com/PhilJay/MPAndroidChart)  简介:与Holo相比要复杂和强大很多,代码量在4万行左右。不过带的例子有了很好的帮助,我们用起来不算难。饼图带很炫的加载动画,如果对界面要求高交互性好,推荐此控件。示意图如下:  ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-01-01_5685d1979da96.jpg) 由于这两个项目都用AS开发,对于很多使用eclipse的同学转换很不方便,我将lib做成jar包并提供了eclipse的demo,下载地址在:  [http://download.csdn.net/detail/lincyang/8517179](http://download.csdn.net/detail/lincyang/8517179)
';

十九:android studio导出jar包(Module)并获得手机信息

最后更新于:2022-04-01 06:42:48

AS中并没有独立的Module 工程,但是可以在普通的Project中加入Module。所谓的Module就是我们通常所指的模块化的一个单元,并常常以jar包的形式存在。下面以一个获取手机信息的例子演示AS中的模块化。 ## 一、项目中新建Module File—>New Module,详细见下图。  ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-01-01_5685d1973a461.jpg)  ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-01-01_5685d197503fd.jpg)  ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-01-01_5685d19761842.jpg) ## 二、新建Java类 新建一个PhoneInfo类,内容如下: ~~~ package com.linc.mylibrary; import android.content.Context; import android.net.wifi.WifiInfo; import android.net.wifi.WifiManager; import android.os.Build; import android.telephony.TelephonyManager; import android.text.format.Formatter; import android.util.Log; import java.io.BufferedReader; import java.io.FileReader; import java.io.IOException; /** * Created by linc on 15-3-19. */ public class PhoneInfo { private String TAG = "PhoneInfo"; private Context mContext; private TelephonyManager mPhoneManager; public PhoneInfo(Context context) { mContext = context; mPhoneManager = (TelephonyManager)mContext.getSystemService(Context.TELEPHONY_SERVICE); } public String getDeviceId() { return mPhoneManager.getDeviceId(); } public String getPhoneModule() { return Build.MODEL; } public String getSerialNumber() { return Build.SERIAL; } public String getPhoneNumber() { return mPhoneManager.getLine1Number(); } public String getMacAddress(){ String result = ""; WifiManager wifiManager = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE); WifiInfo wifiInfo = wifiManager.getConnectionInfo(); result = wifiInfo.getMacAddress(); Log.i(TAG, "macAdd:" + result); return result; } public String[] getCpuInfo() { String str1 = "/proc/cpuinfo"; String str2 = ""; String[] cpuInfo = {"", ""}; //1-cpu型号 //2-cpu频率 String[] arrayOfString; try { FileReader fr = new FileReader(str1); BufferedReader localBufferedReader = new BufferedReader(fr, 8192); str2 = localBufferedReader.readLine(); arrayOfString = str2.split("\\s+"); for (int i = 2; i < arrayOfString.length; i++) { cpuInfo[0] = cpuInfo[0] + arrayOfString[i] + " "; } str2 = localBufferedReader.readLine(); arrayOfString = str2.split("\\s+"); cpuInfo[1] += arrayOfString[2]; localBufferedReader.close(); } catch (IOException e) { } Log.i(TAG, "cpuinfo:" + cpuInfo[0] + " " + cpuInfo[1]); return cpuInfo; } public String getTotalMemory() { String str1 = "/proc/meminfo";// 系统内存信息文件 String str2; String[] arrayOfString; long initial_memory = 0; try { FileReader localFileReader = new FileReader(str1); BufferedReader localBufferedReader = new BufferedReader( localFileReader, 8192); str2 = localBufferedReader.readLine();// 读取meminfo第一行,系统总内存大小 arrayOfString = str2.split("\\s+"); for (String num : arrayOfString) { Log.i(str2, num + "\t"); } initial_memory = Integer.valueOf(arrayOfString[1]).intValue() * 1024;// 获得系统总内存,单位是KB,乘以1024转换为Byte localBufferedReader.close(); } catch (IOException e) { } return Formatter.formatFileSize(mContext, initial_memory);// Byte转换为KB或者MB,内存大小规格化 } } ~~~ 并在Module的AndroidManifest文件中加入两个权限: ~~~ <uses-permission android:name="android.permission.READ_PHONE_STATE" /> <uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/> ~~~ ## 三、app中引入此module 在app的build.gradle中加入此module的dependency,如下: ~~~ dependencies { compile 'com.android.support:appcompat-v7:21.0.3' compile project(':mylibrary') } ~~~ 在app的MainActivity中加入测试代码: ~~~ @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); PhoneInfo info = new PhoneInfo(this); Log.d(TAG,"devices id: "+info.getDeviceId()); Log.d(TAG,"getPhoneModule: "+info.getPhoneModule()); Log.d(TAG,"getSerialNumber: "+info.getSerialNumber()); Log.d(TAG,"getPhoneNumber: "+info.getPhoneNumber()); Log.d(TAG,"getMacAddress: "+info.getMacAddress()); Log.d(TAG,"getCpuInfo: "+info.getCpuInfo()); Log.d(TAG,"getTotalMemory: "+info.getTotalMemory()); } ~~~ ## 四、jar的生成 项目编译之后jar会在下面的目录找到: ~~~ ./mylibrary/build/intermediates/bundles/debug/classes.jar ./mylibrary/build/intermediates/bundles/release/classes.jar ~~~ ## 五、Module的移除 先要在File—>Project Structure中将此module“减“掉后才能在项目中Module右键的Delete键可用。  ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-01-01_5685d19776b4f.jpg) 参考:  [http://www.cnblogs.com/wuya/p/android-studio-gradle-export-jar-assets.html](http://www.cnblogs.com/wuya/p/android-studio-gradle-export-jar-assets.html)  [http://www.cnblogs.com/helloandroid/articles/2210334.html](http://www.cnblogs.com/helloandroid/articles/2210334.html)  [http://blog.csdn.net/hyr83960944/article/details/37519299](http://blog.csdn.net/hyr83960944/article/details/37519299)
';

十八:adb取出安装在手机中的apk

最后更新于:2022-04-01 06:42:46

场景:  朋友看见你Android手机中的游戏或应用很好玩,也想装一个此程序,但限于网络条件不能从网上下载。那么最简单的办法就是直接从你手机中将此apk扣出来给他安装上。 ## pm命令 第一步,找到程序的包名  借助adb shell pm命令,将安装的所有应用包名列出来: ~~~ $ adb shell pm list packages package:android package:cn.wps.moffice package:com.android.backupconfirm package:com.android.bluetooth package:com.android.browser package:com.android.calculator2 package:com.android.camera package:com.android.certinstaller package:com.android.contacts ~~~ 第二步,找到apk的位置 ~~~ $ adb shell pm path com.tence01.mm package:/data/app/com.tence01.mm-1.apk ~~~ 第三步,pull出来 ~~~ $ adb pull /data/app/com.tence01.mm-1.apk ~/apks 2407 KB/s (25567735 bytes in 10.370s) ~~~ ## root的手机会更好办 ~~~ $ adb shell shell@android:/ $ su shell@android:/ # cd data/app shell@android:/data/app # ls com.android.update.dmp-2.apk com.baidu.superservice-1.apk com.tence01.mm-1.apk com.tencent.mm-1.apk ~~~ 或者直接搜索你要的apk: ~~~ shell@android:/ # find -name *.apk ./udisk/我的下载/download/我的应用/aqgj_1365562277812.apk ~~~
';

十七:Linux下的模拟器硬件加速

最后更新于:2022-04-01 06:42:44

Intel提供了一个叫HAXM的虚拟硬件加速技术,全称为:Intel Hardware Accelerated Execution Manager.  只要你的CPU是intel的产品并且支持VT(virtualization Technology)就可以使用HAXM技术将你的模拟器的速度提升至真机的水平。目前此技术支持苹果的Mac系统和Windows系统,但Linux平台不在此列。  ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-01-01_5685d196d53d9.jpg) 要知道Android的编译环境Google首推Linux平台(64位的Ubuntu)而Mac系统排到第二位。那么在Linux平台下是如何硬件加速的呢?  那就是传说中的kvm(Kernel-based Virtual Machine),同样的,它需要硬件的支持,比如intel的VT和AMD的V,它是基于硬件的完全虚拟化。  首先要确定你的cpu满足要求,下面有几个命令可以参考: ~~~ $ egrep -c '(vmx|svm)' /proc/cpuinfo 4 ~~~ 打印的值不为0即可。 下面安装kvm: ~~~ $ sudo apt-get install qemu-kvm $ sudo adduser linc kvm $ sudo apt-get install libvirt-bin ubuntu-vm-builder bridge-utils $ sudo adduser linc libvirtd ~~~ 检验安装是否成功: ~~~ $ sudo virsh -c qemu:///system list Id Name State ---------------------------------------------------- ~~~ 一切顺利,接下来要创建x86或x86_64的模拟器,其他模拟器不支持。如下图:  ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-01-01_5685d196edf24.jpg) 用命令行启动此模拟器: ~~~ $ /opt/sdk/tools/emulator -avd Nexus5API21 -qemu -m 2047 -enable-kvm ~~~ ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-01-01_5685d19712c0e.jpg) 使用起来果然飞快,连打开网页的速度都令人惊奇。当然了,如果不用命令行启动,直接在Android Studio中启动x86_64架构的模拟器,速度也是很快,唯独arm架构的模拟器启动速度奇慢无比。话又说回来,既然有了比较不错的cpu,那么机器的其他配置一定差不了,这样的配置跑起模拟器来肯定要比原来强。 模拟器顺手了,下面就尽情享受开发的乐趣吧。  如果觉得用自带的模拟器不能够满足你的要求,那么可以使用第三方的模拟器[Genymotion](https://www.genymotion.com/#!/),网传开发者反应良好。 参考:  [http://www.mobibrw.com/?p=291](http://www.mobibrw.com/?p=291)
';

十六:getprop与dumpsys命令

最后更新于:2022-04-01 06:42:41

Android设备连接PC后,我们可以通过adb命令完成绝大多数工作。下面借助getprop、dumpsys来了解一些系统相关信息。 ## 一、getprop 此命令的原理很简单,就是从系统的各种配置文件中读取信息。那么这些文件在你用adb shell进入设备内部后很容易找到,它们是: ~~~ init.rc default.prop /system/build.prop ~~~ 此时直接使用cat命令也是可以把这些信息显示出来的。  下面列出比较常用的信息  1.获得IP ~~~ $ adb shell getprop dhcp.wlan0.ipaddress 192.168.0.107 ~~~ 2.手机名称 ~~~ $ adb shell getprop ro.product.device Ulike2 $ adb shell getprop ro.product.model U705T $ adb shell getprop ro.product.name oppo17_12035 ~~~ 3.serial number ~~~ $ adb shell getprop ro.serialno 0000012035ABCXXX ~~~ 4.屏幕密度 ~~~ $ adb shell getprop ro.sf.lcd_density 240 ~~~ 好了,只要使用adb shell getprop就可以把所有的信息都打印出来。而使用setprop命令就可以进行相对应的设置啦。 ## 二、dumpsys Android系统启动时会有大批的服务随之启动,那么我们就可以用dumpsys命令来查看每个服务的运行情况。作为一名Android开发者,我们至少要了解这些Service的存在: ~~~ Currently running services: DMAgent NvRAMAgent SurfaceFlinger accessibility account activity alarm appwidget audio audioprofile backup battery batteryinfo bluetooth bluetooth_a2dp bluetooth_profile_manager bluetooth_socket clipboard connectivity content country_detector cpuinfo device_policy devicestoragemonitor diskstats drm.drmManager dropbox entropy gfxinfo hardware input_method iphonesubinfo isms location media.audio_flinger media.audio_policy media.camera media.mdp_service media.player meminfo memory.dumper mount mtk-agps mtk-epo-client netpolicy netstats network_management notification oppo.com.IRUtils package permission phone power samplingprofiler search sensorservice simphonebook statusbar telephony.registry telephony.registry2 textservices throttle uimode usagestats usb vibrator wallpaper wifi wifip2p window ~~~ 当我们需要知道设备的分辨率时,可以使用如下命令: ~~~ $ adb shell dumpsys window displays WINDOW MANAGER DISPLAY CONTENTS (dumpsys window displays) Display: mDisplayId=0 init=720x1280 320dpi cur=720x1280 app=720x1280 rng=720x670-1280x1230 layoutNeeded=false ~~~ or ~~~ $ adb shell dumpsys window ... Display: init=540x960 base=540x960 cur=540x960 app=540x888 raw=540x960 ~~~ Refer to :  [http://blog.csdn.net/wangjia55/article/details/7446772](http://blog.csdn.net/wangjia55/article/details/7446772)  [http://blog.csdn.net/kevinx_xu/article/details/11846289](http://blog.csdn.net/kevinx_xu/article/details/11846289)  [http://blog.csdn.net/z_guijin/article/details/8203028](http://blog.csdn.net/z_guijin/article/details/8203028)
';

十五:多分辨率适配常用目录

最后更新于:2022-04-01 06:42:39

一个好的App必须要支持绝大多数市面上的设备,适配繁多的分辨率一度让我们陷入了分辨率的海洋。无论如何,这个工作是逃不掉的。 * * * 我们可以用多个layout目录对不同分辨率进行单独布局,如下: ~~~ layout-large-mdpi (1024x600) layout-large-tvdpi (800x1280) layout-large-xhdpi (1200x1920) layout-xlarge-mdpi (1280x800) layout-xlarge-xhdpi (2560x1600) ~~~ 或者直接使用下面这样: ~~~ layout-640x360 layout-800x480 ~~~ * * * 与layout对应的,有不同的drawable: ~~~ res/drawable (default) res/drawable-ldpi/ (240x320 and nearer resolution) res/drawable-mdpi/ (320x480 and nearer resolution) res/drawable-hdpi/ (480x800, 540x960 and nearer resolution) res/drawable-xhdpi/ (720x1280 - Samsung S3, Micromax Canvas HD etc) res/drawable-xxhdpi/ (1080x1920 - Samsung S4, HTC one, Nexus 5, etc) ~~~ * * * 用不同的layout毕竟工作量巨大,我们的实践是用不同的values来对应同layout中的值,目录如下: ~~~ res/values/dimens.xml(default) res/values-ldpi/dimens.xml (240x320 and nearer resolution) res/values-mdpi/dimens.xml (320x480 and nearer resolution) res/values-hdpi/dimens.xml (480x800, 540x960 and nearer resolution) res/values-xhdpi/dimens.xml (720x1280 - Samsung S3, Micromax Canvas HD, etc) res/values-xxhdpi/dimens.xml (1080x1920 - Samsung S4, HTC one, etc) res/values-large/dimens.xml (480x800) res/values-large-mdpi/dimens.xml (600x1024) res/values-sw600dp/dimens.xml (600x1024) res/values-sw720dp/dimens.xml (800x1280) res/values-xlarge-xhdpi/dimens.xml (2560x1600 - Nexus 10") res/values-large-xhdpi/dimens.xml (1200x1920 - Nexus 7"(latest)) ~~~ 有时必须要考虑到密度,如下: ~~~ ldpi 120dpi 0.75 mdpi 160dpi 1 hdpi 240dpi 1.5 xhdpi 320dpi 2 ~~~
';

十四:混淆与反编译

最后更新于:2022-04-01 06:42:37

## 混淆 **Android Studio:**  只需在build.gradle(Module:app)中的buildTypes中增加release的编译选项即可,如下: ~~~ buildTypes { release { minifyEnabled true proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } ~~~ 这个proguard-android.txt是sdk中groguard默认的文件,具体地址在:/opt/sdk/tools/proguard/proguard-android.txt  而proguard-rules.pro是AS中专用的proguard配置文件,其实只是后缀名不同,与Eclipse中的proguard-project.txt是一样的,配置规则相同,后面会详细提到。  老版本开启混淆的命令是runProguard,现在统一用minifyEnabled命令了,将其设为true就好了。  编译的时候可以使用命令: ~~~ ./gradlew assembleRelease ~~~ 或者用上一篇生成签名apk的办法都可。 **Eclipse:**  在project.properties文件中开启proguard配置(放开注释),如下: ~~~ proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt ~~~ 同样,生成签名时代码就会被混淆。 **混淆语法**  请参考${sdk.dir}/tools/proguard/proguard-android.txt文件,需要注意的是文件中虽然有了不混淆Parcelable的语句,如下: ~~~ -keep class * implements android.os.Parcelable { public static final android.os.Parcelable$Creator *; } ~~~ 但是还是要自己把继承自Parcelable的类写进来避免混淆,否则会出现BadParcelableException异常。 ~~~ -keep class com.linc.datatype.XXInfo {*;} ~~~ 为微信分享而引入的jar包,我们不需要对其进行混淆,也需要在proguard-android.txt中注明,如下: ~~~ -keep class com.tencent.** { *; } -keep class com.tencent.mm.sdk.openapi.WXMediaMessage {*;} -keep class com.tencent.mm.sdk.openapi.** implements com.tencent.mm.sdk.openapi.WXMediaMessage$IMediaObject {*;} ~~~ 为了验证是否混淆成功,可以使用下面的反编译工具验证。 * * * ## 反编译 主要用到三个工具:  dex2jar:将dex文件转为jar文件  jd-gui:反编译jar文件  AXMLPrinter2.jar:反编译xml文件 使用方法参见[《反编译apk文件,得到其源代码的方法》](http://blog.csdn.net/lincyang/article/details/6333974 "反编译") 对于Ubuntu64位,运行jd-gui或许会报错:  尝试解决如下: ~~~ $ sudo apt-get install libgtk2.0-0:i386 libnss3:i386 libcurl3-gnutls:i386 libidn11:i386 libpango1.0-0:i386 libpangox-1.0-0:i386 libpangoxft-1.0-0:i386 librtmp0:i386 libxft2:i386 ~~~ 又报错: ~~~ $ /opt/sdk/tools/jd-gui: error while loading shared libraries: libXxf86vm.so.1: cannot open shared object file: No such file or directory ~~~ 解决办法如下: ~~~ $ sudo apt-get install libgtk2.0-0:i386 libxxf86vm1:i386 libsm6:i386 lib32stdc++6 ~~~ 参考:  [http://blog.csdn.net/lincyang/article/details/6333974](http://blog.csdn.net/lincyang/article/details/6333974)
';

十三:APK签名

最后更新于:2022-04-01 06:42:34

Android程序要运行就必须有签名。平时我们用的debug版是用的debug签名,不用我们关心。当我们自己发布程序时,就需要自己的签名了。其实无论用哪个IDE开发,最终只是用了keytool和jarsigner这两个java工具来完成签名任务(在jdk的bin目录下)。其中keytool用来生成keystore(证书),jarsigner用来做签名。  **keytool用法举例如下:** ~~~ keytool -genkey -alias lincapp -keyalg RSA -keysize 1024 -keypass android -validity 365 -keystore lincapp.keystore -storepass android ~~~ **jarsigner用法举例如下:** ~~~ jarsigner -keystore lincapp.keystore -signedjar lincapp_signed.apk lincapp.apk lincapp ~~~ 其实我们直接使用IDE提供的签名功能会更方便一些。  Eclipse:  项目右键—>Android Tools—>Export Singed Application Package,简单填写信息就可以了。注意要记住密码。  ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-01-01_5685d196ac588.jpg) Android Studio:  Build—>Generate Signed APK, 过程与Eclipse类似。  ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-01-01_5685d196baad8.jpg) 参考:  [http://www.cnblogs.com/ok-lanyan/archive/2013/04/02/2995462.html](http://www.cnblogs.com/ok-lanyan/archive/2013/04/02/2995462.html)
';

十二:Android Studio导入第三方类库、jar包和so库

最后更新于:2022-04-01 06:42:32

## 第三方类库源码 将一网友的XMPP代码从ADT转到AS时,发现其使用了第三方类库,源码放在了lib下,直接在AS中Import project,第三方类库并没有自动导入进来,看来需要自己动手了。 项目的目录结构如下: ~~~ XMPP$ ls app build.gradle gradlew import-summary.txt XMPP.iml build gradle gradlew.bat local.properties settings.gradle ~~~ 将第三方源码qqEmoji-lib拷到此目录,修改settings.gradle增加此lib: ~~~ include ':app',':qqEmoji-lib' ~~~ 修改app下的build.gradle,在dependencies内加入: ~~~ dependencies { compile project(':qqEmoji-lib') ... ~~~ 在qqEmoji-lib下新建build.gradle文件,内容参考如下: ~~~ apply plugin: 'android-library' android { compileSdkVersion 19 buildToolsVersion "21.1.2" defaultConfig { minSdkVersion 8 targetSdkVersion 18 } sourceSets { main { manifest.srcFile 'AndroidManifest.xml' java.srcDirs = ['src'] resources.srcDirs = ['src'] aidl.srcDirs = ['src'] renderscript.srcDirs = ['src'] res.srcDirs = ['res'] } } } dependencies { compile 'com.android.support:appcompat-v7:19.1.0' //compile 'com.android.support:support-v4:19.1.0' } ~~~ gradle的配置内容情参考最后第二个链接。 此时项目的结构见下图:  ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-01-01_5685d1967d908.jpg) 此时编译,通过,导入成功! ## 第三方类库jar包 这就简单多了,直接将jar包拷贝到app/libs下,然后在app下的build.gradle中添加此jar的依赖。如下: ~~~ dependencies { compile 'com.android.support:support-v4:19.1.0' compile files('libs/libammsdk.jar') compile files('libs/universal-image-loader-1.8.6-with-sources.jar') compile files('libs/YoumiSdk_v5.00_2015-01-08.jar') } ~~~ ## 第三方so库 通常来说,我们调用第三方的so库是不需要额外工作的,只需将其放入指定目录,然后在java文件中load即可。  比如我引用之前[《第一个NDK程序》](http://blog.csdn.net/lincyang/article/details/6705143)中编译出的libFirstLib.so,将其放到app/src/main/jniLibs/armeabi/下,在源码中引用: ~~~ static { System.loadLibrary("FirstLib"); } ~~~ 即可。程序运行如下图:  ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-01-01_5685d1968fcb8.jpg) 参考:  [http://www.cnblogs.com/neozhu/p/3458759.html](http://www.cnblogs.com/neozhu/p/3458759.html)  [http://www.open-open.com/lib/view/open1415793464648.html](http://www.open-open.com/lib/view/open1415793464648.html)
';

十一:Android Studio和Gradle

最后更新于:2022-04-01 06:42:30

经过两个多月的AS体验,我认为是时候将Android的开发环境迁移到AS上了。目前最新版本是1.0.2(大年30当天升级到1.1.0),除了UI控件拖拽偶尔崩溃的问题(Ubuntu),其他功能用来还是十分流畅和高效。打动我的有如下几个特色: * 智能感知体验特好,堪比VS * 布局预览,手写布局后预览页面即时显示,便于布局调整和优化 * 编辑速度飞快流畅,毫无eclipse的卡顿 * 布局或源码中有图标和颜色的预览,十分直观 * 调试时体验极佳 * 集成了Terminal,喜欢命令行操作的伙伴不用额外启动终端了。 总之一句话,就是用起来特别爽! Android Studio 源于[IntelliJ IDEA](http://blog.csdn.net/lincyang/article/details/www.jetbrains.com/idea/ "IntelliJ IDEA")的社区版,构建工具是[Gradle](http://www.gradle.org/ "Gradle")这个下一代的构建工具,再加上Google为Android定制的一些工具,那么AS必然会成为Android开发工具的经典款。 ## Android Studio的安装 Adnroid官网上不去,我们可以到其他[网站下载](http://www.android-studio.org/index.php/88-download/ "AS download")AS,然后再升级到1.0.2。  AS对系统的要求不低,不过我这i7处理器+8G内存还是毫无压力啊。 Windows ~~~ Microsoft® Windows® 8/7/Vista/2003 (32 or 64-bit) 2 GB RAM minimum, 4 GB RAM recommended 400 MB hard disk space At least 1 GB for Android SDK, emulator system images, and caches 1280 x 800 minimum screen resolution Java Development Kit (JDK) 7 Optional for accelerated emulator: Intel® processor with support for Intel® VT-x, Intel® EM64T (Intel® 64), and Execute Disable (XD) Bit functionality ~~~ Mac OS X ~~~ Mac® OS X® 10.8.5 or higher, up to 10.9 (Mavericks) 2 GB RAM minimum, 4 GB RAM recommended 400 MB hard disk space At least 1 GB for Android SDK, emulator system images, and caches 1280 x 800 minimum screen resolution Java Runtime Environment (JRE) 6 Java Development Kit (JDK) 7 Optional for accelerated emulator: Intel® processor with support for Intel® VT-x, Intel® EM64T (Intel® 64), and Execute Disable (XD) Bit functionality ~~~ On Mac OS, run Android Studio with Java Runtime Environment (JRE) 6 for optimized font rendering. You can then configure your project to use Java Development Kit (JDK) 6 or JDK 7.  Linux ~~~ GNOME or KDE desktop GNU C Library (glibc) 2.11 or later 2 GB RAM minimum, 4 GB RAM recommended 400 MB hard disk space At least 1 GB for Android SDK, emulator system images, and caches 1280 x 800 minimum screen resolution Oracle® Java Development Kit (JDK) 7 ~~~ 下载后将其解压到你指定的路径。我在Ubuntu下工作,就直接将其放到/opt下了。解压后内容如下: ~~~ android-studio3$ ls bin build.txt gradle Install-Linux-tar.txt lib license LICENSE.txt NOTICE.txt plugins ~~~ 值得一说的是,gradle就在这里,一会儿我们可以直接用gradle去做简单的编译工作。首先,我们要执行bin下的studio.sh启动AS,就像Install-Linux-tar.txt中说的,我们可以将这个bin目录放到系统变量中,以后启动AS只需输入studio.sh即可。比如我在.bashrc中添加如下内容: ~~~ export PATH="$PATH:/opt/android-studio3/bin" export PATH="$PATH:/opt/android-studio3/gradle/gradle-2.2.1/bin" ~~~ 首次启动会检测sdk并升级到最新,如果不用代理,这一步我们无法通过,AS就不会启动成功。解决办法就是将自己的Adnroid SDK Manager配好代理到国内的镜像,请参照[《Android实战技巧之九:最新Android开发环境(Eclipse+ADT+Android 5.0) 》](http://blog.csdn.net/lincyang/article/details/42029257 "eclipse adt"),顺利通过升级后,AS会成功启动。后面的事情就简单了,界面清晰明了,就像你用其他IDE一样,上手很快。但是项目结果变化很大(与Eclipse相比),快捷键变化也很大,都要适应一段时间。下载一份[Keymap](https://www.jetbrains.com/idea/docs/IntelliJIDEA_ReferenceCard.pdf "keymap")打印出来,用到了就看看,会很快进入状态。 Tips:  打开项目后修改sdk和jdk路径,设置如下:File –>Other Settings –>Default project Structure  如果你喜欢黑色风格的主题,那么切换到吸血鬼Darcula主题是个不错的选择:File–>Settings–>Appearance–>Theme ## Gradle 项目中有两个build.gradle文件,如下: ~~~ $ find -name build.gradle ./app/build.gradle ./build.gradle ~~~ 项目根目录下的build.gradle只做了比较commen的配置,app下的build.gradle是针对此app更细致的配置: ~~~ apply plugin: 'com.android.application' android { compileSdkVersion 21 buildToolsVersion "21.1.2" defaultConfig { applicationId "com.linc.arrowfall" minSdkVersion 17 targetSdkVersion 21 versionCode 1 versionName "1.0" } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } } dependencies { compile fileTree(dir: 'libs', include: ['*.jar']) compile 'com.android.support:appcompat-v7:21.0.3' } ~~~ Make Project(Ctrl+F9)时,右下角Gradle Console就会打印如下信息: ~~~ Executing tasks: [:app:compileDebugSources] Configuration on demand is an incubating feature. :app:preBuild :app:preDebugBuild :app:checkDebugManifest :app:preReleaseBuild :app:prepareComAndroidSupportAppcompatV72103Library UP-TO-DATE :app:prepareComAndroidSupportSupportV42103Library UP-TO-DATE :app:prepareDebugDependencies :app:compileDebugAidl UP-TO-DATE :app:compileDebugRenderscript UP-TO-DATE :app:generateDebugBuildConfig UP-TO-DATE :app:generateDebugAssets UP-TO-DATE :app:mergeDebugAssets UP-TO-DATE :app:generateDebugResValues UP-TO-DATE :app:generateDebugResources UP-TO-DATE :app:mergeDebugResources UP-TO-DATE :app:processDebugManifest UP-TO-DATE :app:processDebugResources UP-TO-DATE :app:generateDebugSources UP-TO-DATE :app:compileDebugJava :app:compileDebugNdk :app:compileDebugSources BUILD SUCCESSFUL Total time: 10.23 secs ~~~ 先放下AS中的Gradle,我们先从Gradle命令行说起。刚刚提到AS中自带的Gradle路径在android-studio3/gradle/gradle-2.2.1/bin下,将其加入到环境变量(如上),这样在如何位置都可以使用gradle工具了。下面来作一下gradle最简单的使用: ~~~ $ gradle -v ------------------------------------------------------------ Gradle 2.2.1 ------------------------------------------------------------ Build time: 2014-11-24 09:45:35 UTC Build number: none Revision: 6fcb59c06f43a4e6b1bcb401f7686a8601a1fb4a Groovy: 2.3.6 Ant: Apache Ant(TM) version 1.9.3 compiled on December 23 2013 JVM: 1.7.0_71 (Oracle Corporation 24.71-b01) OS: Linux 3.13.0-45-generic amd64 ~~~ gradle是正常工作了,下面来个hello world吧。新建一个build.gradle文件,加入如下代码: ~~~ task helloworld << { println 'hello world' } ~~~ 这个task只输出一条log,执行如下命令: ~~~ $ gradle -q helloworld hello world ~~~ 参数-q只是打印log,这个task也就是此功能而已。  在此目录下执行gradle –gui,调出图形界面的gradle,看看helloworld的其他信息。 **编译Java程序**  现在尝试编译一个最简单的Java程序,在刚刚的目录下新建目录和文件如下: ~~~ $ mkdir -p src/main/java/com/linc; vim src/main/java/com/linc/HelloWorld.java ~~~ 代码内如如下: ~~~ package com.linc; public class HelloWorld { public static void main(String args[]) { System.out.println("hello, world"); } } ~~~ build.gradle文件与src目录平级,内如只有一行: ~~~ apply plugin: 'java' ~~~ 此时运行**gradle build**: ~~~ $ gradle build :compileJava :processResources UP-TO-DATE :classes :jar :assemble :compileTestJava UP-TO-DATE :processTestResources UP-TO-DATE :testClasses UP-TO-DATE :test UP-TO-DATE :check UP-TO-DATE :build BUILD SUCCESSFUL Total time: 2.206 secs ~~~ 此时的目录结构变为如下所示: ~~~ $ tree -L 6 . ├── build │ ├── classes │ │ └── main │ │ └── com │ │ └── linc │ │ └── HelloWorld.class │ ├── dependency-cache │ ├── libs │ │ └── helloworld.jar │ └── tmp │ ├── compileJava │ └── jar │ └── MANIFEST.MF ├── HelloWorld.java └── src └── main └── java └── com └── linc └── HelloWorld.java ~~~ 运行编译好的java程序: ~~~ $ java -cp build/classes/main/ com.linc.HelloWorld hello, world ~~~ Gradle的初体验就到这里,更复杂的构建任务还在后头。有了AS这个强大的工具,Android开发会变得越来越有乐趣! * * * 参考: [http://www.gradle.org/documentation](http://www.gradle.org/documentation)  [http://www.android-studio.org/index.php/88-download/](http://www.android-studio.org/index.php/88-download/)
';

十:获得屏幕物理尺寸、密度及分辨率

最后更新于:2022-04-01 06:42:28

大家帮忙喽! 博主参加2014博客之星活动,大家帮忙投票啦![猛击这里](http://vote.blog.csdn.net/blogstar2014/selection?username=lincyang#content)! 通过程序去了解硬件情况是一件十分有意思的事情。很早我就研究在WM6.5上获得屏幕物理尺寸,但一直没有成功。后来又想要在Android上有所突破,不过在今天之前得到的尺寸都不准确。虽然很多人认为没必要这么较真,因为貌似很多情况下用不到。不过我就当这是一件很有挑战性的事,一定要做到。对,就是这么任性。 源码中android.view包下的Display类提供了很多方法供程序员获得显示相关的信息,通过此类让我们开启了解设备屏幕之旅吧。 #### 一、分辨率 需要注意的原来经常使用的getHeight()与getWidth()已经不推荐使用了,建议使用getSize()来替代。 此方法原型如下: ~~~ public void getSize(Point outSize) {       synchronized (this) {           updateDisplayInfoLocked();           mDisplayInfo.getAppMetrics(mTempMetrics, mDisplayAdjustments);           outSize.x = mTempMetrics.widthPixels;           outSize.y = mTempMetrics.heightPixels;       }   }   ~~~ 参数是一个返回参数,用以返回分辨率的Point,这个Point也比较简单,我们只需要关注x和y这两个成员就可以了。 用法如下: ~~~ private void getDisplayInfomation() {       Point point = new Point();       getWindowManager().getDefaultDisplay().getSize(point);       Log.d(TAG,"the screen size is "+point.toString());   }   ~~~ 结果如下: ` D/MainActivity﹕ the screen size is Point(800, 1280)  ` 此外Display又提供了一个getRealSize方法,原型如下: ~~~ public void getRealSize(Point outSize) {       synchronized (this) {           updateDisplayInfoLocked();           outSize.x = mDisplayInfo.logicalWidth;           outSize.y = mDisplayInfo.logicalHeight;       }   }   ~~~ 从两个方法的实现上看是有区别的,但是在通常情况下二者的返回值相同。那么差异究竟在哪里,下面做一些实验来验证一下。 首先,我将Acitvity设置不同的theme,比如: ~~~ android:theme="@android:style/Theme.Black.NoTitleBar.Fullscreen"   android:theme="@android:style/Theme.NoTitleBar.Fullscreen"   ~~~ 结果还是相同的。 接下来将我的Activity父类变成ActionBarActivity,如下: public class MainActivity extends ActionBarActivity 期望ActionBar会占用一些屏幕,并在程序中动态设置Listview的Item中的图片大小。在机缘巧合之下, 结果验证了在这种情况下,getSize返回的结果变了。 代码如下: ~~~ private void getDisplayInfomation() {       Point point = new Point();       getWindowManager().getDefaultDisplay().getSize(point);       Log.d(TAG,"the screen size is "+point.toString());       getWindowManager().getDefaultDisplay().getRealSize(point);       Log.d(TAG,"the screen real size is "+point.toString());   }   ~~~ Log如下: ~~~ D/MainActivity﹕ the screen size is Point(800, 1202)   D/MainActivity﹕ the screen real size is Point(800, 1280)   ~~~ 如果你不能够轻易复现也不用急,保险起见,为了得到相对正确的信息还是使用getRealSize()吧。 #### 二、屏幕尺寸 设备的物理屏幕尺寸。与几年前不同,目前的手机屏幕已经大到一只手握不下了。标配早已经到了5寸屏时代。 所谓屏幕尺寸指的是屏幕对角线的长度,单位是英寸。 然而不同的屏幕尺寸是可以采用相同的分辨率的,而它们之间的区别在与密度(density)不同。 下面先介绍一下密度的概念,DPI、PPI,最后讲解一下如何根据获得的Display信息去求出屏幕尺寸。这是一个困扰我很久的问题了。 #### 三、屏幕密度 屏幕密度与DPI这个概念紧密相连,DPI全拼是dots-per-inch,即每英寸的点数。也就是说,密度越大,每英寸内容纳的点数就越多。 android.util包下有个DisplayMetrics类可以获得密度相关的信息。 最重要的是densityDpi这个成员,它有如下几个常用值: ~~~ DENSITY_LOW = 120   DENSITY_MEDIUM = 160  //默认值   DENSITY_TV = 213      //TV专用   DENSITY_HIGH = 240   DENSITY_XHIGH = 320   DENSITY_400 = 400   DENSITY_XXHIGH = 480   DENSITY_XXXHIGH = 640   ~~~ 举例如下: ~~~ private void getDensity() {       DisplayMetrics displayMetrics = getResources().getDisplayMetrics();       Log.d(TAG,"Density is "+displayMetrics.density+" densityDpi is "+displayMetrics.densityDpi+" height: "+displayMetrics.heightPixels+           " width: "+displayMetrics.widthPixels);   }   ~~~ Log如下: ~~~ the screen size is Point(1600, 2438)   the screen real size is Point(1600, 2560)   Density is 2.0 densityDpi is 320 height: 2438 width: 1600   ~~~ 有了这些信息,我们是不是就可以计算屏幕尺寸了呢? 首先求得对角线长,单位为像素。 然后用其除以密度(densityDpi)就得出对角线的长度了。 代码如下: ~~~ private void getScreenSizeOfDevice() {       DisplayMetrics dm = getResources().getDisplayMetrics();       int width=dm.widthPixels;       int height=dm.heightPixels;       double x = Math.pow(width,2);       double y = Math.pow(height,2);       double diagonal = Math.sqrt(x+y);          int dens=dm.densityDpi;       double screenInches = diagonal/(double)dens;       Log.d(TAG,"The screenInches "+screenInches);   }   ~~~ Log如下: ~~~ 01-13 16:35:03.026  16601-16601/com.linc.listviewanimation D/MainActivity﹕ the screen size is Point(1600, 2438)   01-13 16:35:03.026  16601-16601/com.linc.listviewanimation D/MainActivity﹕ the screen real size is Point(1600, 2560)   01-13 16:35:03.026  16601-16601/com.linc.listviewanimation D/MainActivity﹕ Density is 2.0 densityDpi is 320 height: 2438 width: 1600 xdpi 338.666 ydpi 338.666   01-13 16:35:03.026  16601-16601/com.linc.listviewanimation D/MainActivity﹕ The screenInches 9.112922229586951   ~~~ 如Log所见,使用heightPixels得出的值是2483而不是正确的2560.从而使结果9.11反倒跟真实屏幕尺寸很接近。下面用正确的height再算一遍。 ~~~ 01-13 16:39:05.476  17249-17249/com.linc.listviewanimation D/MainActivity﹕ the screen size is Point(1600, 2560)   01-13 16:39:05.476  17249-17249/com.linc.listviewanimation D/MainActivity﹕ the screen real size is Point(1600, 2560)   01-13 16:39:05.476  17249-17249/com.linc.listviewanimation D/MainActivity﹕ Density is 2.0 densityDpi is 320 height: 2560 width: 1600 xdpi 338.666 ydpi 338.666   01-13 16:39:05.476  17249-17249/com.linc.listviewanimation D/MainActivity﹕ The screenInches 9.433981132056605   ~~~ 结果是9.43英寸,而真实值是8.91.如果再换一个设备,那么值差的更多。说明上面的计算是错误的。 那么错在哪里呢?densityDpi是每英寸的点数(dots-per-inch)是打印机常用单位(因而也被称为打印分辨率),而不是每英寸的像素数。下面引出PPI这个概念。 #### 四、PPI Pixels per inch,这才是我要的每英寸的像素数(也被称为图像的采样率)。有了这个值,那么根据上面的公式就可以求导出屏幕的物理尺寸了。 还好DisplayMetrics有两个成员是xdpi和ydpi,对其描述是: ` //The exact physical pixels per inch of the screen in the X/Y dimension.  ` 屏幕X/Y轴上真正的物理PPI。 Yes!Got it! 为了保证获得正确的分辨率,我还是使用getRealSize去获得屏幕宽和高像素。所以,经过修改,代码如下: ~~~ private void getScreenSizeOfDevice2() {       Point point = new Point();       getWindowManager().getDefaultDisplay().getRealSize(point);       DisplayMetrics dm = getResources().getDisplayMetrics();       double x = Math.pow(point.x/ dm.xdpi, 2);       double y = Math.pow(point.y / dm.ydpi, 2);       double screenInches = Math.sqrt(x + y);       Log.d(TAG, "Screen inches : " + screenInches);   }   ~~~ Log is as follows: ` 01-13 16:58:50.142  17249-17249/com.linc.listviewanimation D/MainActivity﹕ Screen inches : 8.914015757534717  ` #### 五、DIP 注意不要与上面的DPI混淆,这个DIP是Density Independent Pixel,直译为密度无关的像素。 我们在布局文件中使用的dp/dip就是它。官方推荐使用dp是因为它会根据你设备的密度算出对应的像素。 公式为:pixel = dip*density 需要注意的是,我们在Java代码中对控件设置宽高是不可以设置单位的,而其自带的单位是像素。所以如果动态修改控件大小时, 我们的任务就来了,那就是将像素转换为dp。 实例代码如下: ~~~ //pixel = dip*density;   private int convertDpToPixel(int dp) {       DisplayMetrics displayMetrics = mContext.getResources().getDisplayMetrics();       return (int)(dp*displayMetrics.density);   }      private int convertPixelToDp(int pixel) {       DisplayMetrics displayMetrics = mContext.getResources().getDisplayMetrics();       return (int)(pixel/displayMetrics.density);   }    ~~~ 参考: http://stackoverflow.com/questions/19155559/how-to-get-android-device-screen-size
';

九:最新Android开发环境(Eclipse+ADT+Android 5.0)

最后更新于:2022-04-01 06:42:25

#### 一、一切由运行时错误引起 dalvikvm Could not find class '引用包.类', referenced from method...  其实在编译时也会见到如下错误:        [dx]         [dx] trouble processing:        [dx] bad class file magic (cafebabe) or version (0033.0000)        [dx] ...while parsing com/novell/sasl/client/DigestChallenge.class        [dx] ...while processing com/novell/sasl/client/DigestChallenge.class #### 二、尝试 1.使用JDK7 有推荐使用JDK7来解决类似问题的帖子,可是我照做并没有解决问题。 2.升级build-tools 先来说说我的开发环境吧。 那是在2013年末配置的环境,ADT大版本号是22,tools大版本号也是22,Plantform-tools已经是最新的21,build-tools是18.1.1。 经过同事的实践,问题应该归咎于build-tools版本低的缘故。 #### 三、最新开发环境的搭建(Eclipse & ADT&SDK) ##### 1.各tools的升级 这里我们要重新配置一下代理,去neusoft.edu.cn镜像网站中下载最新的工具和SDK。 启动 Android SDK Manager(命令行中直接输入android),Tools--->Options...,弹出Android SDK Manager - Settings窗口;在HTTP Proxy Server和HTTP Proxy Port输入框内填入mirrors.neusoft.edu.cn(注意没有http等前缀)和80,并且选中Force https://... sources to be fetched using http://...复选框。 再选择Packages--->Reload。 此时会发现我们顺利的取到Packages了,那么我们尽情下载吧。除了最新的Android 5.0.1还没有提供,其他的一应俱全了。 tools更新到最新是24.0.2, build-tools我选择了19.1、20和21.1.2,分别对应API19(4.4.2)、API20(L)和API21(5.0). Android 5.0全部选择。 ##### 2.ADT的升级 由于更tools升级到最新,那么ADT22已经过期了,需要使用23及以上版本的ADT。找到好心人上传的23.03,安装时发现eclipse版本不支持最新的ADT(我使用的Juno),好吧,既然这样就都来新的吧。 ##### 3.eclipse luna 最新的版本是luna,还是130多兆。解压后直接启动。 ##### 4.再次安装ADT 这时在Help--->Install New Software --->Add, 选择ADT23.03 ZIP包,将“Contact all update sites during install to find required software.”勾选掉。 继续完成安装。 一切准备就绪,将之前有问题的项目引入进来,编译,出现内存方面的问题。 #### 四、dex的问题 出现了两个问题: 1.unable to execute dex:java heap space 2.Conversion to Dalvik format failed: Unable to execute dex: GC overhead limit exceeded  配置eclipse.ini,将Xms40m和Xmx512m修改成126m和1024m,这个值要根据自己机器配置调整,只要运行良好就ok。 ~~~ $ cat eclipse.ini    -startup   plugins/org.eclipse.equinox.launcher_1.3.0.v20140415-2008.jar   --launcher.library   plugins/org.eclipse.equinox.launcher.gtk.linux.x86_64_1.1.200.v20140603-1326   -product   org.eclipse.epp.package.java.product   --launcher.defaultAction   openFile   -showsplash   org.eclipse.platform   --launcher.XXMaxPermSize   256m   --launcher.defaultAction   openFile   --launcher.appendVmargs   -vmargs   -Dosgi.requiredJavaVersion=1.6   -XX:MaxPermSize=256m   -Xms126m   -Xmx1028m   ~~~ 重启、clean项目,编译,通过!运行,正常!至此我的最新Android开发环境搭建完成。 #### 五、结论 时刻保持与时俱进的心态,稳定的新工具对我们的工作益处多多。
';

八:Ubuntu下切换JDK版本

最后更新于:2022-04-01 06:42:23

Android L之后推荐使用JDK7编译程序,这是自然发展规律,就像是4年前编译Android 1.6需要使用JDK5一样。 多版本JDK是可以共存的,只需要使用update-alternatives工具就可以随时将它们切换。下面描述安装openjdk和oracle jdk(对不住了sun)以及切换版本的过程。 #### 一、安装openjdk7 ~~~ $ sudo apt-get update   $ sudo apt-get install openjdk-7-jdk   ~~~ 安装完成后找到其安装路径: ~~~ $ dpkg -L openjdk-7-jdk   /.   /usr   /usr/lib   /usr/lib/jvm   /usr/lib/jvm/java-7-openjdk-amd64      $ ls /usr/lib/jvm/java-7-openjdk-amd64/   ASSEMBLY_EXCEPTION  bin  docs  include  jre  lib  man  src.zip  THIRD_PARTY_README   ~~~ #### 二、切换java版本 ~~~ $ sudo update-alternatives --config java   There are 2 choices for the alternative java (providing /usr/bin/java).        Selection    Path                                            Priority   Status   ------------------------------------------------------------   * 0            /usr/lib/jvm/java-6-openjdk-amd64/jre/bin/java   1061      auto mode     1            /usr/lib/jvm/java-6-openjdk-amd64/jre/bin/java   1061      manual mode     2            /usr/lib/jvm/java-7-openjdk-amd64/jre/bin/java   1051      manual mode      Press enter to keep the current choice[*], or type selection number: 2   update-alternatives: using /usr/lib/jvm/java-7-openjdk-amd64/jre/bin/java to provide /usr/bin/java (java) in manual mode.      $ java -version   java version "1.7.0_65"   OpenJDK Runtime Environment (IcedTea 2.5.3) (7u71-2.5.3-0ubuntu0.12.04.1)   ~~~ #### 三、安装Oracle jdk 使用Android Studio做开发,启动IDE就提示: OpenJDK shows intermittent performance and UI issues. We recommend using the Oracle JRE/JDK. 看来还是要安装Oracle的JDK了,因为ubuntu软件源中没有此JDK,所以不能像安装openjdk一样使用apt-get工具。 那么我们还是要去[官网下载jdk7](http://www.oracle.com/technetwork/java/javase/downloads/jdk7-downloads-1880260.html)。 按照以往的惯例,我将这些软件放在/opt目录下。将JDK解压到新建目录jdk下。 用update-alternatives工具来添加java可选配置项(这是一个dpkg的一个实用工具)。 ~~~ $ sudo update-alternatives --install /usr/bin/java java /opt/jdk/jdk1.7.0_71/bin/java 700   $ sudo update-alternatives --install /usr/bin/javac javac /opt/jdk/jdk1.7.0_71/bin/javac 700   $ sudo update-alternatives --install /usr/bin/jar jar /opt/jdk/jdk1.7.0_71/bin/jar 700   ~~~ 700是优先级数值,我这里随便使用了一个数。 查看一下我们的config: ~~~ $ sudo update-alternatives --config java   There are 3 choices for the alternative java (providing /usr/bin/java).        Selection    Path                                            Priority   Status   ------------------------------------------------------------     0            /usr/lib/jvm/java-6-openjdk-amd64/jre/bin/java   1061      auto mode     1            /opt/jdk/jdk1.7.0_71/bin/java                    700       manual mode     2            /usr/lib/jvm/java-6-openjdk-amd64/jre/bin/java   1061      manual mode   * 3            /usr/lib/jvm/java-7-openjdk-amd64/jre/bin/java   1051      manual mode      Press enter to keep the current choice[*], or type selection number: 1   update-alternatives: using /opt/jdk/jdk1.7.0_71/bin/java to provide /usr/bin/java (java) in manual mode   ~~~ 验证是否切换成功: ~~~ $ java -version   java version "1.7.0_71"   Java(TM) SE Runtime Environment (build 1.7.0_71-b14)   Java HotSpot(TM) 64-Bit Server VM (build 24.71-b01, mixed mode)   ~~~ 同样的,当我们需要切换到低版本时选择2或者安装oracle jdk6并将其纳入管理。这样就可以不用通过手动修改环境的方式来灵活切换JDK的版本了。
';