1.1 系统概述
1.1.1 3G
Ø 什么是3G
英文全称3rd-generation,第三代移动通信技术。是指将无线通信与国际互联网等多媒体通信结合的新一代移动通信系统。
* 3G制式:
(欧洲版) WCDMA\HSDPA 中国联通采用
(北美版) CDMA 2000\EV-DO 中国电信采用
(中国版)TD-SCDMA\TD-HSDPA:中国移动采用
* 3G的发展:
1G:只能进行语音通话、模拟信号
2G:包括(GSM\GPRS\EDGE)增加了接收数据的功能,如接收电子邮件或网页
3G:02年国外已经产生,03年开发出中国的3G,09才上市。在传输声音和数据的速度上有很大提升
4G.:是第四代移动通信及其技术的简称,是集高速无线网络与有线网络WLAN于一体的通讯网络能够传输高质量视频、图像和数据,传输速率可高达200MPS以上,目前主流技术有 FDD-LTE、TDD-LTE、WIMAX
* 移动通信上网速度变化
GSM(9K)-->GPRS(42K)-->EDGE(147K)-->WCDMA(2M)-->HSDPA(7.2M)-->FDD-LTE长期演进(200M)
Ø 移动互联网
IT界三大热点:云计算、物联网、移动互联网
& 云计算
云计算是一种通过Internet以服务的方式提供动态可伸缩的虚拟化的资源的计算模式 ,这种模式提供可用的、便捷的、按需的网络访问, 进入可配置的计算资源共享池(资源包括网络,服务器,存储,应用软件,服务),这些资源能够被快速提供,只需投入很少的管理工作,或与服务供应商进行很少的交互。
& 物联网
物联网就是物物相连的互联网。Internet of Things(IOT),也称为Web of Things
物联网的定义是通过射频识别(RFID)、红外感应器、全球定位系统、激光扫描器等信息传感设备,按约定的协议,把任何物品与互联网相连接,进行信息交换和通信,以实现对物品的智能化识别、定位、跟踪、监控和管理的一种网络
& 移动互联网
移动互联网就是将移动通信和互联网二者结合起来,成为一体。也是发展最快、市场潜力最大、前景最诱人的业务,比如:移动社交、移动广告、手机游戏、手机电视、移动商务、移动支付、位置服务、移动电子阅读等
* 移动智能操作系统
目前的智能操作系统有Android 4.4、IOS7、Windows Phone 8、Symbian、RIM BlackBerry、J2ME等,市场占有率高的有Android平台、IOS平台和Windows Phone平台,形成三足鼎立的局面
1.1.2 Android历史与发展
Ø Android发展历程
* Android发展大事件
2005年Google收购 Android Inc. 开始研究Dalvik VM 虚拟机
2007年 开发手机联盟成立,SDK1.0预览版发布
2008年底 第一款Android手机G1诞生 ,Android 通过Apache License开源
* Android版本进化历程
1.X 版本:入门级别,只适用于手机
2.X 版本: 趋于成熟的版本,只适用于手机
3.X 版本:趋于成熟的版本,只适用于平板
4.X 版本:趋于成熟的版本,对平板和手机进行了整合
5.X 版本: 支持64位cpu、默认采用ART运行模式等
Android 1.5 Cupcake(纸杯蛋糕、API Level 3)
Android 1.6 Donut(甜甜圈API Level 4)
Android 2.0/2.0.1/2.1 Eclair(松饼API Level 5、6、7)
Android 2.2/2.2.1 Froyo(冻酸奶API Level 8、9)
Android 2.3 Gingerbread(姜饼API Level 10)
Android 3.0/3.1/3.2 Honeycomb(蜂巢 API Level 11、12、13)
Android 4.0/4.0.3 Ice Cream Sandwich(冰激凌三明治API Level 14、15)
Android 4.1/4.2/4.3 Jelly Bean(果冻豆 API Level 16、17、18)
Android 4.4 KitKat (奇巧巧克力API Level 19)
Android 5.0 代号L (API Level 20)
Ø Android应用场景
手机、平板、智能电视(机顶盒)、穿戴设备(眼镜、手表)、其它智能嵌入设备
1.1.3 Android体系结构
Ø Android体系结构
1. Linux内核层
Android是基于Linux内核的操作系统,在Linux内核层,主要实现安全管理、进程管理、内存管理、电源管理、硬件驱动管理
2. 硬件抽象层
硬件抽象层是对Linux 硬件驱动程序的封装,向上提供接口,屏蔽低层的实现细节。硬件抽象层不开源,可保护硬件厂商的商业秘密,但是会影响系统的性能。
Android对硬件的支持分成了两层,一层放在用户空间(User Space),一层放在内核空间(Kernel Space),硬件抽象层运行在 用户空间, Linux 内核驱动程序运行在内核空间,内核驱动层只提供简单的访问 硬件逻辑,具体的实现细节,都放在硬件抽象层中 ,从而维护了硬件厂商的商业利益。
3. 原生库与Android运行时
Android的原生库主要基于C\C++实现的一些原生组件,包括C库Bionic、浏览器引擎Webkit、多媒体引擎OpenCORE、SQL数据库SQLite、3D渲染引擎OpenGL ES、位图和字体矢量渲染引擎FreeType、2D图像渲染引擎SGL(Skia Graphics Library)、互联网安全协议SSL等。
Android运行时主要包括Java核心库、Dalvik虚拟机,两者一起构成了Android的应用环境基础
4. 应用框架层
应用框架层是Google发布的核心应用所使用的API框架,开发人员可以使用这些框架提供的API来快速开发自己的应用程序,它本身也是用Java语言实现和开发的。
Activity Manager(活动管理)、Window Manager(窗口管理)、View Manager(视图管理)、Notification Manager(通知管理)、Content Provider(内容提供者)、Package Manager(包管理)、Resource Manager(资源管理)、Location Manager(位置管理)
5. 应用层
应用层是基于Android平台开发的应用,采用Java作为开发语言,包括系统自带的应用(短信管理、联系人管理、图库浏览、网页浏览等)和第三方开发的应用
Ø JVM与DVM
* 共同点:
解释执行 byte code字节码文件
在操作系统的进程运行一个VM,并执行一个单独的程序
* 不同点:
程序结构不同:JVM字节码由多个.class文件组成,Davlik 只包含一个 .dex 格式的文件,这个文件包含了程序中所有的类。
架构不同:Dalvik是 register-based基于寄存器,Sun JDK 是 stack-based基于栈。
* Dalvik优势
编译时提前优化代码而不是等到运行时 。
虚拟机很小,占空间小。可以满足可高效运行多种虚拟机实例。
常量池修改为只使用32位的索引,以简化解释器。
* DVM执行过程
1. 编译为class文件
2. 使用dx工具抽取class文件共性形成.dex
3. 维护内部常量池
* ART运行模式
ART模式是Android runtime的简称,在Android4.4版本后出现,通过在安装应用程序时,自动对程序进行代码预读取编译,让程序直接编译成机器语言,并且把它保存起来,免去了Dalvik模式要时时转换代码,实现高效率、省电、手机运行流畅。ART是虚拟机,只是在安装app时,提前编译而已。
1.2 搭建开发环境
1.2.1 开发环境搭建
* 开发工具
JDK、Eclipse、ADT(Android developer tools)插件、Android SDK
* 工具下载
ADT下载地址:http://dl.google.com/android/ADT-22.0.0.zip
SDK下载地址:http://dl.google.com/android/android-sdk_r22-windows.zip
合集版下载地址: developer.android.com
合集版工具包包含:
Eclipse + ADT plugin
Android SDK Tools
Android Platform-tools
The latest Android platform
The latest Android system image for the emulator
* Android-SDK更新
通过Android Manager.exe 工具更新
Android SDK目录介绍
1.2.2 创建AVD模拟器
* 创建模拟器
* 小细节
& AVD配置文件位置(默认):
C:\Documents andSettings\Administrator\.android\avd\AVD2.3.3.avd\config.ini
& AVD 缩放 :启动模拟器—>在launch Option中选择 Scale display to real size
& 模拟器不能保存数据:在模拟器的配置文件中删除.lock文件
1.2.3 手机参数
* 手机屏幕参数:屏幕尺寸、分辨率、屏幕密度
&手机尺寸:5.5 、5.0、4.7、4.3、4.0、3.5英寸
&分辨率: 1080*1920 、640*1136、720*1280、1280*800、1024*600、480*854、480*800
&屏幕密度:120dpi(ldpi) 低清、160dpi(mdip)中清(标清) 、240dpi(hdpi)、360dpi(xhdpi)
* 手机内存、SDCard、CPU、摄像头
* 手机操作系统版本
* 网络制式(GSM\EDGE\WCDMA\HSDPA\TD-SCDMA\WCAMA-2000\TDD-LTE\FDD-LTE)
1.3 第一个Android应用程序
1.3.1 创建应用程序流程
* 创建新项目
* 配置项目
* 配置运行图标属性
1.3.2 Android应用介绍及项目目录结构分析
* Android应用结构介绍
Android 应用程序由应用组件(Activity、Service、ContentProvider、BroadcastReceiver)构成,每一个组件是单独的模块,有着不同的入点,系统可以从这些入点进入到你的应用中,组件在AndroidManifest.xml注册,它们之间松耦合地组织在一起,从而定义你应用的整体功能。
*项目目录结构分析
1.3.3 Android运行过程分析
Ø 项目打包签名
Ø 安装APK
运用adb工具把apk包上传到模拟器(真机)中,目录在data\app\
读取androidManifest.xml清单文件(包名、权限、图标等)
创建文件夹,在data\data\目录下创建以包名为文件夹的目录
写入注册表, 注册表文件data\system\packages.xml
Ø 启动APK
Android系统是一个多用户的Linux系统,应用一旦安装,系统为每个应用分配一个独立的Linux用户ID,当用户点击应用程序图标或者导航到该应用的组件时,Android框架会创建一个虚拟机实例,开启一个进程,创建一个主线程(UI线程),再实例化入口组件,进入组件的生命周期
1.3.4 常用的命令操作
adb shell :进入linux客户端shell命令模式
adb install apk文件 :安装apk文件
adb uninstall 包名 :删除模拟器应用
adb devices :列出所有设备
adb push <local> <remote> 把本地的文件复制到远端
adb pull <remote> <local> 从远端复制文件到本地
mksdcard 大小 <local> 创建sdcard镜像文件
android create avd –name <模拟器名> -target <level> 创建模拟器
emulator –avd avd名 启动模拟器
adb –s <设备名> <命令> 对于有多个设备终端
1.3.5 案例: 应用体验之电话拨号器
实现一个打电话的小程序
* 界面设计
* 代码实现
* 在AndroidManifest.xml中添加打电话权限
<uses-permission android:name="android.permission.CALL_PHONE"/>
1.3.6 DDMS透视图
DDMS(Dalvik Debug Monitor Service) DVM调试监视服务
& Devices : 查看模拟器设备的状态,模拟器运行的进程
& File Explorer: 文件浏览器(导入、导出文件、创建文件夹、删除文件等)
& LogCat: 日志查看工具,日志猫
& Emulator Control: 模拟器控制,模拟一些操作(打电话、发短信)
1.3.7 Android参考文档
Ø 参考文档
官网:developer.android.com或本地(%ANDROID_SDK_HOME%\DOC\)
中文参考文档:wiki.eoe.cn
Ø SDK源码关联
源码:(%ANDROID_SDK_HOME%\source),或通过SDK Manager.exe 从官网下
& 在Eclipse中选中任一系统API,按F3或者CTRL+单击 ,之后找到Java Source Addachment ,指定源码位置即可
& 选择项目中的android.jar包,右键点击属性,之后找到Java Source Addachment ,指定源码位置即可
二、UI控件与布局
2.1 Activity、View、Window关系
* android.app.Activity
Activity是Android四大组件之一,它通过内部的成员变量Window对象来展
示一个与用户交互的界面,界面中的View控件捕获事件,通过WindowManagerService传递消息,Android框架再回调Activity中与捕获事件相关联的方法,从而实现与用户的交互。Activity扮演的是一个控制器的角色
* android.view.View
& View:视图,是用户接口组件的基本构建块,它在屏幕中占用一个矩形区域,它是所有UI控件的基类,如一个按钮或文本框。View负责图形界面渲染及事件处理
& Android已经为我们提供了一系列的标准UI控件供我们直接使用,同时,我们也可以通过继承于View或View的子类,来实现我们自定义的UI控件
& View及其子类的关系
& 对View常用的操作
Set properties 设置属性
Set focus 设置焦点
Set listeners 设置监听
Set visibility 设置是否可见
* Window
Window是Android中的窗口,表示顶级窗口,也就是主窗口,每一个主窗口都拥有一个View,称之为DecorView(装饰视图),它是主窗口的顶级View(DecorView必须是一个布局容器,因为它要容纳其它的View)。当Activtity调用setContentView()时,实际就是调用Window对象的setContentView()方法,执行该方法,把用户定义的View添加到DecorView中,最终完成对View的展示。
2.2 认识常用UI控件(widget)
Android平台提供了一套完备的、功能强大的组件化模型用于搭建用户界面,这套组件化模型以View和 ViewGroup这两个基础布局类为基础。平台本身已预先实现了多种用于构建界面的View子类和ViewGroup子类,他们被分别称为部件(widget)和布局(layout)。
部件(widget)包括Button、TextView、EditText、ListView、CheckBox、RadioButton、Gallery、Spinner等
2.3 布局
2.3.1 ViewGroup
ViewGroup是一个特殊的View,能够容纳其它的View(子控件),它是布局和视图容器的基类
* ViewGroup.LayoutParams 布局参数类属性:
android:layout_width 相对于父控件的宽度 (wrap_content, match_parent,fill_parent)
android:layout_height 相对于父控件高度 (wrap_content,match_parent,fill_parent)
* ViewGroup常用的方法
addView(): 向视图组添加View
removeView():从视图组移去View
getChildCount:获得视图组子控件的数量
getChildAt() : 获得具体某个子控件
* Android的显示单位
& px (pixels)像素 比如480*800像素
& dip或dp (device independent pixels)设备独立像素
dp与设备硬件有关,运行时根据屏幕密度转化为相应的px,最终由px值确定显示区域大小,推荐使用它
& sp (scaled pixels — best for text size)比例像素
主要处理字体的大小,可以根据系统的字体自适应,推荐使用
2.3.2 布局
布局用于定义一个用户接口的可视结构,比如Activity、应用小部件等。
Ø 布局的实现方式
* 通过XML声明UI元素
1. 在xml文件中设计布局
- Attributes设置 : 比如ID 、Layout Paraments设置等
- Layout Position设置 :比如控件在父控件的位置:上下左右等
- Size、padding、Margins :控件高与宽、控件内部间隙、控件之间边距设置
2. 导入布局资源
比如在Activity中:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main_layout);//设置Activity的内容视图
}
* 通过Java代码方式
LinearLayout layout=new LinearLayout(context);//创建一个线性布局对象
layout.addView(new TextView(context));//往线性布局对象中添加一个文本视图子控件
Ø 布局的类别
* cmmon layouts : 普通的布局
该布局提供了唯一的方式去显示已经嵌入在该布局中的视图控件,主要用于有固定界面的布局,包括(Linearlayout、relativeLayout、TableLayout、GridLayout、AbsolutLayout、 FrameLayout,webView等)
* building layout with a adapter: 动态构建的布局
用一个适配器来动态构建布局。当布局的内容是动态的或者前期决定不了的,通过AdapterView的子类与Adapter(适配器)一起来动态构建布局。比如:采用ListView来展示联系人列表,通话记录等
2.3.3 常见的布局
Ø LinearLayout
线性布局,它的子控件是以单一的行或者单一的列排列,子控件不能重叠,具有方向性(水平、垂直),默认是水平方向,可以设置位置和权重
* 常用的XML属性:
android:orientation 线性布局的排列方向(vertical\horizontal)
android:padding 控件内部的间隙
android:gravity 控件内部的排列位置 (center_vertical、center_horizontal等)
android:layout_gravity 位置
android:layout_margin_top 与顶部的边距
android:layout_weight 权重
* 注意点:
- 修饰控件属性时,有layout与无layout的区别
有layout,表示布局属性修饰,它相对于父控件或者父控件中的其他子控件的属性修饰,
无layout,它只针对控件本身,是对该控件内部元素的修饰
- 权重
它是线性布局或者它的子类所特有的属性修饰,它针对的是子控件的宽和高的设置
先预留出没有设置权重的控件的宽或者高,之后对相对于父控件剩余的空间(宽或者高)按权重(比例)分配
Ø FrameLayout
帧布局被设计成在一个屏幕区域显示一个单一的项(single item)。通常FrameLayout显示一个单一的子控件,它支持的布局属性不够丰富,一般通过layout_gravity来设置子控件的位置。
FrameLayout的子控件被绘制在一个堆栈中,最近添加进来的子控件在堆栈的顶部
Ø TableLayout
表格布局,是LinearLayout的子类,以行和列的形式存放子控件,它通常由多个TableRow布局控件组成,TableRow由多个单元格(cell)组成,每个cell设置为View对象 ,表格布局的子控件可以设置权重,但是不能设置方向
Ø GridLayout
网格布局,android 4.0以后出现,布局使用虚细线将布局划分为行、列和单元格,也支持控件在行、列上都有交错排列。有方向性,默认为水平方向,相对于TableLayout,渲染速度更快,更灵活。
对于低版本要使用GridLayout,需添加向下的支持库v7
xmlns:app="http://schemas.android.com/apk/res-auto"
* 常用的XML属性:
android:columnCount 设置列数
android:layout_row 控件的起始行位置
android:layout_column 控件的起始列位置
android:layout_rowSpan 控件跨越行数
layout_columnSpan 控件跨越列数
layout_gravity=“fill” 与layout_rowSpan或columnSpan结合使用,表示填满所跨越的行或者列
Ø AbsoluteLayout
绝对布局,子控件的位置以绝对的位置定位,子控件之间可以重叠,相对于其他布局,缺少灵活性,不建议使用
* 常用的XML属性:
android:layout_x : 相对于父控件的x坐标位置
android:layout_y : 相对于父控件的y坐标位置
Ø RelativeLayout
相对布局,子控件的位置关系可以通过子控件与父控件、子控件与子控件来确定,子控件之间位置可以重叠,拓展性好,灵活方便,是使用最多的布局方式
* 常用的XML属性
android:layout_toLeftOf="@+id/name" 指定控件的左边
android:layout_toRightOf="@+id/name" 指定控件的右边
android:layout_above="@+id/name" 指定控件的上边
android:layout_below="@+id/name" 指定控件的下边
android:layout_alignLeft="@+id/name" 与指定控件左对齐
android:layout_alignRight="@+id/name" 与指定控件右对齐
android:layout_alignTop="@+id/name" 与指定控件顶部对齐
android:layout_alignBottom="@+id/name" 与指定控件底部对齐
android:layout_alignParentLeft="true" 与父控件的左边对齐
android:layout_alignParentRight="true" 与父控件的右边对齐
android:layout_alignParentTop="true" 与父控件顶部对齐
android:layout_alignParentBottom="true" 与父控件底部对齐
android:layout_centerHorizontal="true" 在父控件中水平居中
android:layout_centerVertical="true" 在父控件中垂直居中
Ø 案例:简易计算器界面制作
运用GridLayout布局设计简易计算器界面
Ø 案例:短信发送器设计与实现
实现一个发短信的android小程序
(要求布局管理器为相对布局)
* 界面设计
* 代码实现
* 在AndroidManifest.xml中设置发短信的权限
android:name="android.permission.SEND_SMS"/>
三、 Android事件驱动机制
一般,用户经常会通过界面与应用交互,Android框架采用事件驱动的形式与用户交互,那如何处理用户界面中触发的事件?
可以通过从用户交互的View设置事件监听器的方式来实现对事件的处理,一个事件监听器是View类中一个包含单一回调方法的接口。当注册了监听器的View发生了对应的监听事件时,Android框架就会回调相应的监听方法。
* 常见的用户事件
点击事件、选择事件、触屏事件、长按事件、按键事件
3.1 点击事件
单击事件是事件机制中最常见的事件,通过对控件绑定View.OnClickListener 实现单击事件的监听
3.1.1 点击事件四种书写方式
& 私有类实现方式
& 匿名内部类实现方式
& 布局中对控件添加android:onClick
& Activity实现监听接口
* 案例:对按钮按键监听
对四个按钮实现监听,分别用四种不同的书写方式实现单击监听事件
* 界面设计
* 代码实现
3.2 选择事件
3.2.1 复选事件
复选事件的监听接口:CompoundButton.OnCheckedChangeListener
复选控件CheckBox 有两种状态:选中与未选中状态,对复选控件
* 案例:明密文切换
通过对CheckBox控件的复选监听,实现对EditText内容明密文切换
* 界面设计
* 代码实现
3.2.2 单选事件
单选事件的监听接口:RadioGroup.OnCheckedChangeListener
RadioButton与RadioGroup组合使用才能实现单选功能
* 案例:选择字符集
通过对RadioButton控件的选择监听,实现对字符集的选择
* 界面设计
* 代码实现
3.2.3 下拉列表选择
下拉事件的监听接口:AdapterView.OnItemSelectedListener
* 案例:城市选择
通过对Spinner下拉列表监听,实现对城市的选择
* 界面设计
* 代码实现
3.3 长按与触屏事件
长按事件监听接口:View.OnLongClickListener
触屏事件监听接口:View.OnTouchListener
* 案例:长按图标设置手机桌面壁纸
clearWallpaper :清除桌面壁纸
setWallpaper(BitMap bitmap) :设置桌面壁纸
设置壁纸要添加权限:
<uses-permission android:name="android.permission.SET_WALLPAPER"/>
* 代码实现
3.4 键盘事件
Activity实现了KeyEvent.backcall接口
onKeyDown(int keyCode, KeyEvent event) :当键按下去触发
onBackPress():当返回键按下去触发 ,Activity的方法
模拟器常见的按键:
Back 返回键
Home 手机屏幕桌面
Ctrl+F11 切换模拟器横竖屏幕
F2 手机菜单
F3 电话面板
F8 手机网络开关
四、 Android高级UI
4.1 ProgressBar
ProgressBar 进度条,常用于文件下载进度显示、系统初始化进度等,默认情况是没有进度值的(转圈圈)
* 提示点:
style="@android:style/Widget.ProgressBar.Horizontal" 样式设置
setProgress(int) 设置当前进度值
getProgress() 得到当前进度值
setMax(int) 设置最大值
案例:通过按钮设置进度条进度
* 界面设计:
* 代码实现
4.2 RatingBar
RatingBar 评分进度条,常用于对商品、用户的评价,比如满意度调查等
* 提示点:
setOnRatingBarChangeListener 设置监听器
setNumStars 设置星星的个数(设置总分)
setStepSize 设置分数间隔
getRating 获得当前的分数值
setRating 设置当前的分数值
案例:对欧冠精彩程度打分
* 界面设计:
* 代码实现
4.3 ToggleButton
ToggleButton:开关按钮,它是CompoundButton的子类,实现开与关的效果,比如蓝牙开关、wifi开关、声音开关等
* 提示点:
- 实现的监听接口:CompoundButton.OnCheckedChangeListener
该接口是监听开关按钮状态的改变
- toggle() :取反操作
- xml属性设置
textOn: 表示状态为开的提示文本
textOff: 表示状态为关的提示文本
案例:设置声音开关
* 界面设计
* 代码实现
4.4 ScrollView
ScrollView:滚屏视图,它是FrameLayout的子类,能够被用户滚动的布局容器,它只能拥有一个子控件,经常应用于一个垂直方向的线性布局中。
ScrollView只支持垂直滚动,对于需要水平滚动,则用HorizontalScollView
4.5 ListView
ListView 列表框,常用控件,用来显示相同数据结构的批量数据,比如:从数据库获取的数据列表,从网络解析的批量结构数据,一般都会采用ListView展示数据,系统中的设置、未接来电、通信录等显示可采用ListView进行展示
用ListView展示数据的四个步骤:列表项描述、初始化数据、适配器数据装配、设置适配器
案例:在ListView中显示好友列表
* 界面设计与分析:
* 代码实现
五、Android消息提示机制
在某些情况下,可能需要你去通知用户发生在你应用中的事件,其中一些事件需要用户响应,有的则不需要。Android框架通过消息机制很好的完成上述的需求。
比如:
- 当一个事件完成时(比如保存文件),需要显示一个简短的消息来确认保存成功
- 假如应用正在后台运行,且需要用户注意,那么该应用需要创建一个通知以方便用户做出响应
- 假如用户要操作一个危险的操作,则应该创建一个对话框通知,再一次确认用户的操作
常见的消息提示方式有:
- Logcat(日志猫)
- Toast(瞬时提示)
- Dialog(对话框)
-Notification(通知)
5.1 Logcat日志猫
* 级别 :v、d、i、w、e 级别由低往高
- verbose :混淆的 ,所有信息都可以输出,级别最低
- debug :调试级别
- info:信息级别
- warning:警告级别
- error :错误级别
* 添加过滤器 按照Tag进行过滤
* System.out.println()与Log输出之间的区别
- System.out.println()输出的信息 等级是info级别,标记tag:System.out
- System.out.print()输出信息 需要System.out.flush()刷缓存输出
5.2 Toast瞬时提示
Toast通知是一种浮现在屏幕上层的消息提醒,它只填充消息所需要的空间,而当前正在运行的活动仍然保持其自身的可见性和交互性。这种通知自动淡入淡出且不接受交互事件
Ø 通过代码自定义Toast
* 代码实现
Ø 通过XML自定义Toast
* LayoutInflate :把xml布局文件实例化为View对象
5.3 对话框
对话框通常是一种显示在当前活动之上的小窗口,这时候下层的活动将失去焦点,由对话框来实现与用户的交互,常用于添加简单的数据或对操作进一步确认等,比如删除联系人信息、添加类别等,但对话框不宜过多,会影响用户体验
常见的对话框有:标准对话框、单选对话框、复选对话框、自定义对话框
5.3.1 标准对话框
标准对话框是使用最多的一种对话框样式,包含对话框图标、标题、提示系统、确认和取消。
* 创建标准对话框流程:
1. 生成对话框构建器对象AlertDialog.Builder
2. 设置图标Builder.setIcon
3. 设置标题
4. 设置提示信息
5. 添加确认与取消按钮
6. 对确认与取消按钮中添加监听,实现对话框的业务逻辑
* 案例: 构建标准对话框
* 界面设计
* 代码实现
5.3.2 菜单式对话框
菜单式对话框适用于单选某个列表项或者对某项数据有几种不同的操作等应用场景
* 关注点:
& Builder.setItems(items, listener) :设置单选项
items:单选项字符串数组
listener:单选单击监听
* 运用单选对话框选择Android版本代号
* 界面设计
* 代码实现
5.3.3 复选对话框
复选对话框适用于以对话框的形式复选某个列表
* 关注点:
& Builder.setMultiChoiceItems(CharSequence[] items, boolean[] checkedItems, OnMultiChoiceClickListener listener) : 设置复选监听
items:复选项字符串数组
checkedItems:复选项默认值
listener:复选单击监听
& AlertDialog.getListView() : 得到用于对话框的列表视图—ListView
& SparseBooleanArray : 稀疏布尔数组,用于映射整数到布尔值 ,与一般的布尔数组不同,下标可以允许有间隙,它比用HashMap映射Integers到Booleans 更有效率
& ListView.getCheckedItemPositions() 得到选择项的位置信息及其状态 ,返回值:SparseBooleanArray
* 运用复选对话框选择Android版本代号
* 界面设计
* 代码实现
5.3.4 自定义对话框
系统对话框太单一,在开发中常需要自定义对话框
* 关注点:
& new Dialog(context,theme):以自定义的样式构建对话框
& Dialog.setContentView():设置对话框的布局
& Dialog.findViewById() : 通过findViewById找到对话框布局中的控件
* 自定义视图,实现通过对话框输入信息
* 界面设计
* 代码实现
5.3.5 对话框优化
Ø 对话框缓存
相同对话框每次显示的界面都是一致的,可以通过Activity的对话框缓存实现对话框实例的重复利用,达到优化对话框的目的
* 实现原理图
Ø DialogFragment
* Fragment :碎片、片段
引入fragments主要目的是用在大屏幕设备上支持更加动态和灵活的UI设计,
一个Fragment代表一个用户接口的行为或者部分行为,把几个Fragment混合到一个Activity中,可以创建一个多个页面的UI并可以在多个Activity中复用一个Fragment,碎片必须总是嵌入到一个活动(activity)中,并且它的生命周期直接受到Activity的生命周期的影响。
把fragment 想象成一个activity的模块化区域, 有它自己的生命周期, 接收属于它的输入事件, 并且可以在activity运行期间添加和删除。
* DialogFragment :对话框碎片
用于显示一个对话框窗口的Fragment,它浮于Activity窗口上面,该对话框的显示依赖于Fragment的生命状态
* 实现步骤
- 创建一个类,继承DialogFragment,重写onCreateDialog方法,在该方法中完成对话框的创建
- 在Activity中创建DialogFragment实例,并调用show()方法完成对话框的显示
可以通过DialogFragment.setArguments()\getArguments()传递和接收参数
六、单元测试
在实际开发中,开发android软件的过程需要不断地进行测试。而使用Junit 测试框架,则是正规的Android开发的必用技术,Android很好封装了Junit测试框架,可以模拟发送事件和检测程序处理的正确性
* Android单元测试实现流程
1. 添加测试类库
在AndroidManifest.xml 的<application> 节点 添加测试类库
<uses-library android:name="android.test.runner"/>
2. 设置测试环境
<instrumentation android:name="android.test.InstrumentationTestRunner" android:targetPackage="cn.itcast.filestore"/>
3. 编写测试类
- 继承AndroidTestCase
- 获取上下文getContext()
- 使用断言 assertEquals()
- 查看测试效果
七、Android移动存储
各种Android移动的主要任务是处理数据,如何将需要处理和处理好的有效的存储起来是一个亟待解决的问题,Android系统提供了非常丰富的移动存储方案。
* 常见移动存储方案:
手机内部存储
手机外部存储
SharedPreferences
SQLite
ContentProvider
网络
7.1 文件存储
7.1.1 手机内部存储
手机内部存储,默认在/data/data/<包名>/files 文件夹下存放文件
* 手机内部存储的特点:
& 存放本应用中的私有数据
& 当应用卸载时,/data/data/<包名> 这个目录会同步删除,即手机内部存储的文件
会删除
* 关注点:
& Context.openFileOutput(String name, int mode)
- 往手机内部存储中以某种模式写文件
- name :文件名
- mode :文件操作模式
- return:FileOutputStream
- 文件存放在/data/data/包名/files/
& Context.openFileInput(String name) 从手机内部存储中读取文件
- 从手机内部存储中读文件
- name:文件名
- return:FileInputStream
& getCacheDir() 方法用于获取/data/data/<package name>/cache目录
& getFilesDir() 方法用于获取/data/data/<package name>/files目录
* 文件操作模式
权限 |
说明 |
Context. MODE_PRIVATE【默认】 |
私有权限,只有本Android应用可用 |
Context. MODE_WORLD_READABLE |
全局读权限,其他Android应用只可以读取 |
Context. MODE_WORLD_WRITEABLE |
全局写权限,其他Android应用可写 |
Context. MODE_WORLD_READABLE+ Context. MODE_WORLD_WRITEABLE |
全局读写全新,其他Android应用可读可写 |
Context. MODE_APPEND |
追加模式,在些数据的时候在已有文件后追加写,默认是私有权限只有本应用可读可写 |
7.1.2 外部存储
所有兼容Android的设备都支持一个可共享的“外部存储(external storage)”,可用来保存文件。这可以是一个可移动的存储设备(比如SD卡)或者一个内部的(不可移动的)存储。保存在外部存储的文件是可全局读写的。
* Sdcard存储的特点:
& 依赖于Sdcard,使用SDCard存储,需先检测其状态
& 存在Sdcard的文件是可全局读写的
& 写入Sdcard时,需要权限
* 关注点:
& Environment.getExternalStorageState() 取得外部存储状态
& Environment.getExternalStorageDirectory() 取得外部存储根路径
& 写入外部存储的权限
android.permission.MOUNT_UNMOUNT_FILESYSTEMS
android.permission.WRITE_EXTERNAL_STORAGE
* 外存路径描述
& 取得外部存储的公共共享存储路径
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS)
& .在外存中存放应用的私有文件,当应用删除时,该内容会同步删除 :
context.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS)
目录: /android/data/<包名>/files/<类型>
&.在外存中存放应用的私有缓存文件 ,当应用删除时,该内容会同步删除
context.getExternalCacheDir()
目录:/android/data/<包名>/cache
&.取得外存的根路径
Environment.getExternalStorageDirectory()
Ø 案例 :文件存储
在Activity界面中编辑某文件,实现对该文件在手机内部存储及SDCard的存取
* 界面设计
* 代码实现(手机内部存取)
* 代码实现(SDCard存取)
7.2 SharedPreference
SharedPreferences,是一个非常轻量的数据存储方式,以xml的形式存取简单的键值对数据,数据类型包括(ints,floats,boolean,strings,longs,Set<String>(android 11以后)),存放位置:/data/data/<包名>/shared_prefs,存放的是应用私有的数据,主要用于软件偏好设置,简单信息存取等
* 获取SharedPreference对象
- Context.getSharedPreferences(String name,int mode)
name:指定XML文件名,不需要指定.xml后缀,name存在则打开,没有则创建
mode:文件的操作模式,见文件存储的文件操作模式表格
- Activity.getPreferences(int mode)
name为默认值:即当前访问的Activity的类名
* 操作SharedPreference对象
& 取得参数值
- SharedPreference.getString(key,defValue) 取得参数值,类型为字符串
- SharedPreference.getBoolean(key,defValue) 取得参数值,类型为布尔型
& 存储参数值
- Editor edit = SharedPreferences.edit(); // 获取编辑器
- edit.putString(key, value); // 存储字符串数据
- edit.putBoolean(key, value); // 存布尔数据,
- edit.commit(); // 提交新值
Ø 案例 :运用SharedPreference保存用户登录信息
要求:
1.账号密码验证成功,则进入另一个Activity
2.选中复选框,则用户登录时,把账户及密码信息存入SharedPreference
3.应用下次启动,依据存储的复选框状态值,决定是否填充账户与密码信息
4.对存入SharedPreference的值对信息加密
* 界面设计
* 代码实现
7.3 Pull解析
XML文件是非常重要的数据格式,它可以用来作配置文件,存储数据等,Android中可以通过SAX、DOM、PULL来解析 XML数据
7.3.1 pull解析XML文件
* pull解析:
Xml文件边导入内存,边解析,采用事件驱动机制,当解析到一个节点,返回的是该节点的事件类型,且不会继续往下解析,需手动指向下一个节点,才能继续往下解析,直到文档的结尾。Android默认采用pull解析。
* 事件类型:
- START_DOCUMENT : 开始文档
- START_TAG : 开始标签
- END_TAG : 结束标签
- END_DOCUMENT : 结束文档
7.3.2 pull生成XML文件
Ø 案例:用pull解析及生成XML文件
* 界面设计
* 代码实现 (pull解析)
* 代码实现 (用pull生成xml)
7.4 Sqlite数据库
在Android平台上,集成了一个嵌入式关系型数据库—SQLite,它是一种非常轻量的数据库管理系统,SQLite3支持 NULL、INTEGER、REAL(浮点数字)、TEXT(字符串文本)和BLOB(二进制对象)数据类型,SQLite通过文件来保存数据库,一个文件就是一个数据库
* 常用类介绍
& SQLiteOpenHelper
数据库辅助抽象类,通过实现它的子类可以创建数据库以及实现版本更新,通过getWriteableDatabase获得getReadableDatabase获取数据库访问类
& SQLiteDatabase:数据库访问类
通过数据库访问类,可以实现对数据库的增删改查等操作
7.4.1 Android创建Sqlite数据库
SQLite数据库是在第一次调用的时候创建数据库的
创建数据库的步骤:
1.定义一个db辅助类,继承SQLiteOpenHelper抽象类,通过构造方法设置数据库名及版本信息
2. 重写onCreate()方法,该方法只会在数据库第一次创建的时候调用,在此方法中适合做数据库初始化操作,比如创建数据表等
3. 重写onUpGrade() , 当数据库版本更新时调用,适合做表结构的修改或者添加删除表
* 参考代码:
7.4.2 SQLite数据库增删改查
* 添加记录
* 删除记录
* 查询
* 更新记录
7.4.3 SQLite事务处理
7.5 内容提供者
7.5.1 内容提供者特点介绍
& Android四大组件之一,没有图形界面
& 共享数据给第三方应用程序,统一数据访问方式
& 线性安全,Android系统为每个 ContentProvider提供一个实例(单列模式),通过ContentResolver访问ContentProvider
7.5.2 ContentProvider实现流程
1. 准备需要共享的数据,一般是sqlite数据
2. 创建一个类,继承ContentProvider,实现第三方应用访问数据的方法(增删改查)
3. 在AndroidManifest.xml 进行注册,并且设置android:autorities属性:认证(在系统中该内容提供者的唯一标识)
4. 第三方应用访问ContentProvider, 通过Context.ContentResolver(内容访问者)进行访问,比如:ContentResolver.insert(Uri,ContentValues);
7.5.3 常用API介绍
* Uri:(统一资源标识符)表示要操作的数据
由两部分组成:内容提供者的标识、具体要访问什么,也就是路径
content://cn.itcast.sqlite.provider.books/student/
* UriMatch: 用来匹配Uri的 工具类
UriMatch.addUri(Uri);//注册Uri
UriMatch.match(Uri);匹配Uri
* ContentUris: Uri内容解析
ContentUris.withAppendedId(Uri,id) : 在Uri尾部添加id
ContentUris.parseIdUuri) :解析Uri,获取Uri的id部分
Ø 案例:通过ContentProvider共享数据库
把books.db数据库的book表通过ContentProvider实现数据共享,第三方应用可以对book表实现增删改查操作
* 通过UriMatch注册Uri
* 实现查询操作接口
* 通过获得访问数据类型接口
* 实现插入操作接口
* 实现删除操作接口
* 实现更新操作接口
* 第三方访问ContentProvider
八、菜单设计
8.1 选择菜单
一个Activity最多只能拥有一个选择菜单,当选择菜单第一次访问的时候创建,该Activity销毁没有销毁的情况下,只创建一次
* 创建选择菜单
onCreateOptionsMenu(Menu menu)
* 监听选择菜单
onOptionsItemSelected(MenuItem item)
8.2 上下文菜单
一个组件可以绑定一个上下文菜单,上下文菜单每次弹出,都会重新创建一次
* 注册上下文菜单
注册上下文菜单的两种写法
//registerForContextMenu(bookList);
// bookList.setOnCreateContextMenuListener(this);
* 创建上下文菜单
& onCreateContextMenu(ContextMenu menu, View v,ContextMenuInfo menuInfo)
参数:menu:要创建的上下文菜单
v: 选择项的视图(ListView的Item)
menuInfo: 额外的菜单信息,依赖于选择的视图(V)
& 获取弹出上下文菜单的选项视图信息
//通过适配器上下文菜单信息类来获取 被选中的菜单项的数据信息
AdapterContextMenuInfo adapterInfo=(AdapterContextMenuInfo) menuInfo;
* 监听上下文菜单
onContextItemSelected(MenuItem item)
//通过适配器上下文菜单信息类来获取 被选中的菜单项的数据信息
AdapterContextMenuInfo adapterInfo=(AdapterContextMenuInfo) item.getMenuInfo();
8.3 操作条(ActionBar)
* 1.Action Bar特点
操作栏在Android 3.0版本以后出现,是一个窗口功能用于确定应用程序和用户的位置,并提供给用户操作和导航模式。Action Bar被认为是新版Android系统中重要的交互元素
* 2、Action Bar分成四个区域
- App Icon:可显示软件icon,也可用其他图标代替。当软件不在最高级页面时,图标左侧会显示一个左箭头,用户可以通过这个箭头向上导航。
- 视图切换:如果你的应用要在不同的View中显示数据,这部分允许用户来切换View。一般的作法是用一个drop-down菜单或者是Tab Controls。如果只有一个界面,那这里可以显示App Title或者更长点的商标信息
- Action Buttons:这个放最重要的软件功能,放不下的按钮就自动进入Action overflow了。
- Action overflow:把不常用的Actions移到Action overflow
* 3、Action Bar常用的交互操作
- 选择操作项
与选择菜单一致,都是使用相同的api来创建和监听操作项
- 操作导航选项标签
选项标签要与Fragment相结合,实现界面切换的效果
1. 添加标签 : ActionBar.Tab
2. 监听标签 : ActionBar.TabListener
Ø 案例:通过菜单操作内容提供者的数据
* 界面设计
* 代码实现(更新书籍信息)
* 刷新数据操作
九、 自定义适配器
9.1 为什么要自定义适配器
想操作列表项的界面和数据
* 列表视图、初始数据、列表项布局关系图
9.2 如何自定义适配器
9.3 自定义适配器优化
1. 当某个item进入视野范围内时,就会调用adapter的getView方法,重新渲染item。之前我们在每次渲染item的时候都重新实例化item的布局文件,创建一个View,这样会产生很多的对象,性能不佳
2. 我们尝试使用下面这种循环利用的方案
1> 假设我们的屏幕刚好只能放下3个item
2> 当从状态1—>状态2,有4个item同时出现在屏幕中,因此这4个ItemView都是不同的对象
3> 当从状态2—>状态3,item-0消失在视野中
4> 当从状态3—>状态4,我们可以考虑把之前的item-0移动到item-4的位置,因为item-0跟item-4不会同时出现在我们视野范围中
5> 当从状态4—>状态3,我们可以考虑把之前的item-4移动到item-0的位置
3. 再来看public View getView(int position, View convertView, ViewGroup parent)中的convertView参数,这个是系统帮我们传递进来的,它就代表当前可循环利用的ItemView
4. 注意:虽然性能有提升,但是在渲染item的时候,一定保证当前item要完全覆盖可循环利用item的数据,因为循环利用item可能会造成旧数据残留。
十、Intent意图
Intent负责对应用中一次操作的动作、动作涉及数据、附加数据进行描述,Android则根据此Intent的描述,负责找到对应的组件,将 Intent传递给调用的组件,并完成组件的调用。因此,Intent在这里起着一个媒体中介的作用,专门提供组件互相调用的相关信息,实现调用者与被调用者之间的解耦。
10.1 Intent表现形式
* 调用Activity : startActivity(intent) startActivityForResult(Intent)
* 调用Service:服务 startService(intent) \bindService(intent)绑定服务
* 发送广播 :sendBroadcast(intent)发送无序广播
sendOrderedBroadcast(Intent)发送有序广播
10.2 Intnet 属性设置
* setAction: 设置动作
ACTION_MAIN 、ACTION_VIEW、ACTION_GET_CONTENT、ACTION_EDIT
* setData: 设置数据 :Uri格式的数据,标准数据
* setType:设置数据的类型 :MIME (image/*,video/* ,text/plain)
* addCateGory: 添加你要调用的组件的类别
CATEGORY_LAUNCHER CATEGORY_HOME
CATEGORY_BROWSABLE CATEGORY_DEFAULT
* 案例:在本应用中实现网站的浏览
10.3 显式意图与隐式意图
* 显示调用是直接指定类名,Android不用再去解析intent
* 隐式调用需要设置action、data、category、type,再有Android解析你的意图
对于本应用中的组件要实现隐式调用,需要在AndroidManifest.xml中配置<intent-filter>
* 案例:显示调用第三方应用Activity组件
10.4 Intent附带数据
* 两种写法 :
& 通过Intent.putExtra(key,value)添加
& 通过bundle添加
* 添加额外数据
* 在目标组件中获取上一个组件传递过来的额外数据
十一、Activity活动
11.1 Activity特点介绍
活动,四大组件之一,也是最重要的组件,它通过内置的Window对象来展示一个与用户交互的界面,它的操作都与用户有关,一般一个布局针对于一个Activity界面
View控件捕获事件信息,WindowManagerService传递消息,再由Android框架回调Activity的相应监听方法实现与用户的交互
11.2 开始Activity以及得到返回结果
* startActivity(Intent) :开启一个新的Activity,它将放到活动栈的栈顶
* startActivityForResult(Intent,int) :开启一个新的Activity,当新的Activity结束时,通过setResult(int,Intent)把结果回传给调用者,调用者通过onActivityResult()处理回传结果
* 案例:设置图像视图控件的前景图片
点击图像视图控件,进入图片浏览界面,把选定好的图片作为图像视图控件的前景图片
* 参考代码
11.3 Activity生命周期
应用中的活动是由活动栈进行管理的,当一个新的Activity启动后,它会处于栈顶的位置,与用户进行交互,处于运行的状态;先前的Activity会移到它的下方,处于暂停或者停止状态
* Activity生命周期
- 完全生命周期
自第一次调用onCreate()开始,直至调用onDestroy()为止。Activity在onCreate()中设置所有“全局”状态以完成初始化,而在onDestroy()中释放所有系统资源。
- 可见生命周期
自onStart()调用开始直到相应的onStop()调用结束。在此期间,用户可以在屏幕上看到Activity,尽管它也许并不是位于前台或者也不与用户进行交互。在这两个方法之间,我们可以保留用来向用户显示这个Activity所需的资源。
- 可交互的生命周期
自onResume()调用起,至相应的onPause()调用为止。在此期间,Activity位于前台最上面并与用户进行交互。Activity会经常在暂停和恢复之间进行状态转换。
*Activity生命周期状态
Activity有四个生命周期状态,状态之间改变需要回调相应的生命周期方法来完成
- 运行状态
- 暂停状态
- 停止状态
- 销毁状态
* 生命周期方法
- onCreate(): 创建方法
- onStart(): 开始方法
- onResume(): 获得焦点方法
- onPause() :暂停方法
- onStop() :停止方法
- onRestart() :重新启动方法
- onDestroy() :销毁方法
* 应用场景:
- onCreate(): 创建Activity时调用,一般在这里做初始化的操作,比如控件的初始化,绑定数据到列表中等
- onDestroy():销毁,在这里释放资源 MediaPlayer.release(), 关闭数据库连接
- onStart() 开始方法 :一般注册广播监听 ,绑定服务 onStop()注销监听 ,取消服务绑定
- onpause() 与onResume() ,这两个方法会经常调用,这里不易写耗时的操作,
一般在这里对持久化数据的保存 ,停止动画以及耗CPU的事情;onResume则相反
11.4 Activity管理及启动模式
对Activity实例的管理: 通过任务栈的形式来管理(TaskStack)
* standard :标准模式(每次激活,都会创建一个Activity实例)
* singleTop :栈顶模式 :假如要激活的Activity它的实例刚好在栈顶的话,就不用再重新创建
* singleTask: 单任务模式 : 假如任务栈有该Activity的实例,就不需要重新创建,因为该Activity要与用户交互,所有在该Activity实例前面的Activity都会弹出堆载
* singleInstance: 单实例模式 :主要用于实例共享,会单独开辟一个任务栈来存放该实例,比如浏览器的Activity
11.5 onSaveInstanceState()和 onRestoreInstanceState()
Activity的 onSaveInstanceState() 和 onRestoreInstanceState()并不是生命周期方法,它们不同于 onCreate()、onPause()等生命周期方法,它们并不一定会被触发,当Activity容易被销毁时(如:内存不足、用户直接按Home键、跳转到下一个Activity、屏幕切换(横竖屏))onSaveInstanceState()才会被调用。但是当用户主动去销毁一个Activity时,例如在应用中按返回键,onSaveInstanceState()就不会被调用。因为在这种情况下,用户的行为决定了不需要保存Activity的状态。通常onSaveInstanceState()只适合用于保存一些临时性的状态,而onPause()适合用于数据的持久化保存。
需要注意的是,onSaveInstanceState方法和onRestoreInstanceState方法“不一定”是成对的被调用的,onRestoreInstanceState被调用的前提是,activity “确实”被系统销毁了
11.6 Activity程序响应性
在Android中,应用的响应性被活动管理器(Activity Manager)和窗口管理器(Window Manager)这两个系统服务所监视。当用户触发了输入事件(如键盘输入,点击按钮等), 如果应用5秒内没有响应用户的输入事件,那么,Android会认为该应用无响应,便弹出ANR(Application No Response)对话框
在正常情况下,Android程序会在一条单线程里运行。如果Activity要处理一件比较耗时的工作,应该交给子线程完成,否侧会因为主线程被阻塞,后面的用户输入事件因没能在5秒内响应,导致应用出现ANR对话框。
十二、Android广播机制
当遇到这些问题:电池低、网络断网、下载完成或某个图片被捕获,想通知你的用户,那该怎么办?
在Android平台中, 通过广播机制能很好解决这些问题,当遇到某些系统事件时,比如收到短信、电量偏低等,就会以广播的形式发送事件消息,并且Android框架会自动唤醒订阅了该广播事件类型的广播接收器来处理,处理完毕后,Receiver马上退出。
Android广播机制的特点:
1. 发送者不必关心接受者的情况,发送者与接收者完全的解耦
2. 广播事件是系统级别的事件,而我们开发的应用的事件(比如控件的点击事件),它是属于应用级别的事件
3. 系统内置了大量的广播事件,订阅系统的广播事件可以丰富我们应用的功能
4. 广播机制主要解决的是应用程序之间通信的功能
12.1 Android广播接收器
* 特点:
1. Android四大组件之一,是唯一可以动态注册的组件
2. 没有图形界面,能够自启动,在主线程运行
3. BroadcastReceiver组件生命周期比较短,10秒左右,执行完组件的onReceive()方法后后会立即销毁,所以广播接收器组件应该扮演一个网关的角色,只作简单的信息处理,比如发通知或者Toast;对于复杂的业务应该开启一个Service或者在另一个应用中去完成业务
* 运行流程
首先把要发送的信息及动作封装在Intent中,由系统事件机制触发广播(比如:日期改变、电池电量低、网络断网、收到短信等)或者自己通过Content.sendBroadcast(Intent)发送广播。当Intent发送以后,系统依据发送的Intent信息与已经注册的广播接收器组件进行匹配,若匹配成功,则实例化相应的BroadcastReceiver组件,调用onReceive(Context curContext, Intent broadcastMsg)方法,运行完毕,销毁广播组件。
12.2 自定义广播接收器
* 自定义广播接收器实现流程
1. 定义类,继承BroadcastReceiver,并重写onReceive()方法
2. 在AndroidManifest.xml注册广播接收器
3. 订阅广播事件
* 案例:自定义能监听日期改变的广播接收器
* 参考代码
12.3 无序广播与有序广播
* 无序广播
所有的广播接收器运行在一个未定义的顺序,不能屏蔽结果,不能修改广播, 无法终止广播 ,可通过Context.sendBroadcast发送无序广播
* 有序广播:
有序广播在同一时间传送到一个接收器。由于每个接收器依次执行,它可以结果传播到下一个接收器,或者它可以完全中止的广播,需定义优先级优 先级别在 intent-filter 中的 priority 中声明 ,-1000 到1000 之间 , 值越大 , 优先级越高 . 接收者可以截断广播等,可通过Context.sendOrderBroadcast发送有序广播。
android:priority :设定广播接收器的优先级
abortBroadcast() :截断广播、终止广播传递
* 案例 :短信监听器
* 要求:
1.该应用没有界面,也不能在手机应用程序列表中出现
2.能够获取短信内容及发信人电话号码
3.实现自动回复功能
4.截断短信,系统提供的短信接收器组件不能收到短信
* 参考代码
12.4 动态注册广播接收器
* 应用场景
通过AndroidManifest.xml注册广播接收组件,只有当该应用在Android系统中删除才能够注销广播接收组件。有时需要当应用运行时注册广播接收组件,而应用退出时,注销该广播接收组件,该如何解决?
可以对广播接收组件实现动态注册,广播接收器也是唯一可以动态注册的Android组件,一般在Activity的onStop()注册广播接收组件,在onResume()中注销广播接收组件。
* 案例:对监听日期改变的广播接收器组件实现动态注册
* 参考代码
12.5 广播通知
Notification 是一条显示在应用UI界面之外的通知,一条通知到来时,它首先显示在通知栏中,当对通知往下拉放时,会显示通知的详细信息,当对通知的详细信息框进行点击时,则可通过Intent激活其他组件,实现业务处理。
Notification是Android非常重要的消息提示机制,常与广播接收器组合使用,实现广播通知,比如:短信通知、软件更新通知等
12.6 Android4.0以后版本的广播机制问题
在3.1之后,系统的package manager增加了对处于“stopped state”应用的管理,
指的是安装后从来没有启动过,与此同时系统增加了2个Flag:FLAG_INCLUDE_STOPPED_PACKAGES和FLAG_EXCLUDE_STOPPED_PACKAGES ,
来标识一个intent是否激活处于“stopped state”的应用。 Android默认给所有的广播intent加上FLAG_EXCLUDE_STOPPED_PACKAGES,能在一定程度上避免流氓软件、病毒啊干坏事,还能提高效率,如果用户没有运行过应用,就不会响应了。
不过对于自定义的广播接收器我们可以通过setFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);这个方法来唤醒处于“stopped state”的程序,对于系统发的广播,则无能为力
解决办法:
1. 在你的广播接收器应用中添加一个Activity,让用户运行一次你的应用
2. 通过其他应用发一个自定义广播事件,intent设置为intent.setFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES),即包含停止状态的包也能够被激活,你的广播接收器应用订阅了系统的广播事件,同时也订阅了自定义的广播事件,这样就能够激活处于停止状态的广播接收器组件
十三、Service服务
四大组件之一,需要注册、没有图形界面,生命周期长、不能自启动,需要startService或者bindService来启动服务,默认在主线程运行
主要用于实现生命周期较长的操作,比如:打印服务、下载服务、音乐服务、更新服务
13.1 Android进程等级
Android系统会尽量维持一个进程的生命,直到最终需要为新的更重要的进程腾出内
存空间。为了决定哪个进程该终止,系统会跟据运行于进程内的组件的和组件的状态把进程置于不同的重要性等级。
Android进程共分为五个等级,分别是:前台进程(Foreground Process),可视进程( Visible Process), 服务进程(Service Process), 后台进程(Background Process), 空进程(Empty Process)
前台进程等级最高,空进程等级最低,系统需要内存资源时,会优先回收等级低的进程,比如空进程、后台进程等
* 前台进程
用户当前正在做的事情需要这个进程。如果满足下面的条件,一个进程就被认为是前台进程:
1)这个进程拥有一个正在与用户交互的Activity
2)这个进程拥有一个绑定到正在与用户交互的activity上的Service。
3)这个进程拥有一个前台运行的Service — service调用了方法
startForeground().
4)这个进程拥有一个正在执行其任何一个生命周期回调方法(onCreate(),onStart(
或onDestroy())的Service。
5)这个进程拥有正在执行其onReceive()方法的BroadcastReceiver。
* 可视进程
一个进程不拥有运行于前台的组件,但是依然能影响用户所见。满足下列条件时,进程即为可见:
1)这个进程拥有一个不在前台但仍可见的Activity(它的onPause()方法被调用)。
2)这个进程拥有一个绑定在前台(或者可见)Activity的服务。
一个可见的进程是极其重要的,通常不会被终止,除非内存不够,需要释放内存以便前台进程运行。
* 服务进程
一个进程不在上述两种之内,但它运行着一个被startService()所启动的service。
尽管一个服务进程不直接影响用户所见,但是它们通常做一些用户关心的事情(比如播放音乐或下载数据),所以除非系统没有足够的空间运行前台进程和可见进程时才会终止一个服务进程。
* 后台进程
一个进程拥有一个当前不可见的activity(activity的onStop()方法被调用)。
这样的进程们不会直接影响到用户体验,所以系统可以在任意时刻杀了它们从而为前台、可见、以及服务进程们提供存储空间。
* 空进程
没有运行任何component的进程,保留这个进程主要是为了缓存的需要,这种进程存在的唯一原因是做为缓存以改善组件再次于其中运行时的启动时间
服务生命周期图
13.2 全局服务
一旦服务开启,那么调用者和服务就没有任何关系了,因此哪怕调用者被destroy了
那么服务依旧在运行。且不能调用服务内部中的方法。
* 启动
startService(Activity方法) -->onCreate(Service的生命周期方法,当服务不存在调用,用于初始化服务)-->onStartCommand(Service的生命周期方法)
* 交互
startService(Activity方法)-->onStartCommand(intent) :通过Intent附加数据进行交互
* 关闭
stopService(Activity方法)-->onDestroy(服务的生命周期方法)
13.3 绑定服务
一旦服务开启,那么调用者和服务就有密切关系了,如果所有客户端被destroy了
那么服务也就会被destroy。且可以调用服务内部中的方法。调用者被销毁前,需要对绑定的服务解绑。
* 启动:bindService(Activity方法) -->onCreate(Service为空调用)-->onBind()
* 交互:直接在Activity中拿到Service的实例或者Service的代理对象进行操作
* 关闭:unBindService(Activity方法)-->OnUnbind()-->ondestroy()
案例:通过Service实现音乐播放
13.4 IntentService
这是一个Service的子类,该子类使用线程处理所有启动请求,.你需要做的只是实现onHandleIntent()方法即可.依据Intent的请求指令执行相应的业务。
* 流程介绍:
1. 从应用的主线程当中创建一个默认的线程执行所有的intents发送给onStartCommand()方法,该线程从主线程分离.
2. 创建工作队列,每次传递一个intent 给onHandleIntent()方法实现,不必担心多线程.
3. 所有的请求被处理后服务停止,所以你永远都不必调用stopSelf()函数.
4. 默认实现onBind()方法返回null.
13.5 AIDL实现IPC(进程间通信)
Android Interface Definition Language(Android接口定义语言)
由于Android没有一个进程间共享的内存区域,通过AIDL可以实现进程间的通信
AIDL实现IPC的流程:
1. 在远程服务端定义aidl文件 ,定义好比接口定义,系统工具会自动生成相应的java接口
2. 在服务端的Service中继承该接口的Stub类,作为远程服务的代理对象
3. 在客户端中先拷贝服务端的aidl文件,并且放在与服务端包名一致的包下面
4. 在客户端通过ServiceConnetion来获得远程服务的代理对象,实现远程进程通信
5. 在服务端对Service设置IntentFileter,用于远程组件的调用
6. AIDL是线性安全的,由框架来维护其线性安全
14.1、 Fragment
14.1.1 Fragment介绍
Fragment:片段、碎片, 表现 Activity 中UI的一个行为或者一部分. 可以组合多个fragment放在一个单独的activity中来创建一个多界面区域的UI,并可以在多个activity里重用某一个fragment.把fragment 想象成一个activity的模块化区域, 有它自己的生命周期, 接收属于它的输入事件, 并且可以在activity运行期间添加和删除.
14.1.2 Fragment生命周期
Fragment 必须总是被嵌入到一个activity中, 它们的生命周期直接被其所属的宿主activity的生命周期影响.
14.1.3 Activity管理Fragment
* 在Activity的布局文件添加Fragment