Android技术体系结构
一、Android技术体系结构
1.Android项目目录结构
src 源文件
gen ADT自动生成的JAVA文件,程序员千万不要去修改
Android 4.2.2+Android Private Libraries jar文件
assets 资源文件,图片,音频,视频等
bin 二进制文件,编译过后的文件
libs 第三方的jar文件,即引用第三方的代码
res 也是资源文件,与assets不同,生成的文件都有ID
├ drawable-hdpi 高分辨率图片,我们要为不同分辨率准备不同的图片。
├ drawable-ldpi 低分辨率图片
├ drawable-mdpi 中分辨率图片
├ drawable-xhdpi 超高分辨率图片
├ layout 布局文件
├ menu 菜单
└ values 值,包括字符串,颜色等的定义
AndroidManifest.xml 这个文件是整个应用程序的主配置文件,所有组件都需要在这个文件中注册。
proguard-project.txt 防止被别人反编译,对代码进行混淆。
project.properties 项目的属性设置,比如SDK的版本。
用得最多的是src目录和assets和res两个资源目录,以及AndroidManifest文件。
2.技术结构图
1)Linux Kernel
Google选择了Linux作为Android的底层支撑系统。当前的 Android系统是基于Linux2.6内核,其核心系统服务如安全性、内存管理、进程管理、网路协议以及驱动模型都依赖于Linux内核。
2)Android Runtime
运行时环境可分为核心库和Dalvik虚拟机两部分。
核心库提供了Java语言API中的大多数功能,同时也包含了Android的一些核心API,如android.os、android.net、android.media等等。
Dalvik虚拟机是由Google公司自己设计专门用于Android平台的Java虚拟机,它针对移动终端做了特殊的优化。
3)Libraries
系统库是应用程序框架的支撑,是连接应用程序框架层与Linux内核层的重要纽带。其主要包含以下几个部分:
Surface Manager:执行多个应用程序时候,负责管理显示与存取操作间的互动,另外也负责2D绘图与3D绘图进行显示合成。
Media Framework:多媒体库,支持多种常用的音频、视频格式录制和回放,编码格式包括MPEG4、MP3、H 264、AAC、ARM。
SQLite:轻量级的关系型数据库引擎
OpenGL|ES:根据OpenGL ES 1.0 API标准实现的3D绘图函数库
FreeType:提供点阵字与向量字的描绘与显示
WebKit:开源的浏览器引擎,支持CSS,JAVASCRIPT,DOM等脚本语言
SGL:底层的2D图形渲染引擎
SSL:在Andorid上通信过程中实现安全认证
Libc:从BSD继承来的标准C系统函数库,专门为基于embedded linux的设备定制
4)Applications
应用程序框架层是开发者从事Android应用开发的基础,很多核心应用程序也是通过这一层来实现其核心功能,该层简化了组件的重用,开发人员可以直接使用它提供的组件进行快速的应用程序开发,也可以通过继承而实现个性化的拓展。以下是这次层中,各个部分的功能:
Activity Manager(活动管理器):管理各个应用程序生命周期以及通常的导航回退功能。
Window Manager(窗口管理器):管理所有的窗口程序
Content Provider(内容提供器):通过它可以在不同应用程序之间存取或者分享数据
View System(视图系统):构建应用程序的基本组件
Notification Manager(通知管理器):通过它应用程序可以在状态栏中显示自定义的提示信息
Package Manager(包管理器):Android系统内的程序管理,可以查看Android应用程序以及Activity的相关信息
Telephony Manager(电话管理器):管理所有的移动设备功能
Resource Manager(资源管理器):提供应用程序使用的各种非代码资源,如本地化字符串、图片、布局文件、颜色文件,主题样式,二进制文件等
Location Manager(位置管理器):提供位置服务
XMPP Service(XMPP服务):提供Google Talk服务
3.基于组件的应用程序开发
把常见的功能封装成一个个组件,根据需要的功能把相应的组件组合在一起,构成完整的应用程序,这就是基于组件进行应用程序开发的思想。
Android最重要的四种组件:
1)Activity
作为UI主要负责和用户交互,接受用户操作,把运行结果显示给用户。如果把一个Android程序比作一个网站的话,一个Activity就是一个网页。但手机不宜有太多的Activity。
2)Service
主要负责完成耗时较长的工作,比如网络连接和长时间的IO操作,没有图形化界面,在后台默默运行。
3)Content Provider
内容提供者。可以看作是一种数据共享方法。它提供一个公开的地址,让其他程序访问我的数据。
4)BroadcastReceiver
广播接收器。作用是监听手机系统的行为。手机运行过程中,信息会向外发送广播,比如手机没电、蓝牙关闭等。程序监听到这些广播可以作出相应的反应。
二、Android UI的重要概念
Android UI 的最重要的三个概念,Activity、View、Layout。
下面对这三个概念作一个初步的理解,先浅尝辄止。这样做的目的是先了解一下这些概念,从总体上对这些概念有一个把握和串通,方便后面的学习。
(一)Activity
1.Activity启动流程
一个应用程序至少有一个Activity。且必须有一个默认的启动Activity。
Android应用程序启动的流程如下:
首先,Android操作系统会去访问你的应用程序中的AndroidManifest.xml这个文件,决定启动哪一个Activity。启动默认的Activity之后,会生成这个Activity的对象,一般情况下是MainActivity。生成这个对象后,会去调用这个对象的onCreat方法。然后在onCreate方法里去读取layout目录下的activity_main.xml布局文件,来决定在应用程序里显示什么内容。
2.Activity与布局文件
我们可以在布局文件里修改文字显示的样式,比如
android:textSize="80px" android:background="#FF0000"
所有在res里的文件都会在gen目录里R.java这个文件里生成ID,布局文件也有它的ID。
public static final class layout { public static final int activity_main=0x7f030000; }
R.layout.activity_main就代表这个布局文件
然后在activity的onCreate函数中
protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); }
setContentView就是显示布局文件的内容。
3.在Activity中获取代表控件的对象
为了满足动态显示的需要,写死在布局文件里的控件显然是不行的。
因此我们用代码取代布局,如图所示。这样就可以动态的控制控件的样式。
下面这行就是获取代表控件的对象:
TextView textView = (TextView)findViewById(R.id.textView);
这涉及到View对象,下面就开始介绍View。
(二)View
1.什么是View
View就是控件。如下图:
每一种控件都对应有一个类,View是所有控件的父类。
2.在Activity中获取代表View的对象
首先,我们需要在layout文件里给控件加上一个唯一的ID:
android:id="@+id/textView"
然后,在Activity里声明这个控件:
private TextView textView;
注:这里需要引用textView所在的包
import android.widget.TextView;
在Activity的函数里用findViewById获取这个View,由于findViewById函数的返回类型是View,所以需要向下转型为TextView:
注:这里不是生成对象,只是找到这个对象,对象的生成是由布局文件完成的。
textView = (TextView)findViewById(R.id.textView);
3.设置View的属性
转型完毕以后可以在Activity中对这个控件进行修改,控制它的属性。例如:
textView.setText(“hello world”); textView.setBackgroundColor(Color.BLUE);
在布局里能做到的事情绝大部分代码里也能做到。
4.为View设置监听器
监听器也是一种对象,它监控着控件对象状态的变化。当控件遇到了某种事件,被点击了,被滑动了等等,控件会通知监听器,监听器得到通知之后就执行一些操作。
控件与监听器之间是绑定关系。
一个控件可以绑定多个监听器,不同的监听器用来响应不同的事件。比如监听器一用来响应点击事件,监听器二用来响应长点击事件……
我们以做一个计数器的应用为例,设计一个按键和一个文本框,每点击一下按钮,文本框里的数字加1。用这个例子来说明使用监听器的步骤:
1)获取代表控件的对象
首先,我们在布局文件里加一个Button和TextView,TextView初始值为0。
<TextView android:id="@+id/textView" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textSize="40sp" android:background="#FF0000" android:text="0" /> <Button android:id="@+id/button" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Click Me" />
再到Activity里引入包,声明它
private Button button;
并获取它
button = (Button)findViewById(R.id.button);
2)定义一个类,实现监听器接口
我们在activity里定义一个监听器,要使用一个内部类,并实现监听器接口OnClickListener
class ButtonListener implements OnClickListener{ }
要注意的是,在导入包(CTRL+SHIFT+O)的时候,会弹出一个对话框让你选择引入哪个包,我们选择View.OnClickListener。
Finish之后,我们要实现OnClickListener这个接口的抽象方法,在前面打叉的灯泡上点击会弹出你需要的操作:
直接点击Add unimplemented methods,Eclipse帮你完成抽象方法的复制,这个抽象方法就是onClick:
@Override public void onClick(View v) { // TODO Auto-generated method stub }
这个方法的作用是,当我们把ButtonListener监听器绑定到Button控件上后,当Button被点击时,会执行这个onClick方法。
声明一个全局变量
int count=0;
接着我们完成onClick函数
@Override public void onClick(View v) { count++; textView.setText(count+""); }
至此,我们的监听器就写好了。
3)生成监听器对象
在onCreate函数里生成监听器对象:
ButtonListener buttonListener = new ButtonListener();
4)为控件绑定监听器对象
然后绑定到button上
button.setOnClickListener(buttonListener);
完成。
在Android里监听器种类非常多,而且不同控件监听的方法也不一样,但使用监听器的流程永远是这个流程。
(三)控件布局
1.什么是控件布局
所谓的控件布局方法,就是指控制控件在Activity当中的位置、大小、颜色以及其他控件样式属性的方法。
控件布局关系到不仅仅是好看的问题,更重要的是用户的使用体验。
可以在布局文件中完成布局,也可以在JAVA代码中完成控件布局。
2.控件布局的分类
第一种布局方式是LAYOUT布局方式:
Linear Layout
线性布局,或者横,或者竖,一个个的把控件按顺序摆上去。
Relative Layout
相对布局,通过控件之间的相对位置决定控件的摆放方式。比如先摆好第一个控件,然后指定第二个控件摆放在第一个控件的下方,再指定第二个控件与第一个控件靠左对齐。有点类似DIV+CSS。
第二种布局方式是VIEW布局方式,主要是ADAPTER VIEW:
ListView
定义一个列表,每一项有自己的内容。这个布局是极其常用的布局。
Grid View
即网格布局,把屏幕分成几等分的格子。
3.线性布局的基本使用方法
Eclipse默认生成项目的布局文件是Relative Layout。我们来尝试下自己生成一个布局文件:
在layout文件夹上右键点new->Android XML file,弹出对话框如图:
选择根元素是LinearLayout,Finish。
生成代码如下:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" > </LinearLayout>
android:layout_width="match_parent"表示宽度匹配父控件,也就是和activity宽度一样。
android:orientation="vertical"表示方向垂直,因为LinearLayout还可以水平方向的排放控件,即将vertical改为horizontal
我们来加两个控件:
<TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:background="#FF0000" android:text="老大"/> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:background="#00FF00" android:text="老二"/>
android:layout_height="wrap_content"表示高度自适应内容。
然后把activity里设置为显示我们自己写的这个布局:
setContentView(R.layout.my_layout);
显示结果如下:
如果我们现在什么都不改,只改LinearLayout的方向,由垂直改为水平,会出现什么情况呢?按理应该是在同一行显示,但结果如下:
老二被老大挤跑了,这是因为我们第一个控件的宽度是指定的匹配父控件,把一行全占满了,老二被挤出了屏幕,所以看不到了。
如果我们把老大的宽度改成wrap_content,也就是内容自适应,老二就出现了。
开发过程中,相对布局其实用得更多一些。这里是为了初步了解。
4.长度单位与内外边距
1)距离单位之px
px即像素,如800*480的分辨率,是把屏幕分成横向480个列,纵向800个行,第一个小格子就是一个像素。
但像素不是我们最好的选择,原因下面解释。
我们知道,市面上有各种各样的手机,不同尺寸与不同分辨率都可能搭配在一台手机上。如果我们用像素作单位,可以会出现下面这一种麻烦:
比如,我们设定了一个文本框,我们想让它宽度占到屏幕宽度的一半,在一个320*480像素的手机上,宽度的一半自然是160px,于是我们给这个文本框宽度为160px。这个程序在320*480像素的手机上是正常的,但如果运行在一个640*960分辨率的手机上,就会在视觉上明显变窄,如下图所示:
这就是像素作为长度单位的缺陷。
怎么解决这个问题?我们必须用相对长度取代像素这种绝对长度。这个长度单位就是dp。
2)距离单位之dp
在解释dp之前,必须要先解释一个概念dpi。
前面解释过像素实际上是指点的数量,而dpi(dots per inch),是指每英寸点的数量。
同样尺寸的屏幕,分辨率可能会不同,也就是像素排列的密集程度不同。因此dpi表示的是屏幕的细腻程度。
如下图:
在dpi的概念下,不同手机有了标准化的衡量指标。
由此,引申出一个新的长度单位dp。dp=dip(Device Independent pixels)
dp是一个相对的长度概念,它不代表实际长度,只代表实际长度,即像素基于dpi的系数。也就是说,不同dpi的手机屏幕上,1dp表示的像素长度是不同的。具体怎么不同,看dp换算成px的公式:
px=dp*(dpi/160)
1dp代表多少px呢?答案是不固定的,取决于手机的dpi是多少。
在dpi为160的屏幕上,也就是每英寸160像素的屏幕上,1dp代表1px。这是Android定义的基准值。
那么按照公式,一个20dp宽度的控件,在dpi160的屏幕上,显示为20px。同样的程序,换到dpi320的屏幕上运行,该控件的宽度就会显示为40px。
3)距离单位之sp
sp没有特殊的意思,它是为了适应手机用户对系统字体大小的设置。
如果用户将手机字体设为大,sp的值就会变大,反之亦然。
我们可以得出这样一个推论:
在设置控件的高度和宽度时,一般用dp,而在设置字体大小的时候,一般用sp。
4)控件的外边距与内边距
如图:
外边距与内边距之间就是控件的边界。所以外边距其实就是margin,内边距其实就是padding。
内外边距各有上、下、左、右四个属性: