Android基础知识精简版(转)
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android基础知识精简版(转)相关的知识,希望对你有一定的参考价值。
1. 前言
裁剪了下转载内容,只保留我认为有用的知识点。2. 搭建开发环境
http://tools.android-studio.org/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. 演示案例
41. 查看程序错误信息
? Android 程序中如果出错,错误不会显示在 Console 中,而是显示在 LogCat 界面下。可以从 window – show view 中打开
? 日志信息分为 5 个级别: verbose > debug > info > warn > error 高级的包含低级的
? 可以创建过滤器对日志进行过滤显示,点击绿色加号,可以按照 tag 、 pid 、 level 进行筛选
4.2. 布局
? 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.3. 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 环境
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文件可以解决。
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" , "[email protected]" ));
adapter.add( new User(2, "yzk" , "[email protected]" ));
adapter.add( new User(3, "hsp" , "[email protected]" ));
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 文件
以上是关于Android基础知识精简版(转)的主要内容,如果未能解决你的问题,请参考以下文章
(android筑基系列)之LinearLayout适配问题(android:layout_weight属性)
(android筑基系列)之LinearLayout适配问题(android:layout_weight属性)
(android筑基系列)之LinearLayout适配问题(android:layout_weight属性)