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/

Ÿ 源码

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

 

 

转载于:https://www.cnblogs.com/xxr2015/p/7462579.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值