Android基础总结
原文 http://blog.csdn.net/heimady/article/details/10363995
1. 前言
1.1. 什么是 3G 、 4G
Ÿ 第三代移动通信技术(3rd - Generation),速率一般在 几百 K bps ,较之前的 2G 和 2.5G 在数据传输速度上有很大提升。
Ÿ 第四代移动通信技术( 4th - Generation ),速度可达到 100Mbps 以上,几乎可以满足人们的所有传输数据的需求。
Ÿ 目前主流的 3G 技术标准有三种:
WCDMA :全球 80% 以上的 3G 网络都是采用此种制式。中国联通运营。 186
CDMA2000 :目前日韩及北美使用较多。中国电信运营。 189
TD-SCDMA :中国自主知识产权的 3G 通信技术。中国移动运营。 188
Ÿ 目前主流的 4G 技术为 LTE ,但还没有被广泛应用:
GSM à GPRS à EDGE à WCDMA à HSDPA à HSDPA+ à LTE
1.2. 什么是 Android
Ÿ Android 本义指 “ 机器人 ”,Google 于 2007 年 11 月 5 日宣布的基于 Linux 平台的开源手机操作系统的名称,官方中文名:安卓 。
Ÿ Android 系统早期由原名为 "Android" 的公司开发,谷歌在 2005 年收购 "Android.Inc" 后,继续对 Android 系统开发运营 。
Ÿ 底层 Linux 内核只提供基本功能,其他的应用软件则由各公司自行开发, 大部分程序以 Java 语言编写。
Ÿ 由于 Android 系统的开源特性,很多制造商都在生产 Android 系统的设备,如:摩托罗拉、 HTC 、三星、索爱、 LG 、小米、华为、魅族等。
Ÿ Android 系统除了运行在智能手机上之外,还可以用做平板电脑、电视、汽车等很多设备上。
Ÿ Android 系统架构图:
1.3. Android 的版本升级
Ÿ 1.5 Cupcake(纸杯蛋糕)
拍摄 / 播放影片,并支持上传到 Youtube
支持立体声 蓝牙 耳机,同时改善自动配对性能
最新的采用 WebKit 技术的浏览器,支持复制 / 贴上和页面中搜索
GPS 性能大大提高
提供屏幕虚拟键盘
主屏幕增加音乐播放器和相框 widgets
应用程序自动随着手机旋转
短信、 Gmail 、日暦,浏览器的用户接口大幅改进,如 Gmail 可以批量删除邮件
相机启动速度加快,拍摄图片可以直接上传到 Picasa
来电照片显示
Ÿ 1.6 Donut(甜甜圈)
重新设计的 Android Market
手势支持
支持 CDMA 网络
文字转语音系统( Text-to-Speech )
快速搜索框
全新的拍照接口
查看应用程序耗电
支持 虚拟私人网络 ( VPN )
支持更多的屏幕分辨率。
支持 OpenCore2 媒体引擎
新增面向视觉或听觉困难人群的易用性插件
Ÿ 2.1 Éclair(闪电泡芙)
优化硬件速度
"Car Home" 程序
支持更多的屏幕分辨率
改良的用户界面
新的浏览器的用户接口和支持 HTML5
新的联系人名单
更好的白色 / 黑色背景比率
改进 Google Maps 3.1.2
支持内置相机闪光灯
支持数码变焦
改进的虚拟键盘
支持蓝牙 2.1
支持动态桌面的设计
Ÿ 2.2 Froyo ( 冻酸奶)
支持将软件安装至扩展内存
集成 Adobe Flash 10.1 支持
加强软件 即时编译 的速度
新增软件启动 " 快速 " 至电话和浏览器
USB 分享器和 WiFi 热点功能
支持在浏览器上传档案
更新 Market 中的批量和自动更新
增加对 Microsoft Exchange 的支持(安全政策 , auto-discovery, GAL look-up )
集成 Chrome 的 V8 JavaScript 引擎到浏览器
加强快速搜索小工具
更多软件能透过 Market 更新,类似 2.0/2.1 中的 Map 更新
速度和性能优化
Ÿ 2.3 Gingerbread ( 姜饼 )
修补 UI
支持更大的屏幕尺寸和分辨率( WXGA 及更高)
系统级复制粘贴
重新设计的多点触摸屏幕键盘
本地支持多个镜头(用于视频通话等)和更多传感器(陀螺仪、气压计等)
电话簿集成 Internet Call 功能
强化电源、应用程序管理功能
新增下载管理员
优化游戏开发支持
多媒体音效强化
开放了屏幕截图功能
对黑色及白色的还原更加真实
Ÿ 3.x Honeycomb ( 蜂巢)
仅供平板电脑使用
Google eBooks 上提供数百万本书
支持平板电脑大萤幕、高分辨率
新版 Gmail
Google Talk 视讯功能
3D 加速处理
网页版 Market(Web store) 详细分类显示,依个人 Android 分别设定安装应用程序
新的短消息通知功能
专为平板电脑设计的用户界面(重新设计的通知列与系统列)
加强多任务处理的接口
重新设计适用大屏幕的键盘及复制粘贴功能
多个标签的浏览器以及私密浏览模式
快速切换各种功能的相机
增强的图库与快速滚动的联络人接口
更有效率的 Email 接口
支持多核心处理器
3.2 优化 7 吋平板显示
Ÿ 4.0 Ice Cream Sandwich ( 奶油三明治)
虚拟按键,增大屏幕面积同时控制手机整体大小
桌面插件 Widgets 列表呈现在标签页中,与程序列表类似并且共存
文件夹更容易创建和管理,与 iOS 类似
可定制的桌面系统
可视语音邮件
日历支持缩放操作
Gmail 离线搜索,两行预览,以及底部新快捷栏
音量下键 + 电源键组合截图
改进虚拟键盘纠错
从锁屏界面直接访问应用程序
优化复制粘贴
新版浏览器
新的 Roboto 字体
流量控制系统
相机应用
人脸识别,刷脸解锁
内置照片编辑器
多任务列表
新的图库布局和组织方式
联系人应用整合社交网络信息
Android Beam
http://digi.tech.qq.com/a/20111019/001579.htm
1.4. 主流智能手机操作系统
2. 搭建开发环境
2.1. 所需资源
Ÿ JDK , Java 开发环境。下载地址: http://www.oracle.com
Ÿ Eclipse , IBM 公司开发的一款开源 IDE 。 http://www.eclipse.org
Ÿ Android SDK , Android 开发工具,包含开发 Android 程序所需类库、源码、文档、案例等资源。 http://www.android.com
Ÿ ADT 插件 ,ADT 是 Eclipse 平台下用来开发 Android 应用程序的插件 。 http://www.android.com
2.2. Eclipse 安装 ADT 插件
2.3. 配置 SDK 路径
2.4. 启动虚拟机
Ø 点击机器人图标
Ø 弹出虚拟机管理器
Ø 修改虚拟机默认目录
指定环境变量 android_sdk_home ,通常指定为 SDK 所在目录,可以随意指定。
重启 Eclipse 之后将会以这个目录作为存放虚拟机文件的位置。
Ø 配置虚拟机
Ÿ Name :虚拟机的名字,可随意定义
Ÿ Target :虚拟机版本
Ÿ SD Card - Size :虚拟机的 SDCard 大小,会在本地硬盘创建指定大小的文件用来存储数据,模拟真实手机的 SDCard
如果使用原有文件,可以选择 File 并点击 Browse 指定文件
Ÿ Snapshot : 保存快照,可以提高虚拟机启动速度
Ÿ Skin - Built-in :选择分辨率
HVGA : 480x320
QVGA : 320x240
WQVGA400 : 400x240
WQVGA432 : 432x240
WVGA800 : 800x480
WVGA854 : 854x480
也可以选择 Resolution 自行指定
Ø 成功进入 Android 操作系统界面
Ÿ 如果虚拟机显示无信号,需要对电脑的网络连接进行配置
无论电脑是否联网, IP 地址、子网掩码、默认网关、首选 DNS 服务器都需要配置
Ÿ 电脑如果未连接局域网或互联网,可以见默认网关和首选 DNS 服务器配置成本机IP ,例如:
Ÿ 电脑如果已连接局域网,需要将网关和首选 DNS 服务器进行设置,例如:
Ÿ 如果电脑已连接互联网,正常情况虚拟机不会显示无信号,重启虚拟机
2.5. 命令行操作
为了能在任意目录使用一下命令,需要将 SDK 目录下的 platform-tools文件夹路径和tools文件夹路径配置到 path 环境变量中
Ÿ 列出可以使用的 android 版本
android list targets
Ÿ 列出可以使用的虚拟机
android list avd
Ÿ 创建虚拟机
android create avd –n < 虚拟机名 > -t <Target 版本 ID> -c <SD 卡大小 > -s < 屏幕尺寸 >
Ÿ 启动虚拟机
emulator –avd < 虚拟机名 >
Ÿ 显示已连接的设备
adb devices
Ÿ 导入文件到手机
adb push <Windows 源文件路径 > < 手机目标路径 >
Ÿ 从手机导出文件
adb pull < 手机源文件路径 > <Windows 目录路径 >
Ÿ 安装程序
adb install <apk 文件路径 >
Ÿ 卸载程序
adb uninstall < 包名 >
Ÿ 重启 adb
adb kill-server
abd start-server
3. 开发一个 Android 程序
3.1. 创建 Android 程序
Ø 创建 Android Project
Ÿ Project name :项目名
Ÿ Build Target : Android 版本
Ÿ Application name :程序名,显示在程序列表中,以及程序启动后的标题栏
Ÿ Package name :包名,程序的唯一标识
Ÿ Create Activity :选择程序启动时是否创建一个窗体,设置主窗体名字
Ÿ Min SDK Version :设置运行该程序所需的最低版本
3.2. 安装、卸载程序
Ÿ Eclipse 安装
右键点击工程 – Run as – Android Application
Ÿ 虚拟机卸载
设置 – 应用程序 – 管理应用程序 – 选中要卸载的程序 – 卸载
3.3. 了解项目目录结构
Ÿ src :源代码
Ÿ gen :系统自动生成的文件
R.java 中记录了项目中各种资源 ID
Ÿ res :系统资源,所有文件都会在 R 文件生成资源 ID
drawable :图片
layout :界面布局
values :数据
anim :定义动画的 XML
raw :原生文件
Ÿ assets :资源路径,不会在 R 文件注册
Ÿ project.properties :供 Eclipse 使用,读取该项目使用 Android 版本号。早期版本名为: default.properties
Ÿ AndroidManifest.xml :清单文件,在软件安装的时候被读取
Android 中的四大组件( Activity 、 ContentProvider 、 BroadcastReceiver 、 Service)都需要在该文件中注册
程序所需的权限也需要在此文件中声明,例如:电话、短信、互联网、访问 SD 卡
Ÿ bin :二进制文件,包括 class 、资源文件、 dex 、 apk 等
Ÿ proguard.cfg:用来混淆代码的配置文件,防止别人反编译
3.4. 程序启动过程
Ÿ Eclipse 将 .java 源文件编译成 .class
Ÿ 使用 dx 工具将所有 .class 文件转换为 .dex 文件
Ÿ 再将 .dex 文件和所有资源打包成 .apk 文件
Ÿ 将 .apk 文件安装到虚拟机完成程序安装
Ÿ 启动程序 – 开启进程 – 开启主线程
Ÿ 创建 Activity 对象 – 执行 OnCreate() 方法
Ÿ 按照 main.xml 文件初始化界面
4. 演示案例
4.1. 电话拨号
Ÿ 搭建界面需要组件: TextView 、 EditText 、 Button
Ÿ 当点击 Button 时获取 EditText 中文本
Ÿ 使用 Intent 向系统内置的电话拨号器发送意图拨打电话
Ÿ 注册拨打电话权限
4.2. 查看程序错误信息
Ÿ Android 程序中如果出错,错误不会显示在 Console 中,而是显示在 LogCat 界面下。可以从 window – show view 中打开
Ÿ 日志信息分为 5 个级别: verbose > debug > info > warn > error 高级的包含低级的
Ÿ 可以创建过滤器对日志进行过滤显示,点击绿色加号,可以按照 tag 、 pid 、 level进行筛选
4.3. 将程序安装到真实手机
Ÿ 在电脑上安装手机驱动
有些手机自带驱动,有些没有,可以从官网下载。或者可以使用“豌豆荚”软件自动安装。
Ÿ 在手机设置中打开 USB 调试,将手机用 USB 数据线连接到电脑
我的手机是:三星 i9100
双核1228MHz、1GB RAM 、4GB ROM、480×800 像素 、Android 2.3、4.3 英寸
Ÿ 检查 Eclipse 的设备管理器中是否显示出新设备
如果未能显示出设备,检查驱动安装是否正常, USB 调试是否打开
Ÿ Eclipse 安装程序
Eclipse 上右键点击工程 – Run as – Android Application – 自动安装运行
Ÿ 手动打包安装
右键点击工程 – Export – Export Android Application – 选择或创建密钥对程序签名并打包生成 apk 文件
将 apk 文件放到手机的 SD 卡中,通过手机文件浏览器执行安装
4.4. 短信发送
Ÿ 搭建界面需要组件: TextView 、 EditText 、 Button
Ÿ 给 Button 添加监听器,当被点击的时候获取号码,获取内容
Ÿ 使用 SmsManager 发送短信
Ÿ 需要注册短信发送权限
4.5. 布局
Ø RelativeLayout (相对布局)
Ÿ android-sdk-windows/docs/guide/topics/ui/layout-objects.html#relativelayout
Ø TableLayout (表格布局)
android-sdk-windows/docs/guide/topics/ui/layout-objects.html#tablelayout
Ø FrameLayout (帧布局)
android-sdk-windows/docs/guide/topics/ui/layout-objects.html#framelayout
setRequestedOrientation(ActivityInfo. SCREEN_ORIENTATION_LANDSCAPE );
setRequestedOrientation(ActivityInfo. SCREEN_ORIENTATION_PORTRAIT );
4.6. Junit
Ø 项目中添加测试类
Ÿ 在 AndroidManifest.xml 清单文件中添加配置
< instrumentation android:targetPackage = "cn.itcast.junit" android:name = "android.test.InstrumentationTestRunner" />
< uses-library android:name = "android.test.runner" />
Ÿ 定义一个类继承 AndroidTestCase ,定义测试方法
Ÿ 在 Outline 视图下右键点击测试方法 – Run as – Android Junit Test
Ø 创建测试项目
Ÿ 创建 Android Test Project
Ÿ 输入项目名,选择一个已存在的工程, Eclipse 可以自动配置 Junit 环境
4.7. 日志信息
Ÿ 在 LogCat 视图中我们可以看到程序的日志信息,也可以在程序中输出信息到 LogCat 中
Ÿ 程序中我们可以使用 Log 类来输出信息
Ÿ System.out 和 System.err 输出的信息也会显示在 LogCat 中,注意 System.out 输出信息是 Info 级别, System.err 是 Warn 级别
5. 文件操作( File 、 XML 、 SharedPreferences )
5.1. 读写文件
Ø 写入文件到 SD 卡
Ÿ 需要在清单文件中注册权限
< uses-permission android:name = "android.permission.WRITE_EXTERNAL_STORAGE" />
Ÿ 2.1 版本以下的 SDCard 位置和 2.2 之后版本不同
可以通过Environment.getExternalStorageDirectory()获取当前 SDCard 位置,兼容所有版本
Ÿ 获取 SDCard 状态
通过Environment.getExternalStorageState()方法获取 SDCard 当前状态
常量 Environment.MEDIA_MOUNTED 为已安装
Ø 写入文件
Ÿ 通过 Context. openFileOutput(String name, int mode)可以获取一个文件输入流
name 为文件名, mode 为文件模式,有 4 种模式
输出流指向路径为: /data/data/ 包名 /files/
Ÿ 文件模式在 Context 中有定义常量
MODE_PRIVATE 私有
MODE_WORLD_READABLE 其他程序可读(不可写)
MODE_WORLD_WRITEABLE 其他程序可写(不可读)
模式可以组合使用,例如:MODE_WORLD_READABLE + MODE_WORLD_WRITEABLE
MODE_APPEND 追加
Ø 读取文件
Ÿ 通过 Context. openFileInput(String name)可以获取一个文件输入流
该输入流可以读取 /data/data/ 包名 /files/ 路径下的文件
Ÿ 获取当前程序 Files 文件路径
ContextWrapper.getFilesDir()
5.2. XML
Ø Pull 简介
Ÿ 常见的 XML 解析方式有三种, DOM 、 SAX 、 Pull , Android 系统中推荐使用Pull
Ÿ Pull 解析器是一个开源的 Java 项目, Android 系统内部解析 XML 文件均为此种方式,也可用于 JavaEE 项目
Ÿ Android SDK 中已经集成了 Pull 解析器,无需添加任何 jar 文件
Ÿ Pull 解析器运行方式与 SAX 类似,提供各种事件的判断
Ÿ 官方网站: http://xmlpull.org/
Ø 使用 Pull 解析器解析 XML 文件
Ÿ Xml.newPullParser() 获得解析器
Ÿ parser.setInput(in, "UTF-8" ) 设置输入流以及编码
Ÿ parser.next() 获取下一个解析事件,得到一个事件代码
Ÿ XmlPullParser中定义了常量来标识各种解析事件
START_DOCUMENT 、 END_DOCUMENT 、 START_TAG 、END_TAG 、 TEXT
Ø 使用XmlSerializer写出 XML
Ÿ 使用以下方法生成 XML ,和 XML 文档顺序类似
startDocument
startTag
attribute
text
endTag
endDocument
5.3. 偏好设定( SharedPreferences )
Ÿ 在程序中保存一些配置参数的时候我们经常使用 SharedPreferences
Context.getSharedPreferences(String name, int mode)
该方法可以在 /data/data/<package>/shared_pref/ 目录下创建一个以 name 命名的 xml文件, mode 文件为模式
Ÿ 存储偏好
调用edit()方法可以获取一个 Editor 对象,对数据进行存储,存储之后需要调用 commit()保存到文件
Ÿ 读取偏好
获得SharedPreferences之后调用 getString() 、 getInt() 等方法获取其中设置的值
Ÿ 在 Activity 中获取 SharedPreferences
在 Activity 中可以调用 getPreferences( int mode)方法获得一个SharedPreferences,文件名和 Activity 名一致
6. 数据库( SQLite )
6.1. SQLite 特点
Ÿ Android 平台中嵌入了一个关系型数据库 SQLite ,和其他数据库不同的是 SQLite存储数据时不区分类型
例如一个字段声明为 Integer 类型,我们也可以将一个字符串存入,一个字段声明为布尔型,我们也可以存入浮点数。
除非是主键被定义为 Integer ,这时只能存储 64 位整数
Ÿ 创建数据库的表时可以不指定数据类型,例如:
CREATE TABLE person(id INTEGER PRIMARY KEY AUTOINCREMENT, name VARCHAR(20))
CREATE TABLE person(id INTEGER PRIMARY KEY AUTOINCREMENT, name)
Ÿ SQLite 支持大部分标准 SQL 语句,增删改查语句都是通用的,分页查询语句和 MySQL 相同
SELECT * FROM person LIMIT 20 OFFSET 10
SELECT * FROM person LIMIT 10,20
6.2. 创建数据库
Ÿ 定义类继承SQLiteOpenHelper
Ÿ 声明构造函数, 4 个参数
Ÿ 重写 onCreate ()方法
Ÿ 重写 upGrade() 方法
Ÿ 注意: SQLite 数据库中列一旦创建不能修改,如果一定要修改,需要重新创建表,拷贝数据
6.3. CRUD操作
Ÿ 和 JDBC 访问数据库不同,操作 SQLite 数据库无需加载驱动,不用获取连接,直接可以使用
获取 SQLiteDatabase 对象之后通过该对象直接可以执行 SQL 语句
SQLiteDatabase.execSQL()
SQLiteDatabase.rawQuery()
Ÿ getReadableDatabase()和getWritableDatabase()的区别
查看源代码后我们发现getReadableDatabase()在通常情况下返回的就是getWritableDatabase() 拿到的数据库
只有在抛出异常的时候才会以只读方式打开
Ÿ 数据库对象缓存
getWritableDatabase() 方法最后会使用一个成员变量记住这个数据库对象,下次打开时判断是否重用
Ÿ SQLiteDatabase 封装了 insert() 、 delete ()、 update ()、 query ()四个方法也可以对数据库进行操作
这些方法封装了部分 SQL 语句,通过参数进行拼接
6.4. 事务管理
Ÿ 在使用 SQLite 数据库时可以用 SQLiteDatabase类中定义的相关方法控制事务
beginTransaction() 开启事务
setTransactionSuccessful() 设置事务成功标记
endTransaction() 结束事务
Ÿ endTransaction() 需要放在 finally 中执行,否则事务只有到超时的时候才自动结束,会降低数据库并发效率
7. 内容提供者( ContentProvider )
7.1. 什么是内容提供者
Ÿ 内容提供者是 Android 中的四大组件之一,可以将应用中的数据对外进行共享
Ÿ 内容提供者将数据的访问方式统一,不必针对不同数据类型采取不同的访问策略
Ÿ 内容提供者将数据封装,只暴露出我们希望提供给其他程序的数据
Ÿ 内容提供者中数据更改可被监听
7.2. 创建内容提供者
Ÿ 定义类继承 ContentProvider ,根据需要重写内部方法
Ÿ 在清单文件的 <application> 节点下进行配置, <provider> 标签中需要指定 name 和authorities 属性
name 为类名,包名从程序 Package 开始,以“ . ”开始
authorities :是访问 Provider 时的路径,要唯一
Ÿ URI 代表要操作的数据,由 scheme 、 authorites 、 path 三部分组成
content:// cn.itcast. sqlite . provider / person
scheme :固定为 content ,代表访问内容提供者
authorites : <provider> 节点中的 authorites 属性
path :程序定义的路径,可根据业务逻辑定义
7.3. 完成 CRUD 方法
Ÿ 当程序调用 CRUD 方法时会传入 Uri
Ÿ 我们通过 Uri 判断调用者要操作的数据
可以使用工具类 UriMatcher 来判断 Uri
addURI 方法可以添加 Uri
match 方法可以匹配一个 Uri 判断其类型
Ÿ 根据业务逻辑操作数据
7.4. 访问内容提供者
Ÿ 通过 Context 获得 ContentResolver 对象
Ÿ 调用 ContentResolver 对象的方法即可访问内容提供者
7.5. 完成 getType 方法
Ÿ 如果返回数据是单条数据:vnd.android.cursor.item
Ÿ 如果返回数据是多条数据:vnd.android.cursor.dir
7.6. 监听内容提供者数据变化
Ÿ 在内容提供者中可以通知其他程序数据发生变化
通过 Context 的 getContentResolver() 方法获取 ContentResolver
调用其notifyChange() 方法发送数据修改通知
Ÿ 在其他程序中可以通过ContentObserver监听数据变化
通过 Context 的 getContentResolver() 方法获取 ContentResolver
调用其registerContentObserver() 方法指定对某个 Uri 注册 ContentObserver
自定义ContentObserver,重写 onChange() 方法获取数据
7.7. GIT 获取源代码
Ø 资源地址
Ÿ Git
http://code.google.com/p/msysgit/
Ÿ 源码
注意:
GIT1.7.7 安装后不能卸载,可以用其他版本覆盖后再卸载。
使用 GIT 时不要使用中文目录,否则 GIT GUI 会报错无法启动。删除 C 盘中 .gitconfig文件可以解决。
7.8. 监听短信
Ÿ Android 系统提供了 Provider 对短信进行查询,当发出短信时也会发送更改通知
Ÿ 短信数据库在 com.android.providers.telephony
Ÿ 定义一个 Observer 监听 "content://sms"
Ÿ 在 onChange() 方法中查询 "content://sms"
Ÿ 需要权限android.permission.READ_SMS
7.9. 操作联系人
Ø 获取所有联系人
Ÿ Android 系统中的联系人也是通过 ContentProvider 来对外提供数据的
Ÿ 数据库路径为: /data/data/com.android.providers.contacts/database/contacts2.db
Ÿ 我们需要关注的有 3 张表
raw_contacts :其中保存了联系人 id
data :和 raw_contacts 是多对一的关系,保存了联系人的各项数据
mimetypes :为数据类型
Ÿ Provider 的 authorites 为 com.android.contacts
Ÿ 查询 raw_contacts 表的路径为: contacts
Ÿ 查询 data 表的路径为: contacts/#/data
这个路径为连接查询,直接查询“ mimetype ”字段就可以根据“ mimetype_id ”查询到 mimetypes 表中的数据
Ÿ 先查询 raw_contacts 得到每个联系人的 id ,在使用 id 从 data 表中查询对应数据,根据 mimetype 分类数据
Ø 通过电话号码获取联系人
Ÿ 系统内部提供了根据电话号码获取 data 表数据的功能,路径为: data/phones/filter/*
Ÿ 用电话号码替换“ * ”部分就可以查到所需数据,获取“ display_name ”可以获取到联系人显示名
Ø 添加联系人
Ÿ 先向 raw_contacts 表插入 id ,路径为: raw_contacts
Ÿ 得到 id 之后再向 data 表插入数据,路径为: data
Ø 使用事务添加联系人
Ÿ 在添加联系人得时候是分多次访问 Provider ,如果在过程中出现异常,会出现数据不完整的情况,这些操作应该放在一次事务中
Ÿ 使用ContentResolver的applyBatch(String authority,ArrayList<ContentProviderOperation> operations) 方法可以将多个操作在一个事务中执行
Ÿ 文档位置 :
8. 网络通信
8.1. 获取文本数据
Ÿ 通过 URL 对象封装地址,打开一个 HttpURLConnection
Ÿ 设置头信息之后获取响应码,如果成功返回 200 即可从 HttpURLConnection 中获取输入流读取数据
Ÿ 代码过长屏幕显示不全可以使用 <ScrollView> 进行显示
Ÿ 需要访问网络的权限
< uses-permission android:name = "android.permission.INTERNET" />
8.2. 获取网络图片
Ÿ 通过 BitmapFactory 的 decodeByteArray(byte[] data, int offset, int length)方法将数据转换为图片对象
8.3. 获取 XML
Ÿ 使用 URL 封装路径,打开一个 HttpURLConnection
Ÿ 设置头信息之后获取相应码,从输入流中获取数据
Ÿ 使用 XmlPullPaser 解析
8.4. 获取 JSON
Ÿ 使用 URL 封装路径,打开一个 HttpURLConnection
Ÿ 设置头信息之后获取相应码,从输入流中获取数据
Ÿ 将数据转为 String ,封装成 JSONArray 对象
Ÿ 遍历 JSONArray 对象,调用获取其中的 JSONObject
Ÿ 再从 JSONObject 中获取每个字段的信息
8.5. 发送 GET 请求
Ÿ 拼接路径和参数,通过 URL 进行封装,打开一个 HttpURLConnection ,发送请求
Ÿ 如果参数是中文会出现乱码
Ÿ URL 中包含的中文参数需要使用 URLEncoder 进行编码
Ÿ 服务器端如果是 TOMCAT ,其默认使用 ISO8859-1 编码,接收时需要处理编码问题
8.6. 发送 POST 请求
Ÿ 通过 URL 打开一个 HttpURLConnection
Ÿ 头信息中除了超时时间和请求方式之外还必须设置Content-Type和Content-Length
Ÿ 从 HttpURLConnection 获得输出流输出参数数据
Ÿ 服务端可以使用 request 对象的 setCharacterEncoding方法设置编码
8.7. 发送 XML ,访问 WebService
Ø 发送 XML
Ÿ 通过 URL 封装路径打开一个 HttpURLConnection
Ÿ 设置请求方式,Content-Type和Content-Length
XML 文件的 Content-Type为:text/xml; charset=UTF-8
Ÿ 使用 HttpURLConnection 获取输出流输出数据
Ø WebService
Ÿ WebService 是发布在网络上的 API ,可以通过发送 XML 调用, WebService 返回结果也是 XML 数据
Ÿ WebService 没有语言限制,只要可以发送 XML 数据和接收 XML 数据即可
Ÿ http://www.webxml.com.cn 网站上提供了一些 WebService 服务,我们可以对其进行调用
Ÿ http://webservice.webxml.com.cn/WebServices/MobileCodeWS.asmx?op=getMobileCodeInfo 中提供了电话归属地查询的使用说明
8.8. HTTP 协议上传文件
Ÿ 搭建服务器,完成上传功能
Ÿ 使用浏览器上传,查看请求信息
Ø HttpURLConnection
Ÿ 通过 URL 封装路径打开一个 HttpURLConnection
Ÿ 设置请求方式以及头字段:Content-Type、Content-Length、Host
Ÿ 拼接数据发送
Ø Socket
Ÿ 使用 HttpURLConnection 发送时内部有缓存机制,如果上传较大文件会导致内存溢出
Ÿ 我们可以使用 Socket 发送 TCP 请求,将上传数据分段发送
Ø HttpClient
public void upload(String name, String password, String path) throws Exception {
// 创建 HttpClient 对象
HttpClient client = new HttpClient();
// 设置超时事件
client.getHttpConnectionManager().getParams().setConnectionTimeout(5000);
// 创建一个 Post 请求 , 指定路径
PostMethod postMethod = new PostMethod( "http://192.168.1.102:8080/14.Web/LoginServlet" );
// 封装每个表单项
Part[] parts = { new StringPart( "name" , name), new StringPart( "password" , password), new FilePart( "file" , new File(path)) };
// 给 Post 请求设置实体
postMethod.setRequestEntity( new MultipartRequestEntity(parts, postMethod.getParams()));
// 执行 Post 请求
client.executeMethod(postMethod);
// Post 请求是释放资源
postMethod.releaseConnection();
}
8.9. 多线程断点续传下载器
Ÿ 在下载的时候多个线程并发可以占用服务器端更多资源,从而加快下载速度
Ÿ 手机端下载数据时难免会出现无信号断线、电量不足等情况,所以需要断点续传功能
Ÿ 根据下载数据长度计算每个线程下载的数据位置,程序中开启多个线程并发下载
在请求头中设置 Range 字段就可以获取指定位置的数据,例如: Range: bytes=100-200
Ÿ 在下载过程中记录每个线程已拷贝数据的数量,如果下载中断,下次启动时从记录位置继续下载
Ø 多线程下载
Ÿ 进度条使用 <Progress> 进行配置
默认为圆形进度条,水平进度条需要配置 style 属性, ?android:attr/progressBarStyleHorizontal
使用 android.R.attr. progressBarStyleHorizontal作为样式
Ÿ 当点击下载按钮时开启多线程下载,下载过程中修改进度条进度
设置最大刻度:setMax()
设置当前进度:setProgress()
Ø 断点续传
Ÿ 断点续传需要在下载过程中记录每条线程的下载进度
Ÿ 每次下载开始之前先读取数据库,查询是否有未完成的记录,有就继续下载,没有则创建新记录插入数据库
Ÿ 在每次向文件中写入数据之后,在数据库中更新下载进度
Ÿ 下载完成之后删除数据库中下载记录
Ø Handler 传输数据
Ÿ 主线程中创建的 View 只能在主线程中修改,其他线程只能通过和主线程通信,在主线程中改变 View 数据
Ÿ 我们使用 Handler 可以处理这种需求
主线程中创建 Handler ,重写 handleMessage() 方法
新线程中使用 Handler 发送消息,主线程即可收到消息,并且执行 handleMessage()方法
Ø 动态生成新 View
Ÿ 创建 XML 文件,将要生成的 View 配置好
Ÿ 获取系统服务 LayoutInflater ,用来生成新的 View
LayoutInflater inflater = (LayoutInflater) getSystemService( LAYOUT_INFLATER_SERVICE );
Ÿ 使用inflate( int resource, ViewGroup root)方法生成新的 View
Ÿ 调用当前页面中某个容器的 addView ,将新创建的 View 添加进来
9. 活动( Activity )
9.1. 创建 Activity
Ø 定义 Activity
Ÿ 定义类继承 Activity
Ÿ 在 AndroidManifest.xml 的 <application> 节点中声明 <activity>
Ø 显式意图创建方式
Ÿ 构造函数,代码少
new Intent( this , NewActivity. class );
Ÿ 类名形式,灵活,可扩展性强
intent.setClassName( this , "cn.itcast.activity.NewActivity" );
Ÿ 包名类名形式,可启动其他程序中的 Activity
intent.setClassName( "cn.itcast.downloader" , "cn.itcast.downloader.MainActivity");
Ø 创建 Activity 并传递数据
Ÿ 在意图对象中封装了一个 Bundle 对象,可以用来携带数据
Ÿ 在新 Activity 中可以获得意图对象以获取其中 Bundle 保存的数据
Ø 创建 Activity 获取返回数据
Ÿ 使用startActivityForResult(Intent intent, int requestCode) 方法打开 Activity
Ÿ 重写onActivityResult( int requestCode, int resultCode, Intent data) 方法
Ÿ 新 Activity 中调用 setResult( int resultCode, Intent data) 设置返回数据之后,关闭 Activity 就会调用 onActivityResult方法
Ø 隐式意图创建 Activity
Ÿ 显式意图是指在创建意图时指定了组件,而隐式意图则不指定组件,通过动作、类型、数据匹配对应的组件
Ÿ 在清单文件中定义 <activity> 时需要定义 <intent-filter> 才能被隐式意图启动
Ÿ <intent-filter> 中至少配置一个 <action> 和一个 <category> ,否则无法被启动
Ÿ Intent 对象中设置的 action 、 category 、 data 在 <intent-filter> 必须全部包含才能启动
Ÿ <intent-filter> 中的 <action> 、 <category> 、 <data> 都可以配置多个, Intent 对象中不用全部匹配,每样匹配一个即可启动
Ÿ 如果一个意图可以匹配多个 Activity , Android 系统会提示选择
9.2. 生命周期
Ÿ Acitivity 三种状态
运行: activity 在最前端运行
暂停: activity 可见,但前端还有其他 acti vity ,被覆盖一部分,或者前端 activity 透明
停止: activity 不可见,完全被覆盖
Ÿ 生命周期相关方法
onCreate :创建时调用,或者程序在暂停、停止状态下被杀死之后重新打开时也会调用
onStart : onCreate 之后或者从停止状态恢复时调用
onResume : onStart 之后或者从暂停状态恢复时调用,从停止状态恢复时由于调用onStart ,也会调用 onResume
onPause:进入暂停、停止状态,或者销毁时会调用
onStop:进入停止状态,或者销毁时会调用
onDestroy:销毁时调用
onRestart :从停止状态恢复时调用
Ÿ 保存信息相关方法
onSaveInstanceState:在 Activity 被动的摧毁或停止的时候调用,用于保存运行数据,可以将数据存在在 Bundle 中
onRestoreInstanceState:该方法在 Activity 被重新绘制的时候调用,例如改变屏幕方向, savedInstanceState为onSaveInstanceState保存的数据
9.3. 启动模式
Ÿ 在 AndroidManifest.xml 中的 <activity> 标签中可以配置 android:launchMode 属性,用来控制 Actvity 的启动模式
Ÿ 在 Android 系统中我们创建的 Acitivity 是以栈的形式呈现的
standard :每次调用 startActivity() 启动时都会创建一个新的 Activity 放在栈顶
singleTop :如果启动的 Activity 时,指定 Activity 不在栈顶就创建,如在栈顶,则不再创建
singleTask :如果启动的 Activity 不存在就创建,如果存在直接跳转到指定的 Activity 所在位置
singleInstance :如果启动的 Activity 不存在就创建,如果存在就将指定的 Activity移动到栈顶
9.4. 内存管理
Ÿ Android 系统在运行多个进程时,如果系统资源不足,会强制结束一些进程。优先选择哪个进程来结束是有优先级的。以下顺序靠上的优先结束
空:进程中所有 Activity 都已销毁
后台:进程中有一个停止状态的 Activity
可见:进程中有一个暂停状态的 Activity
前台:进程中正在运行一个 Activity
10. 广播接收者 (BroadcastReceiver)
10.1. 定义广播接收者
Ÿ 定义类继承 BroadcastReceiver ,重写 onReceive 方法
Ÿ 清单文件中声明<receiver>,需要在其中配置<intent-filter>指定接收广播的动作
Ÿ 当接收到匹配广播之后就会执行 onReceive 方法
Ÿ BroadcastReceiver 除了在清单文件中声明,也可以在代码中声明,使用 registerReceiver方法注册 Receiver
10.2. 发送广播
Ø 无序广播
Ÿ 使用sendBroadcast方法发送
Ÿ 被所有广播接收者接收,无序,不可中断
Ÿ 广播时可设置接收者权限,仅当接收者含有权限才能接收
Ÿ 接收者的<receiver>也可设置发送方权限,只接收含有权限应用的广播
Ø 有序广播
Ÿ 使用sendOrderedBroadcast方法发送
Ÿ 接收者可以在<intent-filter>中定义android:priority定义优先级,数字越大优先级越高
Ÿ 被各个广播接收者逐个接收,中途可以中断或者添加数据
abortBroadcast()
getResultExtras( true ).putString( "data" , " 新增数据 " );
10.3. 监听短信接收
Ÿ Android 系统在收到短信的时候会发送一条有序广播,我们如果定义一个接收者接收这个广播,就可以得到短信内容,也可以拦截短信
Ÿ 定义广播接收者接收广播 android.provider.Telephony.SMS_RECEIVED
Ÿ 在 onReceive 方法内部调用 Intent 的 getExtras() 再调用 get(String) 获取其中 pdus字段,得到一个 Object[],其中每一个元素都是一个 byte[]
Ÿ 通过SmsMessage类的createFromPdu方法创建 SmsMessage 对象
Ÿ 从 SmsMessage 对象中即可获取发送者号码、短信内容、发送时间等信息
Ÿ 需要接收短信权限: < uses-permission android:name ="android.permission.RECEIVE_SMS" />
Ÿ Android 系统中收到短信的通知是一个有序通知,我们如需拦截垃圾短信,可以配置较高的 priority,收到信息进行判断是否abortBroadcast()
10.4. 监听呼出电话
Ÿ 定义广播接收者接收 android.intent.action.NEW_OUTGOING_CALL
Ÿ 需要权限 < uses-permission android:name = "android.permission.PROCESS_OUTGOING_CALLS" />
Ÿ 在 onReceive 方法中使用 getResultData() 和 setResultData() 方法获取和设置电话号码
10.5. 生命周期
Ÿ 广播接收者的生命周期是非常短暂的,在接收到广播的时候创建, onReceive() 方法结束之后销毁
Ÿ 广播接收者中不要做一些耗时的工作,否则会弹出 Application No Response 错误对话框
Ÿ 最好也不要在广播接收者中创建子线程做耗时的工作,因为广播接收者被销毁后进程就成为了空进程,很容易被系统杀掉
Ÿ 耗时的较长的工作最好放在服务中完成
11. 服务 (Service)
11.1. 基本概念
Ÿ Service 是一种在后台运行,没有界面的组件,由其他组件调用开始。
Ÿ 创建 Service ,定义类继承 Service , AndroidManifest.xml 中定义 <service>
Ÿ 开启 Service ,在其他组件中调用 startService方法
Ÿ 停止 Service ,调用 stopService方法
11.2. 电话录音
需要权限: android.permission.READ_PHONE_STATE
TelephonyManager manager = (TelephonyManager) getSystemService( TELEPHONY_SERVICE );
manager.listen( new MyListener(), PhoneStateListener. LISTEN_CALL_STATE );
private final class MyListener extends PhoneStateListener {
private String num ;
private MediaRecorder recorder ;
public void onCallStateChanged( int state, String incomingNumber) {
switch (state) {
case TelephonyManager. CALL_STATE_RINGING :
num = incomingNumber;
break ;
case TelephonyManager. CALL_STATE_OFFHOOK :
try {
File file = new File(Environment.getExternalStorageDirectory(), num + "_" + System.currentTimeMillis() + ".3gp" );
recorder = new MediaRecorder();
recorder .setAudioSource(AudioSource. MIC );
recorder .setOutputFormat(OutputFormat. THREE_GPP );
recorder .setAudioEncoder(AudioEncoder. AMR_NB );
recorder .setOutputFile( file .getAbsolutePath());
recorder .prepare();
recorder .start();
} catch (Exception e) {
e.printStackTrace();
}
break ;
case TelephonyManager. CALL_STATE_IDLE :
if ( recorder != null ) {
recorder .stop();
recorder .release();
}
break ;
}
}
}
11.3. 绑定本地服务
Ÿ 使用bindService绑定服务,传入一个自定义的ServiceConnection用来接收 IBinder
Ÿ 定义一个业务接口,其中定义需要的使用的方法
Ÿ 服务中自定义一个 IBinder 继承 Binder 并实现业务接口,在 onBind方法中返回
Ÿ 调用端将 IBinder 转为接口类型,调用接口中的方法即可调用到服务中的方法
11.4. 绑定远程服务
Ÿ 远程绑定服务时无法通过同一个接口来调用方法,这时就需要使用 AIDL 技术
Ÿ 将接口扩展名改为“.aidl”
Ÿ 去掉权限修饰符
Ÿ gen 文件夹下会生成同名接口
Ÿ 将服务中自定义的 IBinder 类改为继承接口中的 S tub
Ÿ ServiceConnection中返回的 IBinder 是代理对象,不能使用强转,改用 S tub.asInterface()
11.5. AIDL 使用自定义类型
Ÿ AIDL 默认只能使用 Java 中基本数据类型和 String 、 List 、 Map , List 和 Map 中的元素类型也只能是这些类型。
Ÿ 如果需要使用其他类型数据,使用的类必须实现 Parcelable 接口以完成序列化和反序列化工作
重写 public void writeToParcel(Parcel dest, int flags)
定义 public static final Parcelable.Creator<Person> CREATOR
Ÿ 定义该类对应的 AIDL
package 包名
parcelable 类名
Ÿ 在接口 AIDL 中导入该类,注意:即使是同一个包也需要导入
12. 多媒体
12.1. 音频播放器
12.2. 视频播放器
screenSV .getHolder().setType(SurfaceHolder. SURFACE_TYPE_PUSH_BUFFERS ); // 设置缓冲区数据
screenSV .getHolder().setKeepScreenOn( true ); // 设置屏幕保持
screenSV .getHolder().addCallback( new MyCallback()); // 设置回调函数
player .reset();
player .setDisplay( screenSV .getHolder()); // 设置显式
player .setDataSource( "/mnt/sdcard/1.mp4" ); // 设置数据源
player .prepare(); // 准备
player .seekTo(position); // 跳转到指定位置
player .start();
12.3. 拍照
Ÿ 需要权限
< uses-permission android:name = "android.permission.CAMERA" />
Ÿ 打开摄像头
Camera.open()
SDK2.3 之后支持前置摄像头, open 方法可以接收一个 int 参数,用来指定哪个摄像头
Ÿ 设置预览显示位置
setPreviewDisplay(SurfaceHolder holder)
注意 SurfaceView 不在前端显示的时候会被销毁,恢复之后会重绘
Ÿ 开始预览
startPreview()
将摄像头拍摄画面显示在 SurfaceView 中,在此之前可对摄像头进行参数配置
getParameters() 方法可以获取摄像头的相关参数Parameters,调用其内部方法即可进行配置
Ÿ 自动对焦
autoFocus(AutoFocusCallback cb)
自动对焦是一个异步操作,如果我们向等待自动对焦结束之后才开始拍照,需要传入一个回调对象,在其回调函数中调用拍照方法
Ÿ 拍照
takePicture(ShutterCallback shutter, PictureCallback raw, PictureCallback jpeg)
拍照也是异步操作,需要通过回调函数来得到拍照之后的数据
注意拍照之后摄像头不回自动回到预览状态,需要重写调用startPreview()方法
12.4. 录像
Ÿ 需要权限
< uses-permission android:name = "android.permission.RECORD_AUDIO" />
< uses-permission android:name = "android.permission.CAMERA" />
Ÿ 创建MediaRecorder
new MediaRecorder()
Ÿ 设置音频输入源
setAudioSource( int audio_source)
Ÿ 设置视频输入源
setVideoSource( int video_source)
Ÿ 设置输出格式
setOutputFormat( int output_format)
Ÿ 设置音频编码器
setAudioEncoder( int audio_encoder)
Ÿ 设置视频编码器
setVideoEncoder( int video_encoder)
Ÿ 设置预览显示位置
setPreviewDisplay(Surface sv)
Ÿ 设置输出文件
setOutputFile(String path)
Ÿ 准备录制
prepare()
Ÿ 开始录制
start()
开始录制之前需要结束摄像头的预览
Ÿ 结束录制释放资源
stop()
release()
13. 通知
13.1. 吐司通知
Ÿ 创建通知
Toast.makeText(Context context, CharSequence text, int duration)
Toast.makeText(Context context, int resId, int duration)
Ÿ 发送通知
show()
13.2. 状态栏通知
Ÿ 获取系统通知服务
NotificationManager nm = (NotificationManager) getSystemService( NOTIFICATION_SERVICE )
Ÿ 创建通知
通过构造函数创建 : Notification( int icon, CharSequence tickerText, long when)
icon: 通知的图片资源 ID
tickerText: 状态栏中显示的消息内容
when: 时间
Ÿ 创建PendingIntent以供点击时发送
PendingIntent.getActivity(Context context, int requestCode, Intent intent, int flags)
context: 当前上下文
requestCode: 请求码
intent: 点击时要发送的意图
flags: 类型 , PendingIntent中提供了常量选择
Ÿ 设置通知点击事件
调用Notification 对象方法 : setLatestEventInfo(Context context, CharSequence contentTitle, CharSequence contentText, PendingIntent contentIntent)
context: 当前上下文
contentTitle: 标题
contentText: 内容
contentIntent: 点击时触发的意图
Ÿ 设置通知点击后清除
设置Notification 对象属性 n. flags = Notification. FLAG_AUTO_CANCEL ;
Ÿ 发送消息
调用Notification对象方法 : notify( int id, Notification notification)
13.3. 对话框通知
Ø 普通对话框
new AlertDialog.Builder( this ) //
.setTitle( " 普通对话框 " ) //
.setMessage( " 普通内容 " ) //
.setCancelable( false ) //
.setPositiveButton( "YES" , listener) // listener 为 OnClickListener 监听器对象 , 监听按钮被选中
.setNeutralButton( "CANCEL" , listener) //
.setNegativeButton( "NO" , listener) //
.show();
Ø 列表对话框
new AlertDialog.Builder( this ) //
.setTitle( " 列表对话框 " ) //
.setCancelable( false ) //
.setItems( items , listener) // listener 为 OnClickListener 监听器对象 , 监听列表项被选中
.show();
Ø 单选对话框
new AlertDialog.Builder( this ) //
.setTitle( " 单选对话框 " ) //
.setCancelable( false ) //
.setSingleChoiceItems( items , 0, choiceLinstener) // 0, 为默认选中索引 , choiceLinstener 为 OnClickListener 监听器对象 , 监听单选按钮被选中
.setPositiveButton( " 确定 " , positiveLinstener) // positiveLinstener 为 OnClickListener 监听器对象 , 监听确定按钮点击
.show();
Ø 多选对话框
new AlertDialog.Builder( this ) //
.setTitle( " 多选对话框 " ) //
.setCancelable( false ) //
.setMultiChoiceItems( items , checkedArr, choiceListener) // checkedArr 为默认选中 , choiceListener 为 OnMultiChoiceClickListener 监听器对象 , 监听多选按钮被选中
.setPositiveButton( " 确定 " , positiveLinstener) // positiveLinstener 为 OnClickListener 监听器对象 , 监听确定按钮点击
.show();
Ø 进度对话框
ProgressDialog dialog = new ProgressDialog( this );
dialog.setProgressStyle(ProgressDialog. STYLE_HORIZONTAL ); // 设置进度条样式
dialog.setTitle( " 下载中 " );
dialog.setMessage( " 请稍候 ..." );
dialog.setCancelable( false );
dialog.setMax(100);
dialog.show();
dialog.setProgress(10); // 设置进度
dialog.dismiss(); // 对话框结束
关于通知的文档位置: android-sdk-windows/docs/guide/topics/ui/notifiers/index.html
14. 常用 UI
14.1. 列表视图 (ListView)
Ø XML 配置
Ÿ 在主界面中配置 <ListView> 标签
Ÿ 在 res/layout/ 文件夹下创建一个新的 xml 文件指定每个条目的布局
Ø Java 代码构建 ListView
Ÿ 获取 ListView 对象
Ÿ 设置一个 Adapter
BaseAdapter :实现内部抽象方法
SimpleAdapter:以 List<Map<String, ?>> 形式封装数据
SimpleCursorAdapter:以 Cursor 对象封装数据, Cursor 中需要有“ _id ”一列
Ÿ 添加 OnItemClickListener
调用 ListView 的 getItemAtPosition(int) 方法可以获取封装数据的容器
如果传入的是 BaseAdapter ,获取到的就是我们自定义方法中返回的内容
如果传入的是SimpleAdapter,获取到的就是一个 Map<String, ?>
如果传入的是SimpleCursorAdapter,获得到的就是一个 Cursor ,并且 Cursor 以指向选中的一条记录
14.2. 单选 (RadioGroup)
Ÿ 定义 <RadioGroup>
Ÿ 在 <RadioGroup> 中定义 <RadioButton> 和 <Button>
Ÿ 处理 Button 的点击事件
Ÿ 根据 ID 获取 RadioGroup 对象,调用其 getCheckedRadioButtonId()方法可以获取其中被选中的RadioGroup 的 ID
Ø 代码
< RadioGroup
android:id = "@+id/lessonsRG"
android:layout_width = "fill_parent"
android:layout_height = "wrap_content"
android:orientation = "horizontal" >
< RadioButton
android:id = "@+id/javaRB"
android:layout_width = "fill_parent"
android:layout_height = "wrap_content"
android:layout_weight = "1"
android:text = "Java" />
< RadioButton
android:id = "@+id/netRB"
android:layout_width = "fill_parent"
android:layout_height = "wrap_content"
android:layout_weight = "1"
android:text = ".Net" />
< RadioButton
android:id = "@+id/phpRB"
android:layout_width = "fill_parent"
android:layout_height = "wrap_content"
android:layout_weight = "1"
android:text = "PHP" />
< Button
android:layout_width = "fill_parent"
android:layout_height = "wrap_content"
android:layout_weight = "1"
android:onClick = " onR radioClick"
android:text = " 确定 " />
</ RadioGroup >
public void onRradioClick(View view) {
RadioGroup lessonRG = (RadioGroup) findViewById(R.id. lesson s RG );
int id = lessonRG.getCheckedRadioButtonId(); // 获取选中的 id
String msg = null ;
switch (id) {
case R.id. javaRB :
msg = "Java" ;
break ;
case R.id. netRB :
msg = ".Net" ;
break ;
case R.id. phpRB :
msg = "PHP" ;
break ;
}
Toast.makeText( this , msg, 0).show();
}
14.3. 多选 (CheckBox)
Ÿ 定义若干 <CheckBox> 和一个 <Button>
Ÿ 处理 Button 的点击事件
Ÿ 根据 ID 获取每个 CheckBox ,调用其 isChecked()方法判断是否被选中
Ø 代码
< LinearLayout
android:layout_width = "fill_parent"
android:layout_height = "wrap_content" >
< CheckBox
android:id = "@+id/javaCB"
android:layout_width = "fill_parent"
android:layout_height = "wrap_content"
android:layout_weight = "1"
android:text = "Java" />
< CheckBox
android:id = "@+id/netCB"
android:layout_width = "fill_parent"
android:layout_height = "wrap_content"
android:layout_weight = "1"
android:text = ".Net" />
< CheckBox
android:id = "@+id/phpCB"
android:layout_width = "fill_parent"
android:layout_height = "wrap_content"
android:layout_weight = "1"
android:text = "PHP" />
< Button
android:layout_width = "fill_parent"
android:layout_height = "wrap_content"
android:layout_weight = "1"
android:onClick = "checkboxOnClick"
android:text = " 确定 " />
</ LinearLayout >
public void checkboxOnClick(View view) {
CheckBox javaCB = (CheckBox) findViewById(R.id. javaCB );
CheckBox netCB = (CheckBox) findViewById(R.id. netCB );
CheckBox phpCB = (CheckBox) findViewById(R.id. phpCB );
StringBuilder sb = new StringBuilder();
sb.append(javaCB.isChecked() ? javaCB.getText() + " " : "" );
sb.append(netCB.isChecked() ? netCB.getText() + " " : "" );
sb.append(phpCB.isChecked() ? phpCB.getText() + " " : "" );
Toast.makeText( this , sb, 0).show();
}
14.4. 下拉列表 ( Spinner )
Ÿ 定义 <Spinner> 标签
Ÿ 创建一个适配器
Ÿ 获取 Spinner 标签,调用 setAdapter(SpinnerAdapter adapter)方法设置一个适配器
Ÿ 调用setOnItemSelectedListener(OnItemSelectedListener listener)方法设置监听器监听选中事件
Ø XML 配置
< Spinner
android:id = "@+id/spinner"
android:layout_width = "fill_parent"
android:layout_height = "wrap_content" />
Ø 使用字符串构建适配器
private void setSpinnerByString() {
final Spinner spinner = (Spinner) findViewById(R.id. spinner );
ArrayAdapter<String> adapter = new ArrayAdapter<String>( this , android.R.layout. simple_spinner_item ); // 设置样式
adapter.setDropDownViewResource(android.R.layout. simple_spinner_dropdown_item ); // 设置下拉后样式
adapter.add( "Java" );
adapter.add( ".Net" );
adapter.add( "PHP" );
spinner.setAdapter(adapter);
spinner.setOnItemSelectedListener( new OnItemSelectedListener() {
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
String selection = (String) spinner.getItemAtPosition(position);
Toast.makeText(getApplicationContext(), selection, 0).show();
}
public void onNothingSelected(AdapterView<?> parent) {
}
});
}
Ø 使用 JavaBean 构建适配器
private void setSpinnerByJavaBean() {
final Spinner spinner = (Spinner) findViewById(R.id. spinner );
ArrayAdapter<User> adapter = new ArrayAdapter<User>( this , android.R.layout.simple_spinner_item );
adapter.setDropDownViewResource(android.R.layout. simple_spinner_dropdown_item );
adapter.add( new User(1, "lhm" , "lhm@itcast.cn" ));
adapter.add( new User(2, "yzk" , "yzk@itcast.cn" ));
adapter.add( new User(3, "hsp" , "hsp@itcast.cn" ));
spinner .setAdapter(adapter);
spinner .setOnItemSelectedListener( new OnItemSelectedListener() {
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
User selection = (User) spinner .getItemAtPosition(position);
Toast.makeText(getApplicationContext(), selection.getName(), 0).show();
}
public void onNothingSelected(AdapterView<?> parent) {
}
});
}
Ø 使用资源文件构建适配器
< string-array name = "items" >
< item > Java </ item >
< item > .Net </ item >
< item > PHP </ item >
</ string-array >
private void setSpinnerByResource() {
final Spinner spinner = (Spinner) findViewById(R.id. spinner );
ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource( this, R.array. items , android.R.layout. simple_spinner_item );
adapter.setDropDownViewResource(android.R.layout. simple_spinner_dropdown_item );
spinner .setAdapter(adapter);
spinner .setOnItemSelectedListener( new OnItemSelectedListener() {
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
CharSequence selection = (CharSequence) spinner .getItemAtPosition(position);
Toast.makeText(getApplicationContext(), selection, 0).show();
}
public void onNothingSelected(AdapterView<?> parent) {
}
});
}
Ø 自定义适配器样式
<? xml version = "1.0" encoding = "utf-8" ?>
< LinearLayout xmlns:android = "http://schemas.android.com/apk/res/android"
android:layout_width = "match_parent"
android:layout_height = "match_parent"
android:orientation = "horizontal" >
< ImageView
android:layout_width = "50dp"
android:layout_height = "50dp"
android:src = "@android:drawable/ic_delete" />
< TextView
android:id = "@+id/content"
android:layout_width = "fill_parent"
android:layout_height = "wrap_content"
android:textSize = "50sp" />
</ LinearLayout >
private void setSpinnerByCustom() {
final Spinner spinner = (Spinner) findViewById(R.id. spinner );
ArrayAdapter<CharSequence> adapter = new ArrayAdapter<CharSequence>( this , R.layout. item , R.id. content );
adapter.add( "Java" );
adapter.add( ".Net" );
adapter.add( "PHP" );
spinner .setAdapter(adapter);
spinner .setOnItemSelectedListener( new OnItemSelectedListener() {
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
String selection = (String) spinner .getItemAtPosition(position);
Toast.makeText(getApplicationContext(), selection, 0).show();
}
public void onNothingSelected(AdapterView<?> parent) {
}
});
}
14.5. 菜单 (Menu)
Ø 添加菜单项
Ÿ 重写 Actvity 的 onCreateOptionsMenu(Menu menu)方法
Ÿ 添加菜单项
调用方法中参数 menu 的 add(CharSequence title) 方法
Ÿ 添加子菜单
调用 menu 对象的 addSubMenu( final CharSequence title)
该方法返回一个SubMenu对象
Ÿ 添加子菜单的菜单项
调用SubMenu对象的add(CharSequence title) 方法
Ø 处理菜单点击事件
Ÿ 重写 Activity 的 onOptionsItemSelected(MenuItem item) 方法
参数 item 即为被选中的菜单项
Ø 代码
public boolean onCreateOptionsMenu(Menu menu) {
menu.add( " 增加 " );
menu.add( " 修改 " );
menu.add( " 删除 " );
SubMenu subMenu = menu.addSubMenu( " 查询 " );
subMenu.add( " 按照序号查询 " );
subMenu.add( " 按照姓名查询 " );
subMenu.add( " 按照邮箱查询 " );
return super .onCreateOptionsMenu(menu);
}
public boolean onOptionsItemSelected(MenuItem item) {
Toast.makeText( this , item.getTitle(), 0).show();
return super .onOptionsItemSelected(item);
}
14.6. 内容提示文本框 ( AutoCompleteTextView)
Ø 单次提示
Ø 代码
< AutoCompleteTextView
android:id = "@+id/actv"
android:layout_width = "fill_parent"
android:layout_height = "wrap_content"
android:completionThreshold = "1" />
private void setAutoCompleteTextView() {
AutoCompleteTextView actv = (AutoCompleteTextView) findViewById(R.id. actv );
String[] items = { "tom" , "tony" , "terry" , " 张孝祥 " , " 张海军 " , " 张泽华 " };
ArrayAdapter<String> adapter = new ArrayAdapter<String>( this , android.R.layout. simple_dropdown_item_1line , items);
actv.setAdapter(adapter);
}
Ø 多次提示
Ø 代码
< MultiAutoCompleteTextView
android:id = "@+id/mactv"
android:layout_width = "fill_parent"
android:layout_height = "wrap_content"
android:completionThreshold = "1" />
private void setMultiAutoCompleteTextView() {
MultiAutoCompleteTextView mactv = (MultiAutoCompleteTextView) findViewById(R.id. mactv );
String[] items = { "tom" , "tony" , "terry" , " 张孝祥 " , " 张海军 " , " 张泽华 " };
ArrayAdapter<String> adapter = new ArrayAdapter<String>( this , android.R.layout. simple_dropdown_item_1line , items);
mactv.setAdapter(adapter);
mactv.setTokenizer( new MultiAutoCompleteTextView.CommaTokenizer());
}
14.7. 手势识别 ( GestureOverlayView)
Ø 创建手势库
Ÿ 导入 SDK 中的工程
android-sdk-windows\samples\android-8\GestureBuilder
这个工程不能直接导入,需要添加三个配置文件:.classpath、.project、default.properties
Ÿ 将工程部署到手机中,创建手势库
手势库会存储在手机 SD 卡的根目录,文件名为: gestures
Ø 代码
将gestures放入 res/raw 文件夹下
< android.gesture.GestureOverlayView
android:id = "@+id/gov"
android:layout_width = "fill_parent"
android:layout_height = "fill_parent"
android:gestureStrokeType = "multiple" />
GestureOverlayView gov = (GestureOverlayView) findViewById(R.id. gov );
final GestureLibrary library = GestureLibraries.fromRawResource( this , R.raw. gestures );
library.load();
gov.addOnGesturePerformedListener( new OnGesturePerformedListener() {
public void onGesturePerformed(GestureOverlayView overlay, Gesture gesture) {
ArrayList<Prediction> list = library.recognize(gesture);
for (Prediction p : list)
System. out .println(p. name + ": " + p. score );
}
});
14.8. 网页视图 (WebView)
Ø 代码
< WebView
android:id = "@+id/webView"
android:layout_width = "fill_parent"
android:layout_height = "fill_parent" />
WebView webView = (WebView) findViewById(R.id. webView );
webView.getSettings().setBuiltInZoomControls( true ); // 放大缩小按钮
webView.getSettings().setJavaScriptEnabled( true ); // JS 允许
webView.setWebChromeClient( new WebChromeClient()); // Chrome 内核
webView.loadUrl( "http://192.168.1.10 0 :8080" );
15. 样式与主题
15.1. 样式
Ø 定义样式
Ÿ 设置样式,在 values 文件夹下的任意文件中的 <resources>中配置 <style> 标签
< style name = " style 1" >
< item name = "android:layout_width" > fill_parent </ item >
< item name = "android:layout_height" > wrap_content </ item >
</ style >
Ÿ 继承样式,在 <style> 标签中配置属性 parent
< style name = " style2 " parent = "@style/ style 1" >
< item name = "android:textColor" > #FF0000 </ item >
</ style >
Ÿ 继承样式,在 name 中引用其他样式
< style name = " style 2. style 3" >
< item name = "android:textSize" > 30sp </ item >
</ style >
Ø 使用样式
Ÿ 在 layout 文件的标签中配置 style 属性
< Button
style = "@style/ style2.style3 "
android:text = " 这是 一个按钮 "
/>
15.2. 主题
Ÿ 定义过的样式也可以应用在 <activity> 和 <application> 标签中,使用 theme属性尽心配置
< style name = "theme" >
< item name = "android:windowNoTitle" > true </ item >
< item name = "android:windowFullscreen" > ?android:windowNoTitle </ item >
</ style >
< activity android:name = ".MainActivity"
android:label = "@string/app_name"
android:theme = "@style/theme"
>
Ÿ ? 表示引用其他属性的值
Ÿ @ 表示访问资源文件
Ÿ 如果使用 android 内置的样式, IDE 自动提示的“ _ ”要替换成“ . ”
16. 国际化与屏幕适配
16.1. 国际化
Ÿ 在 values 和 drawable 文件夹后加上语言以及地区名,程序中需要国际化的部分使用资源 ID
values-en-rUK
values-en-rUS
values-zh-rCN
values-zh-rTW
Ÿ 匹配规则
在匹配资源时先会找语言、地区完全匹配的
如果没有地区匹配的,则查找语言匹配的
如果没有语言匹配的则找默认 values
16.2. 屏幕适配
Ÿ 在 layout 文件夹后加上分辨率,系统会根据屏幕尺寸自动选择
注意分辨率中的乘号是“ x ”不是“ * ”
Ÿ 如果没有匹配的分辨率会找默认 layout 文件夹
17. 动画特效
17.1. Frame
Ÿ 通过多个画面连续播放实现动画效果
Ÿ 详见文档 android-sdk-windows/docs/guide/topics/resources/animation-resource.html
17.2. Tween
Ÿ 将某个组件以渐变的方式实现透明、缩放、移动、旋转等动画效果
Ÿ 详见文档 android-sdk-windows/docs/guide/topics/resources/animation-resource.html
17.3. 使用动画切换 Activity
Ÿ 在 startActivity() 方法调用之后调用 overridePendingTransition( int enterAnim, int exitAnim)方法
enterAnim 进入的动画资源 id
exitAnim 退出的动画 资源 id
17.4. 使用动画翻页
Ÿ XML 配置
< ViewFlipper
android:id = "@+id/viewFlipper"
android:layout_width = "fill_parent"
android:layout_height = "fill_parent"
>
< ImageView
android:layout_width = "wrap_content"
android:layout_height = "wrap_content"
android:src = "@drawable/bb2"
/>
< ImageView
android:layout_width = "wrap_content"
android:layout_height = "wrap_content"
android:src = "@drawable/bb3"
/>
</ ViewFlipper >
Ÿ Java 代码
public boolean onTouchEvent(MotionEvent event) {
ViewFlipper viewFlipper = (ViewFlipper) findViewById(R.id. viewFlipper );
switch (event.getAction()) {
case MotionEvent. ACTION_DOWN :
start = event.getX();
break ;
case MotionEvent. ACTION_UP :
float end = event.getX();
if (end > start ) {
viewFlipper .setInAnimation( this , R.anim. previous_enter );
viewFlipper .setOutAnimation( this , R.anim. previous_exit );
viewFlipper .showPrevious();
} else if (end < start ) {
viewFlipper .setInAnimation( this , R.anim. next_enter );
viewFlipper .setOutAnimation( this , R.anim. next_exit );
viewFlipper .showNext();
}
break ;
}
return super .onTouchEvent(event);
}
18. 其他
18.1. 传感器
Ø 传感器参数
Ÿ 传感器类型
方向 Sensor. TYPE_ORIENTATION
加速 Sensor. TYPE_ACCELEROMETER
光线 Sensor. TYPE_LIGHT
磁场 Sensor. TYPE_MAGNETIC_FIELD
距离 Sensor. TYPE_PROXIMITY
温度 Sensor. TYPE_TEMPERATURE
Ÿ 传感器反应速度
SensorManager. SENSOR_DELAY_FASTEST
SensorManager. SENSOR_DELAY_GAME
SensorManager. SENSOR_DELAY_UI
SensorManager. SENSOR_DELAY_NORMAL
Ø 使用方向传感器
Ÿ 获得传感器管理器
SensorManager manager = (SensorManager) getSystemService( SENSOR_SERVICE );
Ÿ 获得方向传感器
Sensor sensor = manager.getDefaultSensor(Sensor. TYPE_ORIENTATION );
Ÿ 注册监听器
manager .registerListener( listener , sensor , SensorManager. SENSOR_DELAY_NORMAL );
Ÿ 监听器
private final class MySensorEventListener implements SensorEventListener {
public void onSensorChanged(SensorEvent event) {
System. out .println(event. values [0]);
}
public void onAccuracyChanged(Sensor sensor, int accuracy) {
}
}
Ÿ 取消监听器
manager .unregisterListener( listener , sensor );
18.2. 触摸事件
Ø 拖拽
Ÿ XML 配置
< ImageView
android:id = "@+id/image"
android:layout_width = "wrap_content"
android:layout_height = "wrap_content"
android:scaleType = "matrix"
android:src = "@drawable/image" />
Ÿ Java代码
ImageView imageView = (ImageView) findViewById(R.id. image );
imageView.setOnTouchListener( new MyOnTouchListener());
private class MyOnTouchListener implements OnTouchListener {
private float x ;
private float y ;
private Matrix currentMatrix = new Matrix(); // 用来操作图片的矩阵
private Matrix oldMatrix = new Matrix();
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent. ACTION_DOWN : // 按下时
x = event.getX(); // 获取 x 轴坐标
y = event.getY(); // 获取 y 轴坐标
oldMatrix .set( imageView .getImageMatrix()); // 记住位置
break ;
case MotionEvent. ACTION_MOVE : // 移动时
currentMatrix .set( oldMatrix ); // 设置成按下时记住的位置
currentMatrix .postTranslate(event.getX() - x , event.getY() - y ); // 改变位置
break ;
}
imageView .setImageMatrix( currentMatrix ); // 移动图片
return true ;
}
}
Ø 多点触摸
private class MyOnTouchListener implements OnTouchListener {
private float x ; // 图片移动前的 x 轴坐标
private float y ; // 图片移动前的 y 轴坐标
private Matrix currentMatrix = new Matrix(); // 用来移动图片的矩阵
private Matrix oldMatrix = new Matrix(); // 图片移动前的矩阵
private int type ; // 操作类型 , 一根手指触摸还是两根手指触摸
private float start ; // 第二根手指按下时的距离
private float end ; // 两根手指移动后的距离
private PointF point ; // 放大时的中心点
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction() & MotionEvent. ACTION_MASK ) {
case MotionEvent. ACTION_DOWN :
type = 1;
x = event.getX();
y = event.getY();
oldMatrix .set( imageView .getImageMatrix());
break ;
case MotionEvent. ACTION_MOVE :
currentMatrix .set( oldMatrix );
if ( type == 1) { // 1 根手指触摸
currentMatrix .postTranslate(event.getX() - x , event.getY() - y );
} else { // 2 跟手指触摸
end = countDistance(event); // 计算结束时距离
float scale = end / start ; // 计算缩放比例
currentMatrix .postScale(scale, scale, point . x , point . y ); // 设置缩放
}
break ;
case MotionEvent. ACTION_POINTER_DOWN :
type = 2;
start = countDistance(event); // 计算开始时距离
point = countPoint(event); // 计算中心点
oldMatrix .set( imageView .getImageMatrix());
break ;
}
imageView .setImageMatrix( currentMatrix ); // 改变图片
return true ;
}
}
public float countDistance(MotionEvent event) {
float a = event.getX(1) - event.getX(0); // x 轴距离
float b = event.getY(1) - event.getY(0); // y 轴距离
return ( float ) Math.sqrt(a * a + b * b); // 勾股定理
}
public PointF countPoint(MotionEvent event) {
float x = (event.getX(0) + event.getX(1)) / 2; // x 轴中间点
float y = (event.getY(0) + event.getY(1)) / 2; // y 轴中间点
return new PointF(x, y);
}
18.3. 读取 SIM 卡
Ø 电话号码、运营商信息
Ÿ 需要权限
< uses-permission android:name = "android.permission.READ_PHONE_STATE" />
< uses-permission android:name = "android.permission.ACCESS_COARSE_LOCATION" />
Ÿ Java 代码
TelephonyManager manager = (TelephonyManager) getContext().getSystemService(Context. TELEPHONY_SERVICE );
System. out .println( " 电话号码 : " + manager.getLine1Number());
System. out .println( " 运营商编号 : " + manager.getNetworkOperator());
System. out .println( " 运营商名字 : " + manager.getNetworkOperatorName());
Ø 联系人
Ÿ 需要权限
< uses-permission android:name = "android.permission.READ_ CONTACTS " />
< uses-permission android:name = "android.permission. WRITE _ CONTACTS " />
Ÿ Java 代码
Uri uri = Uri.parse( "content://icc/adn" );
Cursor c = getContentResolver().query(uri, null , null , null , null );
while (c.moveToNext())
System. out .println(c.getString(c.getColumnIndex( "name" )) + ": " + c.getString(c.getColumnIndex( "number" )));
Ø 通话记录
Ÿ 需要权限
< uses-permission android:name = "android.permission.READ_ CONTACTS " />
< uses-permission android:name = "android.permission. WRITE _ CONTACTS " />
Ÿ Java 代码
Uri uri = CallLog.Calls. CONTENT_URI ;
Cursor c = getContentResolver().query(uri, null , null , null , null );
while (c.moveToNext())
System. out .println(c.getString(c.getColumnIndex( "number" )) + ": " + c.getString(c.getColumnIndex( "type" )));
Ÿ 源代码
ContactsProvider\src\com\android\providers\contacts\ CallLogProvider.java
18.4. 安装程序
Ÿ 需要权限
< uses-permission android:name = "android.permission. INSTALL_PACKAGES " />
Ÿ Java 代码
File file = new File(Environment.getExternalStorageDirectory(), " test .apk" );
Intent intent = new Intent();
intent.setAction(Intent. ACTION_VIEW );
intent.setDataAndType(Uri.fromFile(file), "application/vnd.android.package-archive" );
startActivity(intent);
18.5. 关闭程序
Ÿ 杀死当前进程
Process.killProcess(Process.myPid());
Ÿ 退出虚拟机
System.exit(0);
Ÿ 根据包名关闭后台进程
ActivityManager manager = (ActivityManager) getSystemService( ACTIVITY_SERVICE );
manager.restartPackage( "cn.itcast.test" );
< uses-permission android:name = "android.permission.RESTART_PACKAGES" />
18.6. 使用 HTML 构建界面
Ÿ HTML
<! DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd" >
< html >
< head >
< meta http-equiv = "Content-Type" content = "text/html; charset=UTF-8" >
< title > Insert title here </ title >
< script type = "text/javascript" >
function show(jsondata) {
var jsonobjs = eval(jsondata);
var table = document.getElementById( "personTable" );
for ( var y = 0; y < jsonobjs.length; y++) {
var tr = table.insertRow(table.rows.length);
var td1 = tr.insertCell(0);
var td2 = tr.insertCell(1);
td2.align = "center" ;
var td3 = tr.insertCell(2);
td3.align = "center" ;
td1.innerHTML = jsonobjs[y].name;
td2.innerHTML = jsonobjs[y].amount;
td3.innerHTML = "<a href='javascript:contact.call(\"" + jsonobjs[y].phone + "\")'>" + jsonobjs[y].phone + "</a>" ;
}
}
</ script >
</ head >
< body onload = "javascript:contact.show C ontacts()" >
< table border = "0" width = "100%" id = "personTable" cellspacing = "0" >
< tr >
< td width = "30%" > 姓名 </ td >
< td width = "30%" align = "center" > 存款 </ td >
< td align = "center" > 电话 </ td >
</ tr >
</ table >
</ body >
</ html >
Ÿ XML 代码
< WebView
android:id = "@+id/webView"
android:layout_width = "fill_parent"
android:layout_height = "fill_parent" />
Ÿ Java 代码
public class MainActivity extends Activity {
private WebView webView ;
public void onCreate(Bundle savedInstanceState) {
super .onCreate(savedInstanceState);
setContentView(R.layout. main );
webView = (WebView) findViewById(R.id. webView );
webView .getSettings().setJavaScriptEnabled( true );
webView .loadUrl( "file:///android_asset/index.html" );
webView .addJavascriptInterface( new Contact(), "contact" );
}
private final class Contact {
public void showContacts() {
String json = "[{\"name\":\"zxx\", \"amount\":\"99999\", \"phone\":\"18600012345\"}]";
webView .loadUrl( "javascript:show('" + json + "')" );
}
public void call(String phone) {
startActivity( new Intent(Intent. ACTION_CALL , Uri.parse( "tel:" + phone)));
}
}
}
18.7. apk 文件反编译
Ÿ 使用解压缩工具打开 apk 文件,找到其中 dex 文件
Ÿ 创建 Java 工程,导入 dex2jar中的所有 jar 文件
Ÿ 创建运行环境运行其中pxb.android.dex2jar.v3.Main 类, 指定 dex 文件地址,会在同目录下生成 jar 文件
Ÿ 使用jd-gui打开 jar 文件获取源码
1. 前言
1.1. 什么是 3G 、 4G
Ÿ 第三代移动通信技术(3rd - Generation),速率一般在 几百 K bps ,较之前的 2G 和 2.5G 在数据传输速度上有很大提升。
Ÿ 第四代移动通信技术( 4th - Generation ),速度可达到 100Mbps 以上,几乎可以满足人们的所有传输数据的需求。
Ÿ 目前主流的 3G 技术标准有三种:
WCDMA :全球 80% 以上的 3G 网络都是采用此种制式。中国联通运营。 186
CDMA2000 :目前日韩及北美使用较多。中国电信运营。 189
TD-SCDMA :中国自主知识产权的 3G 通信技术。中国移动运营。 188
Ÿ 目前主流的 4G 技术为 LTE ,但还没有被广泛应用:
GSM à GPRS à EDGE à WCDMA à HSDPA à HSDPA+ à LTE
1.2. 什么是 Android
Ÿ Android 本义指 “ 机器人 ”,Google 于 2007 年 11 月 5 日宣布的基于 Linux 平台的开源手机操作系统的名称,官方中文名:安卓 。
Ÿ Android 系统早期由原名为 "Android" 的公司开发,谷歌在 2005 年收购 "Android.Inc" 后,继续对 Android 系统开发运营 。
Ÿ 底层 Linux 内核只提供基本功能,其他的应用软件则由各公司自行开发, 大部分程序以 Java 语言编写。
Ÿ 由于 Android 系统的开源特性,很多制造商都在生产 Android 系统的设备,如:摩托罗拉、 HTC 、三星、索爱、 LG 、小米、华为、魅族等。
Ÿ Android 系统除了运行在智能手机上之外,还可以用做平板电脑、电视、汽车等很多设备上。
Ÿ Android 系统架构图:
1.3. Android 的版本升级
Ÿ 1.5 Cupcake(纸杯蛋糕)
拍摄 / 播放影片,并支持上传到 Youtube
支持立体声 蓝牙 耳机,同时改善自动配对性能
最新的采用 WebKit 技术的浏览器,支持复制 / 贴上和页面中搜索
GPS 性能大大提高
提供屏幕虚拟键盘
主屏幕增加音乐播放器和相框 widgets
应用程序自动随着手机旋转
短信、 Gmail 、日暦,浏览器的用户接口大幅改进,如 Gmail 可以批量删除邮件
相机启动速度加快,拍摄图片可以直接上传到 Picasa
来电照片显示
Ÿ 1.6 Donut(甜甜圈)
重新设计的 Android Market
手势支持
支持 CDMA 网络
文字转语音系统( Text-to-Speech )
快速搜索框
全新的拍照接口
查看应用程序耗电
支持 虚拟私人网络 ( VPN )
支持更多的屏幕分辨率。
支持 OpenCore2 媒体引擎
新增面向视觉或听觉困难人群的易用性插件
Ÿ 2.1 Éclair(闪电泡芙)
优化硬件速度
"Car Home" 程序
支持更多的屏幕分辨率
改良的用户界面
新的浏览器的用户接口和支持 HTML5
新的联系人名单
更好的白色 / 黑色背景比率
改进 Google Maps 3.1.2
支持内置相机闪光灯
支持数码变焦
改进的虚拟键盘
支持蓝牙 2.1
支持动态桌面的设计
Ÿ 2.2 Froyo ( 冻酸奶)
支持将软件安装至扩展内存
集成 Adobe Flash 10.1 支持
加强软件 即时编译 的速度
新增软件启动 " 快速 " 至电话和浏览器
USB 分享器和 WiFi 热点功能
支持在浏览器上传档案
更新 Market 中的批量和自动更新
增加对 Microsoft Exchange 的支持(安全政策 , auto-discovery, GAL look-up )
集成 Chrome 的 V8 JavaScript 引擎到浏览器
加强快速搜索小工具
更多软件能透过 Market 更新,类似 2.0/2.1 中的 Map 更新
速度和性能优化
Ÿ 2.3 Gingerbread ( 姜饼 )
修补 UI
支持更大的屏幕尺寸和分辨率( WXGA 及更高)
系统级复制粘贴
重新设计的多点触摸屏幕键盘
本地支持多个镜头(用于视频通话等)和更多传感器(陀螺仪、气压计等)
电话簿集成 Internet Call 功能
强化电源、应用程序管理功能
新增下载管理员
优化游戏开发支持
多媒体音效强化
开放了屏幕截图功能
对黑色及白色的还原更加真实
Ÿ 3.x Honeycomb ( 蜂巢)
仅供平板电脑使用
Google eBooks 上提供数百万本书
支持平板电脑大萤幕、高分辨率
新版 Gmail
Google Talk 视讯功能
3D 加速处理
网页版 Market(Web store) 详细分类显示,依个人 Android 分别设定安装应用程序
新的短消息通知功能
专为平板电脑设计的用户界面(重新设计的通知列与系统列)
加强多任务处理的接口
重新设计适用大屏幕的键盘及复制粘贴功能
多个标签的浏览器以及私密浏览模式
快速切换各种功能的相机
增强的图库与快速滚动的联络人接口
更有效率的 Email 接口
支持多核心处理器
3.2 优化 7 吋平板显示
Ÿ 4.0 Ice Cream Sandwich ( 奶油三明治)
虚拟按键,增大屏幕面积同时控制手机整体大小
桌面插件 Widgets 列表呈现在标签页中,与程序列表类似并且共存
文件夹更容易创建和管理,与 iOS 类似
可定制的桌面系统
可视语音邮件
日历支持缩放操作
Gmail 离线搜索,两行预览,以及底部新快捷栏
音量下键 + 电源键组合截图
改进虚拟键盘纠错
从锁屏界面直接访问应用程序
优化复制粘贴
新版浏览器
新的 Roboto 字体
流量控制系统
相机应用
人脸识别,刷脸解锁
内置照片编辑器
多任务列表
新的图库布局和组织方式
联系人应用整合社交网络信息
Android Beam
http://digi.tech.qq.com/a/20111019/001579.htm
1.4. 主流智能手机操作系统
2. 搭建开发环境
2.1. 所需资源
Ÿ JDK , Java 开发环境。下载地址: http://www.oracle.com
Ÿ Eclipse , IBM 公司开发的一款开源 IDE 。 http://www.eclipse.org
Ÿ Android SDK , Android 开发工具,包含开发 Android 程序所需类库、源码、文档、案例等资源。 http://www.android.com
Ÿ ADT 插件 ,ADT 是 Eclipse 平台下用来开发 Android 应用程序的插件 。 http://www.android.com
2.2. Eclipse 安装 ADT 插件
2.3. 配置 SDK 路径
2.4. 启动虚拟机
Ø 点击机器人图标
Ø 弹出虚拟机管理器
Ø 修改虚拟机默认目录
指定环境变量 android_sdk_home ,通常指定为 SDK 所在目录,可以随意指定。
重启 Eclipse 之后将会以这个目录作为存放虚拟机文件的位置。
Ø 配置虚拟机
Ÿ Name :虚拟机的名字,可随意定义
Ÿ Target :虚拟机版本
Ÿ SD Card - Size :虚拟机的 SDCard 大小,会在本地硬盘创建指定大小的文件用来存储数据,模拟真实手机的 SDCard
如果使用原有文件,可以选择 File 并点击 Browse 指定文件
Ÿ Snapshot : 保存快照,可以提高虚拟机启动速度
Ÿ Skin - Built-in :选择分辨率
HVGA : 480x320
QVGA : 320x240
WQVGA400 : 400x240
WQVGA432 : 432x240
WVGA800 : 800x480
WVGA854 : 854x480
也可以选择 Resolution 自行指定
Ø 成功进入 Android 操作系统界面
Ÿ 如果虚拟机显示无信号,需要对电脑的网络连接进行配置
无论电脑是否联网, IP 地址、子网掩码、默认网关、首选 DNS 服务器都需要配置
Ÿ 电脑如果未连接局域网或互联网,可以见默认网关和首选 DNS 服务器配置成本机IP ,例如:
Ÿ 电脑如果已连接局域网,需要将网关和首选 DNS 服务器进行设置,例如:
Ÿ 如果电脑已连接互联网,正常情况虚拟机不会显示无信号,重启虚拟机
2.5. 命令行操作
为了能在任意目录使用一下命令,需要将 SDK 目录下的 platform-tools文件夹路径和tools文件夹路径配置到 path 环境变量中
Ÿ 列出可以使用的 android 版本
android list targets
Ÿ 列出可以使用的虚拟机
android list avd
Ÿ 创建虚拟机
android create avd –n < 虚拟机名 > -t <Target 版本 ID> -c <SD 卡大小 > -s < 屏幕尺寸 >
Ÿ 启动虚拟机
emulator –avd < 虚拟机名 >
Ÿ 显示已连接的设备
adb devices
Ÿ 导入文件到手机
adb push <Windows 源文件路径 > < 手机目标路径 >
Ÿ 从手机导出文件
adb pull < 手机源文件路径 > <Windows 目录路径 >
Ÿ 安装程序
adb install <apk 文件路径 >
Ÿ 卸载程序
adb uninstall < 包名 >
Ÿ 重启 adb
adb kill-server
abd start-server
3. 开发一个 Android 程序
3.1. 创建 Android 程序
Ø 创建 Android Project
Ÿ Project name :项目名
Ÿ Build Target : Android 版本
Ÿ Application name :程序名,显示在程序列表中,以及程序启动后的标题栏
Ÿ Package name :包名,程序的唯一标识
Ÿ Create Activity :选择程序启动时是否创建一个窗体,设置主窗体名字
Ÿ Min SDK Version :设置运行该程序所需的最低版本
3.2. 安装、卸载程序
Ÿ Eclipse 安装
右键点击工程 – Run as – Android Application
Ÿ 虚拟机卸载
设置 – 应用程序 – 管理应用程序 – 选中要卸载的程序 – 卸载
3.3. 了解项目目录结构
Ÿ src :源代码
Ÿ gen :系统自动生成的文件
R.java 中记录了项目中各种资源 ID
Ÿ res :系统资源,所有文件都会在 R 文件生成资源 ID
drawable :图片
layout :界面布局
values :数据
anim :定义动画的 XML
raw :原生文件
Ÿ assets :资源路径,不会在 R 文件注册
Ÿ project.properties :供 Eclipse 使用,读取该项目使用 Android 版本号。早期版本名为: default.properties
Ÿ AndroidManifest.xml :清单文件,在软件安装的时候被读取
Android 中的四大组件( Activity 、 ContentProvider 、 BroadcastReceiver 、 Service)都需要在该文件中注册
程序所需的权限也需要在此文件中声明,例如:电话、短信、互联网、访问 SD 卡
Ÿ bin :二进制文件,包括 class 、资源文件、 dex 、 apk 等
Ÿ proguard.cfg:用来混淆代码的配置文件,防止别人反编译
3.4. 程序启动过程
Ÿ Eclipse 将 .java 源文件编译成 .class
Ÿ 使用 dx 工具将所有 .class 文件转换为 .dex 文件
Ÿ 再将 .dex 文件和所有资源打包成 .apk 文件
Ÿ 将 .apk 文件安装到虚拟机完成程序安装
Ÿ 启动程序 – 开启进程 – 开启主线程
Ÿ 创建 Activity 对象 – 执行 OnCreate() 方法
Ÿ 按照 main.xml 文件初始化界面
4. 演示案例
4.1. 电话拨号
Ÿ 搭建界面需要组件: TextView 、 EditText 、 Button
Ÿ 当点击 Button 时获取 EditText 中文本
Ÿ 使用 Intent 向系统内置的电话拨号器发送意图拨打电话
Ÿ 注册拨打电话权限
4.2. 查看程序错误信息
Ÿ Android 程序中如果出错,错误不会显示在 Console 中,而是显示在 LogCat 界面下。可以从 window – show view 中打开
Ÿ 日志信息分为 5 个级别: verbose > debug > info > warn > error 高级的包含低级的
Ÿ 可以创建过滤器对日志进行过滤显示,点击绿色加号,可以按照 tag 、 pid 、 level进行筛选
4.3. 将程序安装到真实手机
Ÿ 在电脑上安装手机驱动
有些手机自带驱动,有些没有,可以从官网下载。或者可以使用“豌豆荚”软件自动安装。
Ÿ 在手机设置中打开 USB 调试,将手机用 USB 数据线连接到电脑
我的手机是:三星 i9100
双核1228MHz、1GB RAM 、4GB ROM、480×800 像素 、Android 2.3、4.3 英寸
Ÿ 检查 Eclipse 的设备管理器中是否显示出新设备
如果未能显示出设备,检查驱动安装是否正常, USB 调试是否打开
Ÿ Eclipse 安装程序
Eclipse 上右键点击工程 – Run as – Android Application – 自动安装运行
Ÿ 手动打包安装
右键点击工程 – Export – Export Android Application – 选择或创建密钥对程序签名并打包生成 apk 文件
将 apk 文件放到手机的 SD 卡中,通过手机文件浏览器执行安装
4.4. 短信发送
Ÿ 搭建界面需要组件: TextView 、 EditText 、 Button
Ÿ 给 Button 添加监听器,当被点击的时候获取号码,获取内容
Ÿ 使用 SmsManager 发送短信
Ÿ 需要注册短信发送权限
4.5. 布局
Ø RelativeLayout (相对布局)
Ÿ android-sdk-windows/docs/guide/topics/ui/layout-objects.html#relativelayout
Ø TableLayout (表格布局)
android-sdk-windows/docs/guide/topics/ui/layout-objects.html#tablelayout
Ø FrameLayout (帧布局)
android-sdk-windows/docs/guide/topics/ui/layout-objects.html#framelayout
setRequestedOrientation(ActivityInfo. SCREEN_ORIENTATION_LANDSCAPE );
setRequestedOrientation(ActivityInfo. SCREEN_ORIENTATION_PORTRAIT );
4.6. Junit
Ø 项目中添加测试类
Ÿ 在 AndroidManifest.xml 清单文件中添加配置
< instrumentation android:targetPackage = "cn.itcast.junit" android:name = "android.test.InstrumentationTestRunner" />
< uses-library android:name = "android.test.runner" />
Ÿ 定义一个类继承 AndroidTestCase ,定义测试方法
Ÿ 在 Outline 视图下右键点击测试方法 – Run as – Android Junit Test
Ø 创建测试项目
Ÿ 创建 Android Test Project
Ÿ 输入项目名,选择一个已存在的工程, Eclipse 可以自动配置 Junit 环境
4.7. 日志信息
Ÿ 在 LogCat 视图中我们可以看到程序的日志信息,也可以在程序中输出信息到 LogCat 中
Ÿ 程序中我们可以使用 Log 类来输出信息
Ÿ System.out 和 System.err 输出的信息也会显示在 LogCat 中,注意 System.out 输出信息是 Info 级别, System.err 是 Warn 级别
5. 文件操作( File 、 XML 、 SharedPreferences )
5.1. 读写文件
Ø 写入文件到 SD 卡
Ÿ 需要在清单文件中注册权限
< uses-permission android:name = "android.permission.WRITE_EXTERNAL_STORAGE" />
Ÿ 2.1 版本以下的 SDCard 位置和 2.2 之后版本不同
可以通过Environment.getExternalStorageDirectory()获取当前 SDCard 位置,兼容所有版本
Ÿ 获取 SDCard 状态
通过Environment.getExternalStorageState()方法获取 SDCard 当前状态
常量 Environment.MEDIA_MOUNTED 为已安装
Ø 写入文件
Ÿ 通过 Context. openFileOutput(String name, int mode)可以获取一个文件输入流
name 为文件名, mode 为文件模式,有 4 种模式
输出流指向路径为: /data/data/ 包名 /files/
Ÿ 文件模式在 Context 中有定义常量
MODE_PRIVATE 私有
MODE_WORLD_READABLE 其他程序可读(不可写)
MODE_WORLD_WRITEABLE 其他程序可写(不可读)
模式可以组合使用,例如:MODE_WORLD_READABLE + MODE_WORLD_WRITEABLE
MODE_APPEND 追加
Ø 读取文件
Ÿ 通过 Context. openFileInput(String name)可以获取一个文件输入流
该输入流可以读取 /data/data/ 包名 /files/ 路径下的文件
Ÿ 获取当前程序 Files 文件路径
ContextWrapper.getFilesDir()
5.2. XML
Ø Pull 简介
Ÿ 常见的 XML 解析方式有三种, DOM 、 SAX 、 Pull , Android 系统中推荐使用Pull
Ÿ Pull 解析器是一个开源的 Java 项目, Android 系统内部解析 XML 文件均为此种方式,也可用于 JavaEE 项目
Ÿ Android SDK 中已经集成了 Pull 解析器,无需添加任何 jar 文件
Ÿ Pull 解析器运行方式与 SAX 类似,提供各种事件的判断
Ÿ 官方网站: http://xmlpull.org/
Ø 使用 Pull 解析器解析 XML 文件
Ÿ Xml.newPullParser() 获得解析器
Ÿ parser.setInput(in, "UTF-8" ) 设置输入流以及编码
Ÿ parser.next() 获取下一个解析事件,得到一个事件代码
Ÿ XmlPullParser中定义了常量来标识各种解析事件
START_DOCUMENT 、 END_DOCUMENT 、 START_TAG 、END_TAG 、 TEXT
Ø 使用XmlSerializer写出 XML
Ÿ 使用以下方法生成 XML ,和 XML 文档顺序类似
startDocument
startTag
attribute
text
endTag
endDocument
5.3. 偏好设定( SharedPreferences )
Ÿ 在程序中保存一些配置参数的时候我们经常使用 SharedPreferences
Context.getSharedPreferences(String name, int mode)
该方法可以在 /data/data/<package>/shared_pref/ 目录下创建一个以 name 命名的 xml文件, mode 文件为模式
Ÿ 存储偏好
调用edit()方法可以获取一个 Editor 对象,对数据进行存储,存储之后需要调用 commit()保存到文件
Ÿ 读取偏好
获得SharedPreferences之后调用 getString() 、 getInt() 等方法获取其中设置的值
Ÿ 在 Activity 中获取 SharedPreferences
在 Activity 中可以调用 getPreferences( int mode)方法获得一个SharedPreferences,文件名和 Activity 名一致
6. 数据库( SQLite )
6.1. SQLite 特点
Ÿ Android 平台中嵌入了一个关系型数据库 SQLite ,和其他数据库不同的是 SQLite存储数据时不区分类型
例如一个字段声明为 Integer 类型,我们也可以将一个字符串存入,一个字段声明为布尔型,我们也可以存入浮点数。
除非是主键被定义为 Integer ,这时只能存储 64 位整数
Ÿ 创建数据库的表时可以不指定数据类型,例如:
CREATE TABLE person(id INTEGER PRIMARY KEY AUTOINCREMENT, name VARCHAR(20))
CREATE TABLE person(id INTEGER PRIMARY KEY AUTOINCREMENT, name)
Ÿ SQLite 支持大部分标准 SQL 语句,增删改查语句都是通用的,分页查询语句和 MySQL 相同
SELECT * FROM person LIMIT 20 OFFSET 10
SELECT * FROM person LIMIT 10,20
6.2. 创建数据库
Ÿ 定义类继承SQLiteOpenHelper
Ÿ 声明构造函数, 4 个参数
Ÿ 重写 onCreate ()方法
Ÿ 重写 upGrade() 方法
Ÿ 注意: SQLite 数据库中列一旦创建不能修改,如果一定要修改,需要重新创建表,拷贝数据
6.3. CRUD操作
Ÿ 和 JDBC 访问数据库不同,操作 SQLite 数据库无需加载驱动,不用获取连接,直接可以使用
获取 SQLiteDatabase 对象之后通过该对象直接可以执行 SQL 语句
SQLiteDatabase.execSQL()
SQLiteDatabase.rawQuery()
Ÿ getReadableDatabase()和getWritableDatabase()的区别
查看源代码后我们发现getReadableDatabase()在通常情况下返回的就是getWritableDatabase() 拿到的数据库
只有在抛出异常的时候才会以只读方式打开
Ÿ 数据库对象缓存
getWritableDatabase() 方法最后会使用一个成员变量记住这个数据库对象,下次打开时判断是否重用
Ÿ SQLiteDatabase 封装了 insert() 、 delete ()、 update ()、 query ()四个方法也可以对数据库进行操作
这些方法封装了部分 SQL 语句,通过参数进行拼接
6.4. 事务管理
Ÿ 在使用 SQLite 数据库时可以用 SQLiteDatabase类中定义的相关方法控制事务
beginTransaction() 开启事务
setTransactionSuccessful() 设置事务成功标记
endTransaction() 结束事务
Ÿ endTransaction() 需要放在 finally 中执行,否则事务只有到超时的时候才自动结束,会降低数据库并发效率
7. 内容提供者( ContentProvider )
7.1. 什么是内容提供者
Ÿ 内容提供者是 Android 中的四大组件之一,可以将应用中的数据对外进行共享
Ÿ 内容提供者将数据的访问方式统一,不必针对不同数据类型采取不同的访问策略
Ÿ 内容提供者将数据封装,只暴露出我们希望提供给其他程序的数据
Ÿ 内容提供者中数据更改可被监听
7.2. 创建内容提供者
Ÿ 定义类继承 ContentProvider ,根据需要重写内部方法
Ÿ 在清单文件的 <application> 节点下进行配置, <provider> 标签中需要指定 name 和authorities 属性
name 为类名,包名从程序 Package 开始,以“ . ”开始
authorities :是访问 Provider 时的路径,要唯一
Ÿ URI 代表要操作的数据,由 scheme 、 authorites 、 path 三部分组成
content:// cn.itcast. sqlite . provider / person
scheme :固定为 content ,代表访问内容提供者
authorites : <provider> 节点中的 authorites 属性
path :程序定义的路径,可根据业务逻辑定义
7.3. 完成 CRUD 方法
Ÿ 当程序调用 CRUD 方法时会传入 Uri
Ÿ 我们通过 Uri 判断调用者要操作的数据
可以使用工具类 UriMatcher 来判断 Uri
addURI 方法可以添加 Uri
match 方法可以匹配一个 Uri 判断其类型
Ÿ 根据业务逻辑操作数据
7.4. 访问内容提供者
Ÿ 通过 Context 获得 ContentResolver 对象
Ÿ 调用 ContentResolver 对象的方法即可访问内容提供者
7.5. 完成 getType 方法
Ÿ 如果返回数据是单条数据:vnd.android.cursor.item
Ÿ 如果返回数据是多条数据:vnd.android.cursor.dir
7.6. 监听内容提供者数据变化
Ÿ 在内容提供者中可以通知其他程序数据发生变化
通过 Context 的 getContentResolver() 方法获取 ContentResolver
调用其notifyChange() 方法发送数据修改通知
Ÿ 在其他程序中可以通过ContentObserver监听数据变化
通过 Context 的 getContentResolver() 方法获取 ContentResolver
调用其registerContentObserver() 方法指定对某个 Uri 注册 ContentObserver
自定义ContentObserver,重写 onChange() 方法获取数据
7.7. GIT 获取源代码
Ø 资源地址
Ÿ Git
http://code.google.com/p/msysgit/
Ÿ 源码
注意:
GIT1.7.7 安装后不能卸载,可以用其他版本覆盖后再卸载。
使用 GIT 时不要使用中文目录,否则 GIT GUI 会报错无法启动。删除 C 盘中 .gitconfig文件可以解决。
7.8. 监听短信
Ÿ Android 系统提供了 Provider 对短信进行查询,当发出短信时也会发送更改通知
Ÿ 短信数据库在 com.android.providers.telephony
Ÿ 定义一个 Observer 监听 "content://sms"
Ÿ 在 onChange() 方法中查询 "content://sms"
Ÿ 需要权限android.permission.READ_SMS
7.9. 操作联系人
Ø 获取所有联系人
Ÿ Android 系统中的联系人也是通过 ContentProvider 来对外提供数据的
Ÿ 数据库路径为: /data/data/com.android.providers.contacts/database/contacts2.db
Ÿ 我们需要关注的有 3 张表
raw_contacts :其中保存了联系人 id
data :和 raw_contacts 是多对一的关系,保存了联系人的各项数据
mimetypes :为数据类型
Ÿ Provider 的 authorites 为 com.android.contacts
Ÿ 查询 raw_contacts 表的路径为: contacts
Ÿ 查询 data 表的路径为: contacts/#/data
这个路径为连接查询,直接查询“ mimetype ”字段就可以根据“ mimetype_id ”查询到 mimetypes 表中的数据
Ÿ 先查询 raw_contacts 得到每个联系人的 id ,在使用 id 从 data 表中查询对应数据,根据 mimetype 分类数据
Ø 通过电话号码获取联系人
Ÿ 系统内部提供了根据电话号码获取 data 表数据的功能,路径为: data/phones/filter/*
Ÿ 用电话号码替换“ * ”部分就可以查到所需数据,获取“ display_name ”可以获取到联系人显示名
Ø 添加联系人
Ÿ 先向 raw_contacts 表插入 id ,路径为: raw_contacts
Ÿ 得到 id 之后再向 data 表插入数据,路径为: data
Ø 使用事务添加联系人
Ÿ 在添加联系人得时候是分多次访问 Provider ,如果在过程中出现异常,会出现数据不完整的情况,这些操作应该放在一次事务中
Ÿ 使用ContentResolver的applyBatch(String authority,ArrayList<ContentProviderOperation> operations) 方法可以将多个操作在一个事务中执行
Ÿ 文档位置 :
8. 网络通信
8.1. 获取文本数据
Ÿ 通过 URL 对象封装地址,打开一个 HttpURLConnection
Ÿ 设置头信息之后获取响应码,如果成功返回 200 即可从 HttpURLConnection 中获取输入流读取数据
Ÿ 代码过长屏幕显示不全可以使用 <ScrollView> 进行显示
Ÿ 需要访问网络的权限
< uses-permission android:name = "android.permission.INTERNET" />
8.2. 获取网络图片
Ÿ 通过 BitmapFactory 的 decodeByteArray(byte[] data, int offset, int length)方法将数据转换为图片对象
8.3. 获取 XML
Ÿ 使用 URL 封装路径,打开一个 HttpURLConnection
Ÿ 设置头信息之后获取相应码,从输入流中获取数据
Ÿ 使用 XmlPullPaser 解析
8.4. 获取 JSON
Ÿ 使用 URL 封装路径,打开一个 HttpURLConnection
Ÿ 设置头信息之后获取相应码,从输入流中获取数据
Ÿ 将数据转为 String ,封装成 JSONArray 对象
Ÿ 遍历 JSONArray 对象,调用获取其中的 JSONObject
Ÿ 再从 JSONObject 中获取每个字段的信息
8.5. 发送 GET 请求
Ÿ 拼接路径和参数,通过 URL 进行封装,打开一个 HttpURLConnection ,发送请求
Ÿ 如果参数是中文会出现乱码
Ÿ URL 中包含的中文参数需要使用 URLEncoder 进行编码
Ÿ 服务器端如果是 TOMCAT ,其默认使用 ISO8859-1 编码,接收时需要处理编码问题
8.6. 发送 POST 请求
Ÿ 通过 URL 打开一个 HttpURLConnection
Ÿ 头信息中除了超时时间和请求方式之外还必须设置Content-Type和Content-Length
Ÿ 从 HttpURLConnection 获得输出流输出参数数据
Ÿ 服务端可以使用 request 对象的 setCharacterEncoding方法设置编码
8.7. 发送 XML ,访问 WebService
Ø 发送 XML
Ÿ 通过 URL 封装路径打开一个 HttpURLConnection
Ÿ 设置请求方式,Content-Type和Content-Length
XML 文件的 Content-Type为:text/xml; charset=UTF-8
Ÿ 使用 HttpURLConnection 获取输出流输出数据
Ø WebService
Ÿ WebService 是发布在网络上的 API ,可以通过发送 XML 调用, WebService 返回结果也是 XML 数据
Ÿ WebService 没有语言限制,只要可以发送 XML 数据和接收 XML 数据即可
Ÿ http://www.webxml.com.cn 网站上提供了一些 WebService 服务,我们可以对其进行调用
Ÿ http://webservice.webxml.com.cn/WebServices/MobileCodeWS.asmx?op=getMobileCodeInfo 中提供了电话归属地查询的使用说明
8.8. HTTP 协议上传文件
Ÿ 搭建服务器,完成上传功能
Ÿ 使用浏览器上传,查看请求信息
Ø HttpURLConnection
Ÿ 通过 URL 封装路径打开一个 HttpURLConnection
Ÿ 设置请求方式以及头字段:Content-Type、Content-Length、Host
Ÿ 拼接数据发送
Ø Socket
Ÿ 使用 HttpURLConnection 发送时内部有缓存机制,如果上传较大文件会导致内存溢出
Ÿ 我们可以使用 Socket 发送 TCP 请求,将上传数据分段发送
Ø HttpClient
public void upload(String name, String password, String path) throws Exception {
// 创建 HttpClient 对象
HttpClient client = new HttpClient();
// 设置超时事件
client.getHttpConnectionManager().getParams().setConnectionTimeout(5000);
// 创建一个 Post 请求 , 指定路径
PostMethod postMethod = new PostMethod( "http://192.168.1.102:8080/14.Web/LoginServlet" );
// 封装每个表单项
Part[] parts = { new StringPart( "name" , name), new StringPart( "password" , password), new FilePart( "file" , new File(path)) };
// 给 Post 请求设置实体
postMethod.setRequestEntity( new MultipartRequestEntity(parts, postMethod.getParams()));
// 执行 Post 请求
client.executeMethod(postMethod);
// Post 请求是释放资源
postMethod.releaseConnection();
}
8.9. 多线程断点续传下载器
Ÿ 在下载的时候多个线程并发可以占用服务器端更多资源,从而加快下载速度
Ÿ 手机端下载数据时难免会出现无信号断线、电量不足等情况,所以需要断点续传功能
Ÿ 根据下载数据长度计算每个线程下载的数据位置,程序中开启多个线程并发下载
在请求头中设置 Range 字段就可以获取指定位置的数据,例如: Range: bytes=100-200
Ÿ 在下载过程中记录每个线程已拷贝数据的数量,如果下载中断,下次启动时从记录位置继续下载
Ø 多线程下载
Ÿ 进度条使用 <Progress> 进行配置
默认为圆形进度条,水平进度条需要配置 style 属性, ?android:attr/progressBarStyleHorizontal
使用 android.R.attr. progressBarStyleHorizontal作为样式
Ÿ 当点击下载按钮时开启多线程下载,下载过程中修改进度条进度
设置最大刻度:setMax()
设置当前进度:setProgress()
Ø 断点续传
Ÿ 断点续传需要在下载过程中记录每条线程的下载进度
Ÿ 每次下载开始之前先读取数据库,查询是否有未完成的记录,有就继续下载,没有则创建新记录插入数据库
Ÿ 在每次向文件中写入数据之后,在数据库中更新下载进度
Ÿ 下载完成之后删除数据库中下载记录
Ø Handler 传输数据
Ÿ 主线程中创建的 View 只能在主线程中修改,其他线程只能通过和主线程通信,在主线程中改变 View 数据
Ÿ 我们使用 Handler 可以处理这种需求
主线程中创建 Handler ,重写 handleMessage() 方法
新线程中使用 Handler 发送消息,主线程即可收到消息,并且执行 handleMessage()方法
Ø 动态生成新 View
Ÿ 创建 XML 文件,将要生成的 View 配置好
Ÿ 获取系统服务 LayoutInflater ,用来生成新的 View
LayoutInflater inflater = (LayoutInflater) getSystemService( LAYOUT_INFLATER_SERVICE );
Ÿ 使用inflate( int resource, ViewGroup root)方法生成新的 View
Ÿ 调用当前页面中某个容器的 addView ,将新创建的 View 添加进来
9. 活动( Activity )
9.1. 创建 Activity
Ø 定义 Activity
Ÿ 定义类继承 Activity
Ÿ 在 AndroidManifest.xml 的 <application> 节点中声明 <activity>
Ø 显式意图创建方式
Ÿ 构造函数,代码少
new Intent( this , NewActivity. class );
Ÿ 类名形式,灵活,可扩展性强
intent.setClassName( this , "cn.itcast.activity.NewActivity" );
Ÿ 包名类名形式,可启动其他程序中的 Activity
intent.setClassName( "cn.itcast.downloader" , "cn.itcast.downloader.MainActivity");
Ø 创建 Activity 并传递数据
Ÿ 在意图对象中封装了一个 Bundle 对象,可以用来携带数据
Ÿ 在新 Activity 中可以获得意图对象以获取其中 Bundle 保存的数据
Ø 创建 Activity 获取返回数据
Ÿ 使用startActivityForResult(Intent intent, int requestCode) 方法打开 Activity
Ÿ 重写onActivityResult( int requestCode, int resultCode, Intent data) 方法
Ÿ 新 Activity 中调用 setResult( int resultCode, Intent data) 设置返回数据之后,关闭 Activity 就会调用 onActivityResult方法
Ø 隐式意图创建 Activity
Ÿ 显式意图是指在创建意图时指定了组件,而隐式意图则不指定组件,通过动作、类型、数据匹配对应的组件
Ÿ 在清单文件中定义 <activity> 时需要定义 <intent-filter> 才能被隐式意图启动
Ÿ <intent-filter> 中至少配置一个 <action> 和一个 <category> ,否则无法被启动
Ÿ Intent 对象中设置的 action 、 category 、 data 在 <intent-filter> 必须全部包含才能启动
Ÿ <intent-filter> 中的 <action> 、 <category> 、 <data> 都可以配置多个, Intent 对象中不用全部匹配,每样匹配一个即可启动
Ÿ 如果一个意图可以匹配多个 Activity , Android 系统会提示选择
9.2. 生命周期
Ÿ Acitivity 三种状态
运行: activity 在最前端运行
暂停: activity 可见,但前端还有其他 acti vity ,被覆盖一部分,或者前端 activity 透明
停止: activity 不可见,完全被覆盖
Ÿ 生命周期相关方法
onCreate :创建时调用,或者程序在暂停、停止状态下被杀死之后重新打开时也会调用
onStart : onCreate 之后或者从停止状态恢复时调用
onResume : onStart 之后或者从暂停状态恢复时调用,从停止状态恢复时由于调用onStart ,也会调用 onResume
onPause:进入暂停、停止状态,或者销毁时会调用
onStop:进入停止状态,或者销毁时会调用
onDestroy:销毁时调用
onRestart :从停止状态恢复时调用
Ÿ 保存信息相关方法
onSaveInstanceState:在 Activity 被动的摧毁或停止的时候调用,用于保存运行数据,可以将数据存在在 Bundle 中
onRestoreInstanceState:该方法在 Activity 被重新绘制的时候调用,例如改变屏幕方向, savedInstanceState为onSaveInstanceState保存的数据
9.3. 启动模式
Ÿ 在 AndroidManifest.xml 中的 <activity> 标签中可以配置 android:launchMode 属性,用来控制 Actvity 的启动模式
Ÿ 在 Android 系统中我们创建的 Acitivity 是以栈的形式呈现的
standard :每次调用 startActivity() 启动时都会创建一个新的 Activity 放在栈顶
singleTop :如果启动的 Activity 时,指定 Activity 不在栈顶就创建,如在栈顶,则不再创建
singleTask :如果启动的 Activity 不存在就创建,如果存在直接跳转到指定的 Activity 所在位置
singleInstance :如果启动的 Activity 不存在就创建,如果存在就将指定的 Activity移动到栈顶
9.4. 内存管理
Ÿ Android 系统在运行多个进程时,如果系统资源不足,会强制结束一些进程。优先选择哪个进程来结束是有优先级的。以下顺序靠上的优先结束
空:进程中所有 Activity 都已销毁
后台:进程中有一个停止状态的 Activity
可见:进程中有一个暂停状态的 Activity
前台:进程中正在运行一个 Activity
10. 广播接收者 (BroadcastReceiver)
10.1. 定义广播接收者
Ÿ 定义类继承 BroadcastReceiver ,重写 onReceive 方法
Ÿ 清单文件中声明<receiver>,需要在其中配置<intent-filter>指定接收广播的动作
Ÿ 当接收到匹配广播之后就会执行 onReceive 方法
Ÿ BroadcastReceiver 除了在清单文件中声明,也可以在代码中声明,使用 registerReceiver方法注册 Receiver
10.2. 发送广播
Ø 无序广播
Ÿ 使用sendBroadcast方法发送
Ÿ 被所有广播接收者接收,无序,不可中断
Ÿ 广播时可设置接收者权限,仅当接收者含有权限才能接收
Ÿ 接收者的<receiver>也可设置发送方权限,只接收含有权限应用的广播
Ø 有序广播
Ÿ 使用sendOrderedBroadcast方法发送
Ÿ 接收者可以在<intent-filter>中定义android:priority定义优先级,数字越大优先级越高
Ÿ 被各个广播接收者逐个接收,中途可以中断或者添加数据
abortBroadcast()
getResultExtras( true ).putString( "data" , " 新增数据 " );
10.3. 监听短信接收
Ÿ Android 系统在收到短信的时候会发送一条有序广播,我们如果定义一个接收者接收这个广播,就可以得到短信内容,也可以拦截短信
Ÿ 定义广播接收者接收广播 android.provider.Telephony.SMS_RECEIVED
Ÿ 在 onReceive 方法内部调用 Intent 的 getExtras() 再调用 get(String) 获取其中 pdus字段,得到一个 Object[],其中每一个元素都是一个 byte[]
Ÿ 通过SmsMessage类的createFromPdu方法创建 SmsMessage 对象
Ÿ 从 SmsMessage 对象中即可获取发送者号码、短信内容、发送时间等信息
Ÿ 需要接收短信权限: < uses-permission android:name ="android.permission.RECEIVE_SMS" />
Ÿ Android 系统中收到短信的通知是一个有序通知,我们如需拦截垃圾短信,可以配置较高的 priority,收到信息进行判断是否abortBroadcast()
10.4. 监听呼出电话
Ÿ 定义广播接收者接收 android.intent.action.NEW_OUTGOING_CALL
Ÿ 需要权限 < uses-permission android:name = "android.permission.PROCESS_OUTGOING_CALLS" />
Ÿ 在 onReceive 方法中使用 getResultData() 和 setResultData() 方法获取和设置电话号码
10.5. 生命周期
Ÿ 广播接收者的生命周期是非常短暂的,在接收到广播的时候创建, onReceive() 方法结束之后销毁
Ÿ 广播接收者中不要做一些耗时的工作,否则会弹出 Application No Response 错误对话框
Ÿ 最好也不要在广播接收者中创建子线程做耗时的工作,因为广播接收者被销毁后进程就成为了空进程,很容易被系统杀掉
Ÿ 耗时的较长的工作最好放在服务中完成
11. 服务 (Service)
11.1. 基本概念
Ÿ Service 是一种在后台运行,没有界面的组件,由其他组件调用开始。
Ÿ 创建 Service ,定义类继承 Service , AndroidManifest.xml 中定义 <service>
Ÿ 开启 Service ,在其他组件中调用 startService方法
Ÿ 停止 Service ,调用 stopService方法
11.2. 电话录音
需要权限: android.permission.READ_PHONE_STATE
TelephonyManager manager = (TelephonyManager) getSystemService( TELEPHONY_SERVICE );
manager.listen( new MyListener(), PhoneStateListener. LISTEN_CALL_STATE );
private final class MyListener extends PhoneStateListener {
private String num ;
private MediaRecorder recorder ;
public void onCallStateChanged( int state, String incomingNumber) {
switch (state) {
case TelephonyManager. CALL_STATE_RINGING :
num = incomingNumber;
break ;
case TelephonyManager. CALL_STATE_OFFHOOK :
try {
File file = new File(Environment.getExternalStorageDirectory(), num + "_" + System.currentTimeMillis() + ".3gp" );
recorder = new MediaRecorder();
recorder .setAudioSource(AudioSource. MIC );
recorder .setOutputFormat(OutputFormat. THREE_GPP );
recorder .setAudioEncoder(AudioEncoder. AMR_NB );
recorder .setOutputFile( file .getAbsolutePath());
recorder .prepare();
recorder .start();
} catch (Exception e) {
e.printStackTrace();
}
break ;
case TelephonyManager. CALL_STATE_IDLE :
if ( recorder != null ) {
recorder .stop();
recorder .release();
}
break ;
}
}
}
11.3. 绑定本地服务
Ÿ 使用bindService绑定服务,传入一个自定义的ServiceConnection用来接收 IBinder
Ÿ 定义一个业务接口,其中定义需要的使用的方法
Ÿ 服务中自定义一个 IBinder 继承 Binder 并实现业务接口,在 onBind方法中返回
Ÿ 调用端将 IBinder 转为接口类型,调用接口中的方法即可调用到服务中的方法
11.4. 绑定远程服务
Ÿ 远程绑定服务时无法通过同一个接口来调用方法,这时就需要使用 AIDL 技术
Ÿ 将接口扩展名改为“.aidl”
Ÿ 去掉权限修饰符
Ÿ gen 文件夹下会生成同名接口
Ÿ 将服务中自定义的 IBinder 类改为继承接口中的 S tub
Ÿ ServiceConnection中返回的 IBinder 是代理对象,不能使用强转,改用 S tub.asInterface()
11.5. AIDL 使用自定义类型
Ÿ AIDL 默认只能使用 Java 中基本数据类型和 String 、 List 、 Map , List 和 Map 中的元素类型也只能是这些类型。
Ÿ 如果需要使用其他类型数据,使用的类必须实现 Parcelable 接口以完成序列化和反序列化工作
重写 public void writeToParcel(Parcel dest, int flags)
定义 public static final Parcelable.Creator<Person> CREATOR
Ÿ 定义该类对应的 AIDL
package 包名
parcelable 类名
Ÿ 在接口 AIDL 中导入该类,注意:即使是同一个包也需要导入
12. 多媒体
12.1. 音频播放器
12.2. 视频播放器
screenSV .getHolder().setType(SurfaceHolder. SURFACE_TYPE_PUSH_BUFFERS ); // 设置缓冲区数据
screenSV .getHolder().setKeepScreenOn( true ); // 设置屏幕保持
screenSV .getHolder().addCallback( new MyCallback()); // 设置回调函数
player .reset();
player .setDisplay( screenSV .getHolder()); // 设置显式
player .setDataSource( "/mnt/sdcard/1.mp4" ); // 设置数据源
player .prepare(); // 准备
player .seekTo(position); // 跳转到指定位置
player .start();
12.3. 拍照
Ÿ 需要权限
< uses-permission android:name = "android.permission.CAMERA" />
Ÿ 打开摄像头
Camera.open()
SDK2.3 之后支持前置摄像头, open 方法可以接收一个 int 参数,用来指定哪个摄像头
Ÿ 设置预览显示位置
setPreviewDisplay(SurfaceHolder holder)
注意 SurfaceView 不在前端显示的时候会被销毁,恢复之后会重绘
Ÿ 开始预览
startPreview()
将摄像头拍摄画面显示在 SurfaceView 中,在此之前可对摄像头进行参数配置
getParameters() 方法可以获取摄像头的相关参数Parameters,调用其内部方法即可进行配置
Ÿ 自动对焦
autoFocus(AutoFocusCallback cb)
自动对焦是一个异步操作,如果我们向等待自动对焦结束之后才开始拍照,需要传入一个回调对象,在其回调函数中调用拍照方法
Ÿ 拍照
takePicture(ShutterCallback shutter, PictureCallback raw, PictureCallback jpeg)
拍照也是异步操作,需要通过回调函数来得到拍照之后的数据
注意拍照之后摄像头不回自动回到预览状态,需要重写调用startPreview()方法
12.4. 录像
Ÿ 需要权限
< uses-permission android:name = "android.permission.RECORD_AUDIO" />
< uses-permission android:name = "android.permission.CAMERA" />
Ÿ 创建MediaRecorder
new MediaRecorder()
Ÿ 设置音频输入源
setAudioSource( int audio_source)
Ÿ 设置视频输入源
setVideoSource( int video_source)
Ÿ 设置输出格式
setOutputFormat( int output_format)
Ÿ 设置音频编码器
setAudioEncoder( int audio_encoder)
Ÿ 设置视频编码器
setVideoEncoder( int video_encoder)
Ÿ 设置预览显示位置
setPreviewDisplay(Surface sv)
Ÿ 设置输出文件
setOutputFile(String path)
Ÿ 准备录制
prepare()
Ÿ 开始录制
start()
开始录制之前需要结束摄像头的预览
Ÿ 结束录制释放资源
stop()
release()
13. 通知
13.1. 吐司通知
Ÿ 创建通知
Toast.makeText(Context context, CharSequence text, int duration)
Toast.makeText(Context context, int resId, int duration)
Ÿ 发送通知
show()
13.2. 状态栏通知
Ÿ 获取系统通知服务
NotificationManager nm = (NotificationManager) getSystemService( NOTIFICATION_SERVICE )
Ÿ 创建通知
通过构造函数创建 : Notification( int icon, CharSequence tickerText, long when)
icon: 通知的图片资源 ID
tickerText: 状态栏中显示的消息内容
when: 时间
Ÿ 创建PendingIntent以供点击时发送
PendingIntent.getActivity(Context context, int requestCode, Intent intent, int flags)
context: 当前上下文
requestCode: 请求码
intent: 点击时要发送的意图
flags: 类型 , PendingIntent中提供了常量选择
Ÿ 设置通知点击事件
调用Notification 对象方法 : setLatestEventInfo(Context context, CharSequence contentTitle, CharSequence contentText, PendingIntent contentIntent)
context: 当前上下文
contentTitle: 标题
contentText: 内容
contentIntent: 点击时触发的意图
Ÿ 设置通知点击后清除
设置Notification 对象属性 n. flags = Notification. FLAG_AUTO_CANCEL ;
Ÿ 发送消息
调用Notification对象方法 : notify( int id, Notification notification)
13.3. 对话框通知
Ø 普通对话框
new AlertDialog.Builder( this ) //
.setTitle( " 普通对话框 " ) //
.setMessage( " 普通内容 " ) //
.setCancelable( false ) //
.setPositiveButton( "YES" , listener) // listener 为 OnClickListener 监听器对象 , 监听按钮被选中
.setNeutralButton( "CANCEL" , listener) //
.setNegativeButton( "NO" , listener) //
.show();
Ø 列表对话框
new AlertDialog.Builder( this ) //
.setTitle( " 列表对话框 " ) //
.setCancelable( false ) //
.setItems( items , listener) // listener 为 OnClickListener 监听器对象 , 监听列表项被选中
.show();
Ø 单选对话框
new AlertDialog.Builder( this ) //
.setTitle( " 单选对话框 " ) //
.setCancelable( false ) //
.setSingleChoiceItems( items , 0, choiceLinstener) // 0, 为默认选中索引 , choiceLinstener 为 OnClickListener 监听器对象 , 监听单选按钮被选中
.setPositiveButton( " 确定 " , positiveLinstener) // positiveLinstener 为 OnClickListener 监听器对象 , 监听确定按钮点击
.show();
Ø 多选对话框
new AlertDialog.Builder( this ) //
.setTitle( " 多选对话框 " ) //
.setCancelable( false ) //
.setMultiChoiceItems( items , checkedArr, choiceListener) // checkedArr 为默认选中 , choiceListener 为 OnMultiChoiceClickListener 监听器对象 , 监听多选按钮被选中
.setPositiveButton( " 确定 " , positiveLinstener) // positiveLinstener 为 OnClickListener 监听器对象 , 监听确定按钮点击
.show();
Ø 进度对话框
ProgressDialog dialog = new ProgressDialog( this );
dialog.setProgressStyle(ProgressDialog. STYLE_HORIZONTAL ); // 设置进度条样式
dialog.setTitle( " 下载中 " );
dialog.setMessage( " 请稍候 ..." );
dialog.setCancelable( false );
dialog.setMax(100);
dialog.show();
dialog.setProgress(10); // 设置进度
dialog.dismiss(); // 对话框结束
关于通知的文档位置: android-sdk-windows/docs/guide/topics/ui/notifiers/index.html
14. 常用 UI
14.1. 列表视图 (ListView)
Ø XML 配置
Ÿ 在主界面中配置 <ListView> 标签
Ÿ 在 res/layout/ 文件夹下创建一个新的 xml 文件指定每个条目的布局
Ø Java 代码构建 ListView
Ÿ 获取 ListView 对象
Ÿ 设置一个 Adapter
BaseAdapter :实现内部抽象方法
SimpleAdapter:以 List<Map<String, ?>> 形式封装数据
SimpleCursorAdapter:以 Cursor 对象封装数据, Cursor 中需要有“ _id ”一列
Ÿ 添加 OnItemClickListener
调用 ListView 的 getItemAtPosition(int) 方法可以获取封装数据的容器
如果传入的是 BaseAdapter ,获取到的就是我们自定义方法中返回的内容
如果传入的是SimpleAdapter,获取到的就是一个 Map<String, ?>
如果传入的是SimpleCursorAdapter,获得到的就是一个 Cursor ,并且 Cursor 以指向选中的一条记录
14.2. 单选 (RadioGroup)
Ÿ 定义 <RadioGroup>
Ÿ 在 <RadioGroup> 中定义 <RadioButton> 和 <Button>
Ÿ 处理 Button 的点击事件
Ÿ 根据 ID 获取 RadioGroup 对象,调用其 getCheckedRadioButtonId()方法可以获取其中被选中的RadioGroup 的 ID
Ø 代码
< RadioGroup
android:id = "@+id/lessonsRG"
android:layout_width = "fill_parent"
android:layout_height = "wrap_content"
android:orientation = "horizontal" >
< RadioButton
android:id = "@+id/javaRB"
android:layout_width = "fill_parent"
android:layout_height = "wrap_content"
android:layout_weight = "1"
android:text = "Java" />
< RadioButton
android:id = "@+id/netRB"
android:layout_width = "fill_parent"
android:layout_height = "wrap_content"
android:layout_weight = "1"
android:text = ".Net" />
< RadioButton
android:id = "@+id/phpRB"
android:layout_width = "fill_parent"
android:layout_height = "wrap_content"
android:layout_weight = "1"
android:text = "PHP" />
< Button
android:layout_width = "fill_parent"
android:layout_height = "wrap_content"
android:layout_weight = "1"
android:onClick = " onR radioClick"
android:text = " 确定 " />
</ RadioGroup >
public void onRradioClick(View view) {
RadioGroup lessonRG = (RadioGroup) findViewById(R.id. lesson s RG );
int id = lessonRG.getCheckedRadioButtonId(); // 获取选中的 id
String msg = null ;
switch (id) {
case R.id. javaRB :
msg = "Java" ;
break ;
case R.id. netRB :
msg = ".Net" ;
break ;
case R.id. phpRB :
msg = "PHP" ;
break ;
}
Toast.makeText( this , msg, 0).show();
}
14.3. 多选 (CheckBox)
Ÿ 定义若干 <CheckBox> 和一个 <Button>
Ÿ 处理 Button 的点击事件
Ÿ 根据 ID 获取每个 CheckBox ,调用其 isChecked()方法判断是否被选中
Ø 代码
< LinearLayout
android:layout_width = "fill_parent"
android:layout_height = "wrap_content" >
< CheckBox
android:id = "@+id/javaCB"
android:layout_width = "fill_parent"
android:layout_height = "wrap_content"
android:layout_weight = "1"
android:text = "Java" />
< CheckBox
android:id = "@+id/netCB"
android:layout_width = "fill_parent"
android:layout_height = "wrap_content"
android:layout_weight = "1"
android:text = ".Net" />
< CheckBox
android:id = "@+id/phpCB"
android:layout_width = "fill_parent"
android:layout_height = "wrap_content"
android:layout_weight = "1"
android:text = "PHP" />
< Button
android:layout_width = "fill_parent"
android:layout_height = "wrap_content"
android:layout_weight = "1"
android:onClick = "checkboxOnClick"
android:text = " 确定 " />
</ LinearLayout >
public void checkboxOnClick(View view) {
CheckBox javaCB = (CheckBox) findViewById(R.id. javaCB );
CheckBox netCB = (CheckBox) findViewById(R.id. netCB );
CheckBox phpCB = (CheckBox) findViewById(R.id. phpCB );
StringBuilder sb = new StringBuilder();
sb.append(javaCB.isChecked() ? javaCB.getText() + " " : "" );
sb.append(netCB.isChecked() ? netCB.getText() + " " : "" );
sb.append(phpCB.isChecked() ? phpCB.getText() + " " : "" );
Toast.makeText( this , sb, 0).show();
}
14.4. 下拉列表 ( Spinner )
Ÿ 定义 <Spinner> 标签
Ÿ 创建一个适配器
Ÿ 获取 Spinner 标签,调用 setAdapter(SpinnerAdapter adapter)方法设置一个适配器
Ÿ 调用setOnItemSelectedListener(OnItemSelectedListener listener)方法设置监听器监听选中事件
Ø XML 配置
< Spinner
android:id = "@+id/spinner"
android:layout_width = "fill_parent"
android:layout_height = "wrap_content" />
Ø 使用字符串构建适配器
private void setSpinnerByString() {
final Spinner spinner = (Spinner) findViewById(R.id. spinner );
ArrayAdapter<String> adapter = new ArrayAdapter<String>( this , android.R.layout. simple_spinner_item ); // 设置样式
adapter.setDropDownViewResource(android.R.layout. simple_spinner_dropdown_item ); // 设置下拉后样式
adapter.add( "Java" );
adapter.add( ".Net" );
adapter.add( "PHP" );
spinner.setAdapter(adapter);
spinner.setOnItemSelectedListener( new OnItemSelectedListener() {
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
String selection = (String) spinner.getItemAtPosition(position);
Toast.makeText(getApplicationContext(), selection, 0).show();
}
public void onNothingSelected(AdapterView<?> parent) {
}
});
}
Ø 使用 JavaBean 构建适配器
private void setSpinnerByJavaBean() {
final Spinner spinner = (Spinner) findViewById(R.id. spinner );
ArrayAdapter<User> adapter = new ArrayAdapter<User>( this , android.R.layout.simple_spinner_item );
adapter.setDropDownViewResource(android.R.layout. simple_spinner_dropdown_item );
adapter.add( new User(1, "lhm" , "lhm@itcast.cn" ));
adapter.add( new User(2, "yzk" , "yzk@itcast.cn" ));
adapter.add( new User(3, "hsp" , "hsp@itcast.cn" ));
spinner .setAdapter(adapter);
spinner .setOnItemSelectedListener( new OnItemSelectedListener() {
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
User selection = (User) spinner .getItemAtPosition(position);
Toast.makeText(getApplicationContext(), selection.getName(), 0).show();
}
public void onNothingSelected(AdapterView<?> parent) {
}
});
}
Ø 使用资源文件构建适配器
< string-array name = "items" >
< item > Java </ item >
< item > .Net </ item >
< item > PHP </ item >
</ string-array >
private void setSpinnerByResource() {
final Spinner spinner = (Spinner) findViewById(R.id. spinner );
ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource( this, R.array. items , android.R.layout. simple_spinner_item );
adapter.setDropDownViewResource(android.R.layout. simple_spinner_dropdown_item );
spinner .setAdapter(adapter);
spinner .setOnItemSelectedListener( new OnItemSelectedListener() {
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
CharSequence selection = (CharSequence) spinner .getItemAtPosition(position);
Toast.makeText(getApplicationContext(), selection, 0).show();
}
public void onNothingSelected(AdapterView<?> parent) {
}
});
}
Ø 自定义适配器样式
<? xml version = "1.0" encoding = "utf-8" ?>
< LinearLayout xmlns:android = "http://schemas.android.com/apk/res/android"
android:layout_width = "match_parent"
android:layout_height = "match_parent"
android:orientation = "horizontal" >
< ImageView
android:layout_width = "50dp"
android:layout_height = "50dp"
android:src = "@android:drawable/ic_delete" />
< TextView
android:id = "@+id/content"
android:layout_width = "fill_parent"
android:layout_height = "wrap_content"
android:textSize = "50sp" />
</ LinearLayout >
private void setSpinnerByCustom() {
final Spinner spinner = (Spinner) findViewById(R.id. spinner );
ArrayAdapter<CharSequence> adapter = new ArrayAdapter<CharSequence>( this , R.layout. item , R.id. content );
adapter.add( "Java" );
adapter.add( ".Net" );
adapter.add( "PHP" );
spinner .setAdapter(adapter);
spinner .setOnItemSelectedListener( new OnItemSelectedListener() {
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
String selection = (String) spinner .getItemAtPosition(position);
Toast.makeText(getApplicationContext(), selection, 0).show();
}
public void onNothingSelected(AdapterView<?> parent) {
}
});
}
14.5. 菜单 (Menu)
Ø 添加菜单项
Ÿ 重写 Actvity 的 onCreateOptionsMenu(Menu menu)方法
Ÿ 添加菜单项
调用方法中参数 menu 的 add(CharSequence title) 方法
Ÿ 添加子菜单
调用 menu 对象的 addSubMenu( final CharSequence title)
该方法返回一个SubMenu对象
Ÿ 添加子菜单的菜单项
调用SubMenu对象的add(CharSequence title) 方法
Ø 处理菜单点击事件
Ÿ 重写 Activity 的 onOptionsItemSelected(MenuItem item) 方法
参数 item 即为被选中的菜单项
Ø 代码
public boolean onCreateOptionsMenu(Menu menu) {
menu.add( " 增加 " );
menu.add( " 修改 " );
menu.add( " 删除 " );
SubMenu subMenu = menu.addSubMenu( " 查询 " );
subMenu.add( " 按照序号查询 " );
subMenu.add( " 按照姓名查询 " );
subMenu.add( " 按照邮箱查询 " );
return super .onCreateOptionsMenu(menu);
}
public boolean onOptionsItemSelected(MenuItem item) {
Toast.makeText( this , item.getTitle(), 0).show();
return super .onOptionsItemSelected(item);
}
14.6. 内容提示文本框 ( AutoCompleteTextView)
Ø 单次提示
Ø 代码
< AutoCompleteTextView
android:id = "@+id/actv"
android:layout_width = "fill_parent"
android:layout_height = "wrap_content"
android:completionThreshold = "1" />
private void setAutoCompleteTextView() {
AutoCompleteTextView actv = (AutoCompleteTextView) findViewById(R.id. actv );
String[] items = { "tom" , "tony" , "terry" , " 张孝祥 " , " 张海军 " , " 张泽华 " };
ArrayAdapter<String> adapter = new ArrayAdapter<String>( this , android.R.layout. simple_dropdown_item_1line , items);
actv.setAdapter(adapter);
}
Ø 多次提示
Ø 代码
< MultiAutoCompleteTextView
android:id = "@+id/mactv"
android:layout_width = "fill_parent"
android:layout_height = "wrap_content"
android:completionThreshold = "1" />
private void setMultiAutoCompleteTextView() {
MultiAutoCompleteTextView mactv = (MultiAutoCompleteTextView) findViewById(R.id. mactv );
String[] items = { "tom" , "tony" , "terry" , " 张孝祥 " , " 张海军 " , " 张泽华 " };
ArrayAdapter<String> adapter = new ArrayAdapter<String>( this , android.R.layout. simple_dropdown_item_1line , items);
mactv.setAdapter(adapter);
mactv.setTokenizer( new MultiAutoCompleteTextView.CommaTokenizer());
}
14.7. 手势识别 ( GestureOverlayView)
Ø 创建手势库
Ÿ 导入 SDK 中的工程
android-sdk-windows\samples\android-8\GestureBuilder
这个工程不能直接导入,需要添加三个配置文件:.classpath、.project、default.properties
Ÿ 将工程部署到手机中,创建手势库
手势库会存储在手机 SD 卡的根目录,文件名为: gestures
Ø 代码
将gestures放入 res/raw 文件夹下
< android.gesture.GestureOverlayView
android:id = "@+id/gov"
android:layout_width = "fill_parent"
android:layout_height = "fill_parent"
android:gestureStrokeType = "multiple" />
GestureOverlayView gov = (GestureOverlayView) findViewById(R.id. gov );
final GestureLibrary library = GestureLibraries.fromRawResource( this , R.raw. gestures );
library.load();
gov.addOnGesturePerformedListener( new OnGesturePerformedListener() {
public void onGesturePerformed(GestureOverlayView overlay, Gesture gesture) {
ArrayList<Prediction> list = library.recognize(gesture);
for (Prediction p : list)
System. out .println(p. name + ": " + p. score );
}
});
14.8. 网页视图 (WebView)
Ø 代码
< WebView
android:id = "@+id/webView"
android:layout_width = "fill_parent"
android:layout_height = "fill_parent" />
WebView webView = (WebView) findViewById(R.id. webView );
webView.getSettings().setBuiltInZoomControls( true ); // 放大缩小按钮
webView.getSettings().setJavaScriptEnabled( true ); // JS 允许
webView.setWebChromeClient( new WebChromeClient()); // Chrome 内核
webView.loadUrl( "http://192.168.1.10 0 :8080" );
15. 样式与主题
15.1. 样式
Ø 定义样式
Ÿ 设置样式,在 values 文件夹下的任意文件中的 <resources>中配置 <style> 标签
< style name = " style 1" >
< item name = "android:layout_width" > fill_parent </ item >
< item name = "android:layout_height" > wrap_content </ item >
</ style >
Ÿ 继承样式,在 <style> 标签中配置属性 parent
< style name = " style2 " parent = "@style/ style 1" >
< item name = "android:textColor" > #FF0000 </ item >
</ style >
Ÿ 继承样式,在 name 中引用其他样式
< style name = " style 2. style 3" >
< item name = "android:textSize" > 30sp </ item >
</ style >
Ø 使用样式
Ÿ 在 layout 文件的标签中配置 style 属性
< Button
style = "@style/ style2.style3 "
android:text = " 这是 一个按钮 "
/>
15.2. 主题
Ÿ 定义过的样式也可以应用在 <activity> 和 <application> 标签中,使用 theme属性尽心配置
< style name = "theme" >
< item name = "android:windowNoTitle" > true </ item >
< item name = "android:windowFullscreen" > ?android:windowNoTitle </ item >
</ style >
< activity android:name = ".MainActivity"
android:label = "@string/app_name"
android:theme = "@style/theme"
>
Ÿ ? 表示引用其他属性的值
Ÿ @ 表示访问资源文件
Ÿ 如果使用 android 内置的样式, IDE 自动提示的“ _ ”要替换成“ . ”
16. 国际化与屏幕适配
16.1. 国际化
Ÿ 在 values 和 drawable 文件夹后加上语言以及地区名,程序中需要国际化的部分使用资源 ID
values-en-rUK
values-en-rUS
values-zh-rCN
values-zh-rTW
Ÿ 匹配规则
在匹配资源时先会找语言、地区完全匹配的
如果没有地区匹配的,则查找语言匹配的
如果没有语言匹配的则找默认 values
16.2. 屏幕适配
Ÿ 在 layout 文件夹后加上分辨率,系统会根据屏幕尺寸自动选择
注意分辨率中的乘号是“ x ”不是“ * ”
Ÿ 如果没有匹配的分辨率会找默认 layout 文件夹
17. 动画特效
17.1. Frame
Ÿ 通过多个画面连续播放实现动画效果
Ÿ 详见文档 android-sdk-windows/docs/guide/topics/resources/animation-resource.html
17.2. Tween
Ÿ 将某个组件以渐变的方式实现透明、缩放、移动、旋转等动画效果
Ÿ 详见文档 android-sdk-windows/docs/guide/topics/resources/animation-resource.html
17.3. 使用动画切换 Activity
Ÿ 在 startActivity() 方法调用之后调用 overridePendingTransition( int enterAnim, int exitAnim)方法
enterAnim 进入的动画资源 id
exitAnim 退出的动画 资源 id
17.4. 使用动画翻页
Ÿ XML 配置
< ViewFlipper
android:id = "@+id/viewFlipper"
android:layout_width = "fill_parent"
android:layout_height = "fill_parent"
>
< ImageView
android:layout_width = "wrap_content"
android:layout_height = "wrap_content"
android:src = "@drawable/bb2"
/>
< ImageView
android:layout_width = "wrap_content"
android:layout_height = "wrap_content"
android:src = "@drawable/bb3"
/>
</ ViewFlipper >
Ÿ Java 代码
public boolean onTouchEvent(MotionEvent event) {
ViewFlipper viewFlipper = (ViewFlipper) findViewById(R.id. viewFlipper );
switch (event.getAction()) {
case MotionEvent. ACTION_DOWN :
start = event.getX();
break ;
case MotionEvent. ACTION_UP :
float end = event.getX();
if (end > start ) {
viewFlipper .setInAnimation( this , R.anim. previous_enter );
viewFlipper .setOutAnimation( this , R.anim. previous_exit );
viewFlipper .showPrevious();
} else if (end < start ) {
viewFlipper .setInAnimation( this , R.anim. next_enter );
viewFlipper .setOutAnimation( this , R.anim. next_exit );
viewFlipper .showNext();
}
break ;
}
return super .onTouchEvent(event);
}
18. 其他
18.1. 传感器
Ø 传感器参数
Ÿ 传感器类型
方向 Sensor. TYPE_ORIENTATION
加速 Sensor. TYPE_ACCELEROMETER
光线 Sensor. TYPE_LIGHT
磁场 Sensor. TYPE_MAGNETIC_FIELD
距离 Sensor. TYPE_PROXIMITY
温度 Sensor. TYPE_TEMPERATURE
Ÿ 传感器反应速度
SensorManager. SENSOR_DELAY_FASTEST
SensorManager. SENSOR_DELAY_GAME
SensorManager. SENSOR_DELAY_UI
SensorManager. SENSOR_DELAY_NORMAL
Ø 使用方向传感器
Ÿ 获得传感器管理器
SensorManager manager = (SensorManager) getSystemService( SENSOR_SERVICE );
Ÿ 获得方向传感器
Sensor sensor = manager.getDefaultSensor(Sensor. TYPE_ORIENTATION );
Ÿ 注册监听器
manager .registerListener( listener , sensor , SensorManager. SENSOR_DELAY_NORMAL );
Ÿ 监听器
private final class MySensorEventListener implements SensorEventListener {
public void onSensorChanged(SensorEvent event) {
System. out .println(event. values [0]);
}
public void onAccuracyChanged(Sensor sensor, int accuracy) {
}
}
Ÿ 取消监听器
manager .unregisterListener( listener , sensor );
18.2. 触摸事件
Ø 拖拽
Ÿ XML 配置
< ImageView
android:id = "@+id/image"
android:layout_width = "wrap_content"
android:layout_height = "wrap_content"
android:scaleType = "matrix"
android:src = "@drawable/image" />
Ÿ Java代码
ImageView imageView = (ImageView) findViewById(R.id. image );
imageView.setOnTouchListener( new MyOnTouchListener());
private class MyOnTouchListener implements OnTouchListener {
private float x ;
private float y ;
private Matrix currentMatrix = new Matrix(); // 用来操作图片的矩阵
private Matrix oldMatrix = new Matrix();
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent. ACTION_DOWN : // 按下时
x = event.getX(); // 获取 x 轴坐标
y = event.getY(); // 获取 y 轴坐标
oldMatrix .set( imageView .getImageMatrix()); // 记住位置
break ;
case MotionEvent. ACTION_MOVE : // 移动时
currentMatrix .set( oldMatrix ); // 设置成按下时记住的位置
currentMatrix .postTranslate(event.getX() - x , event.getY() - y ); // 改变位置
break ;
}
imageView .setImageMatrix( currentMatrix ); // 移动图片
return true ;
}
}
Ø 多点触摸
private class MyOnTouchListener implements OnTouchListener {
private float x ; // 图片移动前的 x 轴坐标
private float y ; // 图片移动前的 y 轴坐标
private Matrix currentMatrix = new Matrix(); // 用来移动图片的矩阵
private Matrix oldMatrix = new Matrix(); // 图片移动前的矩阵
private int type ; // 操作类型 , 一根手指触摸还是两根手指触摸
private float start ; // 第二根手指按下时的距离
private float end ; // 两根手指移动后的距离
private PointF point ; // 放大时的中心点
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction() & MotionEvent. ACTION_MASK ) {
case MotionEvent. ACTION_DOWN :
type = 1;
x = event.getX();
y = event.getY();
oldMatrix .set( imageView .getImageMatrix());
break ;
case MotionEvent. ACTION_MOVE :
currentMatrix .set( oldMatrix );
if ( type == 1) { // 1 根手指触摸
currentMatrix .postTranslate(event.getX() - x , event.getY() - y );
} else { // 2 跟手指触摸
end = countDistance(event); // 计算结束时距离
float scale = end / start ; // 计算缩放比例
currentMatrix .postScale(scale, scale, point . x , point . y ); // 设置缩放
}
break ;
case MotionEvent. ACTION_POINTER_DOWN :
type = 2;
start = countDistance(event); // 计算开始时距离
point = countPoint(event); // 计算中心点
oldMatrix .set( imageView .getImageMatrix());
break ;
}
imageView .setImageMatrix( currentMatrix ); // 改变图片
return true ;
}
}
public float countDistance(MotionEvent event) {
float a = event.getX(1) - event.getX(0); // x 轴距离
float b = event.getY(1) - event.getY(0); // y 轴距离
return ( float ) Math.sqrt(a * a + b * b); // 勾股定理
}
public PointF countPoint(MotionEvent event) {
float x = (event.getX(0) + event.getX(1)) / 2; // x 轴中间点
float y = (event.getY(0) + event.getY(1)) / 2; // y 轴中间点
return new PointF(x, y);
}
18.3. 读取 SIM 卡
Ø 电话号码、运营商信息
Ÿ 需要权限
< uses-permission android:name = "android.permission.READ_PHONE_STATE" />
< uses-permission android:name = "android.permission.ACCESS_COARSE_LOCATION" />
Ÿ Java 代码
TelephonyManager manager = (TelephonyManager) getContext().getSystemService(Context. TELEPHONY_SERVICE );
System. out .println( " 电话号码 : " + manager.getLine1Number());
System. out .println( " 运营商编号 : " + manager.getNetworkOperator());
System. out .println( " 运营商名字 : " + manager.getNetworkOperatorName());
Ø 联系人
Ÿ 需要权限
< uses-permission android:name = "android.permission.READ_ CONTACTS " />
< uses-permission android:name = "android.permission. WRITE _ CONTACTS " />
Ÿ Java 代码
Uri uri = Uri.parse( "content://icc/adn" );
Cursor c = getContentResolver().query(uri, null , null , null , null );
while (c.moveToNext())
System. out .println(c.getString(c.getColumnIndex( "name" )) + ": " + c.getString(c.getColumnIndex( "number" )));
Ø 通话记录
Ÿ 需要权限
< uses-permission android:name = "android.permission.READ_ CONTACTS " />
< uses-permission android:name = "android.permission. WRITE _ CONTACTS " />
Ÿ Java 代码
Uri uri = CallLog.Calls. CONTENT_URI ;
Cursor c = getContentResolver().query(uri, null , null , null , null );
while (c.moveToNext())
System. out .println(c.getString(c.getColumnIndex( "number" )) + ": " + c.getString(c.getColumnIndex( "type" )));
Ÿ 源代码
ContactsProvider\src\com\android\providers\contacts\ CallLogProvider.java
18.4. 安装程序
Ÿ 需要权限
< uses-permission android:name = "android.permission. INSTALL_PACKAGES " />
Ÿ Java 代码
File file = new File(Environment.getExternalStorageDirectory(), " test .apk" );
Intent intent = new Intent();
intent.setAction(Intent. ACTION_VIEW );
intent.setDataAndType(Uri.fromFile(file), "application/vnd.android.package-archive" );
startActivity(intent);
18.5. 关闭程序
Ÿ 杀死当前进程
Process.killProcess(Process.myPid());
Ÿ 退出虚拟机
System.exit(0);
Ÿ 根据包名关闭后台进程
ActivityManager manager = (ActivityManager) getSystemService( ACTIVITY_SERVICE );
manager.restartPackage( "cn.itcast.test" );
< uses-permission android:name = "android.permission.RESTART_PACKAGES" />
18.6. 使用 HTML 构建界面
Ÿ HTML
<! DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd" >
< html >
< head >
< meta http-equiv = "Content-Type" content = "text/html; charset=UTF-8" >
< title > Insert title here </ title >
< script type = "text/javascript" >
function show(jsondata) {
var jsonobjs = eval(jsondata);
var table = document.getElementById( "personTable" );
for ( var y = 0; y < jsonobjs.length; y++) {
var tr = table.insertRow(table.rows.length);
var td1 = tr.insertCell(0);
var td2 = tr.insertCell(1);
td2.align = "center" ;
var td3 = tr.insertCell(2);
td3.align = "center" ;
td1.innerHTML = jsonobjs[y].name;
td2.innerHTML = jsonobjs[y].amount;
td3.innerHTML = "<a href='javascript:contact.call(\"" + jsonobjs[y].phone + "\")'>" + jsonobjs[y].phone + "</a>" ;
}
}
</ script >
</ head >
< body onload = "javascript:contact.show C ontacts()" >
< table border = "0" width = "100%" id = "personTable" cellspacing = "0" >
< tr >
< td width = "30%" > 姓名 </ td >
< td width = "30%" align = "center" > 存款 </ td >
< td align = "center" > 电话 </ td >
</ tr >
</ table >
</ body >
</ html >
Ÿ XML 代码
< WebView
android:id = "@+id/webView"
android:layout_width = "fill_parent"
android:layout_height = "fill_parent" />
Ÿ Java 代码
public class MainActivity extends Activity {
private WebView webView ;
public void onCreate(Bundle savedInstanceState) {
super .onCreate(savedInstanceState);
setContentView(R.layout. main );
webView = (WebView) findViewById(R.id. webView );
webView .getSettings().setJavaScriptEnabled( true );
webView .loadUrl( "file:///android_asset/index.html" );
webView .addJavascriptInterface( new Contact(), "contact" );
}
private final class Contact {
public void showContacts() {
String json = "[{\"name\":\"zxx\", \"amount\":\"99999\", \"phone\":\"18600012345\"}]";
webView .loadUrl( "javascript:show('" + json + "')" );
}
public void call(String phone) {
startActivity( new Intent(Intent. ACTION_CALL , Uri.parse( "tel:" + phone)));
}
}
}
18.7. apk 文件反编译
Ÿ 使用解压缩工具打开 apk 文件,找到其中 dex 文件
Ÿ 创建 Java 工程,导入 dex2jar中的所有 jar 文件
Ÿ 创建运行环境运行其中pxb.android.dex2jar.v3.Main 类, 指定 dex 文件地址,会在同目录下生成 jar 文件
Ÿ 使用jd-gui打开 jar 文件获取源码
Android基础总结的更多相关文章
- Android基础测试题(四)
看了前两道题大家有没有发现,测试题少了(一),大家猜猜测试题(一)是什么? Android基础测试题(四): 需求: 建一个方法,格式化输出2016-11-14 10:15:26格式的当前时间,然后截 ...
- Android基础测试题(二)
今天给大家带来的是Android基础测试题(二) 题目要求: 定义一个5位长度的整型数组并初始化,然后构建方法根据用户传入的数字判断是否存在数组中,如果存在,返回所在位置,如果不存在,返回-1 首先第 ...
- Mono.Android 基础
Mono.Android 基础 (地址) Mono.Android项目结构是 — Project + Assets + Resources + drawable + layout + values R ...
- 深入理解gradle编译-Android基础篇
深入理解gradle编译-Android基础篇 导读 Gradle基于Groovy的特定领域语言(DSL)编写的一种自动化建构工具,Groovy作为一种高级语言由Java代码实现,本文将对Gradle ...
- android基础---->JSON数据的解析
上篇博客,我们谈到了XML两种常用的解析技术,详细可以参见我的博客(android基础---->XMl数据的解析).网络传输另外一种数据格式JSON就是我们今天要讲的,它是比XML体积更小的数据 ...
- 基础4 Android基础
基础4 Android基础 1. Activity与Fragment的生命周期. Activity生命周期 打开应用 onCreate()->onStart()->onResume 按BA ...
- Android基础总结(8)——服务
服务(Service)是Android中实现程序后台运行的解决方案,它非常适合用于去执行哪些不需要和用户交互而且还要长期运行的任务.服务的运行不依赖任何用户界面,即使当程序被切换到后台,或者用户打开了 ...
- 【Xamarin开发 Android 系列 4】 Android 基础知识
原文:[Xamarin开发 Android 系列 4] Android 基础知识 什么是Android? Android一词的本义指“机器人”,同时也是Google于2007年11月5日宣布的基于Li ...
- Android基础_web通信3
在Android基础_web通信2中,我运用的JSONObject是Android原生的json类,通过import org.json.JSONObject来导入. 还有另外一种更简单的方法,就是用G ...
- Android 基础:常用布局 介绍 & 使用(附 属性查询)
Android 基础:常用布局 介绍 & 使用(附 属性查询) 前言 在 Android开发中,绘制UI时常需各种布局 今天,我将全面介绍Android开发中最常用的五大布局 含 Andr ...
随机推荐
- AD组策略添加本地账号、设置允许ping回显
AD组策略添加本地账号 1. 管理工具--组策略管理--选择相应GPO(编辑)----首选项--控制面板设置--本地用户和组--右键添加账号 2.域成员计算机刷新组策略(gpupdate/force) ...
- 30-Razor语法基础
以往开发ASP.NET Web Form时,在ASPX页面上都会出现许多夹杂C#/VB.NET与HTML的情况,而先前使用<%...%>这种传统圆角括号的表示法会让HTML标签与ASP.N ...
- 118. 119. Pascal's Triangle -- 杨辉三角形
118. Given numRows, generate the first numRows of Pascal's triangle. For example, given numRows = 5, ...
- Java 集合系列 08 Map架构
java 集合系列目录: Java 集合系列 01 总体框架 Java 集合系列 02 Collection架构 Java 集合系列 03 ArrayList详细介绍(源码解析)和使用示例 Java ...
- WebDataTree 使用XML做数据源绑定数据
英文版原文链接:http://www.infragistics.com/help/topic/e5f07b51-ee2d-4a33-aaac-2f43cffff327 所使用的控件版本为:Infrag ...
- 转载python2进制打包相关
Python模块——struct(字节流,组包拆包实现) http://www.linuxidc.com/Linux/2014-02/97158.htm [日期:2014-02-24] 来源:Linu ...
- MVP Community Camp 社区大课堂
MVP Community Camp 社区大课堂 微软技术社区大课堂开课啦!!!#MVPComCamp# 全中国微软最有价值专家MVP 在 3月21日周五全天齐聚北京国际会议中心为您呈 ...
- css样式书写的问题
经常遇到前端的朋友问及css样式书写的问题,结合自己实际的工作,自己总结了整理了一下,给大家分享: 一.顺序问题:显示属性-位置属性-元素自身属性-文本属性-其他属性 1.显示属性:z-index.d ...
- 对于服务器的识别的条件,header之类的使用
根据上一节的内容的衔接 一:urllib.request的使用 headers的一些属性 User-Agent : 有些服务器或 Proxy 会通过该值来判断是否是浏览器发出的请求Content-Ty ...
- js循环
$('.xcarcoin_tb').each(function(i){ var aika='爱卡币'; if(data[i]==0){ }e ...