Android随手记

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();
       }
    }
}
相关推荐
沐怡旸3 分钟前
【翻译】scrcpy(3.3.3)命令使用文档
android
沐怡旸9 分钟前
【翻译】adb(Android Debug Bridge) 帮助文档
android
QING61811 分钟前
Kotlin 协程中Job和SupervisorJob —— 新手指南
android·kotlin·android jetpack
lichong95123 分钟前
android 使用 java 编写网络连通性检查
android·java·前端
Digitally26 分钟前
如何从iPhone切换到Android
android·ios·iphone
2501_9160074730 分钟前
苹果应用商店上架的系统逻辑,从产品开发到使用 开心上架 上架IPA 交付审核流程
android·ios·小程序·https·uni-app·iphone·webview
r***869843 分钟前
搭建Golang gRPC环境:protoc、protoc-gen-go 和 protoc-gen-go-grpc 工具安装教程
android·前端·后端
e***75391 小时前
SQL Server 数据库迁移到 MySQL 的完整指南
android·数据库·mysql
他叫自己MR张1 小时前
Android 必知必会 - AndroidStudio、AGP、Gradle、Java、Kotlin版本对应关系(官方最新)
android·kotlin·android studio·agp
大雨淅淅1 小时前
【编程语言】Kotlin:从新手到大神的进阶之路
android·开发语言·kotlin