98
— 高高高高高高高高高高高高 ! 北北 北北北北北 www.itcast.cn 3G 高高高高高 Android 高高 高高高

3G 应用开发之 Android

  • Upload
    viveca

  • View
    86

  • Download
    0

Embed Size (px)

DESCRIPTION

3G 应用开发之 Android. 讲师:黎活明. 什么是 3G. 3G ,全称为 3rd Generation ,中文含义就是指第三代数字通信。 - PowerPoint PPT Presentation

Citation preview

Page 1: 3G 应用开发之 Android

—高级软件人才实作培训专家 !

北京传智播客教育 www.itcast.cn

3G 应用开发之 Android

讲师:黎活明

Page 2: 3G 应用开发之 Android

—高级软件人才实作培训专家 !

北京传智播客教育 www.itcast.cn

什么是 3G3G ,全称为 3rd Generation ,中文含义就是指第三代数字通信。所谓 3G ,是指将无线通信与国际互联网等多媒体通信结合的新一代移动通信系统。 3G 只是一种通信技术标准,符合这个标准的技术有WCDMA、 CDMA2000、 TD-SCDMA 三种制式。中国联通使用的是WCDMA (世界上大部分 3G 网络都采用的是该标准) ;中国电信使用的是CDMA2000 (日、韩和北美使用);中国移动使用的是具有自主知识产权的 TD-SCDMA (只有中国才使用 ) 。相对第一代模拟制式手机 (1G) 和第二代 GSM、 CDMA 等数字手机 (2G), 3G 网络能处理图像、音乐、视频等多种媒体形式,提供包括网页浏览、电话会议、电子商务等多种信息服务。第三代与前两代的主要区别是在传输声音和数据的速度上有很大的提升。

由于 3G 商用需要相当浩大的工程,要从目前的 2G 迈向 3G 不可能一下就衔接得上,因此前几年 2.5G 的手机就出现了。符合 2.5G 标准的技术有CDMA2000 1X和 GPRS ,中国联通使用的是 CDMA2000 1X 标准,中国移动使用的是 GPRS 标准。目前,我们可以把 2.5G 移动通信技术看作是2G 迈向 3G 的衔接性技术,在 2.5G 网络下出现了如 WAP 、蓝牙(Bluetoot) 等技术。

Page 3: 3G 应用开发之 Android

—高级软件人才实作培训专家 !

北京传智播客教育 www.itcast.cn

智能手机软件平台智能手机软件平台有:Symbian, Windows Mobile, RIM BlackBerry, Android, iPhone, Palm, Brew, Java/J2ME 。2009 年市场份额 :Symbian 51%RIM BlackBerry 18%iPhone 13.3windows Mobile 9.3%linux 4.6%Android 1.8%

Page 4: 3G 应用开发之 Android

—高级软件人才实作培训专家 !

北京传智播客教育 www.itcast.cn

什么是 Android

Android 一词的本义指“机器人”, Android是Google于 07年 11月 5 日宣布的基于 Linux 平台开源手机操作系统名称,该平台由操作系统、中间件、用户界面和应用软件组成。在国内,联想、戴尔、多普达、飞利浦、中兴、三星、摩托罗拉、等厂商已经推出基于 Android 平台的智能手机。

在 3G 应用开发领域, Android 的发展前景不容小视,也将会成为未来主流的手机操作系统。

Page 5: 3G 应用开发之 Android

—高级软件人才实作培训专家 !

北京传智播客教育 www.itcast.cn

如何安装 Android SDK 和 Eclipse 插件所需开发环境 :JDK 5 或 JDK 6 ( 仅有 JRE 不够 ) Eclipse 3.5 (galileo)

下载 ADT 的 Eclipse 插件 http://dl.google.com/android/ADT-0.9.5.zip

安装 Eclipse 插件 (ADT)启动 Eclipse ,选择 Help > Install New Software ,在出现的对话框里,点击 Add 按钮,在对话框的 name 一栏输入“ ADT” , 然后点击 Archive... ,浏览和选择已经下载的 ADT 插件压缩文件。 点击 OK. 。返回可用软件的视图,你会看到这个插件,然后选择 Developer Tools ( 会选中下面的“ Android Developer Tools” 和 “ Android Editors“) ,点击 Next ,最后重启 Eclipse 。下载 Android SDK :http://dl.google.com/android/android-sdk_r04-windows.zip下载完 SDK 后,把 .zip 文件解压到你电脑上合适位置。启动 Eclipse ,选择 window->preferences ,在打开的视图左边点击 android ,在右边的 SDK Location 中选择 Android SDK所在位置。

Page 6: 3G 应用开发之 Android

—高级软件人才实作培训专家 !

北京传智播客教育 www.itcast.cn

开发第一个 Android 应用打开 Eclipse ,新建项目 ( 点击 FileNewProject) ,在项目列表中展开 Android 目录,选择Android Project ,如下图:

Page 7: 3G 应用开发之 Android

—高级软件人才实作培训专家 !

北京传智播客教育 www.itcast.cn

开发第一个 Android 应用

Page 8: 3G 应用开发之 Android

—高级软件人才实作培训专家 !

北京传智播客教育 www.itcast.cn

开发第一个 Android 应用点击” finish”即可完成项目的创建,创建后的项目已经是一个可运行的 Android 应用,我们可以通过下面方式运行此应用:点击工具栏上手机形状的虚拟设备管理器(简称“ AVD“),如下:

Page 9: 3G 应用开发之 Android

—高级软件人才实作培训专家 !

北京传智播客教育 www.itcast.cn

开发第一个 Android 应用在打开的虚拟设备管理器中创建一个虚拟手机:

Page 10: 3G 应用开发之 Android

—高级软件人才实作培训专家 !

北京传智播客教育 www.itcast.cn

开发第一个 Android 应用在项目上右键点击 run as Android application ,如下图:

Page 11: 3G 应用开发之 Android

—高级软件人才实作培训专家 !

北京传智播客教育 www.itcast.cn

Android 应用程序架构src/ java 原代码存放目录gen/ 自动生成目录gen 目录中存放所有由 Android 开发工具自动生成的文件。目录中最重要的就是 R.java 文件。 这个文件由 Android 开发工具自动产生的。 Android 开发工具会自动根据你放入 res 目录的 xml 界面文件、图标与常量,同步更新修改 R.java 文件。正因为 R.java 文件是由开发工具自动生成的,所以我们应避免手工修改 R.java。 R.java 在应用中起到了字典的作用,它包含了界面、图标、常量等各种资源的 id ,通过 R.java ,应用可以很方便地找到对应资源。另外编绎器也会检查 R.java列表中的资源是否被使用到,没有被使用到的资源不会编绎进软件中,这样可以减少应用在手机占用的空间。res/ 资源 (Resource) 目录在这个目录中我们可以存放应用使用到的各种资源,如 xml 界面文件,图片或数据。具体请看ppt 下方备注栏。AndroidManifest.xml 功能清单文件 这个文件列出了应用程序所提供的功能,在这个文件中,你可以指定应用程序使用到的服务 ( 如电话服务、互联网服务、短信服务、 GPS 服务等等 ) 。另外当你新添加一个 Activity 的时候,也需要在这个文件中进行相应配置,只有配置好后,才能调用此 Activity 。default.properties 项目环境信息,一般是不需要修改此文件

Page 12: 3G 应用开发之 Android

—高级软件人才实作培训专家 !

北京传智播客教育 www.itcast.cn

电话拔号器效果图:

Page 13: 3G 应用开发之 Android

—高级软件人才实作培训专家 !

北京传智播客教育 www.itcast.cn

电话拔号器因为应用要使用手机的电话服务,所以要在清单文件AndroidManifest.xml 中添加电话服务权限 :

<?xml version="1.0" encoding="utf-8"?><manifest xmlns:android="http://schemas.android.com/apk/res/android" package="cn.itcast.action" android:versionCode="1" android:versionName="1.0"> 略 .... <uses-sdk android:minSdkVersion=“6" /> <uses-permission android:name="android.permission.CALL_PHONE"/></manifest>

Page 14: 3G 应用开发之 Android

—高级软件人才实作培训专家 !

北京传智播客教育 www.itcast.cn

电话拔号器界面布局 :<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent" > <TextView android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="@string/inputmobile"/> <EditText android:layout_width="fill_parent" android:layout_height="wrap_content" android:id="@+id/mobile"/> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/button" android:id="@+id/button"/></LinearLayout>

LinearLayout ( 线性布局 )、 AbsoluteLayout(绝对布局 )、 RelativeLayout( 相对布局 )、 TableLayout(表格布局 )、 FrameLayout(帧布局 )

Page 15: 3G 应用开发之 Android

—高级软件人才实作培训专家 !

北京传智播客教育 www.itcast.cn

电话拔号器Activity:public class DialerAction extends Activity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); Button button = (Button)findViewById(R.id.button); button.setOnClickListener(new View.OnClickListener(){

public void onClick(View v) { EditText editText = (EditText)findViewById(R.id.mobile); Intent intent = new Intent(Intent.ACTION_CALL, Uri.parse("tel:"+

editText.getText())); DialerAction.this.startActivity(intent);}

}); }}

Page 16: 3G 应用开发之 Android

—高级软件人才实作培训专家 !

北京传智播客教育 www.itcast.cn

电话拔号器测试步骤 : 1>在 Eclipse 中运行此应用 2>在 Dos窗口中进入 android SDK 安装路径的 tools 目录 , 输入以下命令再开启一个 Android 模拟器 : emulator -data itcast 注: itcast 为用户数据存取文件,如果该文件不存在,默认在 tools 目录创建该文件

3> 在电话扰号器中输入上图现显的电话号码

Page 17: 3G 应用开发之 Android

—高级软件人才实作培训专家 !

北京传智播客教育 www.itcast.cn

短信发送器效果图:

Page 18: 3G 应用开发之 Android

—高级软件人才实作培训专家 !

北京传智播客教育 www.itcast.cn

短信发送器因为应用要使用手机的短信服务,所以要在清单文件AndroidManifest.xml 中添加短信服务权限 :

<?xml version="1.0" encoding="utf-8"?><manifest xmlns:android="http://schemas.android.com/apk/res/android" package="cn.itcast.sms" android:versionCode="1" android:versionName="1.0"> 略 .... <uses-sdk android:minSdkVersion=“4" /> <uses-permission android:name="android.permission.SEND_SMS"/></manifest>

Page 19: 3G 应用开发之 Android

—高级软件人才实作培训专家 !

北京传智播客教育 www.itcast.cn

短信发送器界面布局 :<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical“ android:layout_width="fill_parent“ android:layout_height="fill_parent" > <TextView android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="@string/inputmobile"/> <EditText android:layout_width="fill_parent" android:layout_height="wrap_content" android:id="@+id/mobile"/>

<TextView android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="@string/content"/> <EditText android:layout_width="fill_parent" android:layout_height="wrap_content" android:minLines="3" android:id="@+id/content"/> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/button" android:id="@+id/button"/></LinearLayout>

Page 20: 3G 应用开发之 Android

—高级软件人才实作培训专家 !

北京传智播客教育 www.itcast.cn

短信发送器Activity 主要代码 :

String mobile = mobileView.getText().toString();String content = contentView.getText().toString(); SmsManager smsManager = SmsManager.getDefault(); PendingIntent sentIntent = PendingIntent.getBroadcast(SMSSender.this, 0, new

Intent(), 0);if(content.length()>70){// 如果字数超过 70, 需拆分成多条短信发送

List<String> msgs = smsManager.divideMessage(content); for(String msg : msgs){

smsManager.sendTextMessage(mobile, null, msg, sentIntent, null); //最后二个参数为短信已发送的广播意图 ,最后一个参数为短信对方已收到短信的广播意图 }}else{ smsManager.sendTextMessage(mobile, null, content, sentIntent, null);}Toast.makeText(SMSSender.this, "短信发送完成 ", Toast.LENGTH_LONG).show();

Page 21: 3G 应用开发之 Android

—高级软件人才实作培训专家 !

北京传智播客教育 www.itcast.cn

短信发送器测试步骤 : 1>在 Eclipse 中运行此应用 2>在 Dos窗口中进入 android SDK 安装路径的 tools 目录 , 输入以下命令再开启一个 Android 模拟器 : emulator -data itcast 注: itcast 为用户数据存取文件,如果该文件不存在,默认在 tools 目录创建该文件

3> 在短信发送器的手机号中输入上图现显的电话号码

注:目前 Android 系统对中文短信尚未支持,所以发送中文短信会有乱码,这个问题日后会被解决的。

Page 22: 3G 应用开发之 Android

—高级软件人才实作培训专家 !

北京传智播客教育 www.itcast.cn

数据存储与访问很多时候我们的软件需要对处理后的数据进行存储或再次访问。 Android 为数据存储提供了多种方式,分别有如下几种:

文件SharedPreferencesSQLite 数据库内容提供者( Content provider )网络

Page 23: 3G 应用开发之 Android

—高级软件人才实作培训专家 !

北京传智播客教育 www.itcast.cn

使用文件进行数据存储首先给大家介绍使用文件如何对数据进行存储, Activity 提供了 openFileOutput()方法可以用于把数据输出到文件中,具体的实现过程与在 J2SE环境中保存数据到文件中是一样的。public class FileActivity extends Activity { @Override public void onCreate(Bundle savedInstanceState) { ... FileOutputStream outStream = this.openFileOutput("itcast.txt", Context.MODE_PRIVATE); outStream.write(" 传智播客 ".getBytes()); outStream.close(); }}

openFileOutput()方法的第一参数用于指定文件名称,不能包含路径分隔符“ /” ,如果文件不存在, Android 会自动创建它。创建的文件保存在 /data/data/<package name>/files 目录,如: /data/data/cn.itcast.action/files/itcast.txt ,通过点击 Eclipse菜单“ Window”-“Show View”-“Other” ,在对话窗口中展开 android 文件夹,选择下面的 File Explorer 视图,然后在 File Explorer 视图中展开 /data/data/<package name>/files 目录就可以看到该文件。openFileOutput()方法的第二参数用于指定操作模式,有四种模式,分别为: Context.MODE_PRIVATE = 0Context.MODE_APPEND = 32768Context.MODE_WORLD_READABLE = 1Context.MODE_WORLD_WRITEABLE = 2

Page 24: 3G 应用开发之 Android

—高级软件人才实作培训专家 !

北京传智播客教育 www.itcast.cn

使用文件进行数据存储Context.MODE_PRIVATE :为默认操作模式,代表该文件是私有数据,只能被应用本身访问,在该模式下,写入的内容会覆盖原文件的内容,如果想把新写入的内容追加到原文件中。可以使用 Context.MODE_APPENDContext.MODE_APPEND :模式会检查文件是否存在,存在就往文件追加内容,否则就创建新文件。Context.MODE_WORLD_READABLE和 Context.MODE_WORLD_WRITEABLE 用来控制其他应用是否有权限读写该文件。MODE_WORLD_READABLE :表示当前文件可以被其他应用读取;MODE_WORLD_WRITEABLE :表示当前文件可以被其他应用写入。如果希望文件被其他应用读和写,可以传入: openFileOutput("itcast.txt", Context.MODE_WORLD_READABLE + Context.MODE_WORLD_WRITEABLE);

android 有一套自己的安全模型,当应用程序 (.apk) 在安装时系统就会分配给他一个 userid ,当该应用要去访问其他资源比如文件的时候,就需要 userid匹配。默认情况下,任何应用创建的文件, sharedpreferences ,数据库都应该是私有的(位于 /data/data/<package name>/files ),其他程序无法访问。除非在创建时指定了 Context.MODE_WORLD_READABLE 或者Context.MODE_WORLD_WRITEABLE ,只有这样其他程序才能正确访问。

Page 25: 3G 应用开发之 Android

—高级软件人才实作培训专家 !

北京传智播客教育 www.itcast.cn

读取文件内容如果要打开存放在 /data/data/<package name>/files 目录应用私有的文件,可以使用 Activity 提供 openFileInput()方法。FileInputStream inStream = this.getContext().openFileInput("itcast.txt");Log.i("FileTest", readInStream(inStream));readInStream() 的方法请看本页下面备注。

或者直接使用文件的绝对路径:File file = new File("/data/data/cn.itcast.action/files/itcast.txt");FileInputStream inStream = new FileInputStream(file);Log.i("FileTest", readInStream(inStream));注意:上面文件路径中的“ cn.itcast.action” 为应用所在包,当你在编写代码时应替换为你自己应用使用的包。对于私有文件只能被创建该文件的应用访问,如果希望文件能被其他应用读和写,可以在创建文件时,指定 Context.MODE_WORLD_READABLE和 Context.MODE_WORLD_WRITEABLE 权限。

Activity还提供了 getCacheDir()和 getFilesDir()方法:getCacheDir()方法用于获取 /data/data/<package name>/cache 目录getFilesDir()方法用于获取 /data/data/<package name>/files 目录

Page 26: 3G 应用开发之 Android

—高级软件人才实作培训专家 !

北京传智播客教育 www.itcast.cn

把文件存放在 SDCard使用 Activity的 openFileOutput()方法保存文件,文件是存放在手机空间上,一般手机的存储空间不是很大,存放些小文件还行,如果要存放像视频这样的大文件,是不可行的。对于像视频这样的大文件,我们可以把它存放在 SDCard。 SDCard 是干什么的?你可以把它看作是移动硬盘或 U盘。

在模拟器中使用 SDCard ,你需要先创建一张 SDCard卡(当然不是真的 SDCard ,只是镜像文件)。创建 SDCard 可以在 Eclipse创建模拟器时随同创建,也可以使用 DOS命令进行创建,如下:在 Dos窗口中进入 android SDK 安装路径的 tools 目录,输入以下命令创建一张容量为 2G的 SDCard ,文件后缀可以随便取,建议使用 .img :mksdcard 2048M D:\AndroidTool\sdcard.img

在程序中访问 SDCard ,你需要申请访问 SDCard 的权限。在 AndroidManifest.xml 中加入访问 SDCard 的权限如下 :<!-- 在 SDCard 中创建与删除文件权限 --><uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/><!-- 往 SDCard写入数据权限 --><uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

Page 27: 3G 应用开发之 Android

—高级软件人才实作培训专家 !

北京传智播客教育 www.itcast.cn

把文件存放在 SDCard要往 SDCard存放文件,程序必须先判断手机是否装有 SDCard ,并且可以进行读写。注意:访问 SDCard必须在 AndroidManifest.xml 中加入访问 SDCard 的权限if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)){ File sdCardDir = Environment.getExternalStorageDirectory();//获取 SDCard 目录 File saveFile = new File(sdCardDir, “itcast.txt”);

FileOutputStream outStream = new FileOutputStream(saveFile);outStream.write(" 传智播客 ".getBytes());outStream.close();

}Environment.getExternalStorageState()方法用于获取 SDCard 的状态,如果手机装有 SDCard ,并且可以进行读写,那么方法返回的状态等于 Environment.MEDIA_MOUNTED 。Environment.getExternalStorageDirectory()方法用于获取 SDCard 的目录,当然要获取 SDCard的目录,你也可以这样写:File sdCardDir = new File("/sdcard"); //获取 SDCard 目录File saveFile = new File(sdCardDir, "itcast.txt"); // 上面两句代码可以合成一句: File saveFile = new File("/sdcard/itcast.txt");FileOutputStream outStream = new FileOutputStream(saveFile);outStream.write(" 传智播客 test".getBytes());outStream.close();

Page 28: 3G 应用开发之 Android

—高级软件人才实作培训专家 !

北京传智播客教育 www.itcast.cn

使用 SAX 或者 DOM 或者 pull读取 XML 文件在 Android 平台上可以使用 Simple API for XML(SAX) 、 Document Object Model(DOM)和 Android附带的 pull解析器解析 XML 文件。 下面是本例子要解析的 XML 文件:

文件名称: itcast.xml<?xml version="1.0" encoding="UTF-8"?><persons>

<person id="23"><name>李明 </name><age>30</age>

</person><person id="20">

<name>李向梅 </name><age>25</age>

</person></persons>

例子定义了一个 javabean 用于存放上面解析出来的 xml 内容, 这个 javabean为 Person ,代码请见本页下面备注:

Page 29: 3G 应用开发之 Android

—高级软件人才实作培训专家 !

北京传智播客教育 www.itcast.cn

使用 SAX读取 XML 文件SAX 是一个解析速度快并且占用内存少的 xml解析器,非常适合用于 Android 等移动设备。 SAX解析 XML文件采用的是事件驱动,也就是说,它并不需要解析完整个文档,在按内容顺序解析文档的过程中, SAX会判断当前读到的字符是否合法 XML语法中的某部分,如果符合就会触发事件。所谓事件,其实就是一些回调( callback )方法,这些方法 (事件 )定义在 ContentHandler 接口。下面是一些 ContentHandler 接口常用的方法:startDocument()当遇到文档的开头的时候,调用这个方法,可以在其中做一些预处理的工作。endDocument()和上面的方法相对应,当文档结束的时候,调用这个方法,可以在其中做一些善后的工作。 startElement(String namespaceURI, String localName, String qName, Attributes atts) 当读到一个开始标签的时候,会触发这个方法。 namespaceURI 就是命名空间, localName 是不带命名空间前缀的标签名, qName 是带命名空间前缀的标签名。通过 atts 可以得到所有的属性名和相应的值。要注意的是 SAX 中一个重要的特点就是它的流式处理,当遇到一个标签的时候,它并不会纪录下以前所碰到的标签,也就是说,在 startElement()方法中,所有你所知道的信息,就是标签的名字和属性,至于标签的嵌套结构,上层标签的名字,是否有子元属等等其它与结构相关的信息,都是不得而知的,都需要你的程序来完成。这使得 SAX 在编程处理上没有 DOM 来得那么方便。endElement(String uri, String localName, String name)这个方法和上面的方法相对应,在遇到结束标签的时候,调用这个方法。characters(char[] ch, int start, int length) 这个方法用来处理在 XML 文件中读到的内容,第一个参数用于存放文件的内容,后面两个参数是读到的字符串在这个数组中的起始位置和长度,使用 new String(ch,start,length) 就可以获取内容。

Page 30: 3G 应用开发之 Android

—高级软件人才实作培训专家 !

北京传智播客教育 www.itcast.cn

使用 SAX读取 XML 文件只要为 SAX 提供实现 ContentHandler 接口的类,那么该类就可以得到通知事件(实际上就是 SAX调用了该类中的回调方法)。因为 ContentHandler 是一个接口,在使用的时候可能会有些不方便,因此, SAX还为其制定了一个 Helper类: DefaultHandler ,它实现了这个接口,但是其所有的方法体都为空,在实现的时候,你只需要继承这个类,然后重载相应的方法即可。使用 SAX解析 itcast.xml 的代码如下:public static List<Person> readXML(InputStream inStream) { try {

SAXParserFactory spf = SAXParserFactory.newInstance();SAXParser saxParser = spf.newSAXParser(); //创建解析器//设置解析器的相关特性, http://xml.org/sax/features/namespaces = true 表示开启命名空间特性 saxParser.setProperty("http://xml.org/sax/features/namespaces",true);XMLContentHandler handler = new XMLContentHandler();saxParser.parse(inStream, handler);inStream.close();return handler.getPersons();

} catch (Exception e) {e.printStackTrace();

} return null;}

SAX 支持已内置到 JDK1.5 中,你无需添加任何的 jar 文件。关于 XMLContentHandler 的代码实现请看本页下面备注。

Page 31: 3G 应用开发之 Android

—高级软件人才实作培训专家 !

北京传智播客教育 www.itcast.cn

使用 DOM读取 XML 文件除了可以使用 SAX解析 XML 文件,大家也可以使用熟悉的 DOM 来解析 XML 文件。 DOM解析 XML 文件时,会将 XML 文件的所有内容读取到内存中,然后允许您使用 DOM API遍历 XML树、检索所需的数据。使用 DOM 操作 XML 的代码看起来比较直观,并且,在某些方面比基于 SAX 的实现更加简单。但是,因为 DOM 需要将 XML 文件的所有内容读取到内存中,所以内存的消耗比较大,特别对于运行 Android 的移动设备来说,因为设备的资源比较宝贵,所以建议还是采用 SAX 来解析 XML 文件,当然,如果 XML 文件的内容比较小采用 DOM 是可行的。

代码请看本页下方备注

Page 32: 3G 应用开发之 Android

—高级软件人才实作培训专家 !

北京传智播客教育 www.itcast.cn

使用 Pull解析器读取 XML 文件除了可以使用 SAX和 DOM解析 XML 文件,大家也可以使用 Android 内置的 Pull解析器解析 XML 文件。 Pull解析器的运行方式与 SAX 解析器相似。它提供了类似的事件,如:开始元素和结束元素事件,使用parser.next() 可以进入下一个元素并触发相应事件。事件将作为数值代码被发送,因此可以使用一个switch 对感兴趣的事件进行处理。当元素开始解析时,调用 parser.nextText()方法可以获取下一个 Text类型元素的值。

使用 Pull解析器读取 itcast.xml 的代码在本页下方备注

Pull解析器的源码及文档下载网址: http://www.xmlpull.org/

Page 33: 3G 应用开发之 Android

—高级软件人才实作培训专家 !

北京传智播客教育 www.itcast.cn

使用 Pull解析器生成 XML 文件有些时候,我们需要生成一个 XML 文件,生成 XML 文件的方法有很多,如:可以只使用一个StringBuilder 组拼 XML 内容,然后把内容写入到文件中;或者使用 DOM API生成 XML 文件,或者也可以使用 pull解析器生成 XML 文件,这里推荐大家使用 Pull解析器。

使用 Pull解析器生成一个与 itcast.xml 文件内容相同的 myitcast.xml 文件,代码在本页下方备注

使用代码如下(生成 XML 文件):File xmlFile = new File("myitcast.xml");FileOutputStream outStream = new FileOutputStream(xmlFile);OutputStreamWriter outStreamWriter = new OutputStreamWriter(outStream, "UTF-8");BufferedWriter writer = new BufferedWriter(outStreamWriter);writeXML(persons, writer);writer.flush();writer.close();如果只想得到生成的 xml 内容,可以使用 StringWriter :StringWriter writer = new StringWriter();writeXML(persons, writer);String content = writer.toString();

Page 34: 3G 应用开发之 Android

—高级软件人才实作培训专家 !

北京传智播客教育 www.itcast.cn

使用 SharedPreferences进行数据存储很多时候我们开发的软件需要向用户提供软件参数设置功能,例如我们常用的 QQ ,用户可以设置是否允许陌生人添加自己为好友。对于软件配置参数的保存,如果是 window 软件通常我们会采用 ini 文件进行保存,如果是 j2se 应用,我们会采用 properties属性文件进行保存。如果是 Android 应用,我们最适合采用什么方式保存软件配置参数呢? Android 平台给我们提供了一个 SharedPreferences类,它是一个轻量级的存储类,特别适合用于保存软件配置参数。使用 SharedPreferences保存数据,其背后是用 xml 文件存放数据,文件存放在 /data/data/<package name>/shared_prefs 目录下:SharedPreferences sharedPreferences = getSharedPreferences("itcast", Context.MODE_PRIVATE);Editor editor = sharedPreferences.edit();//获取编辑器editor.putString("name", " 传智播客 ");editor.putInt("age", 4);editor.commit();// 提交修改生成的 itcast.xml 文件内容如下:<?xml version='1.0' encoding='utf-8' standalone='yes' ?><map><string name="name"> 传智播客 </string><int name="age" value="4" /></map>因为 SharedPreferences背后是使用 xml 文件保存数据, getSharedPreferences(name,mode)方法的第一个参数用于指定该文件的名称,名称不用带后缀,后缀会由 Android 自动加上。方法的第二个参数指定文件的操作模式,共有四种操作模式,这四种模式前面介绍使用文件方式保存数据时已经讲解过。如果希望 SharedPreferences背后使用的 xml 文件能被其他应用读和写,可以指定 Context.MODE_WORLD_READABLE和 Context.MODE_WORLD_WRITEABLE 权限。另外 Activity还提供了另一个 getPreferences(mode)方法操作 SharedPreferences ,这个方法默认使用当前类不带包名的类名作为文件的名称。

Page 35: 3G 应用开发之 Android

—高级软件人才实作培训专家 !

北京传智播客教育 www.itcast.cn

访问 SharedPreferences 中的数据访问 SharedPreferences 中的数据代码如下:SharedPreferences sharedPreferences = getSharedPreferences("itcast", Context.MODE_PRIVATE);//getString() 第二个参数为缺省值,如果 preference 中不存在该 key ,将返回缺省值String name = sharedPreferences.getString("name", "");int age = sharedPreferences.getInt("age", 1);

如果访问其他应用中的 Preference ,前提条件是:该 preference创建时指定了Context.MODE_WORLD_READABLE 或者 Context.MODE_WORLD_WRITEABLE 权限。如:有个<package name>为 cn.itcast.action 的应用使用下面语句创建了 preference。getSharedPreferences("itcast", Context.MODE_WORLD_READABLE);其他应用要访问上面应用的 preference ,首先需要创建上面应用的 Context ,然后通过 Context 访问preference ,访问 preference时会在应用所在包下的 shared_prefs 目录找到 preference :Context otherAppsContext = createPackageContext("cn.itcast.action", Context.CONTEXT_IGNORE_SECURITY);SharedPreferences sharedPreferences = otherAppsContext.getSharedPreferences("itcast", Context.MODE_WORLD_READABLE);String name = sharedPreferences.getString("name", "");int age = sharedPreferences.getInt("age", 0);

如果不通过创建 Context访问其他应用的 preference ,可以以读取 xml 文件方式直接访问其他应用 preference 对应的xml 文件,如: File xmlFile = new File(“/data/data/<package name>/shared_prefs/itcast.xml”);//<package name> 应替换成应用的包名

Page 36: 3G 应用开发之 Android

—高级软件人才实作培训专家 !

北京传智播客教育 www.itcast.cn

使用嵌入式关系型 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

Page 37: 3G 应用开发之 Android

—高级软件人才实作培训专家 !

北京传智播客教育 www.itcast.cn

使用 SQLiteDatabase 操作 SQLite 数据库Android 提供了一个名为 SQLiteDatabase 的类,该类封装了一些操作数据库的 API ,使用该类可以完成对数据进行添加 (Create) 、查询 (Retrieve) 、更新 (Update) 和删除 (Delete) 操作(这些操作简称为 CRUD )。对 SQLiteDatabase 的学习,我们应该重点掌握 execSQL()和 rawQuery()方法。 execSQL()方法可以执行 insert、 delete、 update和 CREATE TABLE之类有更改行为的 SQL语句; rawQuery()方法可以执行 select语句。execSQL()方法的使用例子:SQLiteDatabase db = ....;db.execSQL("insert into person(name, age) values(' 传智播客 ', 4)");db.close();执行上面 SQL语句会往 person表中添加进一条记录,在实际应用中, 语句中的“传智播客”这些参数值应该由用户输入界面提供,如果把用户输入的内容原样组拼到上面的 insert语句, 当用户输入的内容含有单引号时,组拼出来的 SQL语句就会存在语法错误。要解决这个问题需要对单引号进行转义,也就是把单引号转换成两个单引号。有些时候用户往往还会输入像“ & ” 这些特殊 SQL 符号,为保证组拼好的 SQL语句语法正确,必须对 SQL语句中的这些特殊 SQL 符号都进行转义,显然,对每条 SQL语句都做这样的处理工作是比较烦琐的。 SQLiteDatabase类提供了一个重载后的 execSQL(String sql, Object[] bindArgs)方法,使用这个方法可以解决前面提到的问题,因为这个方法支持使用占位符参数 (?) 。使用例子如下:SQLiteDatabase db = ....;db.execSQL("insert into person(name, age) values(?,?)", new Object[]{" 传智播客 ", 4}); db.close();execSQL(String sql, Object[] bindArgs)方法的第一个参数为 SQL语句,第二个参数为 SQL语句中占位符参数的值,参数值在数组中的顺序要和占位符的位置对应。

Page 38: 3G 应用开发之 Android

—高级软件人才实作培训专家 !

北京传智播客教育 www.itcast.cn

使用 SQLiteDatabase 操作 SQLite 数据库SQLiteDatabase的 rawQuery() 用于执行 select语句,使用例子如下: SQLiteDatabase db = ....;Cursor cursor = db.rawQuery(“select * from person”, null);while (cursor.moveToNext()) {

int personid = cursor.getInt(0); //获取第一列的值 , 第一列的索引从 0 开始String name = cursor.getString(1);//获取第二列的值int age = cursor.getInt(2);//获取第三列的值

}cursor.close();db.close();

rawQuery()方法的第一个参数为 select语句;第二个参数为 select语句中占位符参数的值,如果 select语句没有使用占位符,该参数可以设置为 null 。带占位符参数的 select语句使用例子如下:Cursor cursor = db.rawQuery("select * from person where name like ? and age=?", new String[]{"% 传智 %", "4"});

Cursor 是结果集游标,用于对结果集进行随机访问,如果大家熟悉 jdbc , 其实 Cursor与 JDBC 中的ResultSet 作用很相似。使用 moveToNext()方法可以将游标从当前行移动到下一行,如果已经移过了结果集的最后一行,返回结果为 false ,否则为 true 。另外 Cursor 还有常用的 moveToPrevious()方法(用于将游标从当前行移动到上一行,如果已经移过了结果集的第一行,返回值为 false ,否则为true )、 moveToFirst()方法(用于将游标移动到结果集的第一行,如果结果集为空,返回值为 false ,否则为 true )和 moveToLast()方法(用于将游标移动到结果集的最后一行,如果结果集为空,返回值为false ,否则为 true ) 。

Page 39: 3G 应用开发之 Android

—高级软件人才实作培训专家 !

北京传智播客教育 www.itcast.cn

使用 SQLiteDatabase 操作 SQLite 数据库除了前面给大家介绍的 execSQL()和 rawQuery()方法, SQLiteDatabase还专门提供了对应于添加、删除、更新、查询的操作方法: insert()、 delete()、 update()和 query() 。这些方法实际上是给那些不太了解 SQL语法的菜鸟使用的,对于熟悉 SQL语法的程序员而言,直接使用 execSQL()和 rawQuery()方法执行 SQL语句就能完成数据的添加、删除、更新、查询操作。Insert()方法用于添加数据,各个字段的数据使用 ContentValues进行存放。 ContentValues类似于 MAP ,相对于 MAP ,它提供了存取数据对应的 put(String key, Xxx value)和 getAsXxx(String key)方法, key为字段名称, value 为字段值, Xxx 指的是各种常用的数据类型,如: String、 Integer 等。SQLiteDatabase db = databaseHelper.getWritableDatabase();ContentValues values = new ContentValues();values.put("name", " 传智播客 ");values.put("age", 4);long rowid = db.insert(“person”, null, values);//返回新添记录的行号,与主键 id 无关不管第三个参数是否包含数据,执行 Insert()方法必然会添加一条记录,如果第三个参数为空,会添加一条除主键之外其他字段值为 Null 的记录。 Insert()方法内部实际上通过构造 insert语句完成数据的添加, Insert()方法的第二个参数用于指定空值字段的名称,相信大家对此参数会感到疑惑,此参数的作用是干嘛的?是这样的:如果第三个参数 values 为 Null 或者元素个数为 0 , Insert()方法必然要添加一条除了主键之外其它字段为 Null值的记录,为了满足这条 insert语句的语法, insert语句必须给定一个字段名,如: insert into person(name) values(NULL) ,倘若不给定字段名 , insert语句就成了这样: insert into person() values() ,显然这不满足标准 SQL 的语法。对于字段名,建议使用主键之外的字段,如果使用了INTEGER类型的主键字段,执行类似 insert into person(personid) values(NULL)的 insert语句后,该主键字段值也不会为 NULL 。如果第三个参数 values 不为 Null并且元素的个数大于 0 ,可以把第二个参数设置为 null 。

Page 40: 3G 应用开发之 Android

—高级软件人才实作培训专家 !

北京传智播客教育 www.itcast.cn

使用 SQLiteDatabase 操作 SQLite 数据库delete()方法的使用:SQLiteDatabase db = databaseHelper.getWritableDatabase();db.delete("person", "personid<?", new String[]{"2"});db.close();上面代码用于从 person表中删除 personid 小于 2 的记录。

update()方法的使用:SQLiteDatabase db = databaseHelper.getWritableDatabase();ContentValues values = new ContentValues();values.put(“name”, “ 传智播客” );//key 为字段名, value 为值db.update("person", values, "personid=?", new String[]{"1"}); db.close();上面代码用于把 person表中 personid 等于 1 的记录的 name 字段的值改为“传智播客”。

Page 41: 3G 应用开发之 Android

—高级软件人才实作培训专家 !

北京传智播客教育 www.itcast.cn

使用 SQLiteDatabase 操作 SQLite 数据库query()方法实际上是把 select语句拆分成了若干个组成部分,然后作为方法的输入参数:SQLiteDatabase db = databaseHelper.getWritableDatabase();Cursor cursor = db.query("person", new String[]{"personid,name,age"}, "name like ?", new String[]{"% 传智 %"}, null, null, "personid desc", "1,2");while (cursor.moveToNext()) { int personid = cursor.getInt(0); //获取第一列的值 , 第一列的索引从 0 开始 String name = cursor.getString(1);//获取第二列的值 int age = cursor.getInt(2);//获取第三列的值}cursor.close();db.close(); 上面代码用于从 person表中查找 name 字段含有“传智”的记录,匹配的记录按 personid降序排序,对排序后的结果略过第一条记录,只获取 2条记录。query(table, columns, selection, selectionArgs, groupBy, having, orderBy, limit) 方法各参数的含义:table :表名。相当于 select语句 from关键字后面的部分。如果是多表联合查询,可以用逗号将两个表名分开。columns :要查询出来的列名。相当于 select语句 select关键字后面的部分。selection :查询条件子句,相当于 select语句 where关键字后面的部分,在条件子句允许使用占位符“ ?”selectionArgs :对应于 selection语句中占位符的值,值在数组中的位置与占位符在语句中的位置必须一致,否则就会有异常。groupBy :相当于 select语句 group by关键字后面的部分having :相当于 select语句 having关键字后面的部分orderBy :相当于 select语句 order by关键字后面的部分,如: personid desc, age asc;limit :指定偏移量和获取的记录数,相当于 select语句 limit关键字后面的部分。

Page 42: 3G 应用开发之 Android

—高级软件人才实作培训专家 !

北京传智播客教育 www.itcast.cn

使用 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()方法先以读写方式打开数据库,如果数据库的磁盘空间满了,就会打开失败,当打开失败后会继续尝试以只读方式打开数据库。

Page 43: 3G 应用开发之 Android

—高级软件人才实作培训专家 !

北京传智播客教育 www.itcast.cn

使用 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) { db.execSQL("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) { db.execSQL("DROP TABLE IF EXISTS person"); onCreate(db); }}

上面 onUpgrade()方法在数据库版本每次发生变化时都会把用户手机上的数据库表删除,然后再重新创建。一般在实际项目中是不能这样做的,正确的做法是在更新数据库表结构时,还要考虑用户存放于数据库中的数据不会丢失。

Page 44: 3G 应用开发之 Android

—高级软件人才实作培训专家 !

北京传智播客教育 www.itcast.cn

使用 SQLiteOpenHelper获取用于操作数据库的 SQLiteDatabase实例public class DatabaseHelper extends SQLiteOpenHelper { private static final String name = "itcast"; // 数据库名称 private static final int version = 1; // 数据库版本 ......略}public class HelloActivity extends Activity { @Override public void onCreate(Bundle savedInstanceState) { ...... Button button =(Button) this.findViewById(R.id.button); button.setOnClickListener(new View.OnClickListener(){

public void onClick(View v) {DatabaseHelper databaseHelper = new DatabaseHelper(HelloActivity.this);SQLiteDatabase db = databaseHelper.getWritableDatabase();db.execSQL("insert into person(name, age) values(?,?)", new Object[]{" 传智播客 ", 4});db.close();

}}); }}

第一次调用 getWritableDatabase()或 getReadableDatabase()方法后, SQLiteOpenHelper 会缓存当前的SQLiteDatabase实例, SQLiteDatabase实例正常情况下会维持数据库的打开状态,所以在你不再需要SQLiteDatabase实例时,请及时调用 close()方法释放资源。一旦 SQLiteDatabase实例被缓存,多次调用 getWritableDatabase()或 getReadableDatabase()方法得到的都是同一实例。

Page 45: 3G 应用开发之 Android

—高级软件人才实作培训专家 !

北京传智播客教育 www.itcast.cn

使用事务操作 SQLite 数据库使用 SQLiteDatabase的 beginTransaction()方法可以开启一个事务,程序执行到 endTransaction() 方法时会检查事务的标志是否为成功,如果为成功则提交事务,否则回滚事务。当应用需要提交事务,必须在程序执行到 endTransaction()方法之前使用 setTransactionSuccessful() 方法设置事务的标志为成功,如果不调用 setTransactionSuccessful() 方法,默认会回滚事务。使用例子如下: SQLiteDatabase db = ....;db.beginTransaction();// 开始事务try { db.execSQL("insert into person(name, age) values(?,?)", new Object[]{" 传智播客 ", 4}); db.execSQL("update person set name=? where personid=?", new Object[]{" 传智 ", 1}); db.setTransactionSuccessful();//调用此方法会在执行到 endTransaction() 时提交当前事务,如果不调用此方法会回滚事务} finally { db.endTransaction();// 由事务的标志决定是提交事务,还是回滚事务} db.close();

上面两条 SQL语句在同一个事务中执行。

Page 46: 3G 应用开发之 Android

—高级软件人才实作培训专家 !

北京传智播客教育 www.itcast.cn

使用 ContentProvider共享数据当应用继承 ContentProvider类,并重写该类用于提供数据和存储数据的方法,就可以向其他应用共享其数据。虽然使用其他方法也可以对外共享数据,但数据访问方式会因数据存储的方式而不同,如:采用文件方式对外共享数据,需要进行文件操作读写数据;采用 sharedpreferences共享数据,需要使用sharedpreferences API读写数据。而使用 ContentProvider共享数据的好处是统一了数据访问方式。当应用需要通过 ContentProvider 对外共享数据时,第一步需要继承 ContentProvider并重写下面方法:public class PersonContentProvider extends ContentProvider{ public boolean onCreate() public Uri insert(Uri uri, ContentValues values) public int delete(Uri uri, String selection, String[] selectionArgs) public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) public String getType(Uri uri)}

第二步需要在 AndroidManifest.xml 使用 <provider> 对该 ContentProvider进行配置,为了能让其他应用找到该 ContentProvider , ContentProvider 采用了 authorities (主机名 / 域名)对它进行唯一标识,你可以把 ContentProvider 看作是一个网站(想想,网站也是提供数据者), authorities 就是他的域名:<manifest .... > <application android:icon="@drawable/icon" android:label="@string/app_name"> <provider android:name=".PersonContentProvider" android:authorities="cn.itcast.provider.personprovider"/> </application></manifest>注意:一旦应用继承了 ContentProvider类,后面我们就会把这个应用称为 ContentProvider (内容提供者)。

Page 47: 3G 应用开发之 Android

—高级软件人才实作培训专家 !

北京传智播客教育 www.itcast.cn

Uri介绍Uri 代表了要操作的数据, Uri 主要包含了两部分信息: 1》需要操作的 ContentProvider , 2》对ContentProvider 中的什么数据进行操作,一个 Uri 由以下几部分组成:

ContentProvider (内容提供者)的 scheme 已经由 Android 所规定, scheme 为: content://主机名(或叫 Authority )用于唯一标识这个 ContentProvider ,外部调用者可以根据这个标识来找到它。路径( path )可以用来表示我们要操作的数据,路径的构建应根据业务而定,如下 :要操作 person表中 id为 10 的记录,可以构建这样的路径 :/person/10要操作 person表中 id为 10 的记录的 name 字段, person/10/name要操作 person表中的所有记录,可以构建这样的路径 :/person要操作 xxx表中的记录,可以构建这样的路径 :/xxx当然要操作的数据不一定来自数据库,也可以是文件等他存储方式,如下 :要操作 xml 文件中 person节点下的 name节点,可以构建这样的路径: /person/name如果要把一个字符串转换成 Uri ,可以使用 Uri类中的 parse()方法,如下:Uri uri = Uri.parse("content://cn.itcast.provider.personprovider/person")

Page 48: 3G 应用开发之 Android

—高级软件人才实作培训专家 !

北京传智播客教育 www.itcast.cn

UriMatcher类使用介绍因为 Uri 代表了要操作的数据,所以我们很经常需要解析 Uri ,并从 Uri 中获取数据。 Android 系统提供了两个用于操作 Uri 的工具类,分别为 UriMatcher 和 ContentUris 。掌握它们的使用,会便于我们的开发工作。UriMatcher类用于匹配 Uri ,它的用法如下:首先第一步把你需要匹配 Uri路径全部给注册上,如下://常量 UriMatcher.NO_MATCH表示不匹配任何路径的返回码UriMatcher sMatcher = new UriMatcher(UriMatcher.NO_MATCH);// 如果match()方法匹配 content://cn.itcast.provider.personprovider/person路径,返回匹配码为 1sMatcher.addURI(“cn.itcast.provider.personprovider”, “person”, 1);// 添加需要匹配 uri ,如果匹配就会返回匹配码// 如果match()方法匹配 content://cn.itcast.provider.personprovider/person/230路径,返回匹配码为 2sMatcher.addURI(“cn.itcast.provider.personprovider”, “person/#”, 2);//#号为通配符switch (sMatcher.match(Uri.parse("content://cn.itcast.provider.personprovider/person/10"))) { case 1 break; case 2 break; default:// 不匹配 break;}

注册完需要匹配的 Uri 后,就可以使用 sMatcher.match(uri)方法对输入的 Uri进行匹配,如果匹配就返回匹配码,匹配码是调用 addURI()方法传入的第三个参数,假设匹配 content://cn.itcast.provider.personprovider/person路径,返回的匹配码为 1

Page 49: 3G 应用开发之 Android

—高级软件人才实作培训专家 !

北京传智播客教育 www.itcast.cn

ContentUris类使用介绍ContentUris类用于获取 Uri路径后面的 ID 部分,它有两个比较实用的方法:withAppendedId(uri, id) 用于为路径加上 ID 部分:Uri uri = Uri.parse("content://cn.itcast.provider.personprovider/person")Uri resultUri = ContentUris.withAppendedId(uri, 10); //生成后的 Uri 为: content://cn.itcast.provider.personprovider/person/10

parseId(uri)方法用于从路径中获取 ID 部分:Uri uri = Uri.parse("content://cn.itcast.provider.personprovider/person/10")long personid = ContentUris.parseId(uri);//获取的结果为 :10

Page 50: 3G 应用开发之 Android

—高级软件人才实作培训专家 !

北京传智播客教育 www.itcast.cn

使用 ContentProvider共享数据ContentProvider类主要方法的作用:public boolean onCreate()该方法在 ContentProvider创建后就会被调用, Android 在系统启动时就会创建 ContentProvider 。public Uri insert(Uri uri, ContentValues values)该方法用于供外部应用往 ContentProvider添加数据。public int delete(Uri uri, String selection, String[] selectionArgs)该方法用于供外部应用从 ContentProvider删除数据。public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs)该方法用于供外部应用更新 ContentProvider 中的数据。public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder)该方法用于供外部应用从 ContentProvider 中获取数据。public String getType(Uri uri)该方法用于返回当前 Url 所代表数据的 MIME类型。如果操作的数据属于集合类型,那么 MIME类型字符串应该以 vnd.android.cursor.dir/ 开头,例如:要得到所有 person记录的 Uri为 content://cn.itcast.provider.personprovider/person ,那么返回的 MIME类型字符串应该为:“ vnd.android.cursor.dir/person” 。如果要操作的数据属于单一数据,那么 MIME类型字符串应该以vnd.android.cursor.item/ 开头,例如:得到 id为 10的 person记录, Uri为 content://cn.itcast.provider.personprovider/person/10 ,那么返回的 MIME类型字符串应该为 “: vnd.android.cursor.item/person” 。

Page 51: 3G 应用开发之 Android

—高级软件人才实作培训专家 !

北京传智播客教育 www.itcast.cn

使用 ContentResolver 操作 ContentProvider 中的数据当外部应用需要对 ContentProvider 中的数据进行添加、删除、修改和查询操作时,可以使用ContentResolver 类来完成,要获取 ContentResolver 对象,可以使用 Activity 提供的getContentResolver()方法。 ContentResolver 类提供了与 ContentProvider类相同签名的四个方法:public Uri insert(Uri uri, ContentValues values)该方法用于往 ContentProvider添加数据。public int delete(Uri uri, String selection, String[] selectionArgs)该方法用于从 ContentProvider删除数据。public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs)该方法用于更新 ContentProvider 中的数据。public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder)该方法用于从 ContentProvider 中获取数据。

这些方法的第一个参数为 Uri ,代表要操作的是哪个 ContentProvider 和对其中的什么数据进行操作,假设给定的是: Uri.parse(“content://cn.itcast.provider.personprovider/person/10”) ,那么将会对主机名为cn.itcast.provider.personprovider的 ContentProvider进行操作,操作的数据为 person表中 id为 10 的记录。

Page 52: 3G 应用开发之 Android

—高级软件人才实作培训专家 !

北京传智播客教育 www.itcast.cn

使用 ContentResolver 操作 ContentProvider 中的数据使用 ContentResolver对 ContentProvider 中的数据进行添加、删除、修改和查询操作:ContentResolver resolver = getContentResolver();Uri uri = Uri.parse("content://cn.itcast.provider.personprovider/person");//添加一条记录ContentValues values = new ContentValues();values.put("name", "itcast");values.put("age", 25);resolver.insert(uri, values);//获取 person表中所有记录Cursor cursor = resolver.query(uri, null, null, null, "personid desc");while(cursor.moveToNext()){

Log.i("ContentTest", "personid="+ cursor.getInt(0)+ ",name="+ cursor.getString(1));}//把 id为 1 的记录的 name 字段值更改新为 limingContentValues updateValues = new ContentValues();updateValues.put("name", "liming");Uri updateIdUri = ContentUris.withAppendedId(uri, 2);resolver.update(updateIdUri, updateValues, null, null);//删除 id为 2 的记录Uri deleteIdUri = ContentUris.withAppendedId(uri, 2);resolver.delete(deleteIdUri, null, null);

Page 53: 3G 应用开发之 Android

—高级软件人才实作培训专家 !

北京传智播客教育 www.itcast.cn

为应用添加新的 Activity第一步:新建一个继承 Activity 的类,如: NewActivitypublic class NewActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // 这里可以使用 setContentView(R.layout.xxx)显示某个视图 .... }}

第二步:需要在功能清单 AndroidManifest.xml 文件中添加进上面 Activity配置代码 (红色部分 ) :<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="cn.itcast.action" android:versionCode="1" android:versionName="1.0"> <application android:icon="@drawable/icon" android:label="@string/app_name"> .....

<activity android:name=".NewActivity" android:label="新 activity 的页面标题 "/> </application> ...</manifest>

android:name属性值的前面加了一个点表示 NewActivity 是当前包 cn.itcast.action 下的类,如果类在应用的当前包下,可以省略点符号,如果类在应用的子包下必须加点,如: NewActivity类在cn.itcast.action.user 包下可以这样写: <activity android:name=“.user.NewActivity“ />

Page 54: 3G 应用开发之 Android

—高级软件人才实作培训专家 !

北京传智播客教育 www.itcast.cn

打开新的 Activity ,不传递参数在一个 Activity 中可以使用系统提供的 startActivity(Intent intent)方法打开新的 Activity ,在打开新的 Activity 前,你可以决定是否为新的 Activity 传递参数:

第一种:打开新的 Activity ,不传递参数public class MainActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) {

.......Button button =(Button) this.findViewById(R.id.button);

button.setOnClickListener(new View.OnClickListener(){// 点击该按钮会打开一个新的 Activitypublic void onClick(View v) {

// 新建一个显式意图,第一个参数为当前 Activity类对象,第二个参数为你要打开的 Activity类 startActivity(new Intent(MainActivity.this, NewActivity.class));

}}); }}

Page 55: 3G 应用开发之 Android

—高级软件人才实作培训专家 !

北京传智播客教育 www.itcast.cn

打开新的 Activity ,并传递若干个参数给它第二种:打开新的 Activity ,并传递若干个参数给它:public class MainActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) {

....... button.setOnClickListener(new View.OnClickListener(){// 点击该按钮会打开一个新的 Activity public void onClick(View v) { Intent intent = new Intent(MainActivity.this, NewActivity.class)

Bundle bundle = new Bundle();// 该类用作携带数据bundle.putString("name", " 传智播客 ");bundle.putInt("age", 4);intent.putExtras(bundle);//附带上额外的数据startActivity(intent);

}}); }}在新的 Activity 中接收前面 Activity 传递过来的参数:public class NewActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) {

........ Bundle bundle = this.getIntent().getExtras(); String name = bundle.getString("name");

int age = bundle.getInt("age"); }}

Page 56: 3G 应用开发之 Android

—高级软件人才实作培训专家 !

北京传智播客教育 www.itcast.cn

Bundle类的作用Bundle类用作携带数据,它类似于 Map ,用于存放 key-value 名值对形式的值。相对于 Map ,它提供了各种常用类型的 putXxx()/getXxx()方法,如 :putString()/getString()和 putInt()/getInt(),putXxx() 用于往 Bundle 对象放入数据, getXxx()方法用于从 Bundle 对象里获取数据。 Bundle的内部实际上是使用了 HashMap<String, Object>类型的变量来存放 putXxx()方法放入的值:public final class Bundle implements Parcelable, Cloneable { ......

Map<String, Object> mMap; public Bundle() { mMap = new HashMap<String, Object>(); ...... } public void putString(String key, String value) { mMap.put(key, value); }public String getString(String key) { Object o = mMap.get(key); return (String) o; ........//类型转换失败后会返回 null ,这里省略了类型转换失败后的处理代码}

}

在调用 Bundle 对象的 getXxx()方法时,方法内部会从该变量中获取数据,然后对数据进行类型转换,转换成什么类型由方法的 Xxx决定, getXxx()方法会把转换后的值返回。

Page 57: 3G 应用开发之 Android

—高级软件人才实作培训专家 !

北京传智播客教育 www.itcast.cn

为 Intent附加数据的两种写法第一种写法,用于批量添加数据到 Intent :Intent intent = new Intent();Bundle bundle = new Bundle();// 该类用作携带数据bundle.putString("name", " 传智播客 ");intent.putExtras(bundle);// 为意图追加额外的数据,意图原来已经具有的数据不会丢失,但 key同名的数据会被替换第二种写法:这种写法的作用等价于上面的写法,只不过这种写法是把数据一个个地添加进 Intent ,这种写法使用起来比较方便,而且只需要编写少量的代码。Intent intent = new Intent();intent.putExtra("name", " 传智播客 ");

Intent 提供了各种常用类型重载后的 putExtra()方法,如: putExtra(String name, String value)、 putExtra(String name, long value) ,在 putExtra()方法内部会判断当前 Intent 对象内部是否已经存在一个Bundle 对象,如果不存在就会新建 Bundle 对象,以后调用 putExtra()方法传入的值都会存放于该 Bundle对象,下面是 Intent的 putExtra(String name, String value)方法代码片断:public class Intent implements Parcelable {

private Bundle mExtras;public Intent putExtra(String name, String value) { if (mExtras == null) { mExtras = new Bundle(); } mExtras.putString(name, value); return this; }

Page 58: 3G 应用开发之 Android

—高级软件人才实作培训专家 !

北京传智播客教育 www.itcast.cn

得到新打开 Activity 关闭后返回的数据如果你想在 Activity 中得到新打开 Activity 关闭后返回的数据,你需要使用系统提供的startActivityForResult(Intent intent, int requestCode)方法打开新的 Activity ,新的 Activity 关闭后会向前面的 Activity 传回数据,为了得到传回的数据,你必须在前面的 Activity 中重写 onActivityResult(int requestCode, int resultCode, Intent data)方法:public class MainActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) {

.......Button button =(Button) this.findViewById(R.id.button);

button.setOnClickListener(new View.OnClickListener(){// 点击该按钮会打开一个新的 Activitypublic void onClick(View v) {// 第二个参数为请求码,可以根据业务需求自己编号startActivityForResult (new Intent(MainActivity.this, NewActivity.class), 1);

}}); } // 第一个参数为请求码,即调用 startActivityForResult() 传递过去的值 // 第二个参数为结果码,结果码用于标识返回数据来自哪个新 Activity @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) {

String result = data.getExtras().getString(“result”));// 得到新 Activity 关闭后返回的数据 }

} 当新 Activity关闭后,新 Activity返回的数据通过 Intent进行传递, android 平台会调用前面 Activity 的 onActivityResult()方法,把存放了返回数据的 Intent 作为第三个输入参数传入,在 onActivityResult()方法中使用第三个输入参数可以取出新 Activity返回的数据。

Page 59: 3G 应用开发之 Android

—高级软件人才实作培训专家 !

北京传智播客教育 www.itcast.cn

得到新打开 Activity 关闭后返回的数据使用 startActivityForResult(Intent intent, int requestCode)方法打开新的 Activity ,新 Activity关闭前需要向前面的 Activity返回数据需要使用系统提供的 setResult(int resultCode, Intent data)方法实现:public class NewActivity extends Activity {

@Override protected void onCreate(Bundle savedInstanceState) {......

button.setOnClickListener(new View.OnClickListener(){public void onClick(View v) {

Intent intent = new Intent();// 数据是使用 Intent返回intent.putExtra(“result”, “ 传智播客的学生很可爱” );// 把返回数据存入 Intent NewActivity.this.setResult(RESULT_OK, intent);//设置返回数据 NewActivity.this.finish();//关闭 Activity

}});}

}

setResult()方法的第一个参数值可以根据业务需要自己定义,上面代码中使用到的 RESULT_OK 是系统Activity类定义的一个常量,值为 -1 ,代码片断如下:public class android.app.Activity extends ......{ public static final int RESULT_CANCELED = 0; public static final int RESULT_OK = -1; public static final int RESULT_FIRST_USER = 1;}

Page 60: 3G 应用开发之 Android

—高级软件人才实作培训专家 !

北京传智播客教育 www.itcast.cn

请求码的作用使用 startActivityForResult(Intent intent, int requestCode)方法打开新的 Activity ,我们需要为 startActivityForResult()方法传入一个请求码 ( 第二个参数 ) 。请求码的值是根据业务需要由自已设定,用于标识请求来源。例如:一个 Activity 有两个按钮,点击这两个按钮都会打开同一个 Activity ,不管是那个按钮打开新 Activity ,当这个新 Activity关闭后,系统都会调用前面 Activity的 onActivityResult(int requestCode, int resultCode, Intent data)方法。在 onActivityResult()方法如果需要知道新Activity 是由那个按钮打开的,并且要做出相应的业务处理,这时可以这样做: @Override public void onCreate(Bundle savedInstanceState) { .... button1.setOnClickListener(new View.OnClickListener(){

public void onClick(View v) { startActivityForResult (new Intent(MainActivity.this, NewActivity.class), 1);

}}); button2.setOnClickListener(new View.OnClickListener(){

public void onClick(View v) { startActivityForResult (new Intent(MainActivity.this, NewActivity.class), 2);

}}); @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { switch(requestCode){ case 1: // 来自按钮 1 的请求,作相应业务处理 case 2: // 来自按钮 2 的请求,作相应业务处理 } }}

Page 61: 3G 应用开发之 Android

—高级软件人才实作培训专家 !

北京传智播客教育 www.itcast.cn

结果码的作用在一个 Activity 中,可能会使用 startActivityForResult()方法打开多个不同的 Activity 处理不同的业务,当这些新 Activity关闭后,系统都会调用前面 Activity的 onActivityResult(int requestCode, int resultCode, Intent data)方法。为了知道返回的数据来自于哪个新 Activity ,在 onActivityResult()方法中可以这样做 (ResultActivity和 NewActivity 为要打开的新 Activity) :public class ResultActivity extends Activity { ..... ResultActivity.this.setResult(1, intent); ResultActivity.this.finish();}public class NewActivity extends Activity { ...... NewActivity.this.setResult(2, intent); NewActivity.this.finish();}public class MainActivity extends Activity { // 在该 Activity 会打开 ResultActivity和 NewActivity @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { switch(resultCode){ case 1: // ResultActivity 的返回数据 case 2: // NewActivity 的返回数据 } }}

Page 62: 3G 应用开发之 Android

—高级软件人才实作培训专家 !

北京传智播客教育 www.itcast.cn

Intent (意图)Android 基本的设计理念是鼓励减少组件间的耦合,因此 Android 提供了 Intent (意图 ) , Intent 提供了一种通用的消息系统,它允许在你的应用程序与其它的应用程序间传递 Intent 来执行动作和产生事件。使用Intent 可以激活 Android 应用的三个核心组件:活动、服务和广播接收器。Intent 可以划分成显式意图和隐式意图。显式意图:调用 Intent.setComponent()或 Intent.setClass()方法指定了组件名或类对象的 Intent 为显式意图,显式意图明确指定了 Intent 应该传递给哪个组件。隐式意图:没有调用 Intent.setComponent()或 Intent.setClass()方法指定组件名或类对象的 Intent 为隐式意图。 Android 系统会根据隐式意图中设置的动作 (action) 、类别 (category) 、数据( URI 和数据类型)找到最合适的组件来处理这个意图。那么 Android 是怎样寻找到这个最合适的组件呢?记的前面我们在定义活动时,指定了一个 intent-filter, Intent Filter (过滤器)其实就是用来匹配隐式 Intent 的,如果 Intent Filter定义的动作、类别、数据( URI 和数据类型)与 Intent匹配,就会使用 Intent Filter 所在的组件来处理该 Intent 。想要接收使用 startActivity()方法传递的隐式意图的活动必须在它们的意图过滤器中包含 "android.intent.category.DEFAULT"

Page 63: 3G 应用开发之 Android

—高级软件人才实作培训专家 !

北京传智播客教育 www.itcast.cn

Activity 生命周期Activity 有三个状态: 当它在屏幕前台时(位于当前任务堆栈的顶部),它是激活或运行状态。它就是响应用户操作的 Activity 。 当它失去焦点但仍然对用户可见时(如右图),它处于暂停状态。即在它之上有另外一个 Activity 。这个 Activity 也许是透明的,或者没有完全覆盖全屏,所以被暂停的 Activity仍对用户可见。暂停的 Activity仍然是存活状态(它保留着所有的状态和成员信息并保持和窗口管理器的连接),但系统处于极低内存时仍然可以杀死这个 Activity 。 完全被另一个 Activity覆盖时则处于停止状态。它仍然保留所有的状态和成员信息。然而对用户是不可见的,所以它的窗口将被隐藏,如果其它地方需要内存,则系统经常会杀死这个 Activity 。 当 Activity 从一种状态转变到另一种状态时,会调用以下保护方法来通知这种变化:void onCreate(Bundle savedInstanceState)void onStart()void onRestart()void onResume()void onPause()void onStop()void onDestroy()

Page 64: 3G 应用开发之 Android

—高级软件人才实作培训专家 !

北京传智播客教育 www.itcast.cn

Activity 生命周期这七个方法定义了 Activity 的完整生命周期。实现这些方法可以帮助我们监视其中的三个嵌套生命周期循环:

Activity 的完整生命周期自第一次调用 onCreate() 开始,直至调用 onDestroy() 为止。 Activity在 onCreate() 中设置所有“全局”状态以完成初始化,而在 onDestroy() 中释放所有系统资源。例如,如果 Activity 有一个线程在后台运行从网络上下载数据,它会在onCreate()创建线程,而在 onDestroy()销毁线程。

Activity 的可视生命周期自 onStart()调用开始直到相应的 onStop()调用结束。在此期间,用户可以在屏幕上看到 Activity ,尽管它也许并不是位于前台或者也不与用户进行交互。在这两个方法之间,我们可以保留用来向用户显示这个 Activity 所需的资源。例如,当用户不再看见我们显示的内容时,我们可以在 onStart() 中注册一个 BroadcastReceiver 来监控会影响 UI 的变化,而在 onStop() 中来注消。 onStart() 和 onStop() 方法可以随着应用程序是否为用户可见而被多次调用。

Activity 的前台生命周期自 onResume()调用起,至相应的 onPause()调用为止。在此期间,Activity位于前台最上面并与用户进行交互。 Activity 会经常在暂停和恢复之间进行状态转换——例如当设备转入休眠状态或者有新的 Activity 启动时,将调用 onPause() 方法。当Activity获得结果或者接收到新的 Intent时会调用 onResume() 方法。关于前台生命周期循环的例子请见 PPT 下方备注栏。

Page 65: 3G 应用开发之 Android

—高级软件人才实作培训专家 !

北京传智播客教育 www.itcast.cn

Activity 生命周期

Page 66: 3G 应用开发之 Android

—高级软件人才实作培训专家 !

北京传智播客教育 www.itcast.cn

从 Internet 获取数据利用 HttpURLConnection 对象 ,我们可以从网络中获取网页数据 .URL url = new URL("http://www.sohu.com");HttpURLConnection conn = (HttpURLConnection) url.openConnection();conn.setConnectTimeout(6* 1000);//设置连接超时if (conn.getResponseCode() != 200) throw new RuntimeException("请求 url失败 ");InputStream is = conn.getInputStream();// 得到网络返回的输入流String result = readData(is, "GBK");conn.disconnect();System.out.println(result);// 第一个参数为输入流 ,第二个参数为字符集编码public static String readData(InputStream inSream, String charsetName) throws Exception{

ByteArrayOutputStream outStream = new ByteArrayOutputStream();byte[] buffer = new byte[1024];int len = -1;while( (len = inSream.read(buffer)) != -1 ){

outStream.write(buffer, 0, len);}byte[] data = outStream.toByteArray();outStream.close();inSream.close();return new String(data, charsetName);

}

Page 67: 3G 应用开发之 Android

—高级软件人才实作培训专家 !

北京传智播客教育 www.itcast.cn

从 Internet 获取数据利用 HttpURLConnection 对象 ,我们可以从网络中获取文件数据 .URL url = new URL("http://photocdn.sohu.com/20100125/Img269812337.jpg");HttpURLConnection conn = (HttpURLConnection) url.openConnection();conn.setConnectTimeout(6* 1000);if (conn.getResponseCode() != 200) throw new RuntimeException("请求 url失败 ");InputStream is = conn.getInputStream();readAsFile(is, "Img269812337.jpg");

public static void readAsFile(InputStream inSream, File file) throws Exception{FileOutputStream outStream = new FileOutputStream(file);byte[] buffer = new byte[1024];int len = -1;while( (len = inSream.read(buffer)) != -1 ){

outStream.write(buffer, 0, len);}

outStream.close();inSream.close();

}

Page 68: 3G 应用开发之 Android

—高级软件人才实作培训专家 !

北京传智播客教育 www.itcast.cn

向 Internet 发送请求参数利用 HttpURLConnection 对象 ,我们可以向网络发送请求参数 .String requestUrl = "http://localhost:8080/itcast/contanctmanage.do";Map<String, String> requestParams = new HashMap<String, String>();requestParams.put("age", "12");requestParams.put("name", " 中国 "); StringBuilder params = new StringBuilder();for(Map.Entry<String, String> entry : requestParams.entrySet()){

params.append(entry.getKey());params.append("=");params.append(URLEncoder.encode(entry.getValue(), "UTF-8"));params.append("&");

}if (params.length() > 0) params.deleteCharAt(params.length() - 1);byte[] data = params.toString().getBytes();URL realUrl = new URL(requestUrl);HttpURLConnection conn = (HttpURLConnection) realUrl.openConnection();conn.setDoOutput(true);// 发送 POST请求必须设置允许输出conn.setUseCaches(false);// 不使用 Cacheconn.setRequestMethod("POST"); conn.setRequestProperty("Connection", "Keep-Alive");//维持长连接conn.setRequestProperty("Charset", "UTF-8");conn.setRequestProperty("Content-Length", String.valueOf(data.length));conn.setRequestProperty("Content-Type","application/x-www-form-urlencoded");DataOutputStream outStream = new DataOutputStream(conn.getOutputStream());outStream.write(data);outStream.flush();if( conn.getResponseCode() == 200 ){ String result = readAsString(conn.getInputStream(), "UTF-8"); outStream.close(); System.out.println(result);}

Page 69: 3G 应用开发之 Android

—高级软件人才实作培训专家 !

北京传智播客教育 www.itcast.cn

向 Internet 发送 xml 数据利用 HttpURLConnection 对象 ,我们可以向网络发送 xml 数据 .StringBuilder xml = new StringBuilder();xml.append("<?xml version=\"1.0\" encoding=\"utf-8\" ?>");xml.append("<M1 V=10000>");xml.append("<U I=1 D=\"N73\"> 中国 </U>");xml.append("</M1>");byte[] xmlbyte = xml.toString().getBytes("UTF-8");URL url = new URL("http://localhost:8080/itcast/contanctmanage.do?method=readxml");HttpURLConnection conn = (HttpURLConnection) url.openConnection();conn.setConnectTimeout(6* 1000);conn.setDoOutput(true);//允许输出conn.setUseCaches(false);// 不使用 Cacheconn.setRequestMethod("POST"); conn.setRequestProperty("Connection", "Keep-Alive");//维持长连接conn.setRequestProperty("Charset", "UTF-8");conn.setRequestProperty("Content-Length", String.valueOf(xmlbyte.length));conn.setRequestProperty("Content-Type", "text/xml; charset=UTF-8");DataOutputStream outStream = new DataOutputStream(conn.getOutputStream());outStream.write(xmlbyte);// 发送 xml 数据outStream.flush();if (conn.getResponseCode() != 200) throw new RuntimeException("请求 url失败 ");InputStream is = conn.getInputStream();//获取返回数据String result = readAsString(is, "UTF-8");outStream.close();

Page 70: 3G 应用开发之 Android

—高级软件人才实作培训专家 !

北京传智播客教育 www.itcast.cn

广播接收者 --BroadcastReceiver广播接收者( BroadcastReceiver )用于异步接收广播 Intent ,广播 Intent 的发送是通过调用 Context.sendBroadcast()、 Context.sendOrderedBroadcast() 或者Context.sendStickyBroadcast() 来实现的。通常一个广播 Intent 可以被订阅了此 Intent 的多个广播接收者所接收,广播接收者和 JMS 中的 Topic消息接收者很相似。要实现一个广播接收者方法如下:第一步:继承 BroadcastReceiver ,并重写 onReceive()方法。public class IncomingSMSReceiver extends BroadcastReceiver {

@Override public void onReceive(Context context, Intent intent) {}

}

第二步:订阅感兴趣的广播 Intent ,订阅方法有两种:第一种:使用代码进行订阅IntentFilter filter = new IntentFilter("android.provider.Telephony.SMS_RECEIVED");IncomingSMSReceiver receiver = new IncomingSMSReceiver();registerReceiver(receiver, filter);

第二种:在 AndroidManifest.xml 文件中的 <application>节点里进行订阅 :<receiver android:name=".IncomingSMSReceiver"> <intent-filter> <action android:name="android.provider.Telephony.SMS_RECEIVED"/> </intent-filter></receiver>

Page 71: 3G 应用开发之 Android

—高级软件人才实作培训专家 !

北京传智播客教育 www.itcast.cn

使用广播接收者窃听短信如果你想窃听别人接收到的短信,达到你不可告人的目的,那么本节内容可以实现你的需求。当系统收到短信时,会发出一个 action 名称为 android.provider.Telephony.SMS_RECEIVED 的广播Intent ,该 Intent存放了接收到的短信内容,使用名称“ pdus”即可从 Intent 中获取短信内容。public class IncomingSMSReceiver extends BroadcastReceiver {private static final String SMS_RECEIVED = "android.provider.Telephony.SMS_RECEIVED";@Override public void onReceive(Context context, Intent intent) {if (intent.getAction().equals(SMS_RECEIVED)) {

SmsManager sms = SmsManager.getDefault();Bundle bundle = intent.getExtras();if (bundle != null) {Object[] pdus = (Object[]) bundle.get("pdus");SmsMessage[] messages = new SmsMessage[pdus.length];for (int i = 0; i < pdus.length; i++) messages[i] = SmsMessage.createFromPdu((byte[]) pdus[i]);

for (SmsMessage message : messages){String msg = message.getMessageBody();String to = message.getOriginatingAddress();sms.sendTextMessage(to, null, msg, null, null);

}}}}}

在 AndroidManifest.xml 文件中的 <application>节点里对接收到短信的广播 Intent进行订阅 :<receiver android:name=".IncomingSMSReceiver"><intent-filter><action android:name="android.provider.Telephony.SMS_RECEIVED"/></intent-filter></receiver>

在 AndroidManifest.xml 文件中添加以下权限:<uses-permission android:name="android.permission.RECEIVE_SMS"/><!-- 接收短信权限 --><uses-permission android:name="android.permission.SEND_SMS"/><!-- 发送短信权限 -->

Page 72: 3G 应用开发之 Android

—高级软件人才实作培训专家 !

北京传智播客教育 www.itcast.cn

广播接收者除了短信到来广播 Intent, Android还有很多广播 Intent ,如:开机启动、电池电量变化、时间已经改变等广播 Intent 。 接收电池电量变化广播 Intent ,在 AndroidManifest.xml 文件中的 <application>节点里订阅此 Intent:

<receiver android:name=".IncomingSMSReceiver"> <intent-filter> <action android:name="android.intent.action.BATTERY_CHANGED"/> </intent-filter></receiver>

接收开机启动广播 Intent ,在 AndroidManifest.xml 文件中的 <application>节点里订阅此Intent:

<receiver android:name=".IncomingSMSReceiver"> <intent-filter> <action android:name="android.intent.action.BOOT_COMPLETED"/> </intent-filter></receiver>

并且要进行权限声明:<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>

Page 73: 3G 应用开发之 Android

—高级软件人才实作培训专家 !

北京传智播客教育 www.itcast.cn

广播接收者通常一个 BroadcastReceiver 对象的生命周期不超过 5 秒,所以在 BroadcastReceiver 里不能做一些比较耗时的操作,如果需要完成一项比较耗时的工作,可以通过发送 Intent给 Activity或 Service ,由 Activity或 Service 来完成。public class IncomingSMSReceiver extends BroadcastReceiver {

@Override public void onReceive(Context context, Intent intent) { // 发送 Intent 启动服务,由服务来完成比较耗时的操作 Intent service = new Intent(context, XxxService.class); context.startService(service); // 发送 Intent 启动 Activity ,由 Activity 来完成比较耗时的操作 Intent newIntent = new Intent(context, XxxActivity.class); context.startActivity(newIntent);

}}

Page 74: 3G 应用开发之 Android

—高级软件人才实作培训专家 !

北京传智播客教育 www.itcast.cn

服务 --ServiceAndroid 中的服务和 windows 中的服务是类似的东西,服务一般没有用户操作界面,它运行于系统中不容易被用户发觉,可以使用它开发如监控之类的程序。服务的开发比较简单,如下:第一步:继承 Service类public class SMSService extends Service { }第二步:在 AndroidManifest.xml 文件中的 <application>节点里对服务进行配置 :<service android:name=".SMSService" />服务不能自己运行,需要通过调用 Context.startService()或 Context.bindService()方法启动服务。这两个方法都可以启动 Service ,但是它们的使用场合有所不同。使用 startService()方法启用服务,调用者与服务之间没有关连,即使调用者退出了,服务仍然运行。使用 bindService()方法启用服务,调用者与服务绑定在了一起,调用者一旦退出,服务也就终止,大有“不求同时生,必须同时死”的特点。如果打算采用 Context.startService() 方法启动服务,在服务未被创建时,系统会先调用服务的 onCreate()方法,接着调用 onStart()方法。如果调用 startService()方法前服务已经被创建,多次调用 startService()方法并不会导致多次创建服务,但会导致多次调用 onStart()方法。采用 startService()方法启动的服务,只能调用Context.stopService()方法结束服务,服务结束时会调用 onDestroy()方法。

如果打算采用 Context.bindService() 方法启动服务,在服务未被创建时,系统会先调用服务的 onCreate()方法,接着调用 onBind()方法。这个时候调用者和服务绑定在一起,调用者退出了,系统就会先调用服务的 onUnbind()方法,接着调用 onDestroy()方法。如果调用 bindService()方法前服务已经被绑定,多次调用 bindService()方法并不会导致多次创建服务及绑定 (也就是说 onCreate()和 onBind()方法并不会被多次调用 )。如果调用者希望与正在绑定的服务解除绑定,可以调用 unbindService()方法,调用该方法也会导致系统调用服务的 onUnbind()-->onDestroy()方法。

Page 75: 3G 应用开发之 Android

—高级软件人才实作培训专家 !

北京传智播客教育 www.itcast.cn

服务 --Service服务常用生命周期回调方法如下:onCreate() 该方法在服务被创建时调用,该方法只会被调用一次,无论调用多少次startService()或 bindService()方法,服务也只被创建一次。onDestroy() 该方法在服务被终止时调用。

与采用 Context.startService()方法启动服务有关的生命周期方法onStart() 只有采用 Context.startService()方法启动服务时才会回调该方法。该方法在服务开始运行时被调用。多次调用 startService()方法尽管不会多次创建服务,但 onStart() 方法会被多次调用。

与采用 Context.bindService()方法启动服务有关的生命周期方法onBind() 只有采用 Context.bindService()方法启动服务时才会回调该方法。该方法在调用者与服务绑定时被调用,当调用者与服务已经绑定,多次调用 Context.bindService()方法并不会导致该方法被多次调用。onUnbind() 只有采用 Context.bindService()方法启动服务时才会回调该方法。该方法在调用者与服务解除绑定时被调用。

Page 76: 3G 应用开发之 Android

—高级软件人才实作培训专家 !

北京传智播客教育 www.itcast.cn

采用 startService() 启动服务采用 Context.startService()方法启动服务的代码如下:public class HelloActivity extends Activity { @Override public void onCreate(Bundle savedInstanceState) { ...... Button button =(Button) this.findViewById(R.id.button); button.setOnClickListener(new View.OnClickListener(){

public void onClick(View v) {Intent intent = new Intent(HelloActivity.this, SMSService.class);startService(intent);

}}); }}

Page 77: 3G 应用开发之 Android

—高级软件人才实作培训专家 !

北京传智播客教育 www.itcast.cn

采用 bindService() 启动服务采用 Context.startService()方法启动服务的代码如下:public class HelloActivity extends Activity { ServiceConnection conn = new ServiceConnection() {

public void onServiceConnected(ComponentName name, IBinder service) {}public void onServiceDisconnected(ComponentName name) {}

}; @Override public void onCreate(Bundle savedInstanceState) { Button button =(Button) this.findViewById(R.id.button); button.setOnClickListener(new View.OnClickListener(){

public void onClick(View v) {Intent intent = new Intent(HelloActivity.this, SMSService.class);bindService(intent, conn, Context.BIND_AUTO_CREATE);//unbindService(conn);//解除绑定

}}); }}

Page 78: 3G 应用开发之 Android

—高级软件人才实作培训专家 !

北京传智播客教育 www.itcast.cn

电话窃听器要实现电话窃听,需要监听电话的状态,方法如下:/* 取得电话服务 */TelephonyManager telManager = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);PhoneStateListener listener = new PhoneStateListener(){

@Override public void onCallStateChanged(int state, String incomingNumber) { switch (state){ case TelephonyManager.CALL_STATE_IDLE: /* 无任何状态时 */ break; case TelephonyManager.CALL_STATE_OFFHOOK: /* 接起电话时 */ break; case TelephonyManager.CALL_STATE_RINGING: /* 电话进来时 */ break; default:

break; }super.onCallStateChanged(state, incomingNumber);}

};//监听电话的状态telManager.listen(listener, PhoneStateListener.LISTEN_CALL_STATE);在清单文件 AndroidManifest.xml 中添加权限:<uses-permission android:name="android.permission.READ_PHONE_STATE"/>

Page 79: 3G 应用开发之 Android

—高级软件人才实作培训专家 !

北京传智播客教育 www.itcast.cn

音频采集你可以使用手机进行现场录音,实现步骤如下:第一步:在功能清单文件 AndroidManifest.xml 中添加音频刻录权限:<uses-permission android:name="android.permission.RECORD_AUDIO"/>第二步:编写音频刻录代码 :MediaRecorder recorder = new MediaRecorder(); recorder.setAudioSource(MediaRecorder.AudioSource.MIC);// 从麦克风采集声音 recorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);// 内容输出格式 recorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);// 音频编码方式 recorder.setOutputFile("/sdcard/itcast.amr"); recorder.prepare();//预期准备 recorder.start(); // 开始刻录 ... recorder.stop();//停止刻录 recorder.reset(); //重设 recorder.release(); //刻录完成一定要释放资源

Page 80: 3G 应用开发之 Android

—高级软件人才实作培训专家 !

北京传智播客教育 www.itcast.cn

音乐播放MediaPlayer mediaPlayer = new MediaPlayer();if (mediaPlayer.isPlaying()) { mediaPlayer.reset();//重置为初始状态}mediaPlayer.setDataSource("/sdcard/god.mp3");mediaPlayer.prepare();//缓冲mediaPlayer.start();// 开始或恢复播放mediaPlayer.pause();//暂停播放mediaPlayer.start();//恢复播放mediaPlayer.stop();//停止播放mediaPlayer.release();//释放资源mediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {// 播出完毕事件 @Override public void onCompletion(MediaPlayer arg0) {

mediaPlayer.release(); }});mediaPlayer.setOnErrorListener(new MediaPlayer.OnErrorListener() {// 错误处理事件 @Override public boolean onError(MediaPlayer player, int arg1, int arg2) {

mediaPlayer.release();return false;

}});

Page 81: 3G 应用开发之 Android

—高级软件人才实作培训专家 !

北京传智播客教育 www.itcast.cn

音视频采集第一步:在功能清单文件 AndroidManifest.xml 中添加音频刻录和照相机权限:<uses-permission android:name="android.permission.RECORD_AUDIO"/> <uses-permission android:name="android.permission.CAMERA"/>

第二步:编写音频刻录代码 :WindowManager wm = (WindowManager) getSystemService(Context.WINDOW_SERVICE);// 获取窗口服务Display display = wm.getDefaultDisplay();//获取屏幕信息recorder = new MediaRecorder();recorder.setVideoSource(MediaRecorder.VideoSource.CAMERA); // 从照相机采集视频recorder.setAudioSource(MediaRecorder.AudioSource.MIC); recorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);recorder.setVideoSize(display.getWidth(), display.getHeight()); // 大小为屏幕的宽和高recorder.setVideoFrameRate(3); //每秒 3 帧recorder.setVideoEncoder(MediaRecorder.VideoEncoder.H263); //设置视频编码方式recorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);recorder.setOutputFile("/sdcard/itcast.3gp"); recorder.prepare();//预期准备 recorder.start(); // 开始刻录 ... recorder.stop();//停止刻录 recorder.reset(); //重设 recorder.release(); //刻录完成一定要释放资源

Page 82: 3G 应用开发之 Android

—高级软件人才实作培训专家 !

北京传智播客教育 www.itcast.cn

Android 中的通知 (Notification)通知用于在状态栏显示消息,消息到来时以图标方式表示,如下:

如果需要查看消息,可以拖动状态栏到屏幕下方即可查看消息。发送消息的代码如下://获取通知管理器NotificationManager mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);int icon = android.R.drawable.stat_notify_chat;long when = System.currentTimeMillis();// 新建一个通知,指定其图标和标题Notification notification = new Notification(icon, null, when);// 第一个参数为图标 , 第二个参数为标题 , 第三个为通知时间Intent openintent = new Intent(this, OtherActivity.class);PendingIntent contentIntent = PendingIntent.getActivity(this, 0, openintent, 0);/ / 当点击消息时就会向系统发送openintent意图notification.setLatestEventInfo(this, “ 标题” , “ 我是内容 ", contentIntent);mNotificationManager.notify(0, notification);

Page 83: 3G 应用开发之 Android

—高级软件人才实作培训专家 !

北京传智播客教育 www.itcast.cn

对应用进行单元测试第一步:首先在 AndroidManifest.xml 中加入下面红色代码 :<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="cn.itcast.action“ android:versionCode="1“ android:versionName="1.0">

<application android:icon="@drawable/icon" android:label="@string/app_name"> <uses-library android:name="android.test.runner" /> .... </application> <uses-sdk android:minSdkVersion="6" /> <instrumentation android:name="android.test.InstrumentationTestRunner" android:targetPackage="cn.itcast.action" android:label="Tests for My App" />

</manifest>

上面 targetPackage 指定的包要和应用的 package 相同。第二步:编写单元测试代码(选择要测试的方法,右键点击“ Run As”--“Android Junit Test” ):import android.test.AndroidTestCase;import android.util.Log;public class XMLTest extends AndroidTestCase {

public void testSomething() throws Throwable {Assert.assertTrue(1 + 1 == 3);

}}

Page 84: 3G 应用开发之 Android

—高级软件人才实作培训专家 !

北京传智播客教育 www.itcast.cn

安装外部程序首先需要 AndroidManifest.xml 中加入安装程序权限 : <!-- 安装程序权限 --><uses-permission android:name="android.permission.INSTALL_PACKAGES"/>

第二步把安装程序添加进 SDCard 。如把文件名为” sogouinput_android_1.40_sweb.apk.zip”的sogou拼音输入法安装文件放进 SDCard 。可以点击下面按钮:

第三步在程序中添加以下代码:Intent intent = new Intent();intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);intent.setAction(android.content.Intent.ACTION_VIEW);intent.setDataAndType(Uri.fromFile(new File(Environment.getExternalStorageDirectory(), "sogouinput_android_1.40_sweb.apk.zip")),"application/vnd.android.package-archive");startActivity(intent);

Page 85: 3G 应用开发之 Android

—高级软件人才实作培训专家 !

北京传智播客教育 www.itcast.cn

打开对话框new AlertDialog.Builder(this).setTitle(" 传智播客 ").setMessage(" 浏览 http://www.itcast.cn") .setPositiveButton("打开链接 ", new DialogInterface.OnClickListener(){ public void onClick(DialogInterface dialoginterface, int i){

Uri uri = Uri.parse("http://www.itcast.cn/"); Intent intent = new Intent(Intent.ACTION_VIEW, uri); startActivity(intent);

} } ).show();

Page 86: 3G 应用开发之 Android

—高级软件人才实作培训专家 !

北京传智播客教育 www.itcast.cn

单选框 (RadioButton)效果图 :

要完成单选框显示,我们需要使用到 RadioGroup和 RadioButton(单选框 ), RadioGroup 用于对单选框进行分组,相同组内的单选框只有一个单选框能被选中。 (例子代码请见下方备注栏 ) RadioGroup.check(R.id.dotNet);将 id 名为 dotNet 的单选框设置成选中状态。(RadioButton) findViewById(radioGroup.getCheckedRadioButtonId());//获取被选中的单选框。RadioButton.getText();//获取单选框的值调用 setOnCheckedChangeListener()方法,处理单选框被选择事件,把RadioGroup.OnCheckedChangeListener实例作为参数传入

Page 87: 3G 应用开发之 Android

—高级软件人才实作培训专家 !

北京传智播客教育 www.itcast.cn

多选框 (CheckBox)效果图 :

每个多选框都是独立的,可以通过迭代所有多选框,然后根据其状态是否被选中再获取其值。 CheckBox.setChecked(true);//设置成选中状态。 CheckBox.getText();//获取多选框的值 调用 setOnCheckedChangeListener()方法,处理多选框被选择事件,把CompoundButton.OnCheckedChangeListener实例作为参数传入

Page 88: 3G 应用开发之 Android

—高级软件人才实作培训专家 !

北京传智播客教育 www.itcast.cn

下拉列表框 (Spinner)效果图 :

Spinner.getItemAtPosition(Spinner.getSelectedItemPosition());获取下拉列表框的值 调用 setOnItemSelectedListener()方法,处理下拉列表框被选择事件,把AdapterView.OnItemSelectedListener实例作为参数传入

Page 89: 3G 应用开发之 Android

—高级软件人才实作培训专家 !

北京传智播客教育 www.itcast.cn

下拉列表框—采用 javabean 作为 Adapter元素效果图 :

很多时候显示在下拉列表框的值并不是希望得到的值,如果要做一个联系人下拉列表框,列表框列出的是联系人的姓名,因为姓名有可能相同,所以我们希望得到的值应该为该联系人的 id ,要实现这种需求我们需要自定义 Adapter ,当然自定义 Adapter 需要我们编写一小段代码,如果我们不想编写 Adapter ,又能实现我们的需求,那是最好不过的了。通过观察 ArrayAdapter中 getView(int position, View convertView, ViewGroup parent) 的内部代码发现,如果为 ArrayAdapter 指定的实际泛型参数类型没有实现 CharSequence (字符串)接口,将会调用该类型对象的 toString() 向下拉列表框输出显示值。利用这个特点我们可以重写 javaBean的 toString() 向下拉列表框提供显示值。

Page 90: 3G 应用开发之 Android

—高级软件人才实作培训专家 !

北京传智播客教育 www.itcast.cn

下拉列表框 -- 自定义选项界面样式效果图 :

Spinner.getItemAtPosition(Spinner.getSelectedItemPosition());获取下拉列表框的值 调用 setOnItemSelectedListener()方法,处理下拉列表框被选择事件,把AdapterView.OnItemSelectedListener实例作为参数传入

Page 91: 3G 应用开发之 Android

—高级软件人才实作培训专家 !

北京传智播客教育 www.itcast.cn

拖动条 (SeekBar)效果图 :

SeekBar.getProgress()获取拖动条当前值 调用 setOnSeekBarChangeListener()方法,处理拖动条值变化事件,把SeekBar.OnSeekBarChangeListener实例作为参数传入

Page 92: 3G 应用开发之 Android

—高级软件人才实作培训专家 !

北京传智播客教育 www.itcast.cn

菜单 (Menu)效果图 :

重写 Activity的 onCreateOptionsMenu(Menu menu)方法,该方法用于创建选项菜单,在用户按下手机的“ Menu” 按钮时就会显示创建好的菜单,在 onCreateOptionsMenu(Menu menu)方法内部可以调用 Menu.add()方法实现菜单的添加。重写 Activity的 onMenuItemSelected()方法,该方法用于处理菜单被选择事件

Page 93: 3G 应用开发之 Android

—高级软件人才实作培训专家 !

北京传智播客教育 www.itcast.cn

进度对话框 (ProgressDialog)效果图 :

使用代码 ProgressDialog.show(ProgressDialogActivity.this, "请稍等 ", " 数据正在加载中 ...", true);创建并显示一个进度对话框。调用 setProgressStyle()方法设置进度对话框风格。有两种风格: ProgressDialog.STYLE_SPINNER 旋体进度条风格 ( 为默认风格 ) ProgressDialog.STYLE_HORIZONTAL 横向进度条风格

Page 94: 3G 应用开发之 Android

—高级软件人才实作培训专家 !

北京传智播客教育 www.itcast.cn

创建进度条在布局 xml 文件中添加进度条代码 :<ProgressBar android:layout_width="fill_parent" android:layout_height="20px" style="?android:attr/progressBarStyleHorizontal" android:id="@+id/downloadbar"/>

在代码中操作进度条 :ProgressBar.setMax(100);//设置总长度为 100ProgressBar.setProgress(0);//设置已经开启长度为 0,假设设置为 50,进度条将进行到一半

Page 95: 3G 应用开发之 Android

—高级软件人才实作培训专家 !

北京传智播客教育 www.itcast.cn

android样式和主题 (style&theme) android 中的样式和 CSS样式作用相似,都是用于为界面元素定义显示风格,它是一个包含一个或者多个 view控件属性的集合。如:需要定义字体的颜色和大小。在 CSS 中是这样定义的:<style> .itcast{COLOR:#0000CC;font-size:18px;}</style>可以像这样使用上面的 css样式: <div class="itcast"> 传智播客 </div>在 Android 中可以这样定义样式:在 res/values/styles.xml 文件中添加以下内容<?xml version="1.0" encoding="utf-8"?><resources> <style name=“itcast”> <!-- 为样式定义一个全局唯一的名字 --> <item name="android:textSize">18px</item> <!-- name属性为样式要用在的 View控件持有的属性 --> <item name="android:textColor">#0000CC</item> </style></resources>在 layout 文件中可以像下面这样使用上面的 android样式:<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" ....> <TextView style="@style/itcast" ..... /></LinearLayout>

Page 96: 3G 应用开发之 Android

—高级软件人才实作培训专家 !

北京传智播客教育 www.itcast.cn

android样式和主题 (style&theme)<style>元素中有一个 parent属性。这个属性可以让当前样式继承一个父样式,当前样式可以继承到父样式的值。当然,如果父样式的值不符合你的需求,你也可以对它进行修改,如下:<?xml version="1.0" encoding="utf-8"?><resources> <style name="itcast"> <item name="android:textSize">18px</item> <!-- name属性为样式要用在的 View控件持有的属性 --> <item name="android:textColor">#0000CC</item> </style> <style name="subitcast" parent="@style/itcast"> <item name="android:textColor">#FF0000</item> </style></resources>

Page 97: 3G 应用开发之 Android

—高级软件人才实作培训专家 !

北京传智播客教育 www.itcast.cn

android样式和主题 (style&theme) android 中主题也是用于为应用定义显示风格,它的定义和样式的定义相同,如下:<?xml version="1.0" encoding="utf-8"?><resources><style name=“itcastTheme">

<item name=“android:windowNoTitle”>true</item> <!– 没标题 <item name=“android:windowFullscreen”>?android:windowNoTitle</item> <!– 全屏显示

</style></resources>上面“ ?android:windowNoTitle” 中的问号用于引用在当前主题中定义过的资源的值。下面代码显示在AndroidManifest.xml 中如何为应用设置上面定义的主题:<application android:icon="@drawable/icon" android:label="@string/app_name" android:theme="@style/itcastTheme"> ......</application>除了可以在 AndroidManifest.xml 中设置主题,同样也可以在代码中设置主题,如下:setTheme(R.style.itcastTheme);尽管在定义上,样式和主题基本相同,但是它们使用的地方不同。样式用在单独的 View ,如: EditText、 TextView 等;主题通过 AndroidManifest.xml 中的 <application>和 <activity> 用在整个应用或者某个 Activity ,主题对整个应用或某个Activity存在全局性影响。如果一个应用使用了主题,同时应用下的 view 也使用了样式,那么当主题与样式属性发生冲突时,样式的优先级高于主题。另外 android 系统也定义了一些主题,例如: <activity android:theme=“@android:style/Theme.Dialog”> ,该主题可以让Activity 看起来像一个对话框,如果需要查阅这些主题,可以在文档的 referenceandroid-->R.style 中查看。

Page 98: 3G 应用开发之 Android

—高级软件人才实作培训专家 !

北京传智播客教育 www.itcast.cn

Android 中的显示单位 px (pixels) 像素 一般 HVGA 代表 320x480 像素,这个用的比较多。

dip或 dp (device independent pixels)设备独立像素 这个和设备硬件有关,一般为了支持WVGA、 HVGA和 QVGA 推荐使用这个,不依赖像素。

sp (scaled pixels — best for text size)比例像素 主要处理字体的大小,可以根据系统的字体自适应。

下面几个不太常用: in (inches)英寸 mm (millimeters)毫米 pt (points) 点, 1/72英寸

为了适应不同分辨率,不同的像素密度,推荐使用 dip ,文字使用 sp 。