《3G应用开发——android学习资料大全》由会员分享,可在线阅读,更多相关《3G应用开发——android学习资料大全(126页珍藏版)》请在金锄头文库上搜索。
1、高级软件人才实作培训专家高级软件人才实作培训专家! !北京传智播客教育 3G3G应用开发之应用开发之AndroidAndroid讲师:黎活明讲师:黎活明高级软件人才实作培训专家高级软件人才实作培训专家! !北京传智播客教育 什么是3G3G,全称为3rd Generation,中文含义就是指第三代数字通信。所谓3G,是指将无线通信与国际互联网等多媒体通信结合的新一代移动通信系统。 3G只是一种通信技术标准,符合这个标准的技术有WCDMA、CDMA2000、TD-SCDMA三种无线接口标准。中国联通使用的是WCDMA(世界上大部分3G网络都采用的是该标准) ;中国电信使用的是CDMA2000 (日
2、、韩和北美使用);中国移动使用的是具有自主知识产权的TD-SCDMA(只有中国才使用) 。相对第一代模拟制式手机(1G)和第二代GSM、CDMA等数字手机(2G),3G手机能处理图像、音乐、视频等多种媒体形式,提供包括网页浏览、电话会议、电子商务等多种信息服务。 3G网络与前两代的主要区别是整合了互联网并且数据传输速度有很大的提升。目前中国正在建设3G网络,大城市的3G网络基本上已经铺设好,像北京铺设好了超过2000个基站,深圳铺设了1000多个基站。但是要全民普及到3G 手机尚且需要几年时间。现在,大家使用的手机大多还是2.5G手机,符合2.5G网络的接口标准有CDMA2000 1X和GPR
3、S,中国联通使用的是CDMA2000 1X标准,中国移动使用的是GPRS标准。目前,我们可以把2.5G移动通信技术看作是2G迈向3G的衔接性技术,在2.5G网络下出现了如WAP、蓝牙(Bluetoot) 等技术。对于2.5G网络,我们应该也要有所了解,因为以后大家到企业中有可能会面对2.5G网络下的应用,如:wap项目。高级软件人才实作培训专家高级软件人才实作培训专家! !北京传智播客教育 什么是什么是AndroidAndroidlAndroid是Google在2007年11月5日推出的开源手机操作系统。目前Android在中国的发展是非常火的,为了节省研发费用,国内很多的手机厂商和移动运营商
4、纷纷加入到了android阵营,其中包括中国移动,中国联通,中国电信,华为,联想等大企业。在中国不管是知名的手机生产厂商还是山寨手机厂商,都已经开始生产Android操作系统的手机。l另外android应用的范围不仅仅在手机,还被应用在汽车、平板电脑、和智能上网设备上,听说国外已经有了安装Android系统,并且能够上网的智能电饭煲,用户在千里之外就可以操作电饭煲进行煮饭。l由于大家大多使用的手机都属傻瓜手机,也就是打打电话、发发短信。从今天开始,大家必须改变这个观念了,大家需要把智能手机看作是一台电脑,只要安装上相应软件它就能完成电脑所能完成的一切。高级软件人才实作培训专家高级软件人才实作培
5、训专家! !北京传智播客教育 智能手机软件平台智能手机软件平台有:Symbian, Windows Mobile, RIM BlackBerry, Android, iPhone, Java/J2ME。2010年市场份额:Symbian 36.6%Android 25.5%iPhone 16.7windows Mobile 2.8%linux 2.1%高级软件人才实作培训专家高级软件人才实作培训专家! !北京传智播客教育 如何安装 Android SDK 和Eclipse 插件所需开发环境所需开发环境:JDK 5或以上版本(仅有JRE不够) 、Eclipse 3.4 或以上版本下载用于在下载用
6、于在Eclipse 开发开发android应用的应用的ADT 插件插件 在企业开发中,很多程序员使用Eclipse IDE作为应用的开发环境。为了使得Android应用的创建,运行和调试更加方便快捷。Android的开发团队专门针对Eclipse IDE定制了一个插件:Android Development Tools(ADT) 下载地址:http:/ Eclipse 插件插件 (ADT)启动 Eclipse,选择 Help Install New Software,在出现的对话框里,点击Add按钮,在对话框的name一栏输入“ADT”, 然后点击Archive.,浏览和选择已经下载的ADT插
7、件插件压缩文件。 点击 OK.。返回可用软件的视图,你会看到这个插件,然后选择Developer Tools (会选中下面的“Android Developer Tools”和 “Android Editors“),点击 Next,最后重启 Eclipse。下载安装下载安装Android SDK:Android SDK包含了开发Android应用所依赖的jar文件、运行环境及相关工具。 下载地址: http:/ Eclipse,选择window-preferences,在打开的视图左边点击android,在右边的SDK Location中选择Android SDK所在位置。高级软件人才实作培训
8、专家高级软件人才实作培训专家! !北京传智播客教育 开发第一个Android应用打开Eclipse,新建项目(点击FileNewProject),在项目列表中展开Android目录,选择Android Project,如下图:高级软件人才实作培训专家高级软件人才实作培训专家! !北京传智播客教育 开发第一个Android应用高级软件人才实作培训专家高级软件人才实作培训专家! !北京传智播客教育 开发第一个Android应用点击”finish”即可完成项目的创建,创建后的项目已经是一个可运行的Android应用,我们可以通过下面方式运行此应用:点击工具栏上机器人形状的虚拟设备管理器(简称“AVD
9、“),如下:高级软件人才实作培训专家高级软件人才实作培训专家! !北京传智播客教育 开发第一个Android应用在打开的虚拟设备管理器中创建一个虚拟手机:高级软件人才实作培训专家高级软件人才实作培训专家! !北京传智播客教育 开发第一个Android应用在项目上右键点击run as Android application,如下图:高级软件人才实作培训专家高级软件人才实作培训专家! !北京传智播客教育 Android应用程序架构src/ java原代码存放目录原代码存放目录gen/ 自动生成目录自动生成目录gen 目录中存放所有由Android开发工具自动生成的文件。目录中最重要的就是R.jav
10、a文件。 这个文件由Android开发工具自动产生的。Android开发工具会自动根据你放入res目录的资源,同步更新修改R.java文件。正因为R.java文件是由开发工具自动生成的,所以我们应避免手工修改R.java。R.java在应用中起到了字典的作用,它包含了各种资源的id,通过R.java,应用可以很方便地找到对应资源。res/ 资源资源(Resource)目录目录在这个目录中我们可以存放应用使用到的各种资源,如xml界面文件,图片或数据。具体请看ppt下方备注栏。assets资源目录资源目录Android除了提供/res目录存放资源文件外,在/assets目录也可以存放资源文件,而
11、且/assets目录下的资源文件不会在R.java自动生成ID,所以读取/assets目录下的文件必须指定文件的路径,如:file:/android_asset/xxx.3gpAndroidManifest.xml 项目清单文件项目清单文件 这个文件列出了应用程序所提供的功能,以后你开发好的各种组件需要在该文件中进行配置,如果应用使用到了系统内置的应用(如电话服务、互联网服务、短信服务、GPS服务等等),你还需在该文件中声明使用权限。default.properties 项目环境信息项目环境信息,一般是不需要修改此文件高级软件人才实作培训专家高级软件人才实作培训专家! !北京传智播客教育 电话
12、拔号器效果图:高级软件人才实作培训专家高级软件人才实作培训专家! !北京传智播客教育 电话拔号器因为应用要使用手机的电话服务,所以要在清单文件AndroidManifest.xml中添加电话服务权限: 略. 高级软件人才实作培训专家高级软件人才实作培训专家! !北京传智播客教育 电话拔号器界面布局: LinearLayout (线性布局)、AbsoluteLayout(绝对布局)、RelativeLayout(相对布局)、TableLayout(表格布局)、FrameLayout(帧布局)高级软件人才实作培训专家高级软件人才实作培训专家! !北京传智播客教育 Android中的显示单位l px
13、 (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 ,文字
14、使用sp。高级软件人才实作培训专家高级软件人才实作培训专家! !北京传智播客教育 电话拔号器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(n
15、ew 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); ); 高级软件人才实作培训专家高级软件人才实作培训专家! !北京传智播客教育 电话拔号器测试步骤: 1在Eclipse中运行此应用
16、2在Dos窗口中进入android SDK安装路径的tools目录,输入以下命令再开启一个Android模拟器: emulator -data itcast 注:itcast为用户数据存取文件,如果该文件不存在,默认在tools目录创建该文件 3在电话扰号器中输入上图现显的电话号码高级软件人才实作培训专家高级软件人才实作培训专家! !北京传智播客教育 “尚未注册网络”错误信息的解决办法打开Android模拟器时,出现无信号,拔打电话或发短信时,提示“尚未注册网络”错误信息的解决方案如下。l 场景一:你的电脑没有连接上互联网,同时也没有在局域网。 解决办法:右键点击网上邻居,选择属性,在网络连接
17、窗口中右键点击本地连接,选择属性,设置TCP/IP属性如下: IP地址:192.168.1.100 子网掩码:255.255.255.0 默认网关:192.168.1.100 首选DNS服务器:192.168.1.100l 场景二:你的电脑没有连接上互联网,但在局域网。 解决办法:右键点击网上邻居,选择属性,在网络连接窗口中右键点击本地连接,选择属性,设置TCP/IP属性如下: IP地址:设置成你所在局域网的IP,如:192.168.1.100 子网掩码:设置成你所在局域网的掩码,如:255.255.255.0 默认网关:设置成你所在局域网的网关,一般网关的IP格式为:*.*.*.1,如:19
18、2.168.1.1 首选DNS服务器:设置成你所在局域网的路由器IP,一般路由器的IP格式为:*.*.*.1,如:192.168.1.1l 最后一种解决方案是:让你的电脑连接上互联网。高级软件人才实作培训专家高级软件人才实作培训专家! !北京传智播客教育 短信发送器效果图:高级软件人才实作培训专家高级软件人才实作培训专家! !北京传智播客教育 短信发送器因为应用要使用手机的短信服务,所以要在清单文件AndroidManifest.xml中添加短信服务权限: 略. 高级软件人才实作培训专家高级软件人才实作培训专家! !北京传智播客教育 短信发送器界面布局: 高级软件人才实作培训专家高级软件人才实
19、作培训专家! !北京传智播客教育 短信发送器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);/如果字数超过70,需拆分成多条短信发送 List m
20、sgs = smsManager.divideMessage(content);for(String msg : msgs) smsManager.sendTextMessage(mobile, null, msg, sentIntent, null); /第四个参数用于告之短信发送状态,最后一个参数用于告之短信接收状态 Toast.makeText(SMSSender.this, 短信发送完成, Toast.LENGTH_LONG).show();高级软件人才实作培训专家高级软件人才实作培训专家! !北京传智播客教育 短信发送器测试步骤: 1在Eclipse中运行此应用 2在Dos窗口中进入
21、android SDK安装路径的tools目录,输入以下命令再开启一个Android模拟器: emulator -data itcast 注:itcast为用户数据存取文件,如果该文件不存在,默认在tools目录创建该文件 3在短信发送器的手机号中输入上图现显的电话号码注:目前Android系统对中文短信尚未支持,所以发送中文短信会有乱码,这个问题日后会被解决的。高级软件人才实作培训专家高级软件人才实作培训专家! !北京传智播客教育 发送彩信可以通过调用系统自带的短信程序发送彩信:Intent intent = new Intent(Intent.ACTION_SEND);intent.put
22、Extra(Intent.EXTRA_STREAM, Uri.parse(file:/sdcard/cong.png);intent.putExtra(address, “13677789999”);intent.putExtra(exit_on_sent, true);intent.putExtra(subject, its subject);intent.putExtra(sms_body, its content);intent.setType(“image/jpeg”); / 视频:video/mpeg* ,文本:text/plainstartActivity(intent);高级软件
23、人才实作培训专家高级软件人才实作培训专家! !北京传智播客教育 对应用进行单元测试在实际开发中,开发android软件的过程需要不断地进行测试。使用Junit测试框架,是正规Android开发的必用技术,在Junit中可以得到组件,可以模拟发送事件和检测程序处理的正确性。第一步:首先在AndroidManifest.xml中加入下面红色代码: . 上面targetPackage指定的包要和应用的package相同。第二步:编写单元测试代码(选择要测试的方法,右键点击“Run As”-“Android Junit Test” ):import android.test.AndroidTestCa
24、se;import android.util.Log;public class XMLTest extends AndroidTestCase public void testSomething() throws Throwable Assert.assertTrue(1 + 1 = 3); 高级软件人才实作培训专家高级软件人才实作培训专家! !北京传智播客教育 数据存储与访问很多时候我们开发的软件需要对处理后的数据进行存储,以供再次访问。Android为数据存储提供了如下几种方式:l文件lSharedPreferences(参数)lSQLite数据库l内容提供者(Content provid
25、er)l网络高级软件人才实作培训专家高级软件人才实作培训专家! !北京传智播客教育 使用文件进行数据存储首先给大家介绍使用文件如何对数据进行存储,Activity提供了openFileOutput()方法可以用于把数据输出到文件中,具体的实现过程与在J2SE环境中保存数据到文件中是一样的。public class FileActivity extends Activity Override public void onCreate(Bundle savedInstanceState) . FileOutputStream outStream = this.openFileOutput(itca
26、st.txt, Context.MODE_PRIVATE); outStream.write(传智播客.getBytes(); outStream.close(); openFileOutput()方法的第一参数用于指定文件名称,不能包含路径分隔符“/” ,如果文件不存在,Android 会自动创建它。创建的文件保存在/data/data/files目录,如: /data/data/cn.itcast.action/files/itcast.txt ,通过点击Eclipse菜单“Window”-“Show View”-“Other”,在对话窗口中展开android文件夹,选择下面的File E
27、xplorer视图,然后在File Explorer视图中展开/data/data/files目录就可以看到该文件。openFileOutput()方法的第二参数用于指定操作模式,有四种模式,分别为: Context.MODE_PRIVATE = 0Context.MODE_APPEND = 32768Context.MODE_WORLD_READABLE = 1Context.MODE_WORLD_WRITEABLE = 2高级软件人才实作培训专家高级软件人才实作培训专家! !北京传智播客教育 使用文件进行数据存储Context.MODE_PRIVATE:为默认操作模式,代表该文件是私有数据
28、,只能被应用本身访问,在该模式下,写入的内容会覆盖原文件的内容,如果想把新写入的内容追加到原文件中。可以使用Context.MODE_APPENDContext.MODE_APPEND:模式会检查文件是否存在,存在就往文件追加内容,否则就创建新文件。Context.MODE_WORLD_READABLE和Context.MODE_WORLD_WRITEABLE用来控制其他应用是否有权限读写该文件。MODE_WORLD_READABLE:表示当前文件可以被其他应用读取;MODE_WORLD_WRITEABLE:表示当前文件可以被其他应用写入。如果希望文件被其他应用读和写,可以传入: openFi
29、leOutput(itcast.txt, Context.MODE_WORLD_READABLE + Context.MODE_WORLD_WRITEABLE);android有一套自己的安全模型,当应用程序(.apk)在安装时系统就会分配给他一个userid,当该应用要去访问其他资源比如文件的时候,就需要userid匹配。默认情况下,任何应用创建的文件,sharedpreferences,数据库都应该是私有的(位于/data/data/files),其他程序无法访问。除非在创建时指定了Context.MODE_WORLD_READABLE或者Context.MODE_WORLD_WRITEA
30、BLE ,只有这样其他程序才能正确访问。高级软件人才实作培训专家高级软件人才实作培训专家! !北京传智播客教育 读取文件内容如果要打开存放在/data/data/files目录应用私有的文件,可以使用Activity提供openFileInput()方法。FileInputStream inStream = this.getContext().openFileInput(itcast.txt);Log.i(FileTest, readInStream(inStream);readInStream()的方法请看本页下面备注。或者直接使用文件的绝对路径:File file = new File(/
31、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权限
32、。Activity还提供了getCacheDir()和getFilesDir()方法:getCacheDir()方法用于获取/data/data/cache目录getFilesDir()方法用于获取/data/data/files目录高级软件人才实作培训专家高级软件人才实作培训专家! !北京传智播客教育 把文件存放在SDCard使用Activity的openFileOutput()方法保存文件,文件是存放在手机空间上,一般手机的存储空间不是很大,存放些小文件还行,如果要存放像视频这样的大文件,是不可行的。对于像视频这样的大文件,我们可以把它存放在SDCard。 SDCard是干什么的?你可以把
33、它看作是移动硬盘或U盘。在模拟器中使用SDCard,你需要先创建一张SDCard卡(当然不是真的SDCard,只是镜像文件)。创建SDCard可以在Eclipse创建模拟器时随同创建,也可以使用DOS命令进行创建,如下:在Dos窗口中进入android SDK安装路径的tools目录,输入以下命令创建一张容量为2G的SDCard,文件后缀可以随便取,建议使用.img:mksdcard 2048M D:AndroidToolsdcard.img在程序中访问在程序中访问SDCard,你需要申请访问你需要申请访问SDCard的权限。的权限。在AndroidManifest.xml中加入访问SDCar
34、d的权限如下:高级软件人才实作培训专家高级软件人才实作培训专家! !北京传智播客教育 把文件存放在SDCard要往SDCard存放文件,程序必须先判断手机是否装有SDCard,并且可以进行读写。注意:访问SDCard必须在AndroidManifest.xml中加入访问SDCard的权限if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED) File sdCardDir = Environment.getExternalStorageDirectory();/获取SDCard目录 File saveF
35、ile = new File(sdCardDir, “itcast.txt”);FileOutputStream outStream = new FileOutputStream(saveFile);outStream.write(传智播客.getBytes();outStream.close();Environment.getExternalStorageState()方法用于获取SDCard的状态,如果手机装有SDCard,并且可以进行读写,那么方法返回的状态等于Environment.MEDIA_MOUNTED。Environment.getExternalStorageDirector
36、y()方法用于获取SDCard的目录,当然要获取SDCard的目录,你也可以这样写:File sdCardDir = new File(/mnt/sdcard); /获取SDCard目录File saveFile = new File(sdCardDir, itcast.txt); /上面两句代码可以合成一句: File saveFile = new File(/mnt/sdcard/itcast.txt);FileOutputStream outStream = new FileOutputStream(saveFile);outStream.write(传智播客test.getBytes(
37、);outStream.close();高级软件人才实作培训专家高级软件人才实作培训专家! !北京传智播客教育 使用SAX或者DOM或者pull解析XML文件在Android平台上可以使用Simple API for XML(SAX) 、 Document Object Model(DOM)和Android附带的pull解析器解析XML文件。 下面是本例子要解析的XML文件:文件名称:itcast.xmlliming30zhangxiaoxiao25例子定义了一个javabean用于存放上面解析出来的xml内容, 这个javabean为Person,代码请见本页下面备注:高级软件人才实作培训专
38、家高级软件人才实作培训专家! !北京传智播客教育 使用SAX读取XML文件SAX是一个解析速度快并且占用内存少的xml解析器,非常适合用于Android等移动设备。 SAX解析XML文件采用的是事件驱动,也就是说,它并不需要解析完整个文档,在按内容顺序解析文档的过程中,SAX会判断当前读到的字符是否合法XML语法中的某部分,如果符合就会触发事件。所谓事件,其实就是一些回调(callback)方法,这些方法(事件)定义在ContentHandler接口。下面是一些ContentHandler接口常用的方法:startDocument()当遇到文档的开头的时候,调用这个方法,可以在其中做一些预处理
39、的工作。endDocument()和上面的方法相对应,当文档结束的时候,调用这个方法,可以在其中做一些善后的工作。 startElement(String namespaceURI, String localName, String qName, Attributes atts) 当读到一个开始标签的时候,会触发这个方法。namespaceURI就是命名空间,localName是不带命名空间前缀的标签名,qName是带命名空间前缀的标签名。通过atts可以得到所有的属性名和相应的值。要注意的是SAX中一个重要的特点就是它的流式处理,当遇到一个标签的时候,它并不会纪录下以前所碰到的标签,也就是说
40、,在startElement()方法中,所有你所知道的信息,就是标签的名字和属性,至于标签的嵌套结构,上层标签的名字,是否有子元属等等其它与结构相关的信息,都是不得而知的,都需要你的程序来完成。这使得SAX在编程处理上没有DOM来得那么方便。endElement(String uri, String localName, String name)这个方法和上面的方法相对应,在遇到结束标签的时候,调用这个方法。characters(char ch, int start, int length) 这个方法用来处理在XML文件中读到的内容,第一个参数为文件的字符串内容,后面两个参数是读到的字符串在这
41、个数组中的起始位置和长度,使用new String(ch,start,length)就可以获取内容。高级软件人才实作培训专家高级软件人才实作培训专家! !北京传智播客教育 使用SAX读取XML文件只要为SAX提供实现ContentHandler接口的类,那么该类就可以得到通知事件(实际上就是SAX调用了该类中的回调方法)。因为ContentHandler是一个接口,在使用的时候可能会有些不方便,因此,SAX还为其制定了一个Helper类:DefaultHandler,它实现了ContentHandler接口,但是其所有的方法体都为空,在实现的时候,你只需要继承这个类,然后重写相应的方法即可。使
42、用SAX解析itcast.xml的代码如下:public static List 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/names
43、paces,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的代码实现请看本页下面备注。高级软件人才实作培训专家高级软件人才实作培训专家! !北京传智播客教育 使
44、用DOM读取XML文件除了使用 SAX可以解析XML文件,大家也可以使用熟悉的DOM来解析XML文件。 DOM解析XML文件时,会将XML文件的所有内容以文档树方式存放在内存中,然后允许您使用DOM API遍历XML树、检索所需的数据。使用DOM操作XML的代码看起来是比较直观的,并且在编码方面比基于SAX的实现更加简单。但是,因为DOM需要将XML文件的所有内容以文档树方式存放在内存中,所以内存的消耗比较大,特别对于运行Android的移动设备来说,因为设备的资源比较宝贵,所以建议还是采用SAX来解析XML文件,当然,如果XML文件的内容比较小采用DOM也是可行的。代码请看本页下方备注高级软
45、件人才实作培训专家高级软件人才实作培训专家! !北京传智播客教育 使用Pull解析器读取XML文件除了可以使用 SAX或DOM解析XML文件之外,大家也可以使用Android内置的Pull解析器解析XML文件。 Pull解析器是一个开源的java项目,既可以用于android,也可以用于JavaEE。如果用在javaEE需要把其jar文件放入类路径中,因为Android已经集成进了Pull解析器,所以无需添加任何jar文件。android系统本身使用到的各种xml文件,其内部也是采用Pull解析器进行解析的。 Pull解析器的运行方式与 SAX 解析器相似。它提供了类似的事件,如:开始元素和结
46、束元素事件,使用parser.next()可以进入下一个元素并触发相应事件。跟SAX不同的是, Pull解析器产生的事件是一个数字,而非方法,因此可以使用一个switch对感兴趣的事件进行处理。当元素开始解析时,调用parser.nextText()方法可以获取下一个Text类型节点的值。使用Pull解析器读取itcast.xml的代码在本页下方备注Pull解析器的源码及文档下载网址:http:/xmlpull.org/xmlpull-website/impls.shtml高级软件人才实作培训专家高级软件人才实作培训专家! !北京传智播客教育 使用Pull解析器生成XML文件有些时候,我们需要
47、生成一个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);OutputStr
48、eamWriter 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 conten
49、t = writer.toString();高级软件人才实作培训专家高级软件人才实作培训专家! !北京传智播客教育 使用SharedPreferences进行数据存储很多时候我们开发的软件需要向用户提供软件参数设置功能,例如我们常用的QQ,用户可以设置是否允许陌生人添加自己为好友。对于软件配置参数的保存,如果是window软件通常我们会采用ini文件进行保存,如果是j2se应用,我们会采用properties属性文件或者xml进行保存。如果是Android应用,我们最适合采用什么方式保存软件配置参数呢?Android平台给我们提供了一个SharedPreferences类,它是一个轻量级的存储
50、类,特别适合用于保存软件配置参数。使用SharedPreferences保存数据,其背后是用xml文件存放数据,文件存放在/data/data/shared_prefs目录下:SharedPreferences sharedPreferences = getSharedPreferences(itcast, Context.MODE_PRIVATE);Editor editor = sharedPreferences.edit();/获取编辑器editor.putString(name, 传智播客);editor.putInt(age, 4);mit();/提交修改生成的itcast.xml文
51、件内容如下:传智播客因为SharedPreferences背后是使用xml文件保存数据,getSharedPreferences(name,mode)方法的第一个参数用于指定该文件的名称,名称不用带后缀,后缀会由Android自动加上。方法的第二个参数指定文件的操作模式,共有四种操作模式,这四种模式前面介绍使用文件方式保存数据时已经讲解过。如果希望SharedPreferences背后使用的xml文件能被其他应用读和写,可以指定Context.MODE_WORLD_READABLE和Context.MODE_WORLD_WRITEABLE权限。另外Activity还提供了另一个getPrefe
52、rences(mode)方法操作SharedPreferences,这个方法默认使用当前类不带包名的类名作为文件的名称。高级软件人才实作培训专家高级软件人才实作培训专家! !北京传智播客教育 访问SharedPreferences中的数据访问SharedPreferences中的数据代码如下:SharedPreferences sharedPreferences = getSharedPreferences(itcast, Context.MODE_PRIVATE);/getString()第二个参数为缺省值,如果preference中不存在该key,将返回缺省值String name = s
53、haredPreferences.getString(name, );int age = sharedPreferences.getInt(age, 1);如果访问其他应用中的Preference,前提条件是:该preference创建时指定了Context.MODE_WORLD_READABLE或者Context.MODE_WORLD_WRITEABLE权限。如:有个为cn.itcast.action的应用使用下面语句创建了preference。getSharedPreferences(itcast, Context.MODE_WORLD_READABLE);其他应用要访问上面应用的pref
54、erence,首先需要创建上面应用的Context,然后通过Context 访问preference ,访问preference时会在应用所在包下的shared_prefs目录找到preference :Context otherAppsContext = createPackageContext(cn.itcast.action, Context.CONTEXT_IGNORE_SECURITY);SharedPreferences sharedPreferences = otherAppsContext.getSharedPreferences(itcast, Context.MODE_WO
55、RLD_READABLE);String name = sharedPreferences.getString(name, );int age = sharedPreferences.getInt(age, 0);如果不通过创建Context访问其他应用的preference,也可以以读取xml文件方式直接访问其他应用preference对应的xml文件,如: File xmlFile = new File(“/data/data/shared_prefs/itcast.xml”);/应替换成应用的包名高级软件人才实作培训专家高级软件人才实作培训专家! !北京传智播客教育 使用嵌入式关系型SQ
56、Lite数据库存储数据在Android平台上,集成了一个嵌入式关系型数据库SQLite,SQLite3支持 NULL、INTEGER、REAL(浮点数字)、TEXT(字符串文本)和BLOB(二进制对象)数据类型,虽然它支持的类型只有五种,但实际上sqlite3也接受varchar(n)、char(n)、decimal(p,s) 等数据类型,只不过在运算或保存时会转成对应的五种数据类型。 SQLite最大的特点是你可以把各种类型的数据保存到任何字段中,而不用关心字段声明的数据类型是什么。例如:可以在Integer类型的字段中存放字符串,或者在布尔型字段中存放浮点数,或者在字符型字段中存放日期型值
57、。 但有一种情况例外:定义为INTEGER PRIMARY KEY的字段只能存储64位整数, 当向这种字段保存除整数以外的数据时,将会产生错误。 另外,在编写CREATE TABLE 语句时,你可以省略跟在字段名称后面的数据类型信息,如下面语句你可以省略 name字段的类型信息:CREATE TABLE person (personid integer primary key autoincrement, name varchar(20)SQLite可以解析大部分标准SQL语句,如:查询语句:select * from 表名 where 条件子句 group by 分组字句 having .
58、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(nam
59、e, age) values(传智,3)更新语句:update 表名 set 字段名=值 where 条件子句。如:update person set name=传智 where id=10删除语句:delete from 表名 where 条件子句。如:delete from person where id=10获取添加记录后自增长的ID值:SELECT last_insert_rowid()高级软件人才实作培训专家高级软件人才实作培训专家! !北京传智播客教育 使用SQLiteOpenHelper对数据库进行版本管理我们在编写数据库应用软件时,需要考虑这样的问题:因为我们开发的软件可能会安
60、装在很多用户的手机上,如果应用使用到了SQLite数据库,我们必须在用户初次使用软件时创建出应用使用到的数据库表结构及添加一些初始化记录,另外在软件升级的时候,也需要对数据表结构进行更新。那么,我们如何才能实现在用户初次使用或升级软件时自动在用户的手机上创建出应用需要的数据库表呢?总不能让我们在每个需要安装此软件的手机上通过手工方式创建数据库表吧?因为这种需求是每个数据库应用都要面临的,所以在Android系统,为我们提供了一个名为SQLiteOpenHelper的抽象类,必须继承它才能使用,它是通过对数据库版本进行管理来实现前面提出的需求。 为了实现对数据库版本进行管理,SQLiteOpen
61、Helper类提供了两个重要的方法,分别是onCreate(SQLiteDatabase db)和onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion),前者用于初次使用软件时生成数据库表,后者用于升级软件时更新数据库表结构。当调用SQLiteOpenHelper的getWritableDatabase()或者getReadableDatabase()方法获取用于操作数据库的SQLiteDatabase实例的时候,如果数据库不存在,Android系统会自动生成一个数据库,接着调用onCreate()方法,onCreate()方法
62、在初次生成数据库时才会被调用,在onCreate()方法里可以生成数据库表结构及添加一些应用使用到的初始化数据。onUpgrade()方法在数据库的版本发生变化时会被调用,一般在软件升级时才需改变版本号,而数据库的版本是由程序员控制的,假设数据库现在的版本是1,由于业务的变更,修改了数据库表结构,这时候就需要升级软件,升级软件时希望更新用户手机里的数据库表结构,为了实现这一目的,可以把原来的数据库版本设置为2(有同学问设置为3行不行?当然可以,如果你愿意,设置为100也行),并且在onUpgrade()方法里面实现表结构的更新。当软件的版本升级次数比较多,这时在onUpgrade()方法里面可
63、以根据原版号和目标版本号进行判断,然后作出相应的表结构及数据更新。getWritableDatabase()和getReadableDatabase()方法都可以获取一个用于操作数据库的SQLiteDatabase实例。但getWritableDatabase() 方法以读写方式打开数据库,一旦数据库的磁盘空间满了,数据库就只能读而不能写,倘若使用getWritableDatabase()打开数据库就会出错。getReadableDatabase()方法先以读写方式打开数据库,如果数据库的磁盘空间满了,就会打开失败,当打开失败后会继续尝试以只读方式打开数据库。高级软件人才实作培训专家高级软件人
64、才实作培训专家! !北京传智播客教育 使用SQLiteOpenHelper对数据库进行版本管理public class DatabaseHelper extends SQLiteOpenHelper /类没有实例化,是不能用作父类构造器的参数,必须声明为静态 private static final String name = itcast; /数据库名称 private static final int version = 1; /数据库版本 public DatabaseHelper(Context context) /第三个参数CursorFactory指定在执行查询时获得一个游标实例的
65、工厂类,设置为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, i
66、nt newVersion) db.execSQL( ALTER TABLE person ADD phone VARCHAR(12) NULL ); /往表中增加一列/ DROP TABLE IF EXISTS person 删除表 在实际项目开发中,当数据库表结构发生更新时,应该避免用户存放于数据库中的数据丢失。高级软件人才实作培训专家高级软件人才实作培训专家! !北京传智播客教育 使用SQLiteDatabase操作SQLite数据库Android提供了一个名为SQLiteDatabase的类,该类封装了一些操作数据库的API,使用该类可以完成对数据进行添加(Create)、查询(Ret
67、rieve)、更新(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语句会
68、往person表中添加进一条记录,在实际应用中, 语句中的“传智播客”这些参数值会由用户输入界面提供,如果把用户输入的内容原样组拼到上面的insert语句, 当用户输入的内容含有单引号时,组拼出来的SQL语句就会存在语法错误。要解决这个问题需要对单引号进行转义,也就是把单引号转换成两个单引号。有些时候用户往往还会输入像“ & ”这些特殊SQL符号,为保证组拼好的SQL语句语法正确,必须对SQL语句中的这些特殊SQL符号都进行转义,显然,对每条SQL语句都做这样的处理工作是比较烦琐的。 SQLiteDatabase类提供了一个重载后的execSQL(String sql, Object bind
69、Args)方法,使用这个方法可以解决前面提到的问题,因为这个方法支持使用占位符参数(?)。使用例子如下:SQLiteDatabase db = .;db.execSQL(insert into person(name, age) values(?,?), new Object传智播客, 4); db.close();execSQL(String sql, Object bindArgs)方法的第一个参数为SQL语句,第二个参数为SQL语句中占位符参数的值,参数值在数组中的顺序要和占位符的位置对应。高级软件人才实作培训专家高级软件人才实作培训专家! !北京传智播客教育 使用SQLiteDatab
70、ase操作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);/获取第三列的值cur
71、sor.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作用很相似。使用moveT
72、oNext()方法可以将游标从当前行移动到下一行,如果已经移过了结果集的最后一行,返回结果为false,否则为true。另外Cursor 还有常用的moveToPrevious()方法(用于将游标从当前行移动到上一行,如果已经移过了结果集的第一行,返回值为false,否则为true )、moveToFirst()方法(用于将游标移动到结果集的第一行,如果结果集为空,返回值为false,否则为true )和moveToLast()方法(用于将游标移动到结果集的最后一行,如果结果集为空,返回值为false,否则为true ) 。高级软件人才实作培训专家高级软件人才实作培训专家! !北京传智播客教育
73、 使用SQLiteDatabase操作SQLite数据库除了前面给大家介绍的execSQL()和rawQuery()方法, SQLiteDatabase还专门提供了对应于添加、删除、更新、查询的操作方法: insert()、delete()、update()和query() 。这些方法实际上是给那些不太了解SQL语法的菜鸟使用的,对于熟悉SQL语法的程序员而言,直接使用execSQL()和rawQuery()方法执行SQL语句就能完成数据的添加、删除、更新、查询操作。Insert()方法用于添加数据,各个字段的数据使用ContentValues进行存放。 ContentValues类似于MAP
74、,相对于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”, nu
75、ll, values);/返回新添记录的行号,与主键id无关不管第三个参数是否包含数据,执行Insert()方法必然会添加一条记录,如果第三个参数为空,会添加一条除主键之外其他字段值为Null的记录。Insert()方法内部实际上通过构造insert SQL语句完成数据的添加,Insert()方法的第二个参数用于指定空值字段的名称,相信大家对该参数会感到疑惑,该参数的作用是什么?是这样的:如果第三个参数values 为Null或者元素个数为0, 由于Insert()方法要求必须添加一条除了主键之外其它字段为Null值的记录,为了满足SQL语法的需要, insert语句必须给定一个字段名,如:i
76、nsert into person(name) values(NULL),倘若不给定字段名 , insert语句就成了这样: insert into person() values(),显然这不满足标准SQL的语法。对于字段名,建议使用主键之外的字段,如果使用了INTEGER类型的主键字段,执行类似insert into person(personid) values(NULL)的insert语句后,该主键字段值也不会为NULL。如果第三个参数values 不为Null并且元素的个数大于0 ,可以把第二个参数设置为null。高级软件人才实作培训专家高级软件人才实作培训专家! !北京传智播客教育
77、 使用SQLiteDatabase操作SQLite数据库delete()方法的使用:SQLiteDatabase db = databaseHelper.getWritableDatabase();db.delete(person, personid?, new String2);db.close();上面代码用于从person表中删除personid小于2的记录。update()方法的使用:SQLiteDatabase db = databaseHelper.getWritableDatabase();ContentValues values = new ContentValues();va
78、lues.put(“name”, “传智播客”);/key为字段名,value为值db.update(person, values, personid=?, new String1); db.close();上面代码用于把person表中personid等于1的记录的name字段的值改为“传智播客”。高级软件人才实作培训专家高级软件人才实作培训专家! !北京传智播客教育 使用SQLiteDatabase操作SQLite数据库query()方法实际上是把select语句拆分成了若干个组成部分,然后作为方法的输入参数:SQLiteDatabase db = databaseHelper.getWr
79、itableDatabase();Cursor cursor = db.query(person, new Stringpersonid,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);/获取第三列的值cu
80、rsor.close();db.close(); 上面代码用于从person表中查找name字段含有“传智”的记录,匹配的记录按personid降序排序,对排序后的结果略过第一条记录,只获取2条记录。query(table, columns, selection, selectionArgs, groupBy, having, orderBy, limit)方法各参数的含义:table:表名。相当于select语句from关键字后面的部分。如果是多表联合查询,可以用逗号将两个表名分开。columns:要查询出来的列名。相当于select语句select关键字后面的部分。selection:查询
81、条件子句,相当于select语句where关键字后面的部分,在条件子句允许使用占位符“?”selectionArgs:对应于selection语句中占位符的值,值在数组中的位置与占位符在语句中的位置必须一致,否则就会有异常。groupBy:相当于select语句group by关键字后面的部分having:相当于select语句having关键字后面的部分orderBy:相当于select语句order by关键字后面的部分,如:personid desc, age asc;limit:指定偏移量和获取的记录数,相当于select语句limit关键字后面的部分。高级软件人才实作培训专家高级软件
82、人才实作培训专家! !北京传智播客教育 使用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 saved
83、InstanceState) . 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 i
84、nto person(name, age) values(?,?), new Object传智播客, 4);db.close(); ); 第一次调用getWritableDatabase()或getReadableDatabase()方法后,SQLiteOpenHelper会缓存当前的SQLiteDatabase实例,SQLiteDatabase实例正常情况下会维持数据库的打开状态,所以在你不再需要SQLiteDatabase实例时,请及时调用close()方法释放资源。一旦SQLiteDatabase实例被缓存,多次调用getWritableDatabase()或getReadableDat
85、abase()方法得到的都是同一实例。高级软件人才实作培训专家高级软件人才实作培训专家! !北京传智播客教育 使用事务操作SQLite数据库使用SQLiteDatabase的beginTransaction()方法可以开启一个事务,程序执行到endTransaction() 方法时会检查事务的标志是否为成功,如果程序执行到endTransaction()之前调用了setTransactionSuccessful() 方法设置事务的标志为成功则提交事务,如果没有调用setTransactionSuccessful() 方法则回滚事务。使用例子如下: SQLiteDatabase db = .;d
86、b.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();/由事务的标志决定是提交事务,还
87、是回滚事务 db.close(); 上面两条SQL语句在同一个事务中执行。高级软件人才实作培训专家高级软件人才实作培训专家! !北京传智播客教育 使用ContentProvider(内容提供者)共享数据ContentProvider 在android中的作用是对外共享数据,也就是说你可以通过ContentProvider把应用中的数据共享给其他应用访问,其他应用可以通过ContentProvider 对你应用中的数据进行添删改查。关于数据共享,以前我们学习过文件操作模式,知道通过指定文件的操作模式为Context.MODE_WORLD_READABLE 或Context.MODE_WORLD_
88、WRITEABLE同样也可以对外共享数据。那么,这里为何要使用ContentProvider 对外共享数据呢?是这样的,如果采用文件操作模式对外共享数据,数据的访问方式会因数据存储的方式而不同,导致数据的访问方式无法统一,如:采用xml文件对外共享数据,需要进行xml解析才能读取数据;采用sharedpreferences共享数据,需要使用sharedpreferences API读取数据。使用ContentProvider对外共享数据的好处是统一了数据的访问方式。当应用需要通过ContentProvider对外共享数据时,第一步需要继承ContentProvider并重写下面方法:publi
89、c 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 q
90、uery(Uri uri, String projection, String selection, String selectionArgs, String sortOrder) public String getType(Uri uri)第二步需要在AndroidManifest.xml使用对该ContentProvider进行配置,为了能让其他应用找到该ContentProvider , ContentProvider 采用了authorities(主机名/域名)对它进行唯一标识,你可以把 ContentProvider看作是一个网站(想想,网站也是提供数据者),authorities
91、就是他的域名: 高级软件人才实作培训专家高级软件人才实作培训专家! !北京传智播客教育 Uri介绍Uri代表了要操作的数据,Uri主要包含了两部分信息:1需要操作的ContentProvider ,2对ContentProvider中的什么数据进行操作,一个Uri由以下几部分组成:ContentProvider(内容提供者)的scheme已经由Android所规定, scheme为:content:/主机名(或叫Authority)用于唯一标识这个ContentProvider,外部调用者可以根据这个标识来找到它。路径(path)可以用来表示我们要操作的数据,路径的构建应根据业务而定,如下:要
92、操作person表中id为10的记录,可以构建这样的路径:/person/10要操作person表中id为10的记录的name字段, person/10/name要操作person表中的所有记录,可以构建这样的路径:/person要操作xxx表中的记录,可以构建这样的路径:/xxx当然要操作的数据不一定来自数据库,也可以是文件、xml或网络等其他存储方式,如下:要操作xml文件中person节点下的name节点,可以构建这样的路径:/person/name如果要把一个字符串转换成Uri,可以使用Uri类中的parse()方法,如下:Uri uri = Uri.parse(content:/cn
93、.itcast.provider.personprovider/person)高级软件人才实作培训专家高级软件人才实作培训专家! !北京传智播客教育 UriMatcher类使用介绍因为Uri代表了要操作的数据,所以我们经常需要解析Uri,并从Uri中获取数据。Android系统提供了两个用于操作Uri的工具类,分别为UriMatcher 和ContentUris 。掌握它们的使用,会便于我们的开发工作。UriMatcher类用于匹配Uri,它的用法如下:首先第一步把你需要匹配Uri路径全部给注册上,如下:/常量UriMatcher.NO_MATCH表示不匹配任何路径的返回码UriMatche
94、r 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.addU
95、RI(“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.i
96、tcast.provider.personprovider/person路径,返回的匹配码为1高级软件人才实作培训专家高级软件人才实作培训专家! !北京传智播客教育 ContentUris类使用介绍ContentUris类用于获取Uri路径后面的ID部分,它有两个比较实用的方法:withAppendedId(uri, id)用于为路径加上ID部分:Uri uri = Uri.parse(content:/cn.itcast.provider.personprovider/person)Uri resultUri = ContentUris.withAppendedId(uri, 10); /
97、生成后的Uri为:content:/cn.itcast.provider.personprovider/person/10parseId(uri)方法用于从路径中获取ID部分:Uri uri = Uri.parse(content:/cn.itcast.provider.personprovider/person/10)long personid = ContentUris.parseId(uri);/获取的结果为:10高级软件人才实作培训专家高级软件人才实作培训专家! !北京传智播客教育 使用ContentProvider共享数据ContentProvider类主要方法的作用:public
98、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, Conte
99、ntValues 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
100、类型字符串应该以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
101、类型字符串应该为:“vnd.android.cursor.item/person”。高级软件人才实作培训专家高级软件人才实作培训专家! !北京传智播客教育 使用ContentResolver操作ContentProvider中的数据当外部应用需要对ContentProvider中的数据进行添加、删除、修改和查询操作时,可以使用ContentResolver 类来完成,要获取ContentResolver 对象,可以使用Activity提供的getContentResolver()方法。 ContentResolver 类提供了与ContentProvider类相同签名的四个方法:public
102、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 ur
103、i, String projection, String selection, String selectionArgs, String sortOrder)该方法用于从ContentProvider中获取数据。这些方法的第一个参数为Uri,代表要操作的ContentProvider和对其中的什么数据进行操作,假设给定的是: Uri.parse(“content:/cn.itcast.providers.personprovider/person/10”),那么将会对主机名为cn.itcast.providers.personprovider的ContentProvider进行操作,操作的数据
104、为person表中id为10的记录。高级软件人才实作培训专家高级软件人才实作培训专家! !北京传智播客教育 使用ContentResolver操作ContentProvider中的数据使用ContentResolver对ContentProvider中的数据进行添加、删除、修改和查询操作:ContentResolver resolver = getContentResolver();Uri uri = Uri.parse(content:/cn.itcast.provider.personprovider/person);/添加一条记录ContentValues values = new Co
105、ntentValues();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字段值更改新为liming
106、ContentValues 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);高级软件人才实作
107、培训专家高级软件人才实作培训专家! !北京传智播客教育 监听ContentProvider中数据的变化如果ContentProvider的访问者需要知道ContentProvider中的数据发生变化,可以在ContentProvider 发生数据变化时调用getContentResolver().notifyChange(uri, null)来通知注册在此URI上的访问者,例子如下:public class PersonContentProvider extends ContentProvider public Uri insert(Uri uri, ContentValues values)
108、 db.insert(person, personid, values);getContext().getContentResolver().notifyChange(uri, null);如果ContentProvider的访问者需要得到数据变化通知,必须使用ContentObserver对数据(数据采用uri描述)进行监听,当监听到数据变化通知时,系统就会调用ContentObserver的onChange()方法:getContentResolver().registerContentObserver(Uri.parse(content:/cn.itcast.providers.pers
109、onprovider/person), true, new PersonObserver(new Handler();public class PersonObserver extends ContentObserverpublic PersonObserver(Handler handler) super(handler); public void onChange(boolean selfChange) /此处可以进行相应的业务处理高级软件人才实作培训专家高级软件人才实作培训专家! !北京传智播客教育 窃听用户发出的短信用户使用系统自带的短信程序发送短信,程序会通过ContentProvi
110、der把短信保存进数据库,并且发出一个数据变化通知,使用ContentObserver对数据变化进行监听,在用户发送短信时,就会被ContentObserver窃听到短信:注册监听:getContentResolver().registerContentObserver(Uri.parse(content:/sms), true, new SmsObserver(new Handler();监听类:private final class SmsObserver extends ContentObserverpublic SmsObserver(Handler handler) super(ha
111、ndler);public void onChange(boolean selfChange) /查询发送箱中的短信(处于正在发送状态的短信放在发送箱)Cursor cursor = getContentResolver().query(Uri.parse(content:/sms/outbox),null, null, null, null); while(cursor.moveToNext()StringBuilder sb = new StringBuilder();sb.append(_id=).append(cursor.getInt(cursor.getColumnIndex(_i
112、d);sb.append(,address=).append(cursor.getString(cursor.getColumnIndex(address);sb.append(;body=).append(cursor.getString(cursor.getColumnIndex(body);sb.append(;time=).append(cursor.getLong(cursor.getColumnIndex(date);Log.i(ReceiveSendSMS, sb.toString(); 高级软件人才实作培训专家高级软件人才实作培训专家! !北京传智播客教育 通信录操作使用Con
113、tentResolver对通信录中的数据进行添加、删除、修改和查询操作:加入读写联系人信息的权限添加与查询代码请见ppt下方高级软件人才实作培训专家高级软件人才实作培训专家! !北京传智播客教育 从从InternetInternet获取数据获取数据利用HttpURLConnection对象,我们可以从网络中获取网页数据.URL url = new URL(http:/);HttpURLConnection conn = (HttpURLConnection) url.openConnection();conn.setConnectTimeout(5* 1000);/设置连接超时conn.set
114、RequestMethod(“GET”);/以get方式发起请求if (conn.getResponseCode() != 200) throw new RuntimeException(请求url失败);InputStream is = conn.getInputStream();/得到网络返回的输入流String result = readData(is, GBK);conn.disconnect();/第一个参数为输入流,第二个参数为字符集编码public static String readData(InputStream inSream, String charsetName) th
115、rows ExceptionByteArrayOutputStream outStream = new ByteArrayOutputStream();byte buffer = new byte1024;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);高级软
116、件人才实作培训专家高级软件人才实作培训专家! !北京传智播客教育 从从InternetInternet获取数据获取数据利用HttpURLConnection对象,我们可以从网络中获取文件数据.URL url = new URL(http:/ conn = (HttpURLConnection) url.openConnection();conn.setConnectTimeout(5* 1000);conn.setRequestMethod(GET);if (conn.getResponseCode() != 200) throw new RuntimeException(请求url失败);I
117、nputStream is = conn.getInputStream();readAsFile(is, Img269812337.jpg); public static void readAsFile(InputStream inSream, File file) throws ExceptionFileOutputStream outStream = new FileOutputStream(file);byte buffer = new byte1024;int len = -1;while( (len = inSream.read(buffer) != -1 )outStream.wr
118、ite(buffer, 0, len); outStream.close();inSream.close();高级软件人才实作培训专家高级软件人才实作培训专家! !北京传智播客教育 向向InternetInternet发送请求参数发送请求参数利用HttpURLConnection对象,我们可以向网络发送请求参数.String requestUrl = http:/localhost:8080/itcast/contanctmanage.do;Map requestParams = new HashMap();requestParams.put(age, 12);requestParams.pu
119、t(name, 中国); StringBuilder params = new StringBuilder();for(Map.Entry 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 = pa
120、rams.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.setRequ
121、estProperty(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.getRespons
122、eCode() = 200 ) String result = readAsString(conn.getInputStream(), UTF-8); outStream.close(); System.out.println(result);高级软件人才实作培训专家高级软件人才实作培训专家! !北京传智播客教育 向向InternetInternet发送发送xmlxml数据数据利用HttpURLConnection对象,我们可以向网络发送xml数据.StringBuilder xml = new StringBuilder();xml.append();xml.append();xml.app
123、end(中国);xml.append();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(5* 1000);conn.setDoOutput(true);/允许输出conn.setUseCaches(false);/不
124、使用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 Dat
125、aOutputStream(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();高级软件人才实作培训专家高级软件人才实作培训专家! !北京传智播客教育 多
126、线程断点续传下载多线程断点续传下载使用多线程下载文件可以更快完成文件的下载,多线程下载文件之所以快,是因为其抢占的服务器资源多。如:假设服务器同时最多服务100个用户,在服务器中一条线程对应一个用户,100条线程在计算机中并非并发执行,而是由CPU划分时间片轮流执行,如果A应用使用了99条线程下载文件,那么相当于占用了99个用户的资源,假设一秒内CPU分配给每条线程的平均执行时间是10ms,A应用在服务器中一秒内就得到了990ms的执行时间,而其他应用在一秒内只有10ms的执行时间。就如同一个水龙头,每秒出水量相等的情况下,放990毫秒的水肯定比放10毫秒的水要多。多线程下载的实现过程:多线程
127、下载的实现过程:1首先得到下载文件的长度,然后设置本地文件的长度。HttpURLConnection.getContentLength();RandomAccessFile file = new RandomAccessFile(QQWubiSetup.exe,rwd);file.setLength(filesize);/设置本地文件的长度2根据文件长度和线程数计算每条线程下载的数据长度和下载位置。如:文件的长度为6M,线程数为3,那么,每条线程下载的数据长度为2M,每条线程开始下载的位置如上图所示。3使用Http的Range头字段指定每条线程从文件的什么位置开始下载,下载到什么位置为止,如:
128、指定从文件的2M位置开始下载,下载到位置(4M-1byte)为止,代码如下:HttpURLConnection.setRequestProperty(Range, bytes=2097152-4194303);4保存文件,使用RandomAccessFile类指定每条线程从本地文件的什么位置开始写入数据。RandomAccessFile threadfile = new RandomAccessFile(QQWubiSetup.exe ,rwd);threadfile.seek(2097152);/从文件的什么位置开始写入数据高级软件人才实作培训专家高级软件人才实作培训专家! !北京传智播客教
129、育 为应用添加新的Activity第一步:新建一个继承Activity的类,如:NewActivitypublic class NewActivity extends Activity Override protected void onCreate(Bundle savedInstanceState) super.onCreate(savedInstanceState); /这里可以使用setContentView(R.layout.xxx)显示某个视图. 第二步:需要在功能清单AndroidManifest.xml文件中添加进上面Activity配置代码(红色部分): . .android
130、:name属性值的前面加了一个点表示NewActivity是当前包cn.itcast.action下的类,如果类在应用的当前包下,可以省略点符号,如果类在应用的子包下必须加点,如:NewActivity类在cn.itcast.action.user包下可以这样写:高级软件人才实作培训专家高级软件人才实作培训专家! !北京传智播客教育 打开新的Activity ,不传递参数在一个Activity中可以使用系统提供的startActivity(Intent intent)方法打开新的Activity,在打开新的Activity前,你可以决定是否为新的Activity传递参数:第一种:打开新的Act
131、ivity,不传递参数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类对
132、象,第二个参数为你要打开的Activity类 startActivity(new Intent(MainActivity.this, NewActivity.class);); 高级软件人才实作培训专家高级软件人才实作培训专家! !北京传智播客教育 打开新的Activity,并传递若干个参数给它第二种:打开新的Activity,并传递若干个参数给它:public class MainActivity extends Activity Override protected void onCreate(Bundle savedInstanceState) . button.setOnClickLi
133、stener(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);); 在新的Ac
134、tivity中接收前面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); 高级软件人才实作培训专家高级软件人才实作培训专家! !北京传智播客教育 Bundle类的作用Bundle类用作
135、携带数据,它类似于Map,用于存放key-value名值对形式的值。相对于Map,它提供了各种常用类型的putXxx()/getXxx()方法,如:putString()/getString()和putInt()/getInt(),putXxx()用于往Bundle对象放入数据,getXxx()方法用于从Bundle对象里获取数据。Bundle的内部实际上是使用了HashMap类型的变量来存放putXxx()方法放入的值:public final class Bundle implements Parcelable, Cloneable . Map mMap; public Bundle()
136、mMap = new HashMap(); . 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()方法会把转换后的值返回。高级软
137、件人才实作培训专家高级软件人才实作培训专家! !北京传智播客教育 为Intent附加数据的两种写法第一种写法,用于批量添加数据到Intent:Intent intent = new Intent();Bundle bundle = new Bundle();/该类用作携带数据bundle.putString(name, 传智播客);intent.putExtras(bundle);/为意图追加额外的数据,意图原来已经具有的数据不会丢失,但key同名的数据会被替换第二种写法:这种写法的作用等价于上面的写法,只不过这种写法是把数据一个个地添加进Intent,这种写法使用起来比较方便,而且只需要编写
138、少量的代码。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,
139、 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; 高级软件人才实作培训专家高级软件人才实作培训专家! !北京传智播客教育 得到新打开Activity 关闭后返回的数据如果你想在Activity中得到新
140、打开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
141、(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);); /第一个参数为请求码,
142、即调用startActivityForResult()传递过去的值 /第二个参数为结果码,结果码用于标识返回数据来自哪个新Activity Override protected void onActivityResult(int requestCode, int resultCode, Intent data) String result = data.getExtras().getString(“result”);/得到新Activity 关闭后返回的数据 当新Activity关闭后,新Activity返回的数据通过Intent进行传递,android平台会调用前面Activity 的onA
143、ctivityResult()方法,把存放了返回数据的Intent作为第三个输入参数传入,在onActivityResult()方法中使用第三个输入参数可以取出新Activity返回的数据。高级软件人才实作培训专家高级软件人才实作培训专家! !北京传智播客教育 得到新打开Activity 关闭后返回的数据使用startActivityForResult(Intent intent, int requestCode)方法打开新的Activity,新Activity关闭前需要向前面的Activity返回数据需要使用系统提供的setResult(int resultCode, Intent data
144、)方法实现: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.
145、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
146、static final int RESULT_FIRST_USER = 1;高级软件人才实作培训专家高级软件人才实作培训专家! !北京传智播客教育 请求码和结果码的作用请求码用于标识结果数据来自哪个startActivityForResult(Intent intent, int requestCode)方法结果码用于为结果数据定义唯一id高级软件人才实作培训专家高级软件人才实作培训专家! !北京传智播客教育 Intent(意图)Android基本的设计理念是鼓励减少组件间的耦合,因此Android提供了Intent (意图) ,Intent提供了一种通用的消息系统,它允许在你的应用程序与其
147、它的应用程序间传递Intent来执行动作和产生事件。使用Intent可以激活Android应用的三个核心组件:活动、服务和广播接收器。Intent可以划分成显式意图和隐式意图。显式意图:调用Intent.setComponent() Intent.setClassName()或Intent.setClass()方法明确指定了组件名的Intent为显式意图,显式意图明确指定了要激活的组件是哪个组件。隐式意图:没有明确指定组件名的Intent为隐式意图。 Android系统会根据隐式意图中设置的动作(action)、类别(category)、数据(URI和数据类型)找到最合适的组件来处理这个意图。
148、查找规则请见ppt下方备注。 高级软件人才实作培训专家高级软件人才实作培训专家! !北京传智播客教育 ActivityActivity生命周期生命周期Activity在运行时会受到一些突然事件的影响,例如:你正使用一个Activity,突然来了一个电话,这时你的应用就要具备处理这些突发事件的能力,要处理这些突发事件,需要用到Activity的生命周期ActivityActivity有三个状态:有三个状态:l 当Activity在屏幕前台时(位于当前任务堆栈的顶部),它处于激活或运行状态。它可以响应用户操作。 l 当Activity上面有另外一个Activity,上面的Activity没有完全覆
149、盖它,或者上面的activity是透明的,这时下方的Activity仍然对用户可见(如右下图),下方的Activity就处于暂停状态。被暂停的Activity仍然对用户可见,并且是存活状态(它保留着所有的状态和成员信息并保持和窗口管理器的连接)。如果系统处于内存不足时会杀死这个Activity。 l 当Activity完全被另一个Activity覆盖时则处于停止状态。它仍然保留所有的状态和成员信息。然而对用户是不可见的,所以它的窗口将被隐藏,如果其它地方需要内存,则系统经常会杀死这个Activity。 当Activity从一种状态转变到另一种状态时,会调用以下保护方法来通知这种变化:void
150、onCreate(Bundle savedInstanceState)void onStart()void onRestart()void onResume()void onPause()void onStop()void onDestroy()高级软件人才实作培训专家高级软件人才实作培训专家! !北京传智播客教育 ActivityActivity生命周期生命周期这七个方法定义了Activity的完整生命周期。实现这些方法可以帮助我们监视其中的三个嵌套生命周期循环:l Activity的完整生命周期完整生命周期自第一次调用onCreate()开始,直至调用onDestroy()为止。Activ
151、ity在onCreate()中设置所有“全局”状态以完成初始化,而在onDestroy()中释放所有系统资源。例如,如果Activity有一个线程在后台运行从网络下载数据,它会在onCreate()创建线程,而在 onDestroy()销毁线程。 l Activity的可视生命周期可视生命周期自onStart()调用开始直到相应的onStop()调用结束。在此期间,用户可以在屏幕上看到Activity,尽管它也许并不是位于前台或者也不与用户进行交互。在这两个方法之间,我们可以保留用来向用户显示这个Activity所需的资源。例如,当用户不再看见我们显示的内容时,我们可以在onStart()中注
152、册一个BroadcastReceiver来监控会影响UI的变化,而在onStop()中来注消。onStart() 和 onStop() 方法可以随着应用程序是否为用户可见而被多次调用。 l Activity的前台生命周期前台生命周期自onResume()调用起,至相应的onPause()调用为止。在此期间,Activity位于前台最上面并与用户进行交互。Activity会经常在暂停和恢复之间进行状态转换例如当设备转入休眠状态或者有新的Activity启动时,将调用onPause() 方法。当Activity获得结果或者接收到新的Intent时会调用onResume() 方法。关于前台生命周期循
153、环的例子请见PPT下方备注栏。高级软件人才实作培训专家高级软件人才实作培训专家! !北京传智播客教育 ActivityActivity生命周期生命周期高级软件人才实作培训专家高级软件人才实作培训专家! !北京传智播客教育 ActivityActivity的的onSaveInstanceState()onSaveInstanceState()和和 onRestoreInstanceState() onRestoreInstanceState()方法方法Activity的 onSaveInstanceState() 和 onRestoreInstanceState()并不是生命周期方法,它们不同于
154、 onCreate()、onPause()等生命周期方法,它们并不一定会被触发。当应用遇到意外情况(如:内存不足、用户直接按Home键)由系统销毁一个Activity时,onSaveInstanceState() 会被调用(由运行状态进入暂停状态或停止状态)。但是当用户主动去销毁一个Activity时,例如在应用中按返回键,onSaveInstanceState()就不会被调用。因为在这种情况下,用户的行为决定了不需要保存Activity的状态。通常onSaveInstanceState()只适合用于保存一些临时性的状态,而onPause()适合用于数据的持久化保存。另外,当屏幕的方向发生了改
155、变, Activity会被摧毁并且被重新创建,如果你想在Activity被摧毁前缓存一些数据,并且在Activity被重新创建后恢复缓存的数据。可以重写Activity的 onSaveInstanceState() 和 onRestoreInstanceState()方法,如下:public class PreferencesActivity extends Activity private String name; protected void onRestoreInstanceState(Bundle savedInstanceState) name = savedInstanceStat
156、e.getString(name); /被重新创建后恢复缓存的数据super.onRestoreInstanceState(savedInstanceState); protected void onSaveInstanceState(Bundle outState) outState.putString(name, liming);/被摧毁前缓存一些数据super.onSaveInstanceState(outState); 高级软件人才实作培训专家高级软件人才实作培训专家! !北京传智播客教育 应用的响应性(应用的响应性(ResponsiveResponsive)在Android中,应用的
157、响应性被活动管理器(Activity Manager)和窗口管理器(Window Manager)这两个系统服务所监视。当用户触发了输入事件(如键盘输入,点击按钮等), 如果应用5秒内没有响应用户的输入事件,那么,Android会认为该应用无响应,便弹出ANR(Application No Response)对话框。如右图。在正常情况下,Android程序会在一条单线程里运行。如果Activity要处理一件比较耗时的工作,应该交给子线程完成,否侧会因为主线程被阻塞,后面的用户输入事件因没能在5秒内响应,导致应用出现ANR对话框。高级软件人才实作培训专家高级软件人才实作培训专家! !北京传智播客
158、教育 广播接收者广播接收者-BroadcastReceiver-BroadcastReceiver广播接收者(BroadcastReceiver)用于接收广播Intent,广播Intent的发送是通过调用Context.sendBroadcast()、Context.sendOrderedBroadcast()来实现的。通常一个广播Intent可以被订阅了此Intent的多个广播接收者所接收,这个特性跟JMS中的Topic消息接收者类似。要实现一个广播接收者方法如下:第一步:继承BroadcastReceiver,并重写onReceive()方法。public class IncomingSM
159、SReceiver 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
160、, filter);第二种:在AndroidManifest.xml文件中的节点里进行订阅: 高级软件人才实作培训专家高级软件人才实作培训专家! !北京传智播客教育 使用广播接收者窃听短信使用广播接收者窃听短信如果你想窃听别人接收到的短信,达到你不可告人的目的,那么本节内容可以实现你的需求。当系统收到短信时,会发出一个广播Intent,Intent的action名称为android.provider.Telephony.SMS_RECEIVED,该Intent存放了系统接收到的短信内容,我们使用名称“pdus”即可从Intent中获取到短信内容。public class IncomingSMS
161、Receiver 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()
162、;if (bundle != null) Object pdus = (Object) bundle.get(pdus);SmsMessage messages = new SmsMessagepdus.length;for (int i = 0; i pdus.length; i+) messagesi = SmsMessage.createFromPdu(byte) pdusi);for (SmsMessage message : messages)String msg = message.getMessageBody();String to = message.getOriginatin
163、gAddress();sms.sendTextMessage(to, null, msg, null, null);在AndroidManifest.xml文件中的节点里对接收到短信的广播Intent进行订阅:在AndroidManifest.xml文件中添加以下权限:高级软件人才实作培训专家高级软件人才实作培训专家! !北京传智播客教育 广播接收者的响应性广播接收者的响应性在Android中,每次广播消息到来时都会创建BroadcastReceiver实例并执行onReceive() 方法, onReceive() 方法执行完后,BroadcastReceiver 的实例就会被销毁。当onR
164、eceive() 方法在10秒内没有执行完毕,Android会认为该程序无响应。所以在BroadcastReceiver里不能做一些比较耗时的操作,否侧会弹出ANR(Application No Response)错误对话框。如果需要完成一项比较耗时的工作,应该通过发送Intent给Service,由Service来完成。这里不能使用子线程来解决,因为BroadcastReceiver的生命周期很短,子线程可能还没有结束BroadcastReceiver就先结束了。BroadcastReceiver一旦结束,此时BroadcastReceiver所在的进程很容易在系统需要内存时被优先杀死,因为
165、它属于空进程(没有任何活动组件的进程)。如果它的所在进程被杀死,那么正在工作的子线程也会被杀死。所以采用子线程来解决是不可靠的。public class IncomingSMSReceiver extends BroadcastReceiver Override public void onReceive(Context context, Intent intent) /发送Intent启动服务,由服务来完成比较耗时的操作 Intent service = new Intent(context, XxxService.class); context.startService(service);
166、高级软件人才实作培训专家高级软件人才实作培训专家! !北京传智播客教育 广播接收者广播接收者除了短信到来广播Intent,Android还有很多广播Intent,如:开机启动、电池电量变化、时间已经改变等广播Intent。l 接收电池电量变化广播Intent ,在AndroidManifest.xml文件中的节点里订阅此Intent: l 接收开机启动广播Intent,在AndroidManifest.xml文件中的节点里订阅此Intent: 并且要进行权限声明:高级软件人才实作培训专家高级软件人才实作培训专家! !北京传智播客教育 拦截外拔电话拦截外拔电话向外拨打电话时系统会发出一个有序广播
167、,虽然该广播最终会被拔号器里的广播接收者所接收并实现电话拔打,但我们可以在广播传递给拔号广播接收者之前先得到该广播,然后清除传递给拔号广播接收者的电话号码,在拔号广播接收者接收到该广播时,由于电话号码为null,因此取消电话拔打。public class OutgoingCallReceiver extends BroadcastReceiver public void onReceive(Context context, Intent intent) setResultData(null); /清除电话,广播被传给系统的接收者后,因为电话为null,取消电话拔打 / 同样如果你想修改外拔的电
168、话号码,可以这样做 / String phone = getResultData();/得到外拔电话 / setResultData(“12593”+ phone);/在电话前面加上12593 接收外拔电话广播Intent,在AndroidManifest.xml文件中的节点里订阅此Intent: 并且要进行权限声明:高级软件人才实作培训专家高级软件人才实作培训专家! !北京传智播客教育 服务服务-Service-ServiceAndroid中的服务类似windows中的服务,服务一般没有用户操作界面,它运行于系统中不容易被用户发觉,可以使用它开发如监控之类的程序。服务的开发比较简单,如下:第
169、一步:继承Service类public class SMSService extends Service 第二步:在AndroidManifest.xml文件中的节点里对服务进行配置:服务不能自己运行,需要通过调用Context.startService()或Context.bindService()方法启动服务。这两个方法都可以启动Service,但是它们的使用场合有所不同。使用startService()方法启用服务,访问者与服务之间没有关连,即使访问者退出了,服务仍然运行。使用bindService()方法启用服务,访问者与服务绑定在了一起,访问者一旦退出,服务也就终止,大有“不求同时生
170、,必须同时死”的特点。采用Context.startService()Context.startService()方法启动服务方法启动服务,只能调用Context.stopService()方法结束服务,服务结束时会调用onDestroy()方法。高级软件人才实作培训专家高级软件人才实作培训专家! !北京传智播客教育 建立能与访问者进行相互通信的本地服务建立能与访问者进行相互通信的本地服务通过startService()和stopService()启动关闭服务。适用于服务和访问者之间没有交互的情况。如果服务和访问者之间需要方法调用或者传递参数,侧需要使用bindService()和unbind
171、Service()方法启动关闭服务。采用Context.bindService()方法启动服务,在服务未被创建时,系统会先调用服务的onCreate()方法,接着调用onBind()方法,这个时候访问者和服务绑定在一起。 如果访问者要与服务进行通信,那么,onBind()方法必须返回Ibinder对象。如果访问者退出了,系统就会先调用服务的onUnbind()方法,接着调用onDestroy()方法。如果调用bindService()方法前服务已经被绑定,多次调用bindService()方法并不会导致多次创建服务及绑定(也就是说onCreate()和onBind()方法并不会被多次调用)。如
172、果访问者希望与正在绑定的服务解除绑定,可以调用unbindService()方法,调用该方法也会导致系统调用服务的onUnbind()-onDestroy()方法。高级软件人才实作培训专家高级软件人才实作培训专家! !北京传智播客教育 服务的生命周期回调方法服务的生命周期回调方法服务的生命周期跟启动服务的方法有关:服务的生命周期跟启动服务的方法有关:l 当采用Context.startService()方法启动服务,与之有关的生命周期方法onCreate() onStart() onDestroy()onCreate()该方法在服务被创建时调用,该方法只会被调用一次,无论调用多少次startS
173、ervice()或bindService()方法,服务也只被创建一次。onStart() 只有采用Context.startService()方法启动服务时才会回调该方法。该方法在服务开始运行时被调用。多次调用startService()方法尽管不会多次创建服务,但onStart() 方法会被多次调用。onDestroy()该方法在服务被终止时调用。l 当采用Context.bindService()方法启动服务,与之有关的生命周期方法onCreate() onBind() onUnbind() onDestroy()onBind()只有采用Context.bindService()方法启动服
174、务时才会回调该方法。该方法在调用者与服务绑定时被调用,当调用者与服务已经绑定,多次调用Context.bindService()方法并不会导致该方法被多次调用。onUnbind()只有采用Context.bindService()方法启动服务时才会回调该方法。该方法在调用者与服务解除绑定时被调用。如果先采用startService()方法启动服务,然后调用bindService()方法绑定到服务,再调用unbindService()方法解除绑定,最后调用bindService()方法再次绑定到服务,触发的生命周期方法如下:onCreate()onStart()onBind()onUnbind(
175、)重载后的方法需返回trueonRebind()高级软件人才实作培训专家高级软件人才实作培训专家! !北京传智播客教育 使用使用AIDLAIDL和远程服务实现进程通信和远程服务实现进程通信 在Android中, 每个应用程序都有自己的进程,当需要在不同的进程之间传递对象时,该如何实现呢? 显然, Java中是不支持跨进程内存共享的。因此要传递对象, 需要把对象解析成操作系统能够理解的数据格式, 以达到跨界对象访问的目的。在JavaEE中,采用RMI通过序列化传递对象。在Android中, 则采用AIDL(Android Interface Definition Language:接口定义语言)
176、方式实现。 AIDL是一种接口定义语言,用于约束两个进程间的通讯规则,供编译器生成代码,实现Android设备上的两个进程间通信(IPC)。AIDL的IPC机制和EJB所采用的CORBA很类似,进程之间的通信信息,首先会被转换成AIDL协议消息,然后发送给对方,对方收到AIDL协议消息后再转换成相应的对象。由于进程之间的通信信息需要双向转换,所以android采用代理类在背后实现了信息的双向转换,代理类由android编译器生成,对开发人员来说是透明的。实现进程通信,一般需要下面四个步骤:(请见页面下方备注栏) 高级软件人才实作培训专家高级软件人才实作培训专家! !北京传智播客教育 进程间传递
177、自定义类型参数进程间传递自定义类型参数Aidl默认支持的类型包话java基本类型(int、long、boolean等)和(String、List、Map、CharSequence),如果要传递自定义的类型该如何实现呢?要传递自定义类型,首先要让自定义类型支持parcelable协议,实现步骤如下:1自定义类型必须实现Parcelable接口,并且实现Parcelable接口的public void writeToParcel(Parcel dest, int flags)方法 。2自定义类型中必须含有一个名称为CREATOR的静态成员,该成员对象要求实现Parcelable.Creator接口
178、及其方法。3 创建一个aidl文件声明你的自定义类型。Parcelable接口的作用:实现了Parcelable接口的实例可以将自身的状态信息(状态信息通常指的是各成员变量的值)写入Parcel,也可以从Parcel中恢复其状态。 Parcel用来完成数据的序列化传递。进程间传递自定义类型的实现过程请参见页面下方备注栏:高级软件人才实作培训专家高级软件人才实作培训专家! !北京传智播客教育 监听电话呼叫状态监听电话呼叫状态要实现电话窃听,需要监听电话的状态,方法如下:/* 取得电话服务 */TelephonyManager telManager = (TelephonyManager) get
179、SystemService(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: /* 接起电话时 */ bre
180、ak; case TelephonyManager.CALL_STATE_RINGING: /* 电话进来时 */ break; default:break; super.onCallStateChanged(state, incomingNumber); ;/监听电话的状态telManager.listen(listener, PhoneStateListener.LISTEN_CALL_STATE);在清单文件AndroidManifest.xml中添加权限:高级软件人才实作培训专家高级软件人才实作培训专家! !Android没有对外公开结束通话的API,如果需要结束通话,必须使用AIDL
181、与电话管理服务进行通信,并调用服务中的API实现结束通话,方法如下:1 从Android的源代码中拷贝以下文件到项目中:com.android.internal.telephony包下的ITelephony.aidlandroid.telephony包下的NeighboringCellInfo.aidl注意:需要在项目中建立对应的包名存放上述两个aidl文件,如右图所示。开发工具会在gen目录下自动生成ITelephony.java2 调用ITelephony.endCall()结束通话:Method method = Class.forName(android.os.ServiceManag
182、er).getMethod(getService, String.class);IBinder binder = (IBinder)method.invoke(null, new ObjectTELEPHONY_SERVICE);ITelephony telephony = ITelephony.Stub.asInterface(binder);telephony.endCall();在清单文件AndroidManifest.xml中添加权限:北京传智播客教育 结束通话结束通话-实现黑名单拦截实现黑名单拦截高级软件人才实作培训专家高级软件人才实作培训专家! !北京传智播客教育 音频采集音频采集
183、你可以使用手机进行现场录音,实现步骤如下:第一步:在功能清单文件AndroidManifest.xml中添加音频刻录权限:第二步:编写音频刻录代码:MediaRecorder recorder = new MediaRecorder(); recorder.setAudioSource(MediaRecorder.AudioSource.MIC);/从麦克风采集声音 recorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);/内容输出格式 recorder.setAudioEncoder(MediaRecorder.Audio
184、Encoder.AMR_NB);/音频编码方式 recorder.setOutputFile(/mnt/sdcard/itcast.amr); recorder.prepare();/预期准备 recorder.start(); /开始刻录 . recorder.stop();/停止刻录 recorder.reset(); /重设 recorder.release(); /刻录完成一定要释放资源高级软件人才实作培训专家高级软件人才实作培训专家! !北京传智播客教育 音乐播放音乐播放MediaPlayer mediaPlayer = new MediaPlayer();if (mediaPlay
185、er.isPlaying() mediaPlayer.reset();/重置为初始状态mediaPlayer.setDataSource(/mnt/sdcard/god.mp3);mediaPlayer.prepare();mediaPlayer.start();/开始或恢复播放mediaPlayer.pause();/暂停播放mediaPlayer.start();/恢复播放mediaPlayer.stop();/停止播放mediaPlayer.release();/释放资源mediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompl
186、etionListener() /播出完毕事件 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; );高级软件人才实作培训专家高级软
187、件人才实作培训专家! !北京传智播客教育 使用使用SoundPoolSoundPool播放音效播放音效 在Android开发中我们经常使用MediaPlayer来播放音频文件,但是MediaPlayer存在一些不足,例如:资源占用量较高、延迟时间较长、不支持多个音频同时播放等。这些缺点决定了MediaPlayer在某些场合的使用情况不会很理想,例如在对时间精准度要求相对较高的游戏开发中。 在游戏开发中我们经常需要播放一些游戏音效(比如:子弹爆炸,物体撞击等),这些音效的共同特点是短促、密集、延迟程度小。在这样的场景下,我们可以使用SoundPool代替MediaPlayer来播放这些音效。 S
188、oundPool(android.media.SoundPool),顾名思义是声音池的意思,主要用于播放一些较短的声音片段,支持从程序的资源或文件系统加载。与MediaPlayer相比,SoundPool的优势在于CPU资源占用量低和反应延迟小。另外,SoundPool还支持自行设置声音的品质、音量、播放比率等参数,支持通过ID对多个音频流进行管理。 就现在已知的资料来说,SoundPool有一些设计上的BUG,从固件版本1.0开始有些还没有修复,我们在使用中应该小心再小心。相信将来Google会修复这些问题,但我们最好还是列出来:1. SoundPool最大只能申请1M的内存空间,这就意味着
189、我们只能用一些很短的声音片段,而不是用它来播放歌曲或者做游戏背景音乐。2. SoundPool提供了pause和stop方法,但这些方法建议最好不要轻易使用,因为有些时候它们可能会使你的程序莫名其妙的终止。建议使用这两个方法的时候尽可能多做测试工作,还有些朋友反映它们不会立即中止播放声音,而是把缓冲区里的数据播放完才会停下来,也许会多播放一秒钟。3. SoundPool的效率问题。其实SoundPool的效率在这些播放类中算是很好的了,但是有的朋友在G1中测试它还是有100ms左右的延迟,这可能会影响用户体验。也许这不能管SoundPool本身,因为到了性能比较好的Droid中这个延迟就可以让
190、人接受了。在现阶段SoundPool有这些缺陷,但也有着它不可替代的优点,基于这些我们建议大在如下情况中多使用SoundPool:1.应用程序中的声效(按键提示音,消息等)2.游戏中密集而短暂的声音(如多个飞船同时爆炸)高级软件人才实作培训专家高级软件人才实作培训专家! !北京传智播客教育 视频播放视频播放在在main.xmlmain.xml布局文件添加用于视频画面绘制的布局文件添加用于视频画面绘制的SurfaceView SurfaceView 控件:控件:SurfaceView surfaceView = (SurfaceView)this.findViewById(R.id.surfac
191、eView);surfaceView.getHolder().setFixedSize(176, 144); /设置分辨率/*下面设置Surface不维护自己的缓冲区,而是等待屏幕的渲染引擎将内容推送到用户面前*/surfaceView.getHolder().setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);MediaPlayer mediaPlayer = new MediaPlayer();mediaPlayer.reset();/重置为初始状态mediaPlayer.setAudioStreamType(AudioManager.STRE
192、AM_MUSIC);/* 设置Video影片以SurfaceHolder播放 */mediaPlayer.setDisplay(surfaceView.getHolder();mediaPlayer.setDataSource(/mnt/sdcard/oppo.mp4);mediaPlayer.prepare();mediaPlayer.start();/播放mediaPlayer.pause();/暂停播放mediaPlayer.start();/恢复播放mediaPlayer.stop();/停止播放mediaPlayer.release();/释放资源高级软件人才实作培训专家高级软件人才
193、实作培训专家! !北京传智播客教育 使用摄像头拍照在在main.xmlmain.xml布局文件添加用于显示取景画面的布局文件添加用于显示取景画面的SurfaceView SurfaceView 控件:控件:SurfaceView surfaceView = (SurfaceView)this.findViewById(R.id.surfaceView);surfaceView.getHolder().setFixedSize(176, 144); /设置分辨率/*下面设置Surface不维护自己的缓冲区,而是等待屏幕的渲染引擎将内容推送到用户面前*/surfaceView.getHolder(
194、).setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);Camera camera = Camera.open();WindowManager wm = (WindowManager) getSystemService(Context.WINDOW_SERVICE);Display display = wm.getDefaultDisplay();Camera.Parameters parameters = camera.getParameters();parameters.setPreviewSize(display.getWidth(), di
195、splay.getHeight();/设置预览照片的大小parameters.setPreviewFrameRate(3);/每秒3帧parameters.setPictureFormat(PixelFormat.JPEG);/设置照片的输出格式parameters.set(jpeg-quality, 85);/照片质量parameters.setPictureSize(display.getWidth(), display.getHeight();/设置照片的大小camera.setParameters(parameters);camera.setPreviewDisplay(surface
196、View.getHolder();/通过SurfaceView显示取景画面camera.startPreview();/开始预览camera.autoFocus(null);/自动对焦camera.takePicture(null, null, null, jpegCallback);/拍照片camera.stopPreview();/停止预览camera.release();/释放摄像头高级软件人才实作培训专家高级软件人才实作培训专家! !北京传智播客教育 音视频采集音视频采集第一步:在功能清单文件AndroidManifest.xml中添加音频刻录和照相机权限: 第二步:编写音频刻录代码:
197、recorder.reset();recorder.setVideoSource(MediaRecorder.VideoSource.CAMERA); /从照相机采集视频recorder.setAudioSource(MediaRecorder.AudioSource.MIC); recorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);recorder.setVideoSize(320, 240);recorder.setVideoFrameRate(3); /每秒3帧recorder.setVideoEncoder(Med
198、iaRecorder.VideoEncoder.H263); /设置视频编码方式recorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);recorder.setOutputFile(/mnt/sdcard/itcast.3gp);recorder.setPreviewDisplay(surfaceView.getHolder().getSurface();recorder.prepare();/预期准备recorder.start();/开始刻录.recorder.stop();/停止刻录recorder.release(); /
199、刻录完成一定要释放资源高级软件人才实作培训专家高级软件人才实作培训专家! !北京传智播客教育 对话框通知对话框通知(Dialog Notification)(Dialog Notification)当你的应用需要显示一个进度条或需要用户对信息进行确认时,可以使用对话框来完成。下面代码将打开一个如右图所示的对话框:new AlertDialog.Builder(context).setTitle(java培训).setCancelable(false) /设置不能通过“后退”按钮关闭对话框.setMessage(浏览传智播客网站?).setPositiveButton(确认,new Dialog
200、Interface.OnClickListener()public void onClick(DialogInterface dialoginterface, int i) Uri uri = Uri.parse(http:/ Intent intent = new Intent(Intent.ACTION_VIEW, uri); startActivity(intent); ).setNegativeButton(取消, new DialogInterface.OnClickListener() public void onClick(DialogInterface dialog, int
201、id) dialog.cancel(); ) .show();/显示对话框上面代码采用的是一个链式调用,像setTitle()、setMessage()这些方法,他们的返回值都是当前对话框对象。高级软件人才实作培训专家高级软件人才实作培训专家! !北京传智播客教育 创建带单选项列表的对话框创建带单选项列表的对话框下面代码将打开一个如右上图所示的选项列表对话框:final String items = java, .net, php;new AlertDialog.Builder(SenderNotificationActivity.this).setTitle(选择语言).setItems(i
202、tems, new DialogInterface.OnClickListener() public void onClick(DialogInterface dialog, int item) Toast.makeText(getApplicationContext(), itemsitem, Toast.LENGTH_SHORT).show(); ).show();/显示对话框下面代码将打开一个如右下图所示的带单选框的列表对话框:final String items = java, .net, php;new AlertDialog.Builder(SenderNotificationAc
203、tivity.this).setTitle(选择语言).setSingleChoiceItems(items, 1, new DialogInterface.OnClickListener() public void onClick(DialogInterface dialog, int item) Toast.makeText(getApplicationContext(), itemsitem, Toast.LENGTH_SHORT).show(); dialog.cancel(); ).show();/显示对话框setSingleChoiceItems()的第二个参数是设置默认选项,选项
204、索引从0开始,-1代表不选择任何选项。高级软件人才实作培训专家高级软件人才实作培训专家! !北京传智播客教育 创建带多选项列表的对话框创建带多选项列表的对话框下面代码将打开一个如右下图所示的多选项列表对话框:final String items = java, .net, php;new AlertDialog.Builder(SenderNotificationActivity.this).setCancelable(false).setTitle(选择语言).setMultiChoiceItems(items, new booleanfalse,true,false, new Dialog
205、Interface.OnMultiChoiceClickListener() Overridepublic void onClick(DialogInterface dialog, int which, boolean isChecked) if(isChecked)Toast.makeText(getApplicationContext(), itemswhich, Toast.LENGTH_SHORT).show();).setPositiveButton(确认,new DialogInterface.OnClickListener()public void onClick(DialogI
206、nterface dialoginterface, int i)dialoginterface.dismiss(); ).show();/显示对话框高级软件人才实作培训专家高级软件人才实作培训专家! !北京传智播客教育 进度对话框进度对话框(ProgressDialog)(ProgressDialog)效果图:l使用代码ProgressDialog.show(ProgressDialogActivity.this, 请稍等, 数据正在加载中., true);创建并显示一个进度对话框。l调用setProgressStyle()方法设置进度对话框风格。有两种风格: ProgressDialog.S
207、TYLE_SPINNER 旋体进度条风格 (为默认风格) ProgressDialog.STYLE_HORIZONTAL 横向进度条风格高级软件人才实作培训专家高级软件人才实作培训专家! !北京传智播客教育 单选框单选框(RadioButton)(RadioButton)效果图:要完成单选框显示,我们需要使用到RadioGroup和RadioButton(单选框),RadioGroup用于对单选框进行分组,相同组内的单选框只有一个单选框能被选中。(例子代码请见下方备注栏)l RadioGroup.check(R.id.dotNet);将id名为dotNet的单选框设置成选中状态。l(Radio
208、Button) findViewById(radioGroup.getCheckedRadioButtonId();/获取被选中的单选框。lRadioButton.getText();/获取单选框的值l调用setOnCheckedChangeListener()方法,处理单选框被选择事件,把RadioGroup.OnCheckedChangeListener实例作为参数传入高级软件人才实作培训专家高级软件人才实作培训专家! !北京传智播客教育 多选框多选框(CheckBox)(CheckBox)效果图:每个多选框都是独立的,可以通过迭代所有多选框,然后根据其状态是否被选中再获取其值。l Che
209、ckBox.setChecked(true);/设置成选中状态。l CheckBox.getText();/获取多选框的值l 调用setOnCheckedChangeListener()方法,处理多选框被选择事件,把CompoundButton.OnCheckedChangeListener实例作为参数传入高级软件人才实作培训专家高级软件人才实作培训专家! !北京传智播客教育 下拉列表框下拉列表框(Spinner)(Spinner)效果图:l Spinner.getItemAtPosition(Spinner.getSelectedItemPosition();获取下拉列表框的值l 调用set
210、OnItemSelectedListener()方法,处理下拉列表框被选择事件,把AdapterView.OnItemSelectedListener实例作为参数传入高级软件人才实作培训专家高级软件人才实作培训专家! !北京传智播客教育 下拉列表框下拉列表框采用采用javabeanjavabean作为作为Adapter元素效果图:l 很多时候显示在下拉列表框的值并不是希望得到的值,如果要做一个联系人下拉列表框,列表框列出的是联系人的姓名,因为姓名有可能相同,所以我们希望得到的值应该为该联系人的id,要实现这种需求我们需要自定义Adapter,当然自定义Adapter需要我们编写一小段代码,如果
211、我们不想编写Adapter,又能实现我们的需求,那是最好不过的了。通过观察ArrayAdapter中getView(int position, View convertView, ViewGroup parent)的内部代码发现,如果为ArrayAdapter指定的实际泛型参数类型没有实现CharSequence(字符串)接口,将会调用该类型对象的toString()向下拉列表框输出显示值。利用这个特点我们可以重写javaBean的toString()向下拉列表框提供显示值。高级软件人才实作培训专家高级软件人才实作培训专家! !北京传智播客教育 下拉列表框下拉列表框-自定义选项界面样式自定义选
212、项界面样式效果图:l Spinner.getItemAtPosition(Spinner.getSelectedItemPosition();获取下拉列表框的值l 调用setOnItemSelectedListener()方法,处理下拉列表框被选择事件,把AdapterView.OnItemSelectedListener实例作为参数传入高级软件人才实作培训专家高级软件人才实作培训专家! !北京传智播客教育 拖动条拖动条(SeekBar)(SeekBar)效果图:l SeekBar.getProgress()获取拖动条当前值l 调用setOnSeekBarChangeListener()方法,
213、处理拖动条值变化事件,把SeekBar.OnSeekBarChangeListener实例作为参数传入高级软件人才实作培训专家高级软件人才实作培训专家! !北京传智播客教育 菜单菜单(Menu)(Menu)效果图:l重写Activity的onCreateOptionsMenu(Menu menu)方法,该方法用于创建选项菜单,在用户按下手机的“Menu”按钮时就会显示创建好的菜单,在onCreateOptionsMenu(Menu menu)方法内部可以调用Menu.add()方法实现菜单的添加。l重写Activity的onMenuItemSelected()方法,该方法用于处理菜单被选择事件
214、通过手机上提供的“MENU”按钮可以打开菜单,如果希望通过代码打开菜单,可以调用Activity的openOptionsMenu()方法。高级软件人才实作培训专家高级软件人才实作培训专家! !北京传智播客教育 进度条(ProgressBar)在布局xml文件中添加进度条代码: 在代码中操作进度条:ProgressBar.setMax(100);/设置最大刻度ProgressBar.setProgress(0);/设置进度条的当前刻度,如果进度条的最大刻度为100,当前刻度为50,进度条将进行到一半。高级软件人才实作培训专家高级软件人才实作培训专家! !北京传智播客教育 输入内容自动完成文本框(
215、输入内容自动完成文本框(AutoCompleteTextView AutoCompleteTextView )AutoCompleteTextView和EditText组件类似,都可以输入文本。但AutoCompleteTextView组件可以和一个字符串数组或List对象绑定,当用户输入两个及以上字符时,系统将在AutoCompleteTextView组件下方列出字符串数组中所有以输入字符开头的字符串,这一点和的搜索框非常相似,当输入某一个要查找的字符串时,google搜索框就会列出以这个字符串开头的最热门的搜索字符串列表。AutoCompleteTextView android:layou
216、t_width=fill_parent“ android:layout_height=wrap_content“ public void onCreate(Bundle savedInstanceState) super.onCreate(savedInstanceState);setContentView(R.layout.main);String names = 老张, 老方, 老毕, 李明 , 李丽, 陈江, abc, acc;AutoCompleteTextView nameText = (AutoCompleteTextView)this.findViewById(R.id.name
217、);ArrayAdapter adapter = new ArrayAdapter(this, android.R.layout.simple_dropdown_item_1line, names);nameText.setAdapter(adapter);高级软件人才实作培训专家高级软件人才实作培训专家! !北京传智播客教育 多次输入多次输入- -内容自动完成文本框(内容自动完成文本框(MultiAutoCompleteTextViewMultiAutoCompleteTextView)除了AutoCompleteTextView控件外,我们还可以使用MultiAutoCompleteTex
218、tView控件来完成连续输入的功能。也就是说,当输入完一个字符串后,在该字符串后面输入一个逗号(,),在逗号前后可以有任意多个空格,然后再输入一个字符串,仍然会显示自动提示列表。使用MultiAutoCompleteTextView时,需要为它的setTokenizer方法指定MultiAutoCompleteTextView.CommaTokenizer类对象实例,该对象表示采用逗号作为输入多个字符串的分隔符。 MultiAutoCompleteTextView android:layout_width=fill_parent“ android:layout_height=wrap_cont
219、ent“ public void onCreate(Bundle savedInstanceState) super.onCreate(savedInstanceState);setContentView(R.layout.main); String names = 老张, 老方, 老毕, 李明 , 李丽, 陈江, abc, acc; MultiAutoCompleteTextView nameText = (MultiAutoCompleteTextView)this.findViewById(R.id.name); ArrayAdapter adapter = new ArrayAdapt
220、er(this, android.R.layout.simple_dropdown_item_1line, names); nameText.setAdapter(adapter); nameText.setTokenizer(new MultiAutoCompleteTextView.CommaTokenizer();高级软件人才实作培训专家高级软件人才实作培训专家! !北京传智播客教育 手势识别手势识别第一步:建立手势库使用SDK自带例子GestureBuilder建立手势库(位置:android-sdk-windowssamplesandroid-8GestureBuilder)。使用G
221、estureBuilder之前,你需要恢复其到开发环境,然后进行编绎并部署到手机上。此时,就可以使用GestureBuilder建立手势库,生成的手势库文件在SCDard上,默认文件名称为:gestures第二步:在应用中加载手势库文件,然后开发手势识别代码。把手势库文件gestures文件拷贝到项目的res/raw目录下。然后在布局文件中添加用于手势绘制的View: 为View添加手势监听事件:gestureOverlayView.addOnGesturePerformedListener();得到手势库:mLibrary = GestureLibraries.fromRawResource
222、(this, R.raw.gestures);加载手势库:mLibrary.load();List predictions = mLibrary.recognize(gesture);/从手势库中查询匹配的内容,匹配的结果可能包括多个相似的内容,匹配度高的结果放在最前面大多数情况下,手势都是通过一笔完成。然而有一些特别的需求就需要通过多个笔画来实现,这时可以使用gestureStrokeType属性进行设置:android:gestureStrokeType=multiple手势识别代码见ppt下方高级软件人才实作培训专家高级软件人才实作培训专家! !北京传智播客教育 android样式和主题
223、(style&theme) android中的样式和CSS样式作用相似,都是用于为界面元素定义显示风格,它是一个包含一个或者多个view控件属性的集合。如:需要定义字体的颜色和大小。在CSS中是这样定义的: .itcastCOLOR:#0000CC;font-size:18px;可以像这样使用上面的css样式:传智播客在Android中可以这样定义样式:在res/values/styles.xml文件中添加以下内容 18px #0000CC 在layout文件中可以像下面这样使用上面的android样式: 高级软件人才实作培训专家高级软件人才实作培训专家! !北京传智播客教育 android样
224、式和主题(style&theme)元素中有一个parent属性。这个属性可以让当前样式继承一个父样式,并且具有父样式的值。当然,如果父样式的值不符合你的需求,你也可以对它进行修改,如下: 18px #0000CC #FF0000 高级软件人才实作培训专家高级软件人才实作培训专家! !北京传智播客教育 android样式和主题(style&theme) android中主题也是用于为应用定义显示风格,它的定义和样式的定义相同,如下:true ! 没标题 ?android:windowNoTitle ! 全屏显示 上面“?android:windowNoTitle”中的问号用于引用在当前主题中定义
225、过的资源的值。下面代码显示在AndroidManifest.xml中如何为应用设置上面定义的主题: .除了可以在AndroidManifest.xml中设置主题,同样也可以在代码中设置主题,如下:setTheme(R.style.itcastTheme);尽管在定义上,样式和主题基本相同,但是它们使用的地方不同。样式用在单独的View,如:EditText、TextView等;主题通过AndroidManifest.xml中的和用在整个应用或者某个 Activity,主题对整个应用或某个Activity进行全局性影响。如果一个应用使用了主题,同时应用下的view也使用了样式,那么当主题和样式属
226、性发生冲突时,样式的优先级高于主题。另外android系统也定义了一些主题,例如:,该主题可以让Activity看起来像一个对话框,还有透明主题:android:style/Theme.Translucent 。如果需要查阅这些主题,可以在文档的referenceandroid-R.style 中查看。高级软件人才实作培训专家高级软件人才实作培训专家! !北京传智播客教育 编码实现软件界面编码实现软件界面Android除了可以使用xml实现软件界面,还可以通过编码方式实现软件的界面,而且在某种情况下只能采用编码方式实现软件的界面,例如:软件运行时需要根据运算结果决定显示某些内容。如果不是必须,
227、建议使用xml,因为这样可以使应用遵守mvc设计模式,具有良好的软件分层结构。下面代码实现了如HelloWorld项目一样的软件界面:public class MainActivity extends Activity public void onCreate(Bundle savedInstanceState) super.onCreate(savedInstanceState); LinearLayout linearLayout = new LinearLayout(this); LinearLayout.LayoutParams layoutParams = new LinearLay
228、out.LayoutParams( ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.FILL_PARENT); TextView textView = new TextView(this); textView.setText(R.string.hello); textView.setId(34); LinearLayout.LayoutParams textParams = new LinearLayout.LayoutParams( ViewGroup.LayoutParams.FILL_PARENT, ViewGroup
229、.LayoutParams.WRAP_CONTENT); linearLayout.addView(textView, textParams); setContentView(linearLayout, layoutParams); 高级软件人才实作培训专家高级软件人才实作培训专家! !北京传智播客教育 Android的状态栏通知(Notification)通知用于在状态栏显示消息,消息到来时以图标方式表示,如下:如果需要查看消息,可以拖动状态栏到屏幕下方即可查看消息。发送消息的代码如下:/获取通知管理器NotificationManager mNotificationManager = (N
230、otificationManager) getSystemService(Context.NOTIFICATION_SERVICE);int icon = android.R.drawable.stat_notify_chat;long when = System.currentTimeMillis();/新建一个通知,指定其图标和标题Notification notification = new Notification(icon, null, when);/第一个参数为图标,第二个参数为短暂提示标题,第三个为通知时间notification.defaults = Notification.
231、DEFAULT_SOUND;/发出默认声音notification.flags |= Notification.FLAG_AUTO_CANCEL;/点击通知后自动清除通知Intent openintent = new Intent(this, OtherActivity.class);PendingIntent contentIntent = PendingIntent.getActivity(this, 0, openintent, 0);/当点击消息时就会向系统发送openintent意图notification.setLatestEventInfo(this, “标题”, “我是内容,
232、contentIntent);mNotificationManager.notify(0, notification);/第一个参数为自定义的通知唯一标识高级软件人才实作培训专家高级软件人才实作培训专家! !北京传智播客教育 使用网页开发软件界面使用网页开发软件界面因为android软件开发分工目前还没有细化,程序员往往需要负责软件界面的开发,虽然软件的界面图片已经由美工设计好了,但如果使用layout技术把软件做成如图片所示的界面确实很困难,而且也比较耗时。Android通过WebView实现了JS代码与Java代码互相通信的功能,使的android软件的界面开发也可以采用HTML网页技术,
233、这样,广大网页美工可以参与进android软件的界面开发工作,从而让程序员从中解脱出来。高级软件人才实作培训专家高级软件人才实作培训专家! !北京传智播客教育 动画(动画(AnimationAnimation)Android提供了2种动画:1 Tween动画动画,通过对 View 的内容进行一系列的图形变换 (包括平移、缩放、旋转、改变透明度)来实现动画效果。动画效果的定义可以采用XML来做也可以采用编码来做。Tween动画有4种类型:2 Frame动画动画,即顺序播放事先做好的图像,跟放胶片电影类似。开发步骤:(1)把准备好的图片放进项目res/ drawable下。(2)在项目的res目录
234、下创建文件夹anim,然后在anim文件夹下面定义动画XML文件,文件名称可以自定义。当然也可以采用编码方式定义动画效果(使用AnimationDrawable类)。(3)为View控件绑定动画效果。调用代表动画的AnimationDrawable的start()方法开始动画。动画的类型动画的类型Xml定义动画使用的配置节点定义动画使用的配置节点编码定义动画使用的类编码定义动画使用的类渐变透明度动画效果 AlphaAnimation渐变尺寸缩放动画效果 ScaleAnimation画面位置移动动画效果 TranslateAnimation画面旋转动画效果RotateAnimation高级软件人
235、才实作培训专家高级软件人才实作培训专家! !北京传智播客教育 传感器的使用传感器类型:方向、加速度(重力)、光线、磁场、距离(临近性)、温度等。 方向传感器: Sensor.TYPE_ORIENTATION加速度(重力)传感器: Sensor.TYPE_ACCELEROMETER光线传感器: Sensor.TYPE_LIGHT磁场传感器: Sensor.TYPE_MAGNETIC_FIELD距离(临近性)传感器: Sensor.TYPE_PROXIMITY温度传感器: Sensor.TYPE_TEMPERATURE/获取某种类型的感应器Sensor sensor = sensorManager
236、.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);/注册监听,获取传感器变化值sensorManager.registerListener(listener, sensor, SensorManager.SENSOR_DELAY_GAME);上面第三个参数为采样率:最快、游戏、普通、用户界面。当应用程序请求特定的采样率时,其实只是对传感器子系统的一个建议,不保证特定的采样率可用。最快: SensorManager.SENSOR_DELAY_FASTEST最低延迟,一般不是特别敏感的处理不推荐使用,该种模式可能造成手机电力大量消耗,由于传递的为原始数据,算
237、法不处理好将会影响游戏逻辑和UI的性能。游戏: SensorManager.SENSOR_DELAY_GAME游戏延迟,一般绝大多数的实时性较高的游戏都使用该级别。普通: SensorManager.SENSOR_DELAY_NORMAL 标准延迟,对于一般的益智类或EASY级别的游戏可以使用,但过低的采样率可能对一些赛车类游戏有跳帧现象。用户界面: SensorManager.SENSOR_DELAY_UI一般对于屏幕方向自动旋转使用,相对节省电能和逻辑处理,一般游戏开发中我们不使用。高级软件人才实作培训专家高级软件人才实作培训专家! !北京传智播客教育 NinePatch图片NinePat
238、ch是一种很有用的PNG图片格式,它可以在特定区域随文字大小进行缩放。如下:从上图可以看到,背景图片的中间区域会随着文字的大小进行缩放。背景图片是一张NinePatch图片。 NinePatch图片可以使用android自带的draw9patch工具来制作,该工具在SDK安装路径的tools目录下。执行该工具,然后点击“File”-“open 9-path”打开一张用于制作NinePatch图片的原来图片。在画布的上方和左方的边上画线指定缩放区域,勾选“Show patches”可显示画定的区域,绿色为固定大小区域,红色为缩放区域,文字会摆放在红色区域。制作完后,点击“File” “save
239、9-path”保存图片,draw9patch工具会自动为图片加上*.9.png后缀。把制作好的图片拷贝进项目的res/drawable目录,然后编写代码。如下:高级软件人才实作培训专家高级软件人才实作培训专家! !北京传智播客教育 关闭应用当应用不再使用时,通常需要关闭应用,可以使用以下三种方法关闭android应用:第一种方法:首先获取当前进程的id,然后杀死该进程。 (建议使用)android.os.Process.killProcess(android.os.Process.myPid()第二种方法:终止当前正在运行的Java虚拟机,导致程序终止System.exit(0);第三种方法:
240、强制关闭与该包有关联的一切执行ActivityManager manager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE); manager.restartPackage(getPackageName();高级软件人才实作培训专家高级软件人才实作培训专家! !北京传智播客教育 判断SIM卡属于哪个移动运营商见备注栏:在文件AndroidManifest.xml中添加权限高级软件人才实作培训专家高级软件人才实作培训专家! !北京传智播客教育 从SIM卡中获取联系人信息Uri uri = Uri.parse(conte
241、nt:/icc/adn);String projection = _id, name, number;Cursor cursor = managedQuery(uri, projection, null, null, name);if(cursor!=null) while(cursor.moveToNext()String name = cursor.getString(cursor.getColumnIndex(name);String phone = cursor.getString(cursor.getColumnIndex(number); 在文件AndroidManifest.xm
242、l中添加权限Android系统内部通过Contentprovider对外共享Sim卡存放的联系人等信息,你可以通过操作Contentprovider来实现Sim卡信息的添删改查操作。 内部实现源代码参见备注栏:高级软件人才实作培训专家高级软件人才实作培训专家! !北京传智播客教育 删除呼叫记录在文件AndroidManifest.xml中添加权限负责存放呼叫记录的内容提供者源码在ContactsProvider项目下:源码路径:comandroidproviderscontactsCallLogProvider.java使用到的数据库在:/data/data/com.android.provi
243、ders.contacts/databases/contacts2.db表名:calls呼叫记录有三种类型:来电:CallLog.Calls.INCOMING_TYPE (常量值:1)外拔:CallLog.Calls.OUTGOING_TYPE(常量值:2)未接:CallLog.Calls.MISSED_TYPE(常量值:3)高级软件人才实作培训专家高级软件人才实作培训专家! !北京传智播客教育 在应用中安装其他程序首先需要AndroidManifest.xml中加入安装程序权限: 第二步把安装程序添加进SDCard。如把文件名为” sogouinput_android_1.40_sweb.a
244、pk.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.a
245、pk.zip),application/vnd.android.package-archive);startActivity(intent);高级软件人才实作培训专家高级软件人才实作培训专家! !北京传智播客教育 如何反编绎APK文件l安装ApkTool工具,该工具可以解码得到资源文件,但不能得到Java源文件。安装环境:需要安装JRE1.61 到http:/ 和apktool-install-windows-2.2_r01-3.tar.bz2 文件。解压两个文件,然后把解压后的文件放在一起,如:c:apktool2 在系统变量PATH中添加进aapt.exe,如:;c:apktoolaapt
246、.exe3 在DOS窗口下进入apktool.jar所在目录。执行DOS命令:apktool d -s c:softxxx.apk c:softsource。命令格式:apktool d opts dir 中的d代表解码,opts代表选项,-s选项代表不解码源文件。lApktool工具只能反编译成smali的中间代码文件,这里需要借助另外一个开源工具Dex2Jar,该工具可以把dex文件转换成jar文件。这个工具不能直接翻译成java文件,但是可以把dex文件转换成jar文件下载地址:http:/ 1 把APK安装包中的classes.dex解压到某个目录下,如:c:soft 2 在DOS窗口下进入dex2jar.bat所在目录,执行DOS命令:dex2jar.bat c:softsourceclasses.dex c:softsource,命令生成classes.dex.dex2jar.jar文件。l安装jd-gui工具,该工具可以把jar文件反编译成Java源文件下载地址:http:/java.decompiler.free.fr/jd-gui/downloads/jd-gui-0.3.3.windows.zip。运行该软件,直接打开classes.dex.dex2jar.jar文件即可看到java源代码。