Android平台开发简介
平台介绍及开发基本流程
2011-4月
什么是Android?
Android是Google在2007年11月5日推出的开源手机操作
系统。目前Android在中国的发展是 非常火的,为了节省研
发费用,国内很多的手机厂商和移动运营商纷纷加入到了
android阵营,其中包括中国移动,中国联通,中国电信,华为,
联想等大企业。在中国不管是知名的手机生产厂商还是山寨手
机厂商,都已经开始生产Android操作系统的手机。另外
android应用的范围不仅仅在手机,还被应用在汽车、平板电脑
、和智能上网设备上,听说国外已经有了安装有Android系统,
并且能够上网的智能电饭煲,用户在千里之外就可以操作电饭
煲进行煮饭。由于大家大多使用的手机都属傻瓜手机,也就是
打打电话、发发短信。从今天开始,大家就应该改变这个观念
了,你们需要把智能手机看作是一台电脑,它能完成电脑所能
完成的一切。所以你可以像在电脑一样,在智能手机上安装软
件,以满足你工作和生活的需要。
如何安装 Android SDK 和Eclipse 插件
所需开发环境:
JDK 5或以上版本(仅有JRE不够) 、Eclipse 或以上版本,推荐使用“伽利略”版。
下载用于在Eclipse 开发android应用的ADT 插件
在企业开发中,很多程序员使用Eclipse IDE作为应用的开发环境。为了使得Android应用的创建,运行
和调试更加方便快捷。Android的开发团队专门针对Eclipse IDE定制了一个插件:Android
Development Tools(ADT)
下载地址:
安装 Eclipse 插件 (ADT)
启动 Eclipse,选择 Help > Install New Software,在出现的对话框里,点击Add按钮,在对话框的
name一栏输入“ADT”, 然后点击Archive...,浏览和选择已经下载的ADT插件压缩文件。
点击 OK.。返回可用软件的视图,你会看到这个插件,然后选择Developer Tools (会选中下面的
“Android Developer Tools”和 “Android Editors“),点击 Next,最后重启 Eclipse。
下载安装Android SDK:
Android SDK包含了开发Android应用所依赖的jar文件、运行环境及相关工具。
下载地址:
下载完SDK后,把.zip文件解压到你电脑上合适位置。启动 Eclipse,选择window->preferences,在打
开的视图左边点击android,在右边的SDK Location中选择Android SDK所在位置。
开发第一个Android应用
打开Eclipse,新建项目(点击FileNewProject),在项目列表中展开Android目录,选择Android
Project,如下图:
开发第一个Android应用
开发第一个Android应用
点击”finish”即可完成项目的创建,创建后的项目已经是一个可
运行的Android应用,我们可以通过下面方式运行此应用:
点击工具栏上机器人形状的虚拟设备管理器(简称“AVD“),如下:
开发第一个Android应用
“尚未注册网络”错误信息的解决
办法
打开Android模拟器时,出现无信号,拔打电话或发短信时,提示“尚未注册网络”错误信息的解决方
案如下。
l 场景一:你的电脑没有连接上互联网,同时也没有在局域网。
解决办法:右键点击网上邻居,选择"属性",在网络连接窗口中右键点击"本地连接",选择"属性",设置TCP/IP属性如下:
IP地址:
子网掩码:
默认网关:
首选DNS服务器:
l 场景二:你的电脑没有连接上互联网,但在局域网。
解决办法:右键点击网上邻居,选择"属性",在网络连接窗口中右键点击"本地连接",选择"属性",设置TCP/IP属性如下:
IP地址:设置成你所在局域网的IP,如:
子网掩码:设置成你所在局域网的掩码,如:
默认网关:设置成你所在局域网的网关,一般网关的IP格式为:*.*.*.1,如:
首选DNS服务器:设置成你所在局域网的路由器IP,一般路由器的IP格式为:*.*.*.1,如:
l 最后一种解决方案是:让你的电脑连接上互联网。
开发第一个Android应用
在项目上右键点击run as Android application,如下图:
Android应用程序架构
src/ java原代码存放目录
gen/ 自动生成目录
gen 目录中存放所有由Android开发工具自动生成的文件。目录中最重要的就是文件。 这个文件
由Android开发工具自动产生的。Android开发工具会自动根据你放入res目录的xml界面文件、图标与
常量,同步更新修改文件。正因为文件是由开发工具自动生成的,所以我们应避免手工
修改。在应用中起到了字典的作用,它包含了界面、图标、常量等各种资源的id,通过
,应用可以很方便地找到对应资源。另外编绎器也会检查列表中的资源是否被使用到,
没有被使用到的资源不会编绎进软件中,这样可以减少应用在手机占用的空间。
res/ 资源(Resource)目录
在这个目录中我们可以存放应用使用到的各种资源,如xml界面文件,图片或数据。
assets资源目录
Android除了提供/res目录存放资源文件外,在/assets目录也可以存放资源文件,而且/assets目录下的
资源文件不会在自动生成ID,所以读取/assets目录下的文件必须指定文件的路径,如:
file:///android_asset/
项目清单文件
这个文件列出了应用程序所提供的功能,以后你开发好的各种组件需要在该文件中进行配置,如果应
用使用到了系统内置的应用(如电话服务、互联网服务、短信服务、GPS服务等等),你还需在该文件
中声明使用权限。
项目环境信息,一般是不需要修改此文件
Android中的显示单位
l px (pixels)像素
一般HVGA代表320x480像素,这个用的比较多。
l dip或dp (device independent pixels)设备独立像素
这个和设备硬件有关,一般为了支持WVGA、HVGA和QVGA 推荐使用这个,不依赖像素。
l sp (scaled pixels — best for text size)比例像素
主要处理字体的大小,可以根据系统的字体自适应。
除了上面三个显示单位,下面还有几个不太常用:
l in (inches)英寸
l mm (millimeters)毫米
l pt (points)点,1/72英寸
为了适应不同分辨率,不同的像素密度,推荐使用dip ,文字使用sp。
Android开发平台是开放的平台,而位于四层框架顶端的应用开发,必然涉及
到Android组件。本文将为大家详细介绍Android组件。
组件(Component),在谈及所谓架构和重用的时候,是一个重要的事情。很多
时候都会说基于组件的软件架构,指的是期望把程序做乐高似的,有一堆接口标准
封装完整的组件放在哪里,想用的时候取上几个一搭配,整个程序就构建完成了。
在开篇的时候就在说,Android是一个为组件化而搭建的平台,它引入所谓Mash-
Up的概念,这使得你在应用的最上层,想做的不组件化都是很困难的一件事,具
体说来,Android有四大组件:
Activity、Service、Broadcast Receiver、Content Provider。
Android四大组建
Activity是为用户操作而展示的可视化用户界面。比如说,一个activity可以展示一个菜单项列
表供用户选择,或者显示一些包含说明的照片。一个短消息应用程序可以包括一个用于显示
做为发送对象的联系人的列表的activity,一个给选定的联系人写短信的activity以及翻阅以前
的短信和改变设置的activity。尽管它们一起组成了一个内聚的用户界面,但其中每个activity
都与其它的保持独立。每个都是以Activity类为基类的子类实现。
一个应用程序可以只有一个activity,或者,如刚才提到的短信应用程序那样,包含很多个。
每个activity的作用,以及其数目,自然取决于应用程序及其设计。一般情况下,总有一个应
用程序被标记为用户在应用程序启动的时候第一个看到的。从一个activity转向另一个的方式
是靠当前的activity启动下一个。
每个activity都被给予一个默认的窗口以进行绘制。一般情况下,这个窗口是满屏的,但它也
可以是一个小的位于其它窗口之上的浮动窗口。一个activity也可以使用超过一个的窗口──比
如,在activity运行过程中弹出的一个供用户反应的小对话框,或是当用户选择了屏幕上特定
项目后显示的必要信息。
窗口显示的可视内容是由一系列视图构成的,这些视图均继承自 View 基类。每个视图均控
制着窗口中一块特定的矩形空间。父级视图包含并组织它子视图的布局。叶节点视图(位于
视图层次最底端)在它们控制的矩形中进行绘制,并对用户对其直接操作做出响应。所以,
视图是activity与用户进行交互的界面。比如说,视图可以显示一个小图片,并在用户指点它
的时候产生动作。Android有很多既定的视图供用户直接使用,包括按钮、文本域、卷轴、菜
单项、复选框等等。
Activity 活动
服务没有可视化的用户界面,而是在一段时间内在后台运行。比如说,一个服务可以在
用户做其它事情的时候在后台播放背景音乐、从网络上获取一些数据或者计算一些东西并提
供给需要这个运算结果的activity使用。每个服务都继承自Service基类。
一个媒体播放器播放播放列表中的曲目是一个不错的例子。播放器应用程序可能有一个或多
个activity来给用户选择歌曲并进行播放。然而,音乐播放这个任务本身不应该为任何activity
所处理,因为用户期望在他们离开播放器应用程序而开始做别的事情时,音乐仍在继续播放。
为达到这个目的,媒体播放器activity应该启用一个运行于后台的服务。而系统将在这个
activity不再显示于屏幕之后,仍维持音乐播放服务的运行。
你可以连接至(绑定)一个正在运行的服务(如果服务没有运行,则启动之)。连接之后,
你可以通过那个服务暴露出来的接口与服务进行通讯。对于音乐服务来说,这个接口可以允
许用户暂停、回退、停止以及重新开始播放。
如同activity和其它组件一样,服务运行于应用程序进程的主线程内。所以它不会对其它组件
或用户界面有任何干扰,它们一般会派生一个新线程来进行一些耗时任务(比如音乐回放)。
Service服务和接收器
广播接收器是一个专注于接收广播通知信息,并做出对应处理的组件。很多广
播是源自于系统代码的──比如,通知时区改变、电池电量低、拍摄了一张照片或
者用户改变了语言选项。应用程序也可以进行广播──比如说,通知其它应用程序
一些数据下载完成并处于可用状态。
应用程序可以拥有任意数量的广播接收器以对所有它感兴趣的通知信息予以响
应。所有的接收器均继承自BroadcastReceiver基类。
广播接收器没有用户界面。然而,它们可以启动一个activity来响应它们收到的信息,
或者用NotificationManager来通知用户。通知可以用很多种方式来吸引用户的注意
力──闪动背灯、震动、播放声音等等。一般来说是在状态栏上放一个持久的图标,
用户可以打开它并获取消息。
Broadcast Receiver 接收器
内容提供者将一些特定的应用程序数据供给其它应用程序使用。数据可以存储
于文件系统、SQLite数据库或其它方式。内容提供者继承于ContentProvider 基类,
为其它应用程序取用和存储它管理的数据实现了一套标准方法。然而,应用程序并
不直接调用这些方法,而是使用一个 ContentResolver 对象,调用它的方法作为替
代。ContentResolver可以与任意内容提供者进行会话,与其合作来对所有相关交
互通讯进行管理。
参阅独立的内容提供者章节获得更多关于使用内容提供者的内容。
每当出现一个需要被特定组件处理的请求时,Android会确保那个组件的应用程序
进程处于运行状态,或在必要的时候启动它。并确保那个相应组件的实例的存在,
必要时会创建那个实例。
Content Provider
当接收到ContentResolver发出的请求后,内容提供者被激活。而其它三种组件
──activity、服务和广播接收器被一种叫做intent的异步消息所激活。intent是一个保
存着消息内容的Intent对象。对于activity和服务来说,它指明了请求的操作名称以及作
为操作对象的数据的URI和其它一些信息。比如说,它可以承载对一个activity的请求,
让它为用户显示一张图片,或者让用户编辑一些文本。而对于广播接收器而言,Intent对
象指明了声明的行为。比如,它可以对所有感兴趣的对象声明照相按钮被按下。
对于每种组件来说,激活的方法是不同的:
通过传递一个Intent对象至 ()或
()以载入(或指定新工作给)一个activity。相应的activity可以通过调用 getIntent()
方法来查看激活它的intent。Android通过调用activity的onNewIntent()方法来传递给它
继发的intent。
一个activity经常启动了下一个。如果它期望它所启动的那个activity返回一个结果,它
会以调用startActivityForResult()来取代startActivity()。比如说,如果它启动了另
外一个activity以使用户挑选一张照片,它也许想知道哪张照片被选中了。结果将会被封
装在一个Intent对象中,并传递给发出调用的activity的onActivityResult() 方法。
组件的连接者--Intent
通过传递一个Intent对象至()将启动一个服务(或给予正
在运行的服务以一个新的指令)。Android调用服务的 onStart()方法并将Intent对象
传递给它。
与此类似,一个Intent可以被调用组件传递给 ()以获取一个正
在运行的目标服务的连接。这个服务会经由onBind() 方法的调用获取这个Intent对象
(如果服务尚未启动,bindService()会先启动它)。比如说,一个activity可以连接
至前述的音乐回放服务,并提供给用户一个可操作的(用户界面)以对回放进行控制。
这个activity可以调用 bindService() 来建立连接,然后调用服务中定义的对象来影
响回放。
应用程序可以凭借将Intent对象传递给 () ,
(), 以及()和其它类似方法来产生一个广播。Android
会调用所有对此广播有兴趣的广播接收器的 onReceive()方法,将intent传递给它们。
Manifest 文件
当Android启动一个应用程序组件之前,它必须知道那个组件是存在
的。所以,应用程序会在一个manifest文件中声明它的组件,这个文件会
被打包到Android包中。这个.apk文件还将涵括应用程序的代码、文件以
及其它资源。
这个manifest文件以XML作为结构格式,而且对于所有应用程序,都叫做
。为声明一个应用程序组件,它还会做很多额外工作,
比如指明应用程序所需链接到的库的名称(除了默认的Android库之外)
以及声明应用程序期望获得的各种权限。
但manifest文件的主要功能仍然是向Android声明应用程序的组件。举例
说明,一个activity可以如下声明:
<activity>元素的name属性指定了实现了这个activity的 Activity的子类。
icon和label属性指向了包含展示给用户的此activity的图标和标签的资源文
件。
其它组件也以类似的方法声明──<service> 元素用于声明服务,
<receiver> 元素用于声明广播接收器,而 <provider> 元素用于声明内容
提供者。 manifest文件中未进行声明的activity、服务以及内容提供者将不
为系统所见,从而也就不会被运行。然而,广播接收器既可以在manifest
文件中声明,也可以在代码中进行动态的创建,并以调用
()的方式注册至系统。
如前所述,一个activity可以启动另外一个,甚至包括与它不处于同一应用程
序之中的。举个例子说,假设你想让用户看到某个地方的街道地图。而已经存在
一个具有此功能的activity了,那么你的activity所需要做的工作就是把请求信息放
到一个Intent对象里面,并把它传递给startActivity()。于是地图浏览器就会显示那
个地图。而当用户按下BACK键的时候,你的activity又会再一次的显示在屏幕上。
对于用户来说,这看起来就像是地图浏览器是你activity所在的应用程序中的一个
组成部分,其实它是在另外一个应用程序中定义,并运行在那个应用程序的进程
之中的。Android将这两个activity放在同一个任务中来维持一个完整的用户体验。
简单的说,任务就是用户所体验到的“应用程序”。它是安排在一个堆栈中的一
组相关的activity。堆栈中的根activity就是启动了这整个任务的那个──一般情况下,
它就是用户在应用程序加载器中所选择的。而堆栈最上方的activity则是当前运行
的──用户直接对其进行操作的。当一个activity启动另外一个的时候,新的activity
就被压入堆栈,并成为当前运行的activity。而前一个activity仍保持在堆栈之中。
当用户按下BACK键的时候,当前activity出栈,而前一个恢复为当前运行的
activity。
Activity和任务
Activity生命周
期
用户界面User Interface
在一个Android应用中,用户界面是由View 和ViewGroup对象构建的。View与
ViewGroup都有很多种类,而它们都是View类的子类。
View
View对象是Android平台中用户界面体现的基础单位。View类是它称为
“widgets(工具)”的子类的基础,它们提供了诸如文本输入框和按钮之类的
UI对象的完整实现。ViewGroup类同样为其被称为“Layouts(布局)”的子类奠
定了基础,它们提供了象流式布局、表格布局以及相对布局之类的布局架构。
View对象是一个数据体,它的属性存储了用于屏幕上一块矩形区域的布局参数及
内容。并负责这块它所辖的这个矩形区域之中所有测量、布局、焦点转换、卷动
以及按键/触摸手势的处理。作为一个用户界面对象,View同时也担任着用户交
互关键点以及交互事件接受者的角色。
布局
Layout
定义并展现你的视图层次的最常用的方法是使用XML布局文件。如同HTML一样,
XML为布局提供了一种可读的结构。XML中的每个元素都是View或ViewGroup对象(抑
或它们的子类)。View对象是树的叶节点,而ViewGroup对象是树的分支(参阅楼上的
视图层次图)。
XML元素的名称与它体现的Java类相对应。所以一个<TextView>元素将在你的UI中生成
一个TextView,而 <LinearLayout>则创建一个LinearLayout视图组。当你载入一个布局
资源时,Android系统会根据你布局中的元素初始化这些运行时对象。
举例来说,一个包含文本视图和一个按钮的简单垂直布局如下:
<?xml version="" encoding="utf-8"?>
<LinearLayout xmlns:android="
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<TextView android:id="@+id/text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello, I am a TextView" />
<Button android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello, I am a Button" />
</LinearLayout>
请注意:LinearLayout 元素包含了TextView 和Button 对象。你可以在其中另外安置一个
LinearLayout (或其它类型的视图组),以延展这个视图层次,构建更复杂的布局。
用户界面事件UI Events
当你在用户界面中加入了一些视图和工具之后,你可能想要知道如何让它
们与用户交互,进而实现你的动作。如欲获得用户界面事件通知,你需要做以
下两件事情之一:
• 定义一个事件侦听器并将其注册至视图。通常情况下,这是你侦听事件的
主要方式。View类包含了一大堆命名类似 On<什么什么>Listener的接口,每个
都带有一个叫做On<什么什么>()的回调方法。比如:
(用以处理视图中的点击), (用以处理视图中的触屏
事件),以及 (用以处理视图中的设备按键事件)。所
以,如果你希望你的视图在它被”点击”(比如选择了一个按钮)的时候获得
通知,你就要实现OnClickListener,定义它的onClick()回调方法(在其中进行
相应处理),并将它用setOnClickListener()方法注册到视图上。
• 为视图覆写一个现有的回调方法。这种方法主要用于你自己实现了一个
View类,并想侦听其上发生的特定事件。比如说当屏幕被触摸
(onTouchEvent()),当轨迹球发生了移动(onTrackballEvent())或者是设备
上的按键被按下(onKeyDown())。这种方式允许你为自己定制的视图中发生
的每个事件定义默认的行为,并决定是否需要将事件传递给其它的子视图。再
说一次,这些是View类相关的回调方法,所以你只能在你构建自定义组件时定
义它们。
如何在视图中处理用户交互请参见处理用户界面事件文档。
资源和资产Resources and Assets
资源是Android应用程序不可或缺的部分。总体而言,资源是你想包含和引入到
应用程序里面的一些外部元素,比如图片、音频、视频、文本字符串、布局、主题等。
每个Android应用程序包含一个资源目录(res/)和资产目录(assets/),资产不经
常被使用,因为它们的应用程序很少。你仅在需要读取原始字节流时才需要保存数据
为资产。资源和资产目录均驻留在Android项目树的顶端,和源代码目录(src/)处
在同一级上。
资源和资产从表面上看没多大区别,不过总体上,在存储外部内容时资源用得更
多。真正的区别在于任何放置在资源目录里的内容可以通过您的应用程序的R类访问,
这是被Android编译过的。而任何存放在资产目录里的内容会保持它的原始文件格式,
为了读取它,你必须使用AssetManager来以字节流的方式读取文件。所以保持文件
和数据在资源中(res/)中会更方便访问。
目录Directory 资源类型Resource Types
res/anim/ XML文件,它们被编译进逐帧动画(frame by frame animation)或补间动画
(tweened animation)对象
res/drawable/ .png、.、.jpg文件,它们被编译进以下的Drawable资源子类型中:
要获得这种类型的一个资源,可以使用(id)
位图文件
9-patches(可变尺寸的位图)
为了获取资源类型,使用().getDrawable()
注意:放在这里的图像资源可能会被aapt工具自动地进行无损压缩优化。比如,一个真彩色但
并不需要256色的PNG可能会被转换为一个带调色板的8位PNG。这使得同等质量的图片占用更
少的资源。所以我们得意识到这些放在该目录下的二进制图像在生成时可能会发生变化。如果
你想读取一个图像位流并转换成一个位图(bitmap),请把图像文件放在res/raw/目录下,这样可
以避免被自动优化。
res/layout/ 被编译为屏幕布局(或屏幕的一部分)的XML文件。参见布局声明(Declaring
Layout)
res/values/ 可以被编译成很多种类型的资源的XML文件。
注意: 不像其他的res/文件夹,它可以保存任意数量的文件,这些文件保存了要创建资源
的描述,而不是资源本身。XML元素类型控制这些资源应该放在R类的什么地方。
尽管这个文件夹里的文件可以任意命名,不过下面使一些比较典型的文件(文件命名的惯
例是将元素类型包含在该名称之中):
定义数据
定义color drawable和颜色的字符串值(color string values)。使用
()和()分别获得这些资源。
定义尺寸值(dimension value)。使用()获得这
些资源。
定义字符串(string)值(使用()或者
()获取这些资源。getText()会保留在UI字符串上应用的丰富的文本样式)。
• 定义样式(style)对象。
res/xml/ 任意的XML文件,在运行时可以通过调用()读取。
res/raw/ 直接复制到设备中的任意文件。它们无需编译,添加到你的应用程序编译产生的
压缩文件中。要使用这些资源,可以调用(),参数是资源
的ID,即。
数据存储与访问
很多时候我们的软件需要对处理后的数据进行存储或再次访问。
Android为数据存储提供了多种方式,分别有如下几种:
l文件
lSharedPreferences(参数)
lSQLite数据库
l内容提供者(Content provider)
l网络
使用文件进行数据存储
首先给大家介绍使用文件如何对数据进行存储,Activity提供了openFileOutput()方法可以用于把数
据输出到文件中,具体的实现过程与在J2SE环境中保存数据到文件中是一样的。
public class FileActivity extends Activity {
@Override public void onCreate(Bundle savedInstanceState) {
...
FileOutputStream outStream = ("", _PRIVATE);
(“ggggg".getBytes());
();
}
}
openFileOutput()方法的第一参数用于指定文件名称,不能包含路径分隔符“/” ,如果文件不存
在,Android 会自动创建它。创建的文件保存在/data/data/<package name>/files目录,如:
/data/data/ ,通过点击Eclipse菜单“Window”-“Show View”-“Other”
,在对话窗口中展开android文件夹,选择下面的File Explorer视图,然后在File Explorer视图中展
开/data/data/<package name>/files目录就可以看到该文件。
openFileOutput()方法的第二参数用于指定操作模式,有四种模式,分别为:
_PRIVATE = 0
_APPEND = 32768
_WORLD_READABLE = 1
_WORLD_WRITEABLE = 2
使用文件进行数据存储
_PRIVATE:为默认操作模式,代表该文件是私有数据,只能被应用本身访问,
在该模式下,写入的内容会覆盖原文件的内容,如果想把新写入的内容追加到原文件中。可以使
用_APPEND
_APPEND:模式会检查文件是否存在,存在就往文件追加内容,否则就创建新文
件。
_WORLD_READABLE和_WORLD_WRITEABLE用来控制其他应
用是否有权限读写该文件。
MODE_WORLD_READABLE:表示当前文件可以被其他应用读取;
MODE_WORLD_WRITEABLE:表示当前文件可以被其他应用写入。
如果希望文件被其他应用读和写,可以传入:
openFileOutput("", _WORLD_READABLE +
_WORLD_WRITEABLE);
android有一套自己的安全模型,当应用程序(.apk)在安装时系统就会分配给他一个userid,当该应
用要去访问其他资源比如文件的时候,就需要userid匹配。默认情况下,任何应用创建的文件,
sharedpreferences,数据库都应该是私有的(位于/data/data/<package name>/files),其他程序
无法访问。除非在创建时指定了_WORLD_READABLE或者
_WORLD_WRITEABLE ,只有这样其他程序才能正确访问。
使用SharedPreferences进行数据
存储
很多时候我们开发的软件需要向用户提供软件参数设置功能,例如我们常用的QQ,用户可以设置是否
允许陌生人添加自己为好友。对于软件配置参数的保存,如果是window软件通常我们会采用ini文件进
行保存,如果是j2se应用,我们会采用properties属性文件或者xml进行保存。如果是Android应用,我
们最适合采用什么方式保存软件配置参数呢?Android平台给我们提供了一个SharedPreferences类,它
是一个轻量级的存储类,特别适合用于保存软件配置参数。使用SharedPreferences保存数据,其背后
是用xml文件存放数据,文件存放在/data/data/<package name>/shared_prefs目录下:
SharedPreferences sharedPreferences = getSharedPreferences("itcast", _PRIVATE);
Editor editor = ();//获取编辑器
("name", "传智播客");
("age", 4);
();//提交修改
生成的文件内容如下:
<?xml version='' encoding='utf-8' standalone='yes' ?>
<map>
<string name="name">传智播客</string>
<int name="age" value="4" />
</map>
因为SharedPreferences背后是使用xml文件保存数据,getSharedPreferences(name,mode)方法的第一个参数用于指定
该文件的名称,名称不用带后缀,后缀会由Android自动加上。方法的第二个参数指定文件的操作模式,共有四种操作模
式,这四种模式前面介绍使用文件方式保存数据时已经讲解过。如果希望SharedPreferences背后使用的xml文件能被其
他应用读和写,可以指定_WORLD_READABLE和_WORLD_WRITEABLE权限。
另外Activity还提供了另一个getPreferences(mode)方法操作SharedPreferences,这个方法默认使用当前类不带包名的类
名作为文件的名称。
访问SharedPreferences中的数据
访问SharedPreferences中的数据代码如下:
SharedPreferences sharedPreferences = getSharedPreferences("itcast", _PRIVATE);
//getString()第二个参数为缺省值,如果preference中不存在该key,将返回缺省值
String name = ("name", "");
int age = ("age", 1);
如果访问其他应用中的Preference,前提条件是:该preference创建时指定了
_WORLD_READABLE或者_WORLD_WRITEABLE权限。如:有个
<package name>为的应用使用下面语句创建了preference。
getSharedPreferences("itcast", _WORLD_READABLE);
其他应用要访问上面应用的preference,首先需要创建上面应用的Context,然后通过Context 访问
preference ,访问preference时会在应用所在包下的shared_prefs目录找到preference :
Context otherAppsContext = createPackageContext("", _IGNORE_SECURITY);
SharedPreferences sharedPreferences = ("itcast",
_WORLD_READABLE);
String name = ("name", "");
int age = ("age", 0);
如果不通过创建Context访问其他应用的preference,也可以以读取xml文件方式直接访问其他应用preference对应的xml
文件,如:
File xmlFile = new File(“/data/data/<package name>/shared_prefs/”);//<package name>应替换成应用的包名
使用嵌入式关系型SQLite数据库
存储数据
除了可以使用文件或SharedPreferences存储数据,还可以选择使用SQLite数据库存储数据。
在Android平台上,集成了一个嵌入式关系型数据库—SQLite,SQLite3支持 NULL、INTEGER、REAL
(浮点数字)、TEXT(字符串文本)和BLOB(二进制对象)数据类型,虽然它支持的类型只有五种,但实际上
sqlite3也接受varchar(n)、char(n)、decimal(p,s) 等数据类型,只不过在运算或保存时会转成对应的五种数
据类型。 SQLite最大的特点是你可以把各种类型的数据保存到任何字段中,而不用关心字段声明的数据类
型是什么。例如:可以在Integer类型的字段中存放字符串,或者在布尔型字段中存放浮点数,或者在字符
型字段中存放日期型值。 但有一种情况例外:定义为INTEGER PRIMARY KEY的字段只能存储64位整数,
当向这种字段保存除整数以外的数据时,将会产生错误。 另外, SQLite 在解析CREATE TABLE 语句时,
会忽略 CREATE TABLE 语句中跟在字段名后面的数据类型信息,如下面语句会忽略 name字段的类型信
息:
CREATE TABLE person (personid integer primary key autoincrement, name varchar(20))
SQLite可以解析大部分标准SQL语句,如:
查询语句:select * from 表名 where 条件子句 group by 分组字句 having ... order by 排序子句
如:select * from person
select * from person order by id desc
select name from person group by name having count()>1
分页SQL与mysql类似,下面SQL语句获取5条记录,跳过前面*3条记录
select * from Account limit 5 offset 3 或者 select * from Account limit 3,5
插入语句:insert into 表名(字段列表) values(值列表)。如: insert into person(name, age) values(‘传智’,3)
更新语句:update 表名 set 字段名=值 where 条件子句。如:update person set name=‘传智‘ where id=10
删除语句:delete from 表名 where 条件子句。如:delete from person where id=10
使用SQLiteOpenHelper对数据库进
行版本管理
我们在编写数据库应用软件时,需要考虑这样的问题:因为我们开发的软件可能会安装在很多用户的手机上,如果
应用使用到了SQLite数据库,我们必须在用户初次使用软件时创建出应用使用到的数据库表结构及添加一些初始化
记录,另外在软件升级的时候,也需要对数据表结构进行更新。那么,我们如何才能实现在用户初次使用或升级软
件时自动在用户的手机上创建出应用需要的数据库表呢?总不能让我们在每个需要安装此软件的手机上通过手工方
式创建数据库表吧?因为这种需求是每个数据库应用都要面临的,所以在Android系统,为我们提供了一个名为
SQLiteOpenHelper的抽象类,必须继承它才能使用,它是通过对数据库版本进行管理来实现前面提出的需求。
为了实现对数据库版本进行管理,SQLiteOpenHelper类提供了两个重要的方法,分别是onCreate(SQLiteDatabase
db)和onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion),前者用于初次使用软件时生成数据库表,
后者用于升级软件时更新数据库表结构。当调用SQLiteOpenHelper的getWritableDatabase()或者getReadableDatabase
()方法获取用于操作数据库的SQLiteDatabase实例的时候,如果数据库不存在,Android系统会自动生成一个数据
库,接着调用onCreate()方法,onCreate()方法在初次生成数据库时才会被调用,在onCreate()方法里可以生成数
据库表结构及添加一些应用使用到的初始化数据。onUpgrade()方法在数据库的版本发生变化时会被调用,一般在
软件升级时才需改变版本号,而数据库的版本是由程序员控制的,假设数据库现在的版本是1,由于业务的变更,
修改了数据库表结构,这时候就需要升级软件,升级软件时希望更新用户手机里的数据库表结构,为了实现这一目
的,可以把原来的数据库版本设置为2(有同学问设置为3行不行?当然可以,如果你愿意,设置为100也行),并且
在onUpgrade()方法里面实现表结构的更新。当软件的版本升级次数比较多,这时在onUpgrade()方法里面可以根据
原版号和目标版本号进行判断,然后作出相应的表结构及数据更新。
getWritableDatabase()和getReadableDatabase()方法都可以获取一个用于操作数据库的SQLiteDatabase实例。但
getWritableDatabase() 方法以读写方式打开数据库,一旦数据库的磁盘空间满了,数据库就只能读而不能写,倘若
使用的是getWritableDatabase() 方法就会出错。getReadableDatabase()方法先以读写方式打开数据库,如果数据
库的磁盘空间满了,就会打开失败,当打开失败后会继续尝试以只读方式打开数据库。
使用SQLiteOpenHelper对数据库进
行版本管理
public class DatabaseHelper extends SQLiteOpenHelper {
//类没有实例化,是不能用作父类构造器的参数,必须声明为静态
private static final String name = “itcast"; //数据库名称
private static final int version = 1; //数据库版本
public DatabaseHelper(Context context) {
//第三个参数CursorFactory指定在执行查询时获得一个游标实例的工厂类,设置为null,代表使用系统默认的工厂类
super(context, name, null, version);
}
@Override public void onCreate(SQLiteDatabase db) {
("CREATE TABLE IF NOT EXISTS person (personid integer primary key autoincrement, name
varchar(20), age INTEGER)");
}
@Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
//…..
}
}
完,谢谢.