Android基础知识精简版(转)

原文  http://blog.csdn.net/heimady/article/details/10363995

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/

? 源码

https://github.com/android

注意:

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
文件

时间: 2024-10-18 14:42:51

Android基础知识精简版(转)的相关文章

Android基础知识(6)—数据持久化之数据存储

阅读前,请浏览此处上方目录. Android基础知识(6)-数据持久化之数据存储 本章内容为个人笔记,参考书籍有:<疯狂的android>第3版.<第一行代码> 首先,我们要知道什么是数据持久化. 数据持久化就是指那些内存中的瞬时数据保存到存储设备中,保证即使手机在关机的情况下,这些数据不会丢失.保存在内存中的数据是处于瞬时状态,保存在存储设备中的数据是处于持久状态.持久化技术则是提供了一种机制可以让数据在瞬时状态和持久状态之间进行转换. Android系统主要提供了三种方式用于简

android基础知识13:AndroidManifest.xml文件解析

1.重要性 AndroidManifest.xml是Android应用程序中最重要的文件之一.它是Android程序的全局配置文件,是每个 android程序中必须的文件.它位于我们开发的应用程序的根目录下,描述了package中的全局数据,包括package中暴露的组件 (activities, services, 等等),以及他们各自的实现类,各种能被处理的数据和启动位置等重要信息. 因此,该文件提供了Android系统所需要的关于该应用程序的必要信息,即在该应用程序的任何代码运行之前系统所

android基础知识

1. 前言 1.1. 什么是3G.4G Ÿ 第三代移动通信技术(3rd - Generation),速率一般在几百Kbps,较之前的2G和2.5G在数据传输速度上有很大提升. Ÿ 第四代移动通信技术(4th - Generation),速度可达到100Mbps以上,几乎可以满足人们的所有传输数据的需求. Ÿ 目前主流的3G技术标准有三种: WCDMA:全球80%以上的3G网络都是采用此种制式.中国联通运营.186 CDMA2000:目前日韩及北美使用较多.中国电信运营. 189 TD-SCDMA

Android基础知识【项目实训】【1】

[该项目实训是Android基础知识的一个综合练习] [项目题目]:校园订餐App设计 综合案例 [设计目标] 1.必要功能 ?快餐店浏览,与订餐 ?今天订餐活动查询与订餐,特价饭菜预定 ?分类订餐查询,预定 ?常定饭菜  预定 ?健康餐推荐 ?定时预定,提前预定 ?订单查看, ?餐馆与饭菜打分,评价 ?用户注册与登录 2.扩展选择功能 ?快速拨打电话 ?饮食跟踪,热量估算 ?系统设置 [项目说明] 该项目为实际应用项目的单机 简化版本,只需要完成Android平台App的设计与开发工作. Ap

Android基础知识【项目实训】【2】

[该项目实训是Android基础知识的一个综合练习,特别提示:项目中会用到一些图片素材,都是随意整理的,稍后会上传一个资源,包含该事项项目的基本功能,也含有图片素材] [项目题目]:校园订餐App设计 综合案例 [目标] 因为项目只涉及基础知识,因此项目中所用数据并不联网,都读取单机数据库.(即将该项目中所用数据,如菜品信息.店铺信息等存入数据库)用户在第一次打开该项目时,会在用户手机上创建这些数据库,并插入测试数据. 1.先制作一个欢迎界面,欢迎的同时,准备数据库 欢迎界面Activity对应

Android基础知识【项目实训】【3】

[该项目实训是Android基础知识的一个综合练习,特别提示:项目中会用到一些图片素材,都是随意整理的,稍后会上传一个资源,包含该事项项目的基本功能,也含有图片素材] [项目题目]:校园订餐App设计 综合案例 [目标] 欢迎界面过后,应该显示app的主界面了,根据[UI设计指导]中的规划,主界面采用上下两级标签导航.这部分是app开发中比较麻烦的一块. 1.先来看一下,最终的效果吧,这样做起来比较有底: 默认显示的主界面,下部是主导航,上面是二级导航,默认打开的是"促销打折"这一版面

Android基础知识【项目实训】【4】

[该项目实训是Android基础知识的一个综合练习,特别提示:项目中会用到一些图片素材,都是随意整理的,稍后会上传一个资源,包含该事项项目的基本功能,也含有图片素材] [项目题目]:校园订餐App设计 综合案例 [目标] 主界面的功能确实比较复杂,因此上一篇知识说的周边内容.现在开始说这个界面的代码和布局文件. 1.先看一下项目的组织结构吧,要不然不好说他们的关系: (1)db包中的都是跟 数据库相关的 (2)eatall中放的都是activity或者fragment (3)entity中放的实

Android基础知识【项目实训】【5】

[该项目实训是Android基础知识的一个综合练习,特别提示:项目中会用到一些图片素材,都是随意整理的,稍后会上传一个资源,包含该事项项目的基本功能,也含有图片素材] [项目题目]:校园订餐App设计 综合案例 [目标] 主界面中包含两个二级子界面,分别是活动界面和账单界面,下面介绍它们的实现代码和布局文件. 1.下面这个是 活动界面的Activity代码,因为这个界面加载时需要 读取数据库中数据了,所有功能的实现上会涉及到 db那个包中一些类. 注意这个Activity也是继承 Activit

看看android基础知识,谁帮我作答

不管怎么着,了解一点android的基本知识还是有必要的,就当开阔一些自己的眼界吧.... android的四大功能组件是_activity_,_service_,_BroadcastReceive广播接收器_,_Content Provider_. android的系统架构是android,_java_虚拟机和_linux_操作系统. 在Activity的___distoryed______状态和__stop_情况下,系统可能会回收Activity. ActivityA中的某个Button的o