1、系统开发概述
2、系统编译简介
3、源码查看工具
4、系统启动流程
5、Handler消息机制
6、AsyncTask原理
系统分层
Linux内核层: 包含Linux内核和驱动模块(比如USB, Camera, 蓝牙等)
Libraries层: 这一层提供动态库(也叫共享库), android运行时库, Dalvik虚拟机等. 编程语言主要为C或C++, 所以可以简单的看成Native层
FrameWork层: 这一层大部分用java语言编写,它是android平台上Java世界的基石
Applications层: 应用层, 主要存放各种各样的应用程序
详细说明:
Linux 内核层
Android基于那个版本研发的:2.6.7
display driver:显卡驱动
camera draver:相机驱动
bluetooth driver:蓝牙驱动
flash memory driver:闪存驱动
Binder(IPC) Driver:Android系统进程间通信.
USB driver:usb驱动
keypad driver:键盘驱动
wifi driver:wifi驱动
audio driver :音频驱动
power Management:电源管理
上面的这些驱动都是用c语言写的
知识拓展:
NFC是Near Field Communication缩写,即近距离无线通讯技术。
库层(libraries图书馆)
surface Manager:显示管理器
Media Framework:多媒体框架
SQLite :所有应用程序都可以使用的强大而轻量级的关系数据库引擎
OpenGl | ES :渲染三维图形引擎
FreeType:是一个完全免费(开源)的、高质量的且可移植的字体引擎
Webkit:是一个开源的浏览器引擎
SGL:基本的2D图形引擎
SSL:(Secure Sockets Layer 安全套接层),及其继任者传输层安全(Transport Layer Security,TLS)
是为网络通信提供安全及数据完整性的一种安全协议。TLS与SSL在传输层对网络连接进行加密。
libc :基本的C语言函数库,包含了C语言最基本的库函数
Android 运行时
Cor Libraries :核心库;核心函数库;核心函式库
dalvik virtual machine:Dalvik虚拟机
应用框架层
Activity Manager :这个类主要用来管理所有设备上的Activities
Window Manger:整个Android的窗口机制是基于一个叫做 WindowManager,其实我们的Activity或者Diolog底层的实现也是通过WindowManager,这个 WindowManager是全局的,整个系统就是这个唯一的东东。它是显示View的最底层了。
Content Providers :Content providers是连接跨进程数据的标准接口。
View System:视图显示系统
Notification Manager :通知管理
Package Manager : 包管理器
Telephony Manager :电话管理器
Resource Manager :资源管理器
Location Manager: 位置管理,用于定位;
XMPP service::XMPP是一种基于标准通用标记语言的子集XML的协议,它继承了在XML环境中灵活的发展性;
应用层:
桌面,联系人,电话,浏览器,第三方软件等等
补充:
Java世界经由JIN层通过IPC方式与Native世界进行交换。IPC(Inter-Process Communication,进程间通信) ,常用的IPC方法Binder,除此之外还可以使用Socket。
现在很多设备开始使用Android系统:例如车载系统;
物联网
操作系统选择:
Android 系统的编译环境目前只支持 Linux 以及 Mac OS 两种操作系统。
注意
如果采用虚拟机安装时需要考虑占用磁盘空间(源码+编译)
如果是2.3 源码需要5G,编译需要10G
google推荐使用64位的操作系统
现在一般是用ubuntu 14.04,我用的是11.10
经验分享:
其中一种是在window 系统上安装虚拟机 ,虚拟机上安装Linux系统;
4.4源码,给盘符90G,尽量多给点;
2.3 源码3.7个G,不包含内核代码;如果下完估计要5G;
下载源码流程相对麻烦点, 但官方文档中有对源码下载进行说明.
官方文档地址: http://source.android.com/source/downloading.html
以下是详细步骤:
1.下载Git(版本控制工具).
2.安装curl(上传和下载数据的工具).
3.安装repo(一个基于git的版本库管理工具, 这里用于自动批量下载android整个项目).
4.创建文件夹, 用于存放下载的Android源码.
5.初始化库.
开始同步下载.
下载源码具体命名和细节:
Android源码下载支持的系统目前只有Ubuntu和Mac OS两种操作系统, 本次以Ubuntu系统为例.
官方网站: http://source.android.com/source/downloading.html
下载Git(版本控制工具). 调出命令行: ctrl + alt + T
sudo apt-get install git
安装curl(上传和下载数据的工具).
sudo apt-get install curl
安装repo(一个基于git的版本库管理工具, 这里用于自动批量下载android整个项目.).
// 创建目录
mkdir bin
// 下载repo脚本到本地bin文件夹下
curl http://android.git.kernel.org/repo >~/bin/repo
// 如果上面下载失败, 采用下面这种方式
curl "http://php.webtutor.pl/en/wp-content/uploads/2011/09/repo" >~/bin/repo
// 给所有用户追加可执行的权限
chmod a+x ~/bin/repo
// 临时把repo添加到环境变量中, 方便后面执行.
// 注意: 每次重启ubuntu之后此环境变量失效, 重新配置就可以了.
export PATH=~/bin:$PATH
创建文件夹, 用于存放下载的Android源码.
// 创建目录
mkdir android_source
// 修改权限
chmod 777 android_source
cd android_source
初始化库.
// 需要先配置git的用户信息
git config --global user.email "[email protected]"
git config --global user.name "yangguangfu"
//b-bracher分支,这里是下载这个版本的目录结构下下来
repo init -u https://android.googlesource.com/platform/manifest -b android-2.3_r1
// 如果上面初始化失败, 用国内的连接下载代码 gingerbread(姜饼)
repo init -u git://codeaurora.org/platform/manifest.git -b gingerbread
// 或
repo init -u git://android.git.kernel.org/platform/manifest.git -b gingerbread
出现以下信息成功初始化
repo initialized in /home/yangguangfu/android_source
开始同步下载.
repo sync
注意: 下载过程中, 因为网络问题, 可能会中断下载. 当中断下载时, 继续使用repo sync命令继续下载,网络比较好的情况下要下载8个小时左右,主要原因是有中断情况。
正在下载中
下载完成:
下载过程中常见问题:
apt-get是一条linux命令,适用于deb包管理式的操作系统,主要用于自动从互联网的软件仓库中搜索、安装、升级、卸载软件或操作系统。是debian,ubuntu发行版的包管理工具,与红帽中的yum工具非常类似。
apt-get install xxxx 安装
apt-get remove xxxx 卸载但不删除配置
apt-get purge xxxx 卸载并且删除相关配置
curl是利用URL语法在命令行方式下工作的文件传输工具。
下载时可能会出现失败的情况:需要多试几次,或者
apt-get update
apt-get install git-core curl --fix-missing
10.10配置软件源:
systemàadministrationàsynaptic package manageràsettingàrepositoriesàsoftware sources
Ubuntu 的软件源列表存放在 /etc/apt/sources.list 当中。
google的http://source.android.com/source/downloading.html,为了防止连接数过多,每个ip都需要认证。。。
第一步:从这里 the password generator(https://android.googlesource.com/new-password) 获取用户名和密码
第二步:将上面的页面上以machine开头的两行复制到 ~/.netrc文件中
第三步:repo init -u https://android.googlesource.com/a/platform/manifest 多了个“/a”
然后就可以repo sync了
一点小提示:有时候google的android服务器老是断,总不能让我们守在电脑旁边一直手工重新./repo sync吧,这可是需要N个小时才能下载完的啊。
我们就写个小脚本让电脑自动reposync,直到下载成功为止:
#!/bin/shcount=0
ret=1
while [ $ret -ne 0 ]
do
repo syncret=$?
count=$(( $count + 1))
echo "try $count, ret:$ret"
done
echo "try $count, ret:$ret"
把上面的内容复制到一个文件里tryrepo.sh
然后修改tryrepo.sh的属性,开始自动工作吧。第二点早上应该就大功告成了
chmod a+x tryrepo.sh./tryrepo.sh
编译环境搭建--安装软件
编译的目的-修改了代码、风格、或者功能。小米手机、锤子手机等待。
JDK安装(不同的源码编译时需要的JDK版本不同)
android2.2需要JDK5
android2.3需要JDK6,如果你安装的是JDK5直接报错。
安装编译时依赖的软件(如: zip, gcc, g++, libesd0-dev, lib32z1-dev…等等)
编译:make -j4 (-j4为可选参数, j4代表4核同时编译)
2、在编译源码之前需要做一些准备操作, 详细步骤如下:
1. 安装JDK, google官方要求编译2.3源码需要JDK1.6.
1). 下载JDK1.6, 下载地址:
http://download.oracle.com/otn/java/jdk/6u45-b06/jdk-6u45-linux-x64.bin
2). 创建目录.
sudo mkdir /usr/java
3). 把下载好的jdk-6u45-linux-x64.bin拷贝到上面创建的目录下.
sudo cp /home/liyindong/jdk-6u45-linux-x64.bin /usr/java
4). 添加可执行权限.
sudo chmod 755 /usr/java/jdk-6u45-linux-x64.bin
5). 解压.
cd /usr/java
sudo ./jdk-6u45-linux-x64.bin
6). 配置环境变量.这块需要路径要对
export JAVA_HOME=/usr/java/jdk1.6.0_45
export PATH=$PATH:$JAVA_HOME/bin
export CLASSPATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
7). 验证是否成功.
yangguangfu@yangguangfu-VirtualBox:~$ java -version
java version "1.6.0_45"
Java(TM) SE Runtime Environment (build 1.6.0_45-b06)
Java HotSpot(TM) 64-Bit Server VM (build 20.45-b01, mixed mode)
2. 安装其他编译时依赖的软件.
注意: ubuntu自带的源中速度比较慢, 有些软件找不到, 所以需要修改为国内的源, 修改源步骤如下:
1). 备份ubuntu自带的源.
sudo cp /etc/apt/sources.list /etc/apt/sources.list.old
2). 修改源文件.
sudo gedit /etc/apt/sources.list
3). 这时会弹出一个文本编辑框, 先删除所有内容, 然后把以下内容拷贝进去, 并保存.
deb http://mirrors.163.com/ubuntu/ trusty main restricted universe multiverse
deb http://mirrors.163.com/ubuntu/ trusty-security main restricted universe multiverse
deb http://mirrors.163.com/ubuntu/ trusty-updates main restricted universe multiverse
deb http://mirrors.163.com/ubuntu/ trusty-proposed main restricted universe multiverse
deb http://mirrors.163.com/ubuntu/ trusty-backports main restricted universe multiverse
deb-src http://mirrors.163.com/ubuntu/ trusty main restricted universe multiverse
deb-src http://mirrors.163.com/ubuntu/ trusty-security main restricted universe multiverse
deb-src http://mirrors.163.com/ubuntu/ trusty-updates main restricted universe multiverse
deb-src http://mirrors.163.com/ubuntu/ trusty-proposed main restricted universe multiverse
deb-src http://mirrors.163.com/ubuntu/ trusty-backports main restricted universe multiverse
deb http://mirrors.sohu.com/ubuntu/ trusty main restricted universe multiverse
deb http://mirrors.sohu.com/ubuntu/ trusty-security main restricted universe multiverse
deb http://mirrors.sohu.com/ubuntu/ trusty-updates main restricted universe multiverse
deb http://mirrors.sohu.com/ubuntu/ trusty-proposed main restricted universe multiverse
deb http://mirrors.sohu.com/ubuntu/ trusty-backports main restricted universe multiverse
deb-src http://mirrors.sohu.com/ubuntu/ trusty main restricted universe multiverse
deb-src http://mirrors.sohu.com/ubuntu/ trusty-security main restricted universe multiverse
deb-src http://mirrors.sohu.com/ubuntu/ trusty-updates main restricted universe multiverse
deb-src http://mirrors.sohu.com/ubuntu/ trusty-proposed main restricted universe multiverse
deb-src http://mirrors.sohu.com/ubuntu/ trusty-backports main restricted universe multiverse
deb http://mirrors.oschina.net/ubuntu/ trusty main restricted universe multiverse
deb http://mirrors.oschina.net/ubuntu/ trusty-backports main restricted universe multiverse
deb http://mirrors.oschina.net/ubuntu/ trusty-proposed main restricted universe multiverse
deb http://mirrors.oschina.net/ubuntu/ trusty-security main restricted universe multiverse
deb http://mirrors.oschina.net/ubuntu/ trusty-updates main restricted universe multiverse
deb-src http://mirrors.oschina.net/ubuntu/ trusty main restricted universe multiverse
deb-src http://mirrors.oschina.net/ubuntu/ trusty-backports main restricted universe multiverse
deb-src http://mirrors.oschina.net/ubuntu/ trusty-proposed main restricted universe multiverse
deb-src http://mirrors.oschina.net/ubuntu/ trusty-security main restricted universe multiverse
deb-src http://mirrors.oschina.net/ubuntu/ trusty-updates main restricted universe multiverse
4). 保存之后, 更新数据源.
sudo apt-get update
执行完上面几步, 数据源就更新完成了, 下面就开始安装编译依赖的软件, 同样, 在终端中以行为单位依次输入以下命令:
sudo apt-get install gnupg
sudo apt-get install flex
sudo apt-get install bison
sudo apt-get install gperf
sudo apt-get install zip
sudo apt-get install curl
sudo apt-get install build-essential
sudo apt-get install libesd0-dev
sudo apt-get install libwxgtk2.6-dev
sudo apt-get install libsdl-dev
sudo apt-get install lsb-core
sudo apt-get install lib32readline-gplv2-dev
sudo apt-get install g++-multilib
sudo apt-get install lib32z1-dev
sudo apt-get install libswitch-perl
这个过程有些费时,快的话一个小时左右。
3. 开始编译, 在你下载源码的目录下, 执行一下命令:
make
编译整个系统——make,耗时较长
编译SDK——make sdk
单个模块编译——make Media Provider,会将该模块依赖的所有模块也一起编译
编译某个目录下的模块——mm
编译某个目录下的指定模块——mmm
所有结果都在/out 目录
/out/host/:存放开发工具, 如:emulator,adb,aapt 等。
/out/target/common/:主要存放 Java 应用代码和 Java 库。
/out/target/product/
/out/target/product/
编译结束后会生成镜像文件和一些目录
ramdisk.img:在启动时将被 Linux 内核挂载为只读分区,它包含了 /init 文件和一些配置文件。它用来挂载其他系统镜像并启动 init 进程。
system.img:包含了 Android OS 的系统文件,共享库,可执行文件以及预置的应用程序,将被挂载为根分区。
userdata.img:将被挂载为 /data,包含了应用程序相关的数据以及和用户相关的数据。
刷机:一般是系统升级或是换系统。
烧机:重新灌录软件。包括应用软件和操作系统(OS)。
Android Build 系统是用来编译 Android 系统,Android SDK 以及相关文档的一套框架。众所周知,Android 是一个开源的操作系统。Android 的源码中包含了许许多多的模块。 不同厂商的不同设备对于 Android 系统的定制都是不一样的。如何将这些模块统一管理起来,如何能够在不同的操作系统上进行编译,如何在编译时能够支持面向不同的硬件设备,不同的编译类型, 且还要提供面向各个产商的定制扩展,是非常有难度的。 但 Android Build 系统很好的解决了这些问题,这里面有很多值得我们开发人员学习的地方。对于 Android 平台开发人员来说,本文可以帮助你熟悉你每天接触到的构建环境。对于其他开发人员来说,本文可以作为一个 GNU Make 的使用案例,学习这些成功案例,可以提升我们的开发经验。
要学会看源代码,比较我们今天学习Android启动流程、handler消息机制等等都是通过看源码学习的。如果有一天你需要研究多媒体模块,怎么办,看源代码。
安装工具
第一次安装需要输入序列号。点击keygen.exe生成即可。
2、工具使用:
新建源码工程: ProjectàNew project
设置工程路径
where do you want to store the project data files?
你想保存的工程数据文件在哪里?
导入源码
源码的导入方式一:具体需要研究那个模块,就将该模块导入
源码的导入方式二:导入整个源码,以Add Tree方式
修改文字大小:OptionsàDocument Options…àScreen Fonts…
如图:
点击上面的OK
点击上面的OK
选中要加载的代码如下图
点击上图Add Tree 后会弹出两个对话框
第一个对话框:不用管
第二个对话框:点击确定
加载代码中。。如下图
加载后如下图
点击Close
加载后搜索Activity或者Context
查看代码流程:
1、搜索init.c---选择(system/core/init.c)双击--->在左边搜索:main---->里面有定义变量,创建各种目录,挂载目录,初始化日志,初始化解析配置文件--->
2、搜索Init.rc--->选择(system/core/rootdir)双击打开----->early-init(最高级别)---->设置全局变量、创建目录、加载目录----->netd(噪声等效温差)---->ril-daemon(守护进程服务)-->zygote(孵化器这个很重要)------->bootanim(启动动画)----->keystore(签名);
zygote(孵化器这个)----->app_process是个目录呢(\frameworks\base\cmds\app_process)---->打开里面文件------->搜索:main方法------>AppRunTime(应用运行时)---->启动zygote(孵化器)------>
搜索ZygoteInit.java---->左边搜索main方法--->
VMRuntime.getRuntime().setMinimumHeapSize(5 * 1024 * 1024)(设置5MB空间)----->ZygoteInit.class.getClassLoader().getResourceAsStream(
PRELOADED_CLASSES)---->
5、源码目录下搜索:preloaded-classes(frameworks\base)
---->打开查看(里面就是很多类,这些类是系统运行时需要)--->startSystemServer(Zygote孵化器进程开始孵化系统核心服务)--->
6、搜索SystemServer(看到的是ServerThread)---->查看左边SystemServer---->
main方法----->System.loadLibrary("android_servers");加载c库--->init1调用动态连接库中的C函数----->
7、//这里init1的函数函数定义在
(frameworks\base\services\jni\com_android_server_SystemServer.cpp) native public static void init1(String[] args);
----->
8、com_android_server_SystemServer.cpp的代码片段如下------>
把native方法init1,映射到android_server_SystemServer_init1(这里定义函数指针)----->>转调----->>extern "C" int system_init();--->
右边搜索-->system_init---->查看并写注释--->
SystemServer类中静态方法init2---->查看并写注释--->
左边搜索:ServerThread---->找run方法里面就是启动系统核心服务并且放到ServiceManager进行同一管理--->
ActivityManangerService ---->systemReady方法如具体实现-->
---->ActivityStack中的resumeTopActivityLocked--->具体实现-->
startHomeActivityLocked----> Home界面显示,这时Android系统启动完毕,进入待机画面
查看源码细节:
当系统引导程序启动Linux内核时,内核会加载各种数据结构和驱动程序,有了驱动之后,开始启动Android系统并加载用户级别的第一个进程init(system/core/init/Init.c)
int main(int argc, char **argv)
{
....
//定义各种变量
int keychord_fd_init = 0;
//创建各种文件夹
mkdir("/dev", 0755);
....
//挂载文件夹
mount("devpts", "/dev/pts", "devpts", 0, NULL);
//初始化日志
log_init();
//初始化解析配置文件
init_parse_config_file("/init.rc");
......
return 0;
}
加载Init.rc(system/core/rootdir)文件。主要启动了一个zygote(孵化器)进程,此进程是Android系统启动关键服务的一个母进程:
service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server
socket zygote stream 666
onrestart write /sys/android_power/request_state wake
onrestart write /sys/power/state on
onrestart restart media
onrestart restart netd
//app_process是个目录呢-\frameworks\base\cmds\app_process
Zygote(孵化器)进程初始化在Appmain.cpp(frameworks\base\cmds\appprocess),代码如下
int main(int argc, const char* const argv[])
{
//定义Android运行时环境
AppRuntime runtime;
int i = runtime.addVmArguments(argc, argv);
// Next arg is parent directory
if (i < argc) {
runtime.mParentDir = argv[i++];
}
.......
bool startSystemServer = (i < argc) ?
strcmp(argv[i], "--start-system-server") == 0 : false;
setArgv0(argv0, "zygote");
set_process_name("zygote");
//使运行时环境启动Zygote的初始化
runtime.start("com.android.internal.os.ZygoteInit",
startSystemServer);
.......
}
现在从C或者C++进入Java世界中,初始化ZygoteInit.java这个类,代码如下:
public static void main(String argv[]) {
try {
//加载系统运行时依赖的类
preloadClasses();
//加载资源文件
preloadResources();
if (argv[1].equals("true")) {
//Zygote孵化器进程开始孵化系统核心服务
startSystemServer();
} else if (!argv[1].equals("false")) {
throw new RuntimeException(argv[0] + USAGE_STRING);
}
........
}
//开始孵化系统核心服务方法
private static boolean startSystemServer()
throws MethodAndArgsCaller, RuntimeException {
/* Hardcoded command line to start the system server */
String args[] = {
"--setuid=1000",
"--setgid=1000",
"--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,3001,3002,3003",
"--capabilities=130104352,130104352",
"--runtime-init",
"--nice-name=system_server",
"com.android.server.SystemServer",
};
........................
//Zygote孵化器分叉开启SystemServer类,并且把上面定义的参数,传给SystemServer类,用户启动系统关键服务。
pid = Zygote.forkSystemServer(
parsedArgs.uid, parsedArgs.gid,
parsedArgs.gids, debugFlags, null,
parsedArgs.permittedCapabilities,
parsedArgs.effectiveCapabilities);
..................
}
Zygote进程分叉出SystemServer类,main函数如下:
public static void main(String[] args) {
.......
//加载本地的动态链接库。
System.loadLibrary("android_servers");
//调用动态连接库中的C函数。
init1(args);
}
//这里init1的函数函数定义在(frameworks\base\services\jni\com_android_server_SystemServer.cpp)
native public static void init1(String[] args);
comandroidserver_SystemServer.cpp的代码片段如下:
static JNINativeMethod gMethods[] = {
/* name, signature, funcPtr */
//把native方法init1,映射到android_server_SystemServer_init1(这里定义函数指针)
{ "init1", "([Ljava/lang/String;)V", (void*) android_server_SystemServer_init1 },
};
int register_android_server_SystemServer(JNIEnv* env)
{
//转调
return jniRegisterNativeMethods(env, "com/android/server/SystemServer",
gMethods, NELEM(gMethods));
}
//此方法没有方法体
extern "C" int system_init();
system_init()方法体,在system_init.cpp类,代码如下;
extern "C" status_t system_init()
{
//开启一些硬件相关服务
SensorService::instantiate();
// Start the media playback service
MediaPlayerService::instantiate();
// Start the camera service
CameraService::instantiate();
// Start the audio policy service
AudioPolicyService::instantiate();
}
.......
//获取Android运行时环境
AndroidRuntime* runtime = AndroidRuntime::getRuntime();
LOGI("System server: starting Android services.\n");
//调用SystemServer类中静态方法init2,从native 层转调Java层
runtime->callStatic("com/android/server/SystemServer", "init2");
........
}
SystemServer类中静态方法init2代码如下:
public static final void init2() {
Slog.i(TAG, "Entered the Android system server!");
//进入Android系统服务的初始化
Thread thr = new ServerThread();
thr.setName("android.server.ServerThread");
thr.start();
}
ServerThread中的Run中的run方法如下:
.....
//初始化系统服务,并且添加各种服务到ServiceManager,便于管理;
ServiceManager.addService("entropy", new EntropyService());
......
//调用了ActivityManagerService 的systemReady的方法
((ActivityManagerService)ActivityManagerNative.getDefault())
.systemReady(new Runnable() {
public void run() {
//
if (connectivityF != null) connectivityF.systemReady();
if (dockF != null) dockF.systemReady();
if (usbF != null) usbF.systemReady();
if (uiModeF != null) uiModeF.systemReady();
if (recognitionF != null) recognitionF.systemReady();
.........
}
});
.....................
}
ActivityManangerService 下的systemReady方法如下:
public void systemReady(final Runnable goingCallback) {
......
//调用ActivityStack中的resumeTopActivityLocked的方法去启动Activity
mMainStack.resumeTopActivityLocked(null);
}
ActivityStack中的resumeTopActivityLocked方法如下:
final boolean resumeTopActivityLocked(ActivityRecord prev) {
//找到第一个当前没有关闭的Activity,系统刚刚启动没有任何Activity执行,所有next为null
ActivityRecord next = topRunningActivityLocked(null);
// Remember how we'll process this pause/resume situation, and ensure
// that the state is reset however we wind up proceeding.
final boolean userLeaving = mUserLeaving;
mUserLeaving = false;
if (next == null) {
// There are no more activities! Let's just start up the
// Launcher...
if (mMainStack) {
//启动Launcher 应用的第一个Activity页面
return mService.startHomeActivityLocked();
}
}
}
Home界面显示,这时Android系统启动完毕,进入待机画面;
Handler: 消息处理器.
发送消息
处理消息
Message: 消息(数据载体).
MessageQueue: 消息队列(存储消息).
Looper: 轮询器.
去MessageQueue取消息
分发给Handler处理
查看源码步骤:
1、查看 Message.java(\frameworks\base\core\java\android\os)源代码---->
obtain()方法以及同名方法---->讲解-->
2.查看Handler无参构造方法---->
myLooper()--->prepare()--->prepareMainLooper()--->
消息队列MessageQueue创建-->在Looper构造方法里构造
Looper的创建--->prepare()方法中
谁调用prepareMainLooper?---->
搜索ActivityThread.java--->看一看main方法-->
Looper类中的loop方法-->main方法执行loop-->
使用Handler对象发消息,sendMessage--->
回到loop方法,主线程被唤醒,继续执行while循环--->
Handler中的dispatchMessage方法-->
用户在使用Handler时,必须实现handleMessage方法处理消.
Handler消息机制
Message对象的创建:
Message msg = new Message();
Message msg = Message.obtain();
Handler对象,初始化完毕后,其中主线程的Looper对象已经开始轮询,循环取消息,但没有消息,主线程处于休眠。代码如下:
new Handler(){
//得到一个主线程的Looper对象
mLooper = Looper.myLooper();
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread that has not called Looper.prepare()");
}
//主线程的消息队列对象
mQueue = mLooper.mQueue;
mCallback = null;
}
主线程的Looper的初始化,在ActivityThread.java中的main函数中,代码如下:
public static final void main(String[] args) {
.....
//在主线程中调用了prepareMainLooper方法,此方法中创建了一个Looper对象,此Looper对象就是主线程中的Looper.
Looper.prepareMainLooper();
.....
Looper.loop();
}
}
Looper类中的loop方法,其中有一个死循环,是否阻塞主线程?设计概念管道(Pipe),管道可以实现进程间通信。原理:管道其实即使Linux系统一种通讯方式,实现方式主要是一个特殊的文件来实现,此文件有两个描述符(对文件进程操作的一个句柄(引用)),一个是读取的,一个是写的。
应用场景:主线程拿着读取的描述符在等待读取,这时候子线程拿着写入的操作符进行写入,当写入时候会唤醒主线程,主线程开始读取子线程写入的内容。执行循环的代码。
Handler的场景:主线程在while循环中,取消息:1,取到消息后,分发消息;2.没取到消息,阻塞主线程,主线程休眠。当子线程sendMessage发消息时,这时用写入的描述符希写入到管道中,主线程被唤醒,继续跑它的循环,取消息。
public static final void loop() {
Looper me = myLooper();
MessageQueue queue = me.mQueue;
while (true) {
Message msg = queue.next(); // might block
//if (!me.mRun) {
// break;
//}
if (msg != null) {
if (msg.target == null) {
// No target is a magic identifier for the quit message.
return;
}
if (me.mLogging!= null) me.mLogging.println(
">>>>> Dispatching to " + msg.target + " "
+ msg.callback + ": " + msg.what
);
msg.target.dispatchMessage(msg);
if (me.mLogging!= null) me.mLogging.println(
"<<<<< Finished to " + msg.target + " "
+ msg.callback);
msg.recycle();
}
}
}
使用Handler对象发消息,sendMessage代码如下:
public final boolean sendMessage(Message msg) {
//1.转调
return sendMessageDelayed(msg, 0);
}
public final boolean sendMessageDelayed(Message msg, long delayMillis) {
if (delayMillis < 0) {
delayMillis = 0;
}
//2.转调
return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}
public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
boolean sent = false;
MessageQueue queue = mQueue;
if (queue != null) {
//3.把当前handler对象赋值给Message中的target对象;
msg.target = this;
//4.把消息传递给消息队列存起来。
sent = queue.enqueueMessage(msg, uptimeMillis);
}
else {
RuntimeException e = new RuntimeException(
this + " sendMessageAtTime() called with no mQueue");
Log.w("Looper", e.getMessage(), e);
}
return sent;
}
//此方法是把传递进来的消息按照先后顺序或者时间来进行排序,并且存起来。
final boolean enqueueMessage(Message msg, long when) {
........
msg.when = when;
//Log.d("MessageQueue", "Enqueing: " + msg);
Message p = mMessages;
if (p == null || when == 0 || when < p.when) {
msg.next = p;
mMessages = msg;
needWake = mBlocked; // new head, might need to wake up
} else {
Message prev = null;
while (p != null && p.when <= when) {
prev = p;
p = p.next;
}
msg.next = prev.next;
prev.next = msg;
needWake = false; // still waiting on head, no need to wake up
}
}
if (needWake) {
nativeWake(mPtr);
}
return true;
}
主线程被唤醒,继续执行while循环。
public static final void loop() {
Looper me = myLooper();
//取出刚刚发送的消息
MessageQueue queue = me.mQueue;
while (true) {
Message msg = queue.next(); // might block
//if (!me.mRun) {
// break;
//}
if (msg != null) {
if (msg.target == null) {
// No target is a magic identifier for the quit message.
return;
}
if (me.mLogging!= null) me.mLogging.println(
">>>>> Dispatching to " + msg.target + " "
+ msg.callback + ": " + msg.what
);
//因为Message中的target对象就是handler对象,这里其实调用的是handler中的dispatchMessage方法。
msg.target.dispatchMessage(msg);
if (me.mLogging!= null) me.mLogging.println(
"<<<<< Finished to " + msg.target + " "
+ msg.callback);
msg.recycle();
}
}
}
Handler中的dispatchMessage方法,代码如下:
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
//调用了自动的handleMessage
handleMessage(msg);
}
}
/**
* Subclasses must implement this to receive messages.
* 子类必须实现此方法接收消息
*/
public void handleMessage(Message msg) {
}
用户在使用Handler时,必须实现handleMessage方法处理消息,代码如下:
Handler handler = new Handler(){
public void handleMessage(Message msg){
.....
//处理不同的消息
}
}
InternalHandler: 消息处理器, 用于处理线程之间消息.
ThreadPoolExecutor: 线程池, 用于处理耗时任务.
new AsyncTask
//2.在主线程执行,做一条准备操作;
public void onPreExecute(){
}
//3.运行在子线程中,做一些耗时的操作,比如联网请求数据。
public String doInBackground(String ...params){
return null;
}
//4.result就是doInBackground方法返回的值,做一些释放资源的操作。
public void onPostExecute(String result){
}
}.execute(String ...params);//1.在主线程中执行这个方法,要开始执行异步任务了;
创建一个小工程名字叫:自定义异步任务,并且自定义类CommonAsyncTask
package com.example.asynctask;
/**
* 自定义异步任务
*
*/
public abstract class CommonAsyncTask {
/**
* 执行任务之前,调用该方法,运行在主线程中。
*/
public abstract void onPreExecute();
/**
* 运作在子线程中,需要执行耗时任务。
*/
public abstract String doInBackground(String ...params);
/**
*
* 在任务执行之后,调用该方法,运行在主线程中
*/
public abstract void onPostExecute(String result);
/**
* 开始之异步任务.
* @param params 参数
*/
public void execute(String ...params){
}
}
开始执行任务并实现相关方法
在里面在写相应方法
public void execute(final String ...params){
onPreExecute();
new Thread(){
public void run() {
String result = doInBackground(params);
};
}.start();
}
class InternalHandler extends Handler{
@Override
public void handleMessage(Message msg) {
}
}
Ctrl+Shift+x---功能是把小写变成大小
Ctrl+1--->提示创建变量
private IntenalHandler handler;
public void execute(final String ...params){
if(handler == null){
handler = new InternalHandler();
}
onPreExecute();
new Thread(){
public void run() {
String result = doInBackground(params);
//1.第一种写法。
//Message msg =handler.obtainMessage(DOINBACKGROUND_FINISH, result);
//handler.sendMessage(msg);
//2.推荐这种写法
handler.obtainMessage(DOINBACKGROUND_FINISH, result).sendToTarget();
//3.第三种写法
//Message msg = new Message();
//msg.what = DOINBACKGROUND_FINISH;
//msg.obj = result;
//handler.sendMessage(msg);
};
}.start();
}
class IntenalHandler extends Handler{
@Override
public void handleMessage(Message msg) {
if(msg.what==DOINBACKGROUND_FINISH){
String result = (String) msg.obj;
System.out.println("子线程执行完成:"+result);
onPostExecute(result);
}
}
}
在点击事件中使用
public void click(View view){
new CommonAsyncTask() {
@Override
public void onPreExecute() {
printThreadName("当前是onPreExecute方法");
}
@Override
public String doInBackground(String... params) {
printThreadName("当前是doInBackground方法");
SystemClock.sleep(10000);
System.out.println("doInBackground收到的参数:"+params[0]+","+params[1]);
return "请求成功";
}
@Override
public void onPostExecute(String result) {
printThreadName("当前是onPostExecute方法");
Toast.makeText(MainActivity.this, "当前是onPostExecute方法:"+result, 1).show();
}
}.execute(new String[]{"参数1","参数2"});
}
/**
* 输出当前正在运行的进程名称
* @param msg
*/
public void printThreadName(String msg){
System.out.println("当前线程名称:"+Thread.currentThread().getName()+",消息是:"+msg);
}
查看源代码顺序
在Source Insight 搜索AsyncTask.java->接着查找execute方法
查看onPreExecute();是一个空方法--->
分析mWorker.mParams = params---->mWorker在AsyncTask构造方法中初始化
mWorker以参数传给FutureTask构造方法-->查看FutureTask构造方法
看源码可知道WorkerRunnable是Callable的实现类
看FutureTask构造方法中的Sync类,里的callable是mWorker
分析 sExecutor.execute(mFuture);
查看sExecutor--->线程池
mFuture 指的就是FutureTask
查看mWorker的初始化过程
查看mWorker的初始化过程,代码如下:
//mWorker在AsyncTask构造方法在一开始一步任务时,已经调用。
public AsyncTask() {
mWorker = new WorkerRunnable
public Result call() throws Exception {
......
}
};
//1.把mWorker对象传递给了FutureTask的构造函数
mFuture = new FutureTask
@Override
protected void done() {
.......
}
};
}
//FutureTask类中接收了Callable的类型,其实WorkerRunnable类型实现了Callable的类型。
public FutureTask(Callable
if (callable == null)
throw new NullPointerException();
//2.把callable也就是mWorker传递给Sync构造方法
sync = new Sync(callable);
}
Sync(Callable
//把接收过来的callable(mWorker)对象赋值给Sync的成员变量callable;
this.callable = callable;
}
sExecutor.execute(mFuture);线程池开始执行任务,我们塞给它Runable,这个时候只需要看mFuture的run方法即可。
public void run() {
//1.调用了Sync中innerRun方法
sync.innerRun();
}
void innerRun() {
if (!compareAndSetState(READY, RUNNING))
return;
runner = Thread.currentThread();
if (getState() == RUNNING) { // recheck after setting thread
V result;
try {
//2.调用了callable(mWorker)的call方法,获取一个返回结果
result = callable.call();
} catch (Throwable ex) {
setException(ex);
return;
}
//4.把结果传递给set方法
set(result);
} else {
releaseShared(0); // cancel
}
}
//在AsyncTask构造方法中初始化。
mWorker = new WorkerRunnable
public Result call() throws Exception {
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
//3.调用了用户实现的doInBackground方法,去执行一个耗时的任务,运行在子线程中。
//doInBackground的参数是execute方法传进来的参数。
return doInBackground(mParams);
}
};
protected void set(V v) {
//5.继续把参数传给innerSet方法
sync.innerSet(v);
}
void innerSet(V v) {
for (;;) {
int s = getState();
if (s == RAN)
return;
if (s == CANCELLED) {
// aggressively release to set runner to null,
// in case we are racing with a cancel request
// that will try to interrupt runner
releaseShared(0);
return;
}
if (compareAndSetState(s, RAN)) {
//6.把doInBackground返回的方法结果负责给成员变量result;
result = v;
releaseShared(0);
//7.调用FutureTask中的done方法
done();
return;
}
}
}
//该方法默认在AsyncTask构造方法中初始化,并且覆盖done方法。
mFuture = new FutureTask
@Override
protected void done() {
Message message;
Result result = null;
try {
//8.调用FutureTask中的get方法获取result(doInBackground)方法的结果。
result = get();
} catch (InterruptedException e) {
android.util.Log.w(LOG_TAG, e);
} catch (ExecutionException e) {
throw new RuntimeException("An error occured while executing doInBackground()",
e.getCause());
} catch (CancellationException e) {
message = sHandler.obtainMessage(MESSAGE_POST_CANCEL,
new AsyncTaskResult
message.sendToTarget();
return;
} catch (Throwable t) {
throw new RuntimeException("An error occured while executing "
+ "doInBackground()", t);
}
//11.创建一个消息对象
message = sHandler.obtainMessage(MESSAGE_POST_RESULT,
new AsyncTaskResult
//12.把当前消息使用sHandler(IntenalHandler其实就是Handler)发送出去。
message.sendToTarget();
}
};
public V get() throws InterruptedException, ExecutionException {
//9.转调Sync中的innerGet方法
return sync.innerGet();
}
V innerGet() throws InterruptedException, ExecutionException {
......
//10.把result(doInBackgroud的结果)返回回去.result成员变量在innerSet方法中赋值。详情看第6步。
return result;
}
private static class InternalHandler extends Handler {
@SuppressWarnings({"unchecked", "RawUseOfParameterizedType"})
@Override
public void handleMessage(Message msg) {
AsyncTaskResult result = (AsyncTaskResult) msg.obj;
switch (msg.what) {
case MESSAGE_POST_RESULT:
// There is only one result
//13.调用AsyncTask中的finish()方法,并且把doInBackground方法中执行的结果传递进去。
result.mTask.finish(result.mData[0]);
break;
case MESSAGE_POST_PROGRESS:
result.mTask.onProgressUpdate(result.mData);
break;
case MESSAGE_POST_CANCEL:
result.mTask.onCancelled();
break;
}
}
}
private void finish(Result result) {
if (isCancelled()) result = null;
//14.把doInBackgroud的返回的结果传递给用户实现的onPostExecute方法,这个方法是执行在主线程中。用户可以做一些更新页面的操作。
onPostExecute(result);
mStatus = Status.FINISHED;
}