activity的生命周期
创建时
onCreate() - onStart() - onResume() - onPause() - onStop() - onDestroy()
切换时
a切换到b
a.onCreate() - a.onStart() - a.onResume - a.onPause - b.onCreate() - b.onStart() - b.onResume() - a.onStop()
b切换回a
b.onPause() - a.onRestart() - a.onStart() - a.onResume() - b.onStop() - b.onDestory()
Handler相关
Handler是什么
一句话总结:Handler是用于与跨线程通信的,而每个线程都有自己的looper,looper管理线程的任务,所以其实Handler就是用于与looper通信的,在Handler里装哪个looper,最终代码就在哪个线程上跑
Looper
Looper的ThreadLocal
Looper内部有个成员变量sThreadLocal<Looper
>,用于在不同的线程获取不同(每个线程独有的)looper
Looper.prepare()的内部其实是sThreadLocal.set(new Looper),就是创建一个新的looper,set到当前线程里去,以后在这个线程里拿的looper就是这里来的
Looper.myLooper()的内部是sThreadLocal.get(),就是去get了一下之前set的looper
Android开机流程
电源键
按下电源键后,引导芯片代码从固化在ROM中的地方开始执行,加载引导程序BootLoader到RAM中,然后执行
BootLoader
BootLoader是在操作系统内核运行之前运行。可以初始化硬件设备、建立内存空间映射图,从而将系统的软硬件环境带到一个合适状态,以便为最终调用操作系统内核准备好正确的环境。
Kernel
Android内核启动时,会设置缓存、被保护存储器、计划列表,加载驱动。当内核完成系统设置,它首先在系统文件中寻找"init.rc"文件,然后启动init进程
init
init进程是第一个用户空间的进程,也就是第1号进程(第0号进程是linux)
init进程在system/core/init/main.cpp文件的main函数中,分为两个阶段完成启动过程
第一阶段时进行一些目录创建、设备节点创建和设备挂载的动作(毕竟Android跑在linux上)
第二阶段启动属性服务(指定文件读取属性、系统属性等)、解析init.rc文件并启动相关进程
其中第二阶段的init.rc不止一份,例如google、soc、odm厂商都有自己的init.rc
Zygote
Zygote进程由init进程启动,他是Android系统的第一个进程(pid为0)
init拉起Zygote的简化代码如下
cpp
Result<void> Service::Start() {
...
pid_t pid = -1;
if (namespaces_.flags) {
pid = clone(nullptr, nullptr, namespaces_.flags | SIGCHLD, nullptr);
} else {
pid = fork();// 1.fork创建service进程(也就是zygote进程)
}
if (pid == 0) {
...
if (!ExpandArgsAndExecv(args_, sigstop_)) {
PLOG(ERROR) << "cannot execv('" << args_[0]
<< "'). See the 'Debugging init' section of init's README.md for tips";
}
...
}
}
可以看到,Zygote由init进程fork(创建父进程的子进程)而来(估计是在linux虚拟机里创建,所以pid为0?),下面的ExpandArgsAndExecv用于指定Zygote的执行路径
所有的应用程序进程以及系统服务进程(SystemServer)都是由Zygote进程孕育(fork)出来的,zygote本身是Native应用程序,与驱动内核无关。
Zygote主要工作有两个
1、启动socket服务,监听socket,响应启动应用请求,有app点开的时候socket服务端会fork生成新的app进程(Dalvik虚拟机)
2、启动systemserver
SystemServer
启动各种系统服务,例如上下文管理器、电池服务、窗口管理器等
Android四层架构
应用程序层
应用框架层
类库层
linux内核
synchronized加锁
首先明确,synchronized锁住的对象都是final的,也就是说如果我们对class中的某个函数加synchronized关键字,其实锁住的是这个class(例子中锁住的是StopThread.class),例如
这段代码中,有两个函数都被添加了synchronized关键字,那么不管有多少对象(线程)调用这两个函数其中的任意一个,同一时间只有一个函数会被执行(毕竟底层是用class.fun(),这个class被锁住了那么就只有一个fun能被执行),也就是说这个class中不管有多少函数被添加了synchronized关键字,同一时间执行的函数都只能有一个,这种做法其实会导致代码效率降低
Service和IntentService
Service
当应用组件通过startService方法来启动Service 时,Service 则会处于启动状态(跑在主线程),一旦服务启动,它就会在后台无限期的运行,生命周期独立于启动它的组件,即使启动它的组件已经销毁了也不受任何影响(除非手机内存要满了,被系统杀掉),通过这种方式启动的服务不好与组件之间通信
一般来说,我们想要Service的服务,会通过bindService来启动
如果服务和用户在一个进程内,直接让Service回传一个Binder就行了
java
public class MusicService extends Service implements IPlayer{
public static final String TAG = "MusicService";
private LocalService mBinder = new LocalService();
public class LocalService extends Binder{
public MusicService getService(){
return MusicService.this;
}
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
return mBinder;
}
@Override
public void play() {
Log.i(TAG,"music play...");
}
@Override
public void pause() {
Log.i(TAG,"music pause...");
}
@Override
public void stop() {
Log.i(TAG,"music stop...");
}
@Override
public int getProgress() {
return 100;
}
@Override
public int getDuration() {
return 10240;
}
}
这样用户在bindService的时候,用ServiceConnection拿到回传的binder就可以调用服务的能力了
如果服务和用户不在同一个进程,用AIDL就行
在服务端和用户端都新建统一的AIDL,在服务端实现AIDL,然后在onBind()函数里回传这个AIDL.stub()
用户端在ServiceConnection里拿到回传的binder也一样可以调用服务的能力了
IntentService
Service默认是跑在主线程上的,并且如果不手动关闭的话就要等系统回收,而IntentService是跑在其他线程上的,并且在他的任务执行完毕后,就自动停止了
java
public class MyIntentService extends IntentService {
public static final String TAG ="MyIntentService";
/**
* Creates an IntentService. Invoked by your subclass's constructor.
*
* @param name Used to name the worker thread, important only for debugging.
*/
public MyIntentService() {
super("MyIntentService");
}
@Override
protected void onHandleIntent(@Nullable Intent intent) {
// 这里已经是工作线程,在这里执行操作就行
boolean isMainThread = Thread.currentThread() == Looper.getMainLooper().getThread();
Log.i(TAG,"is main thread:"+isMainThread);
// 执行耗时下载操作
mockDownload();
}
/**
* 模拟执行下载
*/
private void mockDownload(){
try {
Thread.sleep(5000);
Log.i(TAG,"下载完成...");
}catch (Exception e){
e.printStackTrace();
}
}
}