深入Android应用开发_核心技术解析与最佳实践
感谢作者的奉献,以下是我读了这本书的笔记,也只是摘录对我有用的片段,分享之:
一.深入解析android核心组件和应用框架
1.listView下空列表的显示问题.重写适配器的isEmpty(),或HoneyComb中主要是通过ListFragment的setEmptyText();
2.InputMethodService ,一种输入法在界面上由3部分构成,即软输入视图(Soft InputView)、候选视图(Candidates View)和全屏模式(Fullscreen Mode).
3.IntentService,在gallery3d应用中,CacheService即是IntentService的一个示例.
4.绑定服务的Android组件在销毁前应解除绑定,否则会造成内存泄漏.
5.pendingIntent,
6.(应用框架解析,service框架)基于AIDL的远程服务(在J2EE中,采用RMI的方式, 可以通过序列化传递对象. 在Android中, 则采用AIDL的方式. )
7.(应用框架解析,service框架)基于Messenger的远程服务(http://blog.csdn.net/luoshengyang/article/details/6817933);
8.(应用框架解析,activity管理机制),acitivity栈和Task的定义和区别,以及android:taskAffinity属性
9.对话框框架,按照Android的规则,每个对话框对应一个对话框ID.
二.Android资源框架详解
1.sp和dip有相似的含义,与屏幕上每平方英寸含多少像素无关.
2.特殊标签:viewStub/requestFocus/merge/include
3.android支持XLIFF(XML Localization Interchange File Format)和通配符(在一个字符串标签中android仅支持一个通配符).
4.切换语言的实现:
Resources resources = getResources();
Configuration config = resources.getConfiguration();
DisplayMetrics dm = resources.getDisplayMetrics();
config. locale = Locale.SIMPLIFIED_CHINESE;
resources.updateConfiguration(config, dm);
通过类似的设置,开发者也可以切换屏幕密度、MCC、MNC、屏幕方向等,当然部分设置可能需要高级别的权限。
5.string资源文件中,如果该字符串资源不必本地化,则需要设置其translatable属性为fasle;
6.系统资源在frameworks\base\core\res\res\values\目录下的public.xml中定义.
7.android允许属性支持多种属性格式。
8.MenuInflater在加载XML资源文件时采用的解析器为XmlPullParser.处于性能方面的考虑,目前MenuInflater尚不支持加载未经处理的XML资源文件.
9.如果希望显示菜单的内容,onPrepareOptionsMenu()方法必须返回true,否则返回false.
10.子菜单不支持图标和二级子菜单.
11.PopupMenu.当菜单被销毁时,通过PopupMenu.OnDismissListener可以监听到菜单被销毁的消息.
12.asset,断言中限制文件大小为1MB.同样在res和raw下的资源文件也有这样的限制.在android中,断言的管理是通过AssetManager进行的.
13.在启动其他应用嵌,需要在zygote进程中奖先加载的图片资源定义在arrays.xml中的preloaded_drawables数组中,将颜色资源定义在arrays.xml中的preloaded_color_state_lists数组汇总,状态栏加载的顺序定义在arrays.xml中的status_bar_icon_order数组中.
第三章:Android UI控件精要
- 为了使TextView滚动起来,还需要做如下设置:tv.setMovementMethod(scrollingMovementMethod.getInstance());
-
WebView webView = new WebView (this );webView.setWebViewClient( new WebViewClient(){@Overridepublic boolean shouldOverrideUrlLoading(WebView view, String url) {//返回true,表示驻留应用处理 url,返回false,表示WebView处理 urlreturn super .shouldOverrideUrlLoading(view, url);}});
- SlidingDrawer由手柄(handle)和内容(content)两个子视图组成,其父控件必须是FrameLayout或RelativeLayout.
- ScrollView提供了一种在有限的屏幕上展现更多信息的方式,其意图是作为设计模式汇总装饰着模式的装饰者出现,仅支持垂直滚动.如果想为水品滚动滑块,可以使用HorizontalScrollView,另外注意,在Android3.2中,用ScrollView冯胡子那个WebView会失效.
- EditText,如果希望在获得焦点时选择内容,可以配置android:selectAllOnFocus="true",更灵活的光标选择可以通过setSelection()方法进行.
- AutoCompleteTextView不支持数据源的更新.其职能实现单选功能,如果希望实现多选,则需使用MultiAutoCompleteTextView.
- ToggleButton可以记忆选择状态.
- RatingBar常用在评价场景中,用于给出评级.
- RemoterViews
- 在android中,UI桌面不见目前仅支持App Widgets、Live folders两种形式。这两种形式都是跨进程的远程视图。
- 对于listView 和android还支持透视图和尾视图。
- 上、下午的表示在不同的语言中有不同的表示方法。获得一个本地化的上、下午表述的DateUtils方法如下:public static String getAMPMString(int ampm);返回星期的本地化表述的DateUtils方法如下:public static String getMonthString(int month,int abbrev);其中,month的值可为Calendar.JANUARY,abbrev的值可为DateUTils.LENTH_LONG,DateUtils.LENTH_MEDIUM等。
- Fragment还支持事物处理的概念,可以依次处理多个操作。
- ListFragment,在设置适配器时,必须采用ListFragment.setListAdapter()方法,在ListView中常用的ListView.setAdapter()方法会太哦过一些重要的初始化工作(如适配器的getView()方法)而导致程序异常。
第四章:深入解析Android数据存储与管理
- 对于assets目录下的静态数据,存在单个文件最大支持1MB的局限。
- android开始支持在SD卡上的应用私有目录,在Froyo版本后,通过getExternalFilesDir()可以获得具体路径。SD上的应用私有目录和内部存储一样,在应用卸载时,将会被清空并删除。在使用SD卡目录时,需注意SD卡是否挂载,可通过Environment.getExternalStorageState()方法进行判断。如果返回值为Environment.MEDIA_MOUNTED,表示SD卡处于挂载状态,可以放心使用。
- 开源版本的SQLite3没有对数据进行加密保护,因此存储敏感数据是个十分头疼的问题。好在SQLite3在框架层提供了加密算法的接口,有需要的开发者可以自行添加相关加密算法。
- 在android里,原生方法处理SQLite的方式:采用raw方法来操作SQLite数据库,可以减少代码和提高处理效率,但必须做好SQL语句异常处理。
- HashSet还支持从资源文件中家在数组。HashSet不支持线程安全,其集合项可以为null。
- FileInputStream和FileOutputStream专门用于文件的读写,以字节为单位进行流处理,与编码无关,所以不会存在乱码问题。FileReader和FileWriter则以字符为单位进行流处理。
- byte数组的最大存储容量为64MB,当一个文件超过64MB时,需要分多个流进行读写。另外,当在两个不同的线程间进行文件读写时,同步会变得比较困难,这时可以考虑运用管道,即PipedInputStream、PipedOutputStream等。当程序对读写的速率要求较高时,FileChannel会是比FileInputStream/FileOutputStream更好的选择。FileChannel是线程安全的。
- 当需要对内容进行分析时,就需用到FileReader和FileWriter,它们经常和BufferedReader、BufferedWriter组合使用。
- 考虑到硬盘存取的速度远低于内存中数据的存取速度,为了减小对硬盘的存取,在内存汇总建立了缓冲区(默认为512字节),这样可以提高存取的效率,这就是BufferedInputStream、BufferedOutputStream优于InputStream、OutputStream之处。
- StringReader和StringWriter是专门针对字符串设计的。StringReader多用于XML的解析的场景。
- 除了刘类型的I/O管理和文件管理外,Android还提供了MemoryFile和FileChannel进行I/O管理.MemoryFile是对Ashmem驱动的封装器,而Ashmem本职上是基于共享内存的,在dev目录下对应的设备为\dev\ashmem.相比于传统的内存分配机制,如malloc,Ashmem的好处是提供了辅助内核内存回收算法的pin\unpin机制,使通过MemoryFile进行I/O操作可以在很大程度上提高效率.
- FileChannel是MMAP的一个上层封装.利用FileChannel可以更高效的读写文件,而且FileChannel是线程安全的.
- MemoryFile,创建一个MemoryFile对象即可在共享内存上分配一块区域.通过MemoryFile对象读写数据的方式有流和字节两种.
- FileChannel.MapMode支持3种类型的映射模式,即READ_ONLY、PRIVATE和READ_WRITE。
- 目前,android在Honeycomb中引入了JsonWriter和JsonReader两个类,极大的简化了操作。
第五章:摄入解析Android通信机制
- Intent通信
-
- Intent通信实际上是对open-Binder通信机制的封装。在linux中,存在D-Bus和open-Binder两种进程间通信机制,其中D-Bus应用的更加广泛.但在Android中,采用的是open-Binder通信机制,D-Bus旨在开源BT协议栈BlueZ中得到了应用.
- Parcelable接口:是android特定的序列化接口,他比Serializable接口更有效,还可以避免Serializable接口存在的一些问题.Parcelable接口通常用于Binder和AIDL场景中.
- UI事件处理
-
- 在框架层,WindowManagerService是事件处理的神经中枢,它控制着事件如何进一步向UI层派发.
- 在android中,手势识别是通过GestureDetector实现的.
- android 的多点触控在本质上需要LCD驱动和程序本身设计商的支持.模拟器无法实现多点触控的测试.
- 当案件事件发生后,Linux驱动会将补货到的输入时间传递给EventHub.cpp.EventHub是Linux驱动和android框架层的接口.
- TimerTask会阻塞主线程,对资源的消耗比另起一个线程要好.对于比较耗时的计算,不建议放在TimerTask中运行.
第六章:深入解析android多线程编程
- Handler的removeCallbacks()方法可以移除代运行的线程,通过postAtTime()方法可以在特定时间将线程放入消息队列.
- android线程优先级是依据Linux设置的,其优先级是用数字表示的,范围是-20~19,其中-20为最高优先级,19为最低优先级.优先级的设置通常用处处理冰法线程产生的阻塞,防止重要性较低的线程占用大量的CPU资源.方法:Process.setThreadPriority(priority);priority参数在Thread有一些静态属性可以用.
- 在android中,从activity,View和Ui主线程3个层次提供了4中方式来接入UI线程.
-
- acitivity的runOnUiThread(Runnable);
- View的post(Runnable);
- View的postDelayed(Runnable,long);
- Handler
- 相比Thread加Handler的封装,AsyncTask更为可靠,更易于维护.AsyncTask的缺点是,一单线程开启即dobackground方法执行后无法向线程发送消息,仅能通过预先设置i好的标记来控制逻辑,当然可以通过挂起线程并等待标志位的改变来进行通信.
- android目前提供了两种消息类型,一种是post消息,一种是send消息.其中post消息会在未来某一时间加入消息队列,而send消息则会立即加入到消息队列.
- synchronized关键字并不能继承,对于父类的同步方法,在子类中必须再次显示生命才能成为同步方法.synchronized关键字的局限在于在试图获得锁时无法设定超时和中断,每个锁只有一个条件,在某些场景下可能不够用.
- android提供了类似于Asynctask的AsyncQueryHandler方法来解决这一问题(对于SQLite的调用,可能会存在多处同事执行读写操作的场景,这种场景也需要考虑线程的安全性)
第七章:深入解析android网络编程
- 在android4.0中,开始支持流量的监控,对企业应用也增强了支持,通过VpnService允许应用构建自己的VPN.
- 在android中,采用的蓝牙协议栈是Bluez,作为一个开源的蓝牙协议栈,Bluez提供了BT所有的常用功能.
- SSL:在android.net.http包中,提供了SslCertificate和SslError来描述X509数字证书信息.在javax.net.ssl包中,通过HttpsURLConnection可以管理HTTP连接,通过SSLServer-Socket可以创建SSL套接字.org.apache.http.conn.ssl包中还提供了SSLSocketFactory等类来执行SSL套接字的创建等.
- 在android中,ConnectivityManager提供对网络如WIFI,BT,WIMAX,GPRS,UMTS的连接性管理.
- 对于HTTPS协议,可通过HttpsURLConnection建立HTTPS链接.系统会现场时TSL和SSL2,当链接建立失败时,再尝试SSL3.
- 在J2SE 1.4中,Sun引入了NIO,在进行Java应用向android移植时,会出现一些Java NIO的兼容性问题,通常是NIO对IPv6的支持存在问题,会抛出java.net.SocketException:Bad address family异常.目前解决的方法是,通过setProperty(propObj,put,"java.net.preferIPv6Addresses","false")来禁止IPv6,然后进行Selector.open()等操作.
- 在Linux中,Java NIO是基于管道实现的.NIO主要使用了Channel和Selector来实现,其基于时间驱动的单线程处理可以有效地节省系统开销,并降低线程死锁的概率.在实际的开发中,NIO通常用于本地数据复制和网络传输中.
- android网络编程接口
-
- RTP协议,实时传输协议RTP主要用于VOIP,push-to-talk,电话会议等场景中.android.net.rtp包
- Web服务是基于XML和HTTPS的一种分布式计算服务,其通信协议主要基于SOAP,服务通过WSDL描述,发现和获得服务的元数据则通过UDDI来描述.调用Web服务的方式包括RPC,SOA,REST等.Web服务的安全可以通过Web-Security,SSL,数字证书等3中方法来实现,通过Web-Reliability可进行可信赖的Web服务间消息传递.目前Web服务的框架有Ajax2,metro,cxf等.
- KSOAP2是一个针对Android平台的轻量级的SOAP库,适用于资源受限的环境,不支持Web-Security.
- 在Honeycomb中,getElementsByTagname()方法无法获得NodeList,即DOM解析器在Honeycomb中会因严重的bug而无法使用.
- 基于UDP协议的套接字
-
- 基于UDP协议的套接字主要是通过DatagramSocket进行的,DatagramSocket在通信的两端均适用.DatagramSocket对象通过send()方法发送消息,通过receive()方法接收消息,通过connect()方法建立和服务器的连接.
- 在Android中,Cookie的管理是通过CookieSyncManager来实现的,通常为了获得优异的性能,在RAM中保存Cookie,但是由于某种需要,通过CookieSyncManager可以将Cookie保存到永久存储空间中.CookieSyncManager在运行期间以单子模式出现,一旦创建了CookieSyncManager,系统将单独启动一个线程来执行Cookie在RAM和永久存储空间之间的同步,系统会通过一个定时器每5min执行一次同步操作.CookieManager对Cookie的管理本职上是对CookieSyncManager的封装,因此在管理Cookie时,必须先创建CookieSyncManager实例.
- SIP协议支持TCP和UDP两种传输协议,由于SIP本身具有握手机制,因此首选UDP.
- NFC支持的数据格式为Ndef.注意,在Android2.3中,仅支持基于android.nfc,action.TAG_DISCOVERED的intent过滤器.
- RIL层是对底层蜂窝接入技术的封装,是Android和协议栈通信的接口.它提供了语音,数据,短信,SIM卡管理已经STK应用等功能,其实现的接口遵循无线协议规范.在android中,RIL层的代码主要位于hardware\ril中.从某种意义上讲,RIL层是通话服务(Telephony Service)和基带硬件中间的抽象层.
- RIL移植:在android源代码中,给出了一个VENDOR RIL 的参考实现,即reference-ril.c,并最终将其编译成librefrence.so共享库.reference-ril.c负责与硬件的通信,将来自上层的命令转换为AT指令,然后传递给应经.根据硬件厂商的不同OEM厂商需要修改reference-ril.c.需要注意的是,如果定义了RIL_SHLIB,那么VENDOR RIL会被编译为共享库,或直接被编入RIL守护进程.
- 报文分析:开源的抓包工具,Wireshark(以前称为Ethereal).是一个网络抓包分析工具.
第八章:Android图形,图像与动画精要
- android的渲染分为2D渲染和3D渲染两种,其中2D渲染的引擎为Skia,3D渲染的引擎为OpenGL ES.
- 在存储数据时,对BMP图像的扫描方式按从左到右,从下到上的顺序进行.
- Drawable与视图的区别在于,Drawable无法接收事件.
- 在android中进行图像变换需要使用Matrix类,该类中包含了一个3*3的矩阵,专门用于进行图像变换匹配.Matrix没有结构体,必须对其进行初始化.通过气reset()方法,可以得到一个单位矩阵.
- 缩略图:多种方式
-
- 通过BitmapFactory的Options来设置采样大小,按照比例取得缩放图像.
- 如果希望取得固定大小的缩放图像,以上方法不合适.
- 在android 2.2中,引入了ThumbnailUtils类,利用它可以针对图像生缩略图,针对视频生成首帧的缩略图.目前android提供了两种缩略图模式,一种为MINI_KIND(512像素*384像素)模式,一种为MICRO_KIND(96像素*96像素)模式.
- 图像浏览:
-
- 倒影效果的实现
- 缩放效果的实现:除了可通过ScaleDrawable实现外,还可通过Matrix的方式实现.
- 圆角图像的显示
- 人脸检测
-
- 人脸检测主要是FaceDetector类中进行.在android4.0中,人脸检测用来实现解锁功能,非常有特色.
- 在执行具体的人脸检测室,所采用的算法对图像也有要求,其利用的元数据必须为RGB565格式的Bitmap,图像不能太小,否则会检测不到,图像也不能太大,否则易造成加载异常.
- 在android4.0中,为了进行人脸检测,可以通过Camera的setFaceDetectionListener()来设置Camera.FaceDetectionListener监听器.
- 3D图像处理
-
- 在android3.0中,google引入了RenderScript,这样在进行3D处理时,开发者有OpenGL,RenderScript两种工具可供选择.就具体的场景而言,google提供的建议如下:如果开发者只开发简单的应用,且性能不是关键,或者希望有更好的灵活性和调试支持,则需要考虑OpenGL;如果考虑移植性且不会用到OpenGL的全部功能,则RenderScript是个不错的选择.
- RenderScript在原生代码层为开发者提供了一组能进行高性能3D图形渲染和计算的API,使开发者可以利用C语言(C99标准)以更底层,更搞笑的方式实现3D效果.不同于已有的NDK,为了实现跨平台,RenderScript在编译过程中会被编译为中间字节码(LLVM),在执行时才通过JIT技术转化为机器码,这样可以避免开发阶段需要面对某种特定机器架构而带来的各种问题.RenderScript总体上采用的是主从架构.
- android允许使用硬件加速来渲染应用,但出于系统负载的考虑,android推荐针对activity进行硬件加速,以避免系统负载过重,方法如下:myActivity.requestWindowFeature(Window.FEATURE_OPENGL);并不是所有的2D基本图形都支持硬件加速,如PathEffect目前就不支持.
- 在图形处理上,android支持基于Shader的多种渲染特效.
- 更底层的渲染是通过android渲染管理器Surface Flinger进行管理的.
- Surface:android图形系统中一个最重要的概念是Surface.每个Surface都会创建一个画布(Canvas)对象,每个画布对象都对应于一个位图(Bitmap)对象,该位图对象中存储着视图(View)及其子类等UI控件在Surface上的内容.框架层通过Window传递的标志位(flags)来决定创建的Surface的类型.
- 通常情况下,每个Surface对应两个缓冲:前端缓冲(Front Buffer)和后端缓冲(Back Buffer).后端缓冲即在画布对象上渲染信息时画布对象对应订单那个位图对象.
- 每个Surface对应一个Layer对象,Surface Flinger负责将各个Layer对象的前端换重组合并渲染到屏幕上.Layer共有4种模式:Layer,LayerDim,LayerBlur,LayerBuffer.这4种模式分别与4种类型的Surface对应.
- 动画处理:目前android支持3种动画,补间动画(Tween Animation用于实现android控件本身的动画效果),帧动画(用于实现类似GIF格式动画的效果),属性动画(属性动画是在android3.0中引入的).
-
- 确实需要在android环境下支持GIF格式动画,变通的方法是通过WebView来加载,只需要URI设为本地GIF资源文件即可.但这样要消耗大量的资源,创建一个WebView对象至少需要8MB的RAM.
- 补间动画Tween Animation:补间动画并不只针对图像,它还支持TextView等视图对象.android的控件动画效果军事基于补间动画实现的.最常用的控件动画是基于ViewAnimator类进行的.
- 动画的进度是通过插补器(Interpolator)来控制的.如果默认的插补器还无法满足开发者的需求,那么开发者可以通过实现TimeInterpolator接口自定义一个插补器.
- 帧动画:为了连续显示一组图像,产生动画效果android需要利用XML资源文件和AnimationDrawable协同工作.AnimationDrawable的start()方法不能再activity的onCreate()方法中调用,这是因为此时图像资源尚未完全加载.如果希望能在Activity启动后立即开始动画,那么可以在Activity的onWindowFocusChanged()方法中执行start()方法的调用.
- 属性动画:在android3.0中引入,为开发者提供了更强的自定义动画的能力.属性动画在游戏开发中比较常见.
- 布局动画:android3.0中,还引入了布局动画,其作用域ViewGroup及其子类.,需要为其设置LayoutTransition属性.
第九章 深入解析android多媒体编程
- 音频本身的播放涉及的多媒体引擎是OpenCore和Stagefright.在默认情况下,OpenCore在android2.2及以前版本中应用,而在交心的android版本中,Stagefright则成了默认的多媒体引擎.
- 对于背景音乐,将MediaPlayer封装在Serviece中即可实现.
- 音频处理
- 视频处理
-
- 视频状态机
- 两种方案:一种是基于VideoView,一种是基于SurfaceView.
- android4.0中提供了与SurfaceView想死的TextureView来支持视频或OpenGL场景,但TextureView的用法更类似于普通的视图.另外,在android4.0中,开发者还可以显式的设置Surface,方法为setSurface().
- MediaRecorder的许多方法间存在依赖关系,如setVideoSource()方法和setAudioSource()方法必须在setOutFormat()方法前设置:通过setOrientationHint()方法设置角度,必须在prepare()方法前调用;通过setMaxDuration()方法设置持续时间,则必须在setOutFormat()方法后并在prepare()方法前进行.在开发视频录制的应用嵌,必须了解这些依赖关系.
- 在android4.0中,当完成了一段视频的录制后,系统会广播android.hardware.action.NEW_VIDEO消息.
- Camera服务
- TTS的实现
-
- android1.6及以后版本中,android开始通过支持语音合成的Svox语音引擎,即TTS(Text To Speech).
第十章 Android跨语言调用详解
- 在C语言中调用会变语言只需通过关键_asm_将会变代码封装即可.会变代码在C语言中的实现形式因编译环境不同而有所不同,在Android中采用的是GCC编译器.
- 汇编语言对C语言的调用需要通过关键字BL进行,如果涉及参数传递,则实现比较复杂.
- 在C++与C语言的相互调用中,注意关键字_cplusplus和extern"C"的用法即可,其中_cplusplus为C++的关键字,表示作用域内的代码为C++代码,而extern"C"是为了保证C++和C是互通的.这是因为在编译生成汇编码时,两者的处理有所不同,在C++中,为了支持重载机制,在编译生成汇编码时,要对函数的名称进行一些处理,而在C语言中,则不需要如此.
- 在C语言调用C++时,由于C语言不能直接饮用声明了extern"C"的C++头文件,因此在调用C++头文件中庸extern"C"声明的函数时,需声明其为外部函数.
- Java对C/C++的调用
-
- 定义JNI原生接口
-
- 根据管用的场景不同,JNI接口的定义方式有两种,分别为普通调用和定向调用.在Android中,普通调用的JNI定义通常用于框架层,而定向调用的JNI蒂尼通常用于应用层.
- 普通调用的步骤:JNI接口定义->JNI接口映射->注册JNI接口映射->设置在共享库加载时JNI接口映射.
- 定向调用:接口名的定义由3部分组成:Java声明、Java包名、函数名。在加载共享库时,如果无法找到对应原生方法的JNI接口,会抛出UnsatisfiedLinkError异常。
- 在C/C++中,要得到特定环境变量所致的路径,利用getenv()函数即可.const char* root = getenv("ANDROID_ROOT");
- JNI的编译,只需要设置LOCAL_PATH,LOCAL_MODULE,LOCAL_SRC_FILES等环境变量,然后根据需要知名是编译成共享库还是静态库即可.
- JNI调用Java方法得当原生接口在结构体JNINativeInterface中定义,JNI调用Java方法的过程如下:FindClass(查询Java类)->GetMethodID(获取Java方法句柄)->Call*Method(调用Java方法)
- 在JNI里直接创建Java对象,在操作结束后,应释放对Java类的引用.
- 由于C和C++在可执行文件布局上的不同,JNI接口的调用方式在JNIEnv指针的操作上也略有不同
第十一章 Android 安全框架解析
- android的主要安全机制包括Java混淆器,接入权限,数字证书,SSL,数据库安全,虚拟机(安全沙箱),文件访问控制等.
- android自带的java混淆器为著名的proguard.
- 接入权限
-
- 框架层额接入权限定义在frameworks\base\core\res\androidManifest.xml中.
- 创建接入权限
-
- 和常规的理解不同,高级别权限并不兼容低级别权限.对于signatureOrSystem级别的权限,在基于SDK开发的环境中,在调试应用时无法接入这个级别权限的服务.这点在进行源代码级别开发时需要注意.
- 设置应用权限的方式有两种方式:
-
- 一种是设置共享用户ID:android在权限管理上应用了Linux的ACL权限机制.通过在每个应用中使用sharedUserId属性可共享系统账户权限.android源代码树携带的系统证书位于build\target\product\security目录下.目前采用的签名算法为RSA算法.
- 一种是直接设置应用或组建额接入权限.
-
- 直接设置应用的接入权限
- 设置activity的接入权限
- 数据库的接入权限:主要分为3个层次,读,写,搜索
- 验证权限
-
- 如果调用方用友相应的权限,则权限验证的返回值为PackageManager.PERMISSION_GRANTED,否则返回PackageManager.PERMISSION_DENIED.
- 框架层接入限制,在框架层,为了隐藏某些方法或实现类,避免被第三方开发者开发的应用程序调用,提供了hide限制的方法.当框架层的API发生变化是,需要先通过make update-api来更新current.xml,否则会因为一致性问题导致系统遍以上的失败.在基于源代码开发时,hide限制无效.
- 数字证书
-
- android允许用友相同数字签名的应用运行在同一个进程中,这同样有利于在多个应用中共享数据.Android Markets强制要求所有应用程序的数字证书的有效期要持续到2033年10月22日以后.
- 在进行数字签名后,可用zipalign工具来优化应用.
第十二章 android 的调试,测试与性能优化
- 当发生android ANR错误时,错误信息会保存在\data\anr\traces.txt中,这有助于在无法实施查看日志的情况下分析Bug.
- Android调试
- 在Eclipse中集成的DMSS并没有呈现出全部的DMSS能力,如果希望观察系统更详细的信息,可以直接启动SDK\tools\ddms
- android测试
- Monkey压力测试的过程中,
- Android性能优化
- zipalign提供了4字节的便捷对其来映射内存,通过空间换时间的方式来提高APK加载的执行效率.
第十三章 深入解析android编译系统
- 源代码编译
-
- 映像文件
-
- 在android中,默认的文件系统为YAFFS2,当然,OEM厂商可以根据自己的需要,选择其他的文件系统.
- 在源代码中,YAFFS2文件系统的实现位于external\yaffs2\yaffs2目录下,它针对大容量的NAND Flash进行了优化,具有挂载时间段等优点.
- 在当前的只能终端中,另一个比较常用的文件系统是UBIFS,它是由IBM和Nokia公司的工程师于2006年开发的一款高效的嵌入式文件系统.
- 映像格式默认支持yaffs2,ext4,vfat等.
- 映像文件的生成配置位于build\core\Makefile中.
- 编译方法
-
- 除了基本的全系统编译外,android还提供了集中快捷方式供编译和查找使用
- 编译环境
-
- 在Froyo版本后,Android对Java的要求从Java5提升到Java6,同时对驻留的操作系统的要求从32位升级到64位,另外要求具备Python2.4,Git1.5.4或更高版本.
- 对于Gingerbread或更高的版本,Android要求支持Java6,采用Sun java6或者Open JDK6均可.对于Froyo及更低的版本,android要求支持Java5,这主要与当时android无法兼容Java6的overide属性有关.
- 如果希望进行原生代码的内存泄漏方面的检测,那么还需要包装Valgrind包.
- 为了获取android的源代码,必须安装repo,repo是Google对git的封装,使对git的操作更加方便.(repo也是不断升级的,并对驻留的操作系统的配置有依赖性,比如对Python就有要求,偶尔会繁盛更新后无法操作repo的情况.)
- 如果基于源代码的方式进行开发,内核的代码是必须的,通常可以从硬件厂商那里获得最新的代码.当前android源代码树中已经包含了Qualcomm,TI,Qemu(模拟器),Sansung,NVIDIA等厂商的代码.
- 基本编译过程
-
- 过程主要包括3部分,设置环境变量,设置编译属性配置,执行编译.
- android还支持多CPU的编译,例如执行make -j4,意味着编译工作可以同时在最多4个CPU上同时进行,这在CPU普遍为多喝架构的今天,是个不错的设计.遗憾的是,android没有发布官方的基于分布式编译的工具,无法有效地利用局域网内部的空闲计算能力.
- 快捷方式
-
- croot:用于改变当前路径到android根目录.
- m:用于从android根目录开始编译.
- mm:用于编译当前目录下的所有模块.
- mmm:用于编译特定目录下的所有模块
- cgrep:用于在C/C++文件中查找
- jgrep:用于在Java文件中查找
- resgrep:用于在资源文件中查找
- godir:用于跳转到某个目录.
- 主要脚本
-
- android中的脚本类文件主要用来配置产品,目标板,以及根据开发者的Host和Target来选择相应的工具并设定相应的编译选项.
- SDK编译
-
- windows下的sdk的生成以来与Linux,Mac下的SDK,这以为着为了编译windows下的sdk,必须先编译Linux或Mac下的SDK.生成windows下的SDK以为着将Linux或Mac下的SDK中与操作系统相关的UNIX二进制文件替换为windows下的二进制文件. Cygwin仿真环境
- NDK编译
-
- NDK提供的原生方法只是Android原地阿妈能力的一个子集.
- NDK要求为GNU Make3.81及以上版本.
- NDK的配置脚本主要有android.mk和Application.mk两种
- 虽然android NDK提供了STLport库供加载,但是在少数场景中,依然需要重新编译STLport库.
- GDB调试
-
- 为了进行原生代码的调试,NDK提供了远程GDB调试手段,其主要调试脚本为ndk-gdb.ndk-gdb仅在Foryo及以上版本中受到支持.为了进行GDB调试,要求你工程处于debug模式下,这需要在AndroidManifest.xml文件中生命android:debuggable属性为true,同时在进行NDK编译时生成的动态库也是debug模式的.
- NativieACtivity实现
-
- 在android SDK中,提供了一个NativeActivity类,可以与android框架和原生代码进行通信.实现NativeActivity有两种方法,一是通过native_activity.h头文件,而是通过android_native_app_glue.h头文件.从本质上讲,NativeActivity的实现仍是基于JNI进行的.
-
- 应用程序编译
-
- 应用程序的编译主要基于Android.mk文件进行,为了在编译前清楚遗留的中间文件,需要实现CleanSpec.mk.Android的应用层代码主要遵循APACHE2许可文件.
- 文件系统的配置
-
- 在System\core\rootdir\目录下的Android.mk中会加载外部文件系统的挂在信息,相关信息定在vold.fstad文件中.
- 编译工具:
-
- 整个编译系统都是基于make进行的.
- 在android中,C库采用的是Google优化自BSD的Bionic,而非标注你的blibc.
- 在android中,原生代码采用的交叉编译工具链为arm-eabi-4.4.3,其能够将原生代码编译为ARM架构的二进制文件.
- 在通过NDK编译一些移植过来的嗲吗时需要注意,arm-eabi-4.4.3对代码的要求更加严格,在低版本编译器下编译通过的代码在arm-eabi-4.4.3下并不一定能顺利编译通过.arm-eabi-4.4.3下并不一定能顺利编译通过.下并不一定能顺利编译通过.
- 当然在编译模拟器部分的原生代码时,并不需要进行交叉编译,采用的编译器为i686-unknown-linux-gnu-4.2.1
- 在ARM架构下,编译出的可执行文件的格式为ELF.如果希望构建自己的交叉编译环境,则需要用到Crosstool工具,如果希望检测实现的原生代码是否存在内存泄漏,则会用到Valgrind工具.
- fastboot模式
第十四章 android启动过程详解
-
- 在android中,在BootLoader加载系统映像后,会通过system\core\rootdir目录下的init.rc脚本年进行初始化配置.在init.rc中可以配置系统是去,设置日志登记,设置全局环境变量,挂载文件系统,初始化网络配置,配置系统属性,启动守护京城等,具体:配置系统时区->设置日志等级->设置全局变量->创建挂载点并设置权限->->挂载文件系统->初始化网络配置->配置系统属性->启动守护进程.启动过程中的配置是系统正常运行的基本保证.
- vold(volume daemon)和Linux标注你的eudev类似,均通过sysfs为内核和用户层提供通信.
- 应用的启动过程
-
- AAPT允许开发者查看,创建,更新与ZIP兼容的压缩文件(ZIP JAR APK),同时还将资源编译到断言asset中.
- resource.arsc为资源文件,在android 2.3前,采用的是UTF-16编码,在android 2.3 及以后版本中,采用的是UTF-8编码.
- 在android中,采用的java混淆器为开源的ProGuard 4.4.
- DEX字节码借鉴了Linux的BusyBox和Qt中的SingleBuild编译模式采用的最大限度服用信息的设计思想,能够有效的减小生成文件的大小.
- 如果不希望应用在系统低内存时被系统销毁,需将Application变迁的android:persistent属性设置为true.
- 在启动Activity的过程中,为了进行JUnit测试,具体Activity的onCreate()方法的调用时通过Instrumentation的callActivityOnCreate()方法进行的,在应用的启动过程中会不断调用Instrumentation.
第十五章 深入解析android系统管理
- 内存管理
-
- 虚引用一般没有实际意义,仅观察GC的活动状态,对于测试比较实用,同时必须和应用队列ReferenceQueue一起实用.
- 垃圾回收策略
-
- 在android中通常每个应用占据一个虚拟机,所以android的垃圾回收是基于应用进行的.
- 事实上,在android的原生代码层,通过引入应用技术机制,android同样实现了自动垃圾回收,相关的实现位于\frameworks\base\include\utils\RefBase.h中.几乎所有的原生类均继承了RefBase类,RefBase类会维护对象的强引用和弱应用计数,一单强引用计数为0,对象自动释放自己.
- 应用管理
-
- 应用的启动
-
- 分为两种,一种是通过启动器启动,另一种是通过Intent消息启动.
- 如果在通过Intent消息启动前,希望判断欲启动的应用是否已经安装,目前有两种方法可以检测相关的信息,一种是检测相关的UI组件是否存在,另一种是检测安装包是否存在.
- 电源管理
-
- 在移动终端中,耗电大的3个方面主要是触摸屏,CUP和WiFi.android的整个电源管理也主要集中在这3个方面.
- android的电源管理主要是通过唤醒锁和定时器来切换系统状态的.
- 在android的电源管理框架中PowerManagerService是核心部分,它和Linux内核的交互是通过power.c来实现的.power.c和内核的交互是通过SYS文件来实现的.
- 唤醒锁策略:android中,上层应用可以利用的一个电源管理策略是唤醒锁WakeLock,通过设置标志位可以控制屏幕的背光,键盘灯和CPU.除非确实需要,否则不建议获取唤醒锁.另外唤醒锁必须成对使用,如果申请后没有释放会造成系统故障,是系统永远无法进入休眠模式.
- 下载管理
-
- 有时可能需要关注下载过程,这可以通过监控数据库来实现.extends contentObserver
- 系统配置
-
- 系统数据库
-
- 数据主要存储在settings.db数据库中.数据条目以<key,value>的形式存在,所有的值均以字符串形式存储.
- 系统属性:
-
- 配置系统属性是配置android系统信息的一个方面,部分信息在编译时配置,部分信息在运行时调用接口来配置.系统属性存储在\tmp\目录下的android-sysprop文件中.
- 数据管理
-
- 数据备份
-
- 在Foryo及以上版本中,android支持应用数据的备份,数据备份功能主要是通过bmgr工具来实现的.为了申请响应应用的数据备份密钥,每个密钥仅对应一个包名.在默认情况下,android仅提供对应用的私有文件和配置文件的备份.
- 剪切板管理
-
- 剪切板管理是在Gingerbread中引入的,在Honeycomb中完善的.简单类型的数据直接存储于剪切板上,复杂的数据存储于SQLite中.
- 使用剪切板时,对数据的操作时通过剪切对象(Clip Obejct)进行的,叫企鹅对象有3种:文本,URI,Intent.需要注意,剪切板管理是可以跨应用进行的,而且剪切板只能维护一个剪切对象,新内容会覆盖旧内容.
- 设备管理
-
- 驱动调试工具:
-
- dmesg显示开机信息
- insmod挂载驱动
- 网络管理工具
-
- android并不支持ifconfig.
- netstat
- netcfg:是android自定义的用于查看网卡信息的工具.
- 应用调试工具
-
- am工具:其可以在命令行下启动应用,服务,广播,回归测试,profiling,GDB调试监控(monitoring)等,在一些环境受限的场合非常有用.其位于system/bin目录下.
- dumpsys工具
-
- 其可以观察到当前运行的广播,Activity栈,服务,进程,安装包,内存信息,闹钟,省电配置,窗体信息,渲染信息,电池信息等.
- pm工具
-
- 其可以列出安装包的信息,比如权限,也可以配置应用的安装位置.
- 属性配置工具
-
- 获取属性:查看属性时通过getprop进行的: #adb shell getprop
- 设置属性:setprop ,setprop <key> <value>
- 观察属性:watchprops,如:#watchprops
- getevent/sendevent工具:是android系统下的工具,可以模拟多种按键和触屏操作,产生的是原始事件(raw event),原始事件经过处理产生最终的事件.(sendevent命令中数字格式为十进制,getevent命令中数字格式为十六进制,getevent用来监控按键,拖动,滑动事件.)
- 系统管理工具
-
- df:用来查看文件系统的磁盘占用情况,#adb shell df
- mount显示文件系统:可以用来挂载文件系统和显示当前文件系统的挂在情况,但是要注意,android不支持unmount工具
- 传感器管理
-
- 在框架层,传感器的管理是通过SensorManager进行的.和其他系统服务一样,通过getSystemService()方法可以获取SensorManager的句柄.
- USB管理
-
- 在android3.1中,google将底层的USB管理框架上移并由开发者开发,这就是android.hardware.usb包的由来.android.hardware.usb包并不仅用于adb调试,还用于插拔以及状态模式的广播.
- 在android.hardware.usb包中,UsbManager提供了最上层的USB管理.可以对USB设备进行权限判断和获取临时权限.
- 应用发布
-
- 语言环境:在Froyo版本中,支持26种语言,在Gingerbread中,支持包括阿拉伯语在内的57种语言.在android中,其语言和国家的代码遵循ISO 639和ISO 3199标准.
- 语言环境主要涉及3个方面的内容:字符集,排列方向,用语长度
-
- 字符集
-
- 注意的是:UTF-8为了保持和ASCII兼容,在支持ASCII字符集中的字符时执行8位编码,在支持中文等字符时执行24位编码,而UTF-16则对所有字符执行16位编码.当然对于机器编码,还存在big-endian和little-endian的问题.
- 用语长度:目前解决用语长度兼容性的办法不是很多.
- 屏幕布局:对于第三方开发者开发的应用,需要特别注意resizeable属性,应将其值设为true,这样才能自适应新的屏幕大小.
- 发布应用:步骤
-
- 设置版本信息
- 设置应用图标和应用名
- 关闭调试信息
- 添加各种许可文件
- 为应用程序进行数字证书签名
- 进行发布测试
- 发布应用程序
附录A:
- QEMU仿真器,跨平台模拟器,能够进行芯片级别的模拟和各种外围设备的模拟.在GPL许可下发布,在android中,QEMU的代码位于external\qemu目录中.效率然不如xen,单模拟爱移动终端还是可以轻松胜任的.
- 对于Linux环境下的缺陷管理工具,作者推荐Bugzilla3,Bugfree,Jira等.这些缺陷管理工具的数据一般是基于MySQL进行的管理.
- 在Linux世界汇总,软件管理有三大工具即APT,YUM,YAST可供使用.Ubuntu采用的是APT软件管理工具.
- 源代码阅读与分析
-
- Kscope作为Cscope的前端,为大规模C/C++工程(如Linux Kernel)提供了一个优秀的源代码编译和分析环境.需要说明的是,Kscope无意代替当前Linux/KDE下的集成开发环境,如KDevelop等,Kscope并不提供源代码的编译,调试等功能.
- 源代码查看
-
- VI
- GEdit
- KWrite
- 开发工具
-
- 代码比较与合并(Linux下)
-
- Beyond Compare
- Meld:对于开发者常用的subversion,其自身携带的合并工具相对比较简单,为了更方便的在进行SVN操作时进行比较,可以将subversion的合并工具设置为Meld.
- 作者的建议是:为工程维护两个路径:一个是和版本管理系统同步的目录,一个是开发的目录.当开发完成一个功能时,及时地将其同步到版本管理系统目录上.当开发需要回滚时,通过版本管理系统目录同步即可.
- KDiff3:易用性方面不如Meld.
- 版本管理与控制
-
- SVN
-
- SVN服务器有两种运行模式:独立服务器运行模式和借助Apache运行模式.在Linux下,最常使用的SVN服务器端工具为subversion.SVN存储版本数据也有两种方法:BDB和FSFS.因为BDB方式在服务器中断时,有可能锁住数据,所以FSFS方式更安全一点.
- KEESVN
-
- 是Ubuntu下最常用的SVN客户端工具,但由于android源代码过于庞大,KDESVN在数据同步过程中会存在操作上的延迟.在默认情况下KDESVN不支持将so共享库导入到仓库中.对于这种情况,可以在Windows下通过TortoiseSVN导入共享库.
- git
-
- Git是LInux Kernel源代码的控制工具,由Linux的创始人Linus Torvalds开发,是Google在Git基础上改进的REPO,是android的版本控制工具.
- ClearCase
- 查看SQLite3数据库
-
- Ubuntu上可以使用sqliteman
附录C:编码规范
- 命名规范