1. 前言

1.1. 什么是3G、4G

Ÿ 第三代移动通信技术(3rd - Generation),速率一般在几百Kbps,较之前的2G和2.5G在数据传输速度上有很大提升。

Ÿ 第四代移动通信技术(4th - Generation),速度可达到100Mbps以上,几乎可以满足人们的所有传输数据的需求。

Ÿ 目前主流的3G技术标准有三种:

TD-SCDMA:中国自主知识产权的3G通信技术。中国移动运营。 188

Ÿ 目前主流的4G技术为LTE,但还没有被广泛应用:

GSM à GPRS à EDGE à WCDMA à HSDPA à HSDPA+ à LTE

1.2. 什么是Android

Ÿ Android本义指“机器人”,Google于2007年11月5日宣布的基于Linux平台的开源手机操作系统的名称,官方中文名:安卓 。

Ÿ Android系统早期由原名为"Android"的公司开发,谷歌在2005年收购"Android.Inc"后,继续对Android系统开发运营。

Ÿ 底层Linux内核只提供基本功能,其他的应用软件则由各公司自行开发,大部分程序以Java语言编写。

Ÿ 由于Android系统的开源特性,很多制造商都在生产Android系统的设备,如:摩托罗拉、HTC、三星、索爱、LG、小米、华为、魅族等。

Ÿ Android系统除了运行在智能手机上之外,还可以用做平板电脑、电视、汽车等很多设备上。

Ÿ Android系统架构图:

1.3. Android的版本升级

Ÿ 1.5 Cupcake(纸杯蛋糕)

拍摄/播放影片,并支持上传到Youtube

支持立体声蓝牙耳机,同时改善自动配对性能

最新的采用WebKit技术的浏览器,支持复制/贴上和页面中搜索

GPS性能大大提高

提供屏幕虚拟键盘

主屏幕增加音乐播放器和相框widgets

应用程序自动随着手机旋转

短信、Gmail、日暦,浏览器的用户接口大幅改进,如Gmail可以批量删除邮件

相机启动速度加快,拍摄图片可以直接上传到Picasa

来电照片显示

Ÿ 1.6 Donut(甜甜圈)

重新设计的Android Market

手势支持

支持CDMA网络

文字转语音系统(Text-to-Speech)

快速搜索框

全新的拍照接口

查看应用程序耗电

支持虚拟私人网络(VPN)

支持更多的屏幕分辨率。

支持OpenCore2媒体引擎

新增面向视觉或听觉困难人群的易用性插件

Ÿ 2.1 Éclair(闪电泡芙)

优化硬件速度

"Car Home"程序

支持更多的屏幕分辨率

改良的用户界面

新的浏览器的用户接口和支持HTML5

新的联系人名单

更好的白色/黑色背景比率

改进Google Maps 3.1.2

支持Microsoft Exchange

支持内置相机闪光灯

支持数码变焦

改进的虚拟键盘

支持蓝牙2.1

支持动态桌面的设计

Ÿ 2.2 Froyo(冻酸奶)

支持将软件安装至扩展内存

集成Adobe Flash 10.1支持

加强软件即时编译的速度

新增软件启动"快速"至电话和浏览器

USB分享器和WiFi热点功能

支持在浏览器上传档案

更新Market中的批量和自动更新

增加对Microsoft Exchange的支持(安全政策, auto-discovery, GAL look-up)

集成ChromeV8 JavaScript引擎到浏览器

加强快速搜索小工具

更多软件能透过Market更新,类似2.0/2.1中的Map更新

速度和性能优化

Ÿ 2.3 Gingerbread(姜饼)

修补UI

支持更大的屏幕尺寸和分辨率(WXGA及更高)

系统级复制粘贴

重新设计的多点触摸屏幕键盘

本地支持多个镜头(用于视频通话等)和更多传感器(陀螺仪、气压计等)

电话簿集成Internet Call功能

支持近场通信NFC

强化电源、应用程序管理功能

新增下载管理员

优化游戏开发支持

多媒体音效强化

YAFFS转换到ext4文件系统

开放了屏幕截图功能

对黑色及白色的还原更加真实

Ÿ 3.x Honeycomb(蜂巢)

仅供平板电脑使用

Google eBooks上提供数百万本书

支持平板电脑大萤幕、高分辨率

新版Gmail

Google Talk视讯功能

3D加速处理

网页版Market(Web store)详细分类显示,依个人Android分别设定安装应用程序

新的短消息通知功能

专为平板电脑设计的用户界面(重新设计的通知列与系统列)

加强多任务处理的接口

重新设计适用大屏幕的键盘及复制粘贴功能

多个标签的浏览器以及私密浏览模式

快速切换各种功能的相机

增强的图库与快速滚动的联络人接口

更有效率的Email接口

支持多核心处理器

3.2优化7吋平板显示

Ÿ 4.0 Ice Cream Sandwich(奶油三明治)

虚拟按键,增大屏幕面积同时控制手机整体大小

桌面插件Widgets列表呈现在标签页中,与程序列表类似并且共存

文件夹更容易创建和管理,与iOS类似

可定制的桌面系统

可视语音邮件

日历支持缩放操作

Gmail离线搜索,两行预览,以及底部新快捷栏

音量下键+电源键组合截图

改进虚拟键盘纠错

从锁屏界面直接访问应用程序

优化复制粘贴

新版浏览器

新的Roboto字体

流量控制系统

相机应用

人脸识别,刷脸解锁

内置照片编辑器

多任务列表

新的图库布局和组织方式

联系人应用整合社交网络信息

Android Beam

http://digi.tech.qq.com/a/20111019/001579.htm

1.4. 主流智能手机操作系统

2. 搭建开发环境

2.1. 所需资源

Ÿ JDK,Java开发环境。下载地址:http://www.oracle.com

Ÿ Eclipse,IBM公司开发的一款开源IDE。http://www.eclipse.org

Ÿ Android SDK,Android 开发工具,包含开发Android程序所需类库、源码、文档、案例等资源。http://www.android.com

Ÿ ADT插件,ADT 是 Eclipse 平台下用来开发 Android 应用程序的插件。http://www.android.com

2.2. Eclipse安装ADT插件

2.3. 配置SDK路径

2.4. 启动虚拟机

Ø 点击机器人图标

Ø 弹出虚拟机管理器

Ø 修改虚拟机默认目录

指定环境变量android_sdk_home,通常指定为SDK所在目录,可以随意指定。

重启Eclipse之后将会以这个目录作为存放虚拟机文件的位置。

Ø 配置虚拟机

Ÿ Name:虚拟机的名字,可随意定义

Ÿ Target:虚拟机版本

Ÿ SD Card - Size:虚拟机的SDCard大小,会在本地硬盘创建指定大小的文件用来存储数据,模拟真实手机的SDCard

如果使用原有文件,可以选择File并点击Browse指定文件

Ÿ Snapshot: 保存快照,可以提高虚拟机启动速度

Ÿ Skin - Built-in:选择分辨率

HVGA:480x320

QVGA:320x240

WQVGA400:400x240

WQVGA432:432x240

WVGA800:800x480

WVGA854:854x480

也可以选择Resolution自行指定

Ø 成功进入Android操作系统界面

Ÿ 如果虚拟机显示无信号,需要对电脑的网络连接进行配置

无论电脑是否联网,IP地址、子网掩码、默认网关、首选DNS服务器都需要配置

Ÿ 电脑如果未连接局域网或互联网,可以见默认网关和首选DNS服务器配置成本机IP,例如:

Ÿ 电脑如果已连接局域网,需要将网关和首选DNS服务器进行设置,例如:

Ÿ 如果电脑已连接互联网,正常情况虚拟机不会显示无信号,重启虚拟机

2.5. 命令行操作

为了能在任意目录使用一下命令,需要将SDK目录下的platform-tools文件夹路径和tools文件夹路径配置到path环境变量中

Ÿ 列出可以使用的android版本

android list targets

Ÿ 列出可以使用的虚拟机

android list avd

Ÿ 创建虚拟机

android create avd –n <虚拟机名> -t <Target版本ID> -c <SD卡大小> -s <屏幕尺寸>

Ÿ 启动虚拟机

emulator –avd <虚拟机名>

Ÿ 显示已连接的设备

adb devices

Ÿ 导入文件到手机

adb push <Windows源文件路径> <手机目标路径>

Ÿ 从手机导出文件

adb pull <手机源文件路径> <Windows目录路径>

Ÿ 安装程序

adb install <apk文件路径>

Ÿ 卸载程序

adb uninstall <包名>

Ÿ 重启adb

adb kill-server

abd start-server

3. 开发一个Android程序

3.1. 创建Android程序

Ø 创建Android Project

Ÿ Project name:项目名

Ÿ Build Target:Android版本

Ÿ Application name:程序名,显示在程序列表中,以及程序启动后的标题栏

Ÿ Package name:包名,程序的唯一标识

Ÿ Create Activity:选择程序启动时是否创建一个窗体,设置主窗体名字

Ÿ Min SDK Version:设置运行该程序所需的最低版本

3.2. 安装、卸载程序

Ÿ Eclipse安装

右键点击工程 – Run as – Android Application

Ÿ 虚拟机卸载

设置 – 应用程序 – 管理应用程序 – 选中要卸载的程序 – 卸载

3.3. 了解项目目录结构

Ÿ src:源代码

Ÿ gen:系统自动生成的文件

R.java 中记录了项目中各种资源ID

Ÿ res:系统资源,所有文件都会在R文件生成资源ID

drawable:图片

layout:界面布局

values:数据

anim:定义动画的XML

raw:原生文件

Ÿ assets:资源路径,不会在R文件注册

Ÿ project.properties:供Eclipse使用,读取该项目使用Android版本号。早期版本名为:default.properties

Ÿ AndroidManifest.xml:清单文件,在软件安装的时候被读取

Android中的四大组件(Activity、ContentProvider、BroadcastReceiver、Service)都需要在该文件中注册

程序所需的权限也需要在此文件中声明,例如:电话、短信、互联网、访问SD卡

Ÿ bin:二进制文件,包括class、资源文件、dex、apk等

Ÿ proguard.cfg:用来混淆代码的配置文件,防止别人反编译

3.4. 程序启动过程

Ÿ Eclipse将.java源文件编译成.class

Ÿ 使用dx工具将所有.class文件转换为.dex文件

Ÿ 再将.dex文件和所有资源打包成.apk文件

Ÿ 将.apk文件安装到虚拟机完成程序安装

Ÿ 启动程序 – 开启进程 – 开启主线程

Ÿ 创建Activity对象 – 执行OnCreate()方法

Ÿ 按照main.xml文件初始化界面

4. 演示案例

4.1. 电话拨号

Ÿ 搭建界面需要组件:TextView、EditText、Button

Ÿ 当点击Button时获取EditText中文本

Ÿ 使用Intent向系统内置的电话拨号器发送意图拨打电话

Ÿ 注册拨打电话权限

4.2. 查看程序错误信息

Ÿ Android程序中如果出错,错误不会显示在Console中,而是显示在LogCat界面下。可以从window – show view中打开

Ÿ 日志信息分为5个级别:verbose > debug > info > warn > error 高级的包含低级的

Ÿ 可以创建过滤器对日志进行过滤显示,点击绿色加号,可以按照tag、pid、level进行筛选

4.3. 将程序安装到真实手机

Ÿ 在电脑上安装手机驱动

有些手机自带驱动,有些没有,可以从官网下载。或者可以使用“豌豆荚”软件自动安装。

Ÿ 在手机设置中打开USB调试,将手机用USB数据线连接到电脑

我的手机是:三星 i9100

双核1228MHz、1GB RAM 、4GB ROM、480×800像素、Android 2.3、4.3英寸

Ÿ 检查Eclipse的设备管理器中是否显示出新设备

如果未能显示出设备,检查驱动安装是否正常,USB调试是否打开

Ÿ Eclipse安装程序

Eclipse上右键点击工程 – Run as – Android Application – 自动安装运行

Ÿ 手动打包安装

右键点击工程 – Export – Export Android Application – 选择或创建密钥对程序签名并打包生成apk文件

将apk文件放到手机的SD卡中,通过手机文件浏览器执行安装

4.4. 短信发送

Ÿ 搭建界面需要组件:TextView、EditText、Button

Ÿ 给Button添加监听器,当被点击的时候获取号码,获取内容

Ÿ 使用SmsManager发送短信

Ÿ 需要注册短信发送权限

4.5. 布局

Ø RelativeLayout(相对布局)

Ÿ android-sdk-windows/docs/guide/topics/ui/layout-objects.html#relativelayout

Ø TableLayout(表格布局)

android-sdk-windows/docs/guide/topics/ui/layout-objects.html#tablelayout

Ø FrameLayout(帧布局)

android-sdk-windows/docs/guide/topics/ui/layout-objects.html#framelayout

setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);

setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);

4.6. Junit

Ø 项目中添加测试类

Ÿ 在AndroidManifest.xml清单文件中添加配置

<instrumentation android:targetPackage="cn.itcast.junit" android:name="android.test.InstrumentationTestRunner" />

<uses-library android:name="android.test.runner" />

Ÿ 定义一个类继承AndroidTestCase,定义测试方法

Ÿ 在Outline视图下右键点击测试方法 – Run as – Android Junit Test

Ø 创建测试项目

Ÿ 创建Android Test Project

Ÿ 输入项目名,选择一个已存在的工程,Eclipse可以自动配置Junit环境

4.7. 日志信息

Ÿ 在LogCat视图中我们可以看到程序的日志信息,也可以在程序中输出信息到LogCat中

Ÿ 程序中我们可以使用Log类来输出信息

Ÿ System.out和System.err输出的信息也会显示在LogCat中,注意System.out输出信息是Info级别,System.err是Warn级别

5. 文件操作(File、XML、SharedPreferences)

5.1. 读写文件

Ø 写入文件到SD卡

Ÿ 需要在清单文件中注册权限

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

Ÿ 2.1版本以下的SDCard位置和2.2之后版本不同

可以通过Environment.getExternalStorageDirectory()获取当前SDCard位置,兼容所有版本

Ÿ 获取SDCard状态

通过Environment.getExternalStorageState()方法获取SDCard当前状态

常量 Environment.MEDIA_MOUNTED 为已安装

Ø 写入文件

Ÿ 通过Context.openFileOutput(String name, int mode)可以获取一个文件输入流

name为文件名,mode为文件模式,有4种模式

输出流指向路径为:/data/data/包名/files/

Ÿ 文件模式在Context中有定义常量

MODE_PRIVATE 私有

MODE_WORLD_READABLE 其他程序可读(不可写)

MODE_WORLD_WRITEABLE 其他程序可写(不可读)

模式可以组合使用,例如:MODE_WORLD_READABLE + MODE_WORLD_WRITEABLE

MODE_APPEND 追加

Ø 读取文件

Ÿ 通过Context.openFileInput(String name)可以获取一个文件输入流

该输入流可以读取 /data/data/包名/files/ 路径下的文件

Ÿ 获取当前程序Files文件路径

ContextWrapper.getFilesDir()

5.2. XML

Ø Pull简介

Ÿ 常见的XML解析方式有三种,DOM、SAX、Pull,Android系统中推荐使用Pull

Ÿ Pull解析器是一个开源的Java项目,Android系统内部解析XML文件均为此种方式,也可用于JavaEE项目

Ÿ Android SDK中已经集成了Pull解析器,无需添加任何jar文件

Ÿ Pull解析器运行方式与SAX类似,提供各种事件的判断

Ÿ 官方网站:http://xmlpull.org/

Ø 使用Pull解析器解析XML文件

Ÿ Xml.newPullParser() 获得解析器

Ÿ parser.setInput(in, "UTF-8") 设置输入流以及编码

Ÿ parser.next() 获取下一个解析事件,得到一个事件代码

Ÿ XmlPullParser中定义了常量来标识各种解析事件

START_DOCUMENT、END_DOCUMENT 、START_TAG 、END_TAG 、TEXT

Ø 使用XmlSerializer写出XML

Ÿ 使用以下方法生成XML,和XML文档顺序类似

startDocument

startTag

attribute

text

endTag

endDocument

5.3. 偏好设定(SharedPreferences)

Ÿ 在程序中保存一些配置参数的时候我们经常使用SharedPreferences

Context.getSharedPreferences(String name,int mode)

该方法可以在/data/data/<package>/shared_pref/目录下创建一个以name命名的xml文件,mode文件为模式

Ÿ 存储偏好

调用edit()方法可以获取一个Editor对象,对数据进行存储,存储之后需要调用commit()保存到文件

Ÿ 读取偏好

获得SharedPreferences之后调用getString()、getInt()等方法获取其中设置的值

Ÿ 在Activity中获取SharedPreferences

在Activity中可以调用getPreferences(int mode)方法获得一个SharedPreferences,文件名和Activity名一致

6. 数据库(SQLite)

6.1. SQLite特点

Ÿ Android平台中嵌入了一个关系型数据库SQLite,和其他数据库不同的是SQLite存储数据时不区分类型

例如一个字段声明为Integer类型,我们也可以将一个字符串存入,一个字段声明为布尔型,我们也可以存入浮点数。

除非是主键被定义为Integer,这时只能存储64位整数

Ÿ 创建数据库的表时可以不指定数据类型,例如:

CREATE TABLE person(id INTEGER PRIMARY KEY AUTOINCREMENT, name VARCHAR(20))

CREATE TABLE person(id INTEGER PRIMARY KEY AUTOINCREMENT, name)

Ÿ SQLite支持大部分标准SQL语句,增删改查语句都是通用的,分页查询语句和MySQL相同

SELECT * FROM person LIMIT 20 OFFSET 10

SELECT * FROM person LIMIT 10,20

6.2. 创建数据库

Ÿ 定义类继承SQLiteOpenHelper

Ÿ 声明构造函数,4个参数

Ÿ 重写onCreate()方法

Ÿ 重写upGrade()方法

Ÿ 注意:SQLite数据库中列一旦创建不能修改,如果一定要修改,需要重新创建表,拷贝数据

6.3. CRUD操作

Ÿ 和JDBC访问数据库不同,操作SQLite数据库无需加载驱动,不用获取连接,直接可以使用

获取SQLiteDatabase对象之后通过该对象直接可以执行SQL语句

SQLiteDatabase.execSQL()

SQLiteDatabase.rawQuery()

Ÿ getReadableDatabase()和getWritableDatabase()的区别

查看源代码后我们发现getReadableDatabase()在通常情况下返回的就是getWritableDatabase()拿到的数据库

只有在抛出异常的时候才会以只读方式打开

Ÿ 数据库对象缓存

getWritableDatabase()方法最后会使用一个成员变量记住这个数据库对象,下次打开时判断是否重用

Ÿ SQLiteDatabase封装了insert()、delete()、update()、query()四个方法也可以对数据库进行操作

这些方法封装了部分SQL语句,通过参数进行拼接

6.4. 事务管理

Ÿ 在使用SQLite数据库时可以用SQLiteDatabase类中定义的相关方法控制事务

beginTransaction() 开启事务

setTransactionSuccessful() 设置事务成功标记

endTransaction() 结束事务

Ÿ endTransaction()需要放在finally中执行,否则事务只有到超时的时候才自动结束,会降低数据库并发效率

7. 内容提供者(ContentProvider)

7.1. 什么是内容提供者

Ÿ 内容提供者是Android中的四大组件之一,可以将应用中的数据对外进行共享

Ÿ 内容提供者将数据的访问方式统一,不必针对不同数据类型采取不同的访问策略

Ÿ 内容提供者将数据封装,只暴露出我们希望提供给其他程序的数据

Ÿ 内容提供者中数据更改可被监听

7.2. 创建内容提供者

Ÿ 定义类继承ContentProvider,根据需要重写内部方法

Ÿ 在清单文件的<application>节点下进行配置,<provider>标签中需要指定name和authorities属性

name为类名,包名从程序Package开始,以“.”开始

authorities:是访问Provider时的路径,要唯一

Ÿ URI代表要操作的数据,由scheme、authorites、path三部分组成

content://cn.itcast.sqlite.provider/person

scheme:固定为content,代表访问内容提供者

authorites:<provider>节点中的authorites属性

path:程序定义的路径,可根据业务逻辑定义

7.3. 完成CRUD方法

Ÿ 当程序调用CRUD方法时会传入Uri

Ÿ 我们通过Uri判断调用者要操作的数据

可以使用工具类UriMatcher来判断Uri

addURI方法可以添加Uri

match方法可以匹配一个Uri判断其类型

Ÿ 根据业务逻辑操作数据

7.4. 访问内容提供者

Ÿ 通过Context获得ContentResolver对象

Ÿ 调用ContentResolver对象的方法即可访问内容提供者

7.5. 完成getType方法

Ÿ 如果返回数据是单条数据:vnd.android.cursor.item

Ÿ 如果返回数据是多条数据:vnd.android.cursor.dir

7.6. 监听内容提供者数据变化

Ÿ 在内容提供者中可以通知其他程序数据发生变化

通过Context的getContentResolver()方法获取ContentResolver

调用其notifyChange()方法发送数据修改通知

Ÿ 在其他程序中可以通过ContentObserver监听数据变化

通过Context的getContentResolver()方法获取ContentResolver

调用其registerContentObserver()方法指定对某个Uri注册ContentObserver

自定义ContentObserver,重写onChange()方法获取数据

7.7. GIT获取源代码

Ø 资源地址

Ÿ Git

http://code.google.com/p/msysgit/

Ÿ 源码

https://github.com/android

注意:

GIT1.7.7安装后不能卸载,可以用其他版本覆盖后再卸载。

使用GIT时不要使用中文目录,否则GIT GUI会报错无法启动。删除C盘中.gitconfig文件可以解决。

7.8. 监听短信

Ÿ Android系统提供了Provider对短信进行查询,当发出短信时也会发送更改通知

Ÿ 短信数据库在 com.android.providers.telephony

Ÿ 定义一个Observer监听"content://sms"

Ÿ 在onChange()方法中查询"content://sms"

Ÿ 需要权限android.permission.READ_SMS

7.9. 操作联系人

Ø 获取所有联系人

Ÿ Android系统中的联系人也是通过ContentProvider来对外提供数据的

Ÿ 数据库路径为:/data/data/com.android.providers.contacts/database/contacts2.db

Ÿ 我们需要关注的有3张表

raw_contacts:其中保存了联系人id

data:和raw_contacts是多对一的关系,保存了联系人的各项数据

mimetypes:为数据类型

Ÿ Provider的authorites为com.android.contacts

Ÿ 查询raw_contacts表的路径为:contacts

Ÿ 查询data表的路径为:contacts/#/data

这个路径为连接查询,直接查询“mimetype”字段就可以根据“mimetype_id”查询到mimetypes表中的数据

Ÿ 先查询raw_contacts得到每个联系人的id,在使用id从data表中查询对应数据,根据mimetype分类数据

Ø 通过电话号码获取联系人

Ÿ 系统内部提供了根据电话号码获取data表数据的功能,路径为:data/phones/filter/*

Ÿ 用电话号码替换“*”部分就可以查到所需数据,获取“display_name”可以获取到联系人显示名

Ø 添加联系人

Ÿ 先向raw_contacts表插入id,路径为:raw_contacts

Ÿ 得到id之后再向data表插入数据,路径为:data

Ø 使用事务添加联系人

Ÿ 在添加联系人得时候是分多次访问Provider,如果在过程中出现异常,会出现数据不完整的情况,这些操作应该放在一次事务中

Ÿ 使用ContentResolver的applyBatch(String authority,ArrayList<ContentProviderOperation> operations) 方法可以将多个操作在一个事务中执行

Ÿ 文档位置:

file:///F:/Itcast/lib/android-sdk-windows/docs/reference/android/provider/ContactsContract.RawContacts.html

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类改为继承接口中的Stub

Ÿ ServiceConnection中返回的IBinder是代理对象,不能使用强转,改用Stub.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="onRradioClick"

android:text="确定" />

</RadioGroup>

public void onRradioClick(View view) {

RadioGroup lessonRG = (RadioGroup) findViewById(R.id.lessonsRG);

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(:8080");

15. 样式与主题

15.1. 样式

Ø 定义样式

Ÿ 设置样式,在values文件夹下的任意文件中的<resources>中配置<style>标签

<style name="style1">

<item name="android:layout_width">fill_parent</item>

<item name="android:layout_height">wrap_content</item>

</style>

Ÿ 继承样式,在<style>标签中配置属性parent

<style name="style2" parent="@style/style1">

<item name="android:textColor">#FF0000</item>

</style>

Ÿ 继承样式,在name中引用其他样式

<style name="style2.style3">

<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.showContacts()">

<table border="0" width="100%" id="personTable" cellspacing="0">

<tr>

<td width="30%">姓名</td>

<td width="30%" align="center">存款</td>

<td align="center">电话</td>

</tr>

</table>

</body>

</html>

Ÿ XML代码

<WebView

android:id="@+id/webView"

android:layout_width="fill_parent"

android:layout_height="fill_parent" />

Ÿ Java代码

public class MainActivity extends Activity {

private WebView webView;

public void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.main);

webView = (WebView) findViewById(R.id.webView);

webView.getSettings().setJavaScriptEnabled(true);

webView.loadUrl("file:///android_asset/index.html");

webView.addJavascriptInterface(new Contact(), "contact");

}

private final class Contact {

public void showContacts() {

String json = "[{\"name\":\"zxx\", \"amount\":\"99999\", \"phone\":\"18600012345\"}]";

webView.loadUrl("javascript:show('" + json + "')");

}

public void call(String phone) {

startActivity(new Intent(Intent.ACTION_CALL, Uri.parse("tel:" + phone)));

}

}

}

18.7. apk文件反编译

Ÿ 使用解压缩工具打开apk文件,找到其中dex文件

Ÿ 创建Java工程,导入dex2jar中的所有jar文件

Ÿ 创建运行环境运行其中pxb.android.dex2jar.v3.Main 类, 指定dex文件地址,会在同目录下生成jar文件

Ÿ 使用jd-gui打开jar文件获取源码

Android基础总结(精华完整版)的更多相关文章

  1. Android studio gradle配置完整版(转)

    Android studio gradle配置完整版https://my.oschina.net/u/1471093/blog/539075 Android studio 自定义打包apk名 - pe ...

  2. python基础篇(完整版)

    目录 计算机基础之编程和计算机组成 什么是编程语言 什么是编程 为什么要编程 编程语言的分类 机器语言(低级语言) 汇编语言 高级语言 计算机的五大组成 CPU(相当于人类的大脑) 多核CPU(多个大 ...

  3. android应用版本更新功能---完整版

    源码下载地址:csdn下载地址:http://download.csdn.net/download/csdn576038874/9526085 博客园下载地址:http://files.cnblogs ...

  4. 转 Android Activity之间动画完整版详解

    标签:Android Activity动画详解 原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 .作者信息和本声明.否则将追究法律责任.http://mzh3344258.blog.5 ...

  5. Android学习之基础知识十三 — 四大组件之服务详解第二讲(完整版的下载示例)

    上一讲学习了很多关于服务的使用技巧,但是当在真正的项目里需要用到服务的时候,可能还会有一些棘手的问题让你不知所措.接下来就来综合运用一下,尝试实现一下在服务中经常会使用到的功能——下载. 在这一讲我们 ...

  6. Android版的菜谱客户端应用源码完整版

    Android版的菜谱客户端应用源码完整版,这个文章是从安卓教程网转载过来的,不是本人的原创,希望能够帮到大家的学习吧. <ignore_js_op> 152936qc7jdnv6vo0c ...

  7. 老王Python培训视频教程(价值500元)【基础进阶项目篇 – 完整版】

    老王Python培训视频教程(价值500元)[基础进阶项目篇 – 完整版] 教学大纲python基础篇1-25课时1.虚拟机安装ubuntu开发环境,第一个程序:hello python! (配置开发 ...

  8. 爱拼图游戏android源码完整版

    这个是一款爱拼图游戏源码完整版,该游戏源码比较完整的,可以支持音乐的播放在游戏的玩的过程中,还可以控制系统的声音等,可以支持多种图片的选择来进行玩的,还可以根据自己的爱好选择不同的难度来的,级别分为: ...

  9. android应用商店完整版源码

    这个是从一个安卓学习的网站上转载过来的,android应用商店完整版源码,大家可以看看一下吧. _op><ignore_js_op> <ignore_js_op>< ...

随机推荐

  1. 遇见Lambda

    转自:http://www.cnblogs.com/allenlooplee/archive/2012/07/03/2574119.html 在学习generate时候发现C++中的匿名函数,上面博文 ...

  2. Centos6.4安装JDK

    链接地址:http://www.iteye.com/topic/1130311 1.先看看OpenJDK的安装包 $ rpm -qa |grep javatzdata-java-2013b-1.el6 ...

  3. 如何使用SublimeText风格的代码高亮样式 添加Zed Coding(EMMET)插件

    因为觉得博客园自带的代码高亮样式很单一,不符合作为前端的我的审美习惯,于是下定决心要想办法折腾出一个方法来应用上另外一套代码高亮样式. 虽然探索的过程是很痛苦的,但最后还是成功了,但也不枉付出的那些努 ...

  4. [LeetCode]题解(python):012-Integer to Roman

    题目来源: https://leetcode.com/problems/integer-to-roman/ 题意分析: 这道题是要把在区间[1-3999]的数字转化成罗马数字. 题目思路: 只要知道了 ...

  5. Kettle之数据抽取、转换、装载

    Kettle 官网 ETL利器Kettle实战应用解析系列 利用kettle组件导入excel文件到数据库 kettle中实现动态SQL查询 java中调用kettle转换文件

  6. Android 6.0 新特性 整理 资料来自网络

    Android 6.0新特性 Runtime Permissions Doze and App Standby Apache HTTP Client Removal BoringSSL Access ...

  7. c++ 复制构造函数和赋值函数

    c++ 自动提供了下面这些成员函数 1默认构造函数 2.复制构造函数 3.赋值操作符 4.默认析构函数 5.地址操作符 赋值构造函数copy construtor 用于将一个对象复制到新创建的对象中, ...

  8. Poj 1002 487-3279(二叉搜索树)

    题目链接:http://poj.org/problem?id=1002 思路分析:先对输入字符进行处理,转换为标准形式:插入标准形式的电话号码到查找树中,若有相同号码计数器增加1,再中序遍历查找树. ...

  9. Eddy's爱好(dfs+容斥)

    Eddy's爱好 Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total S ...

  10. 倒计时IE10+

    直接上代码,dome 里边有我做的列表倒计时(多个同时倒计时)下面是我做的例子,颜色可以自己设置的 <p name="daojishi" style="width: ...