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();
       }
    }
}
相关推荐
戏谑29 分钟前
Android 常用布局
android·view
拭心12 小时前
Google 提供的 Android 端上大模型组件:MediaPipe LLM 介绍
android
带电的小王14 小时前
WhisperKit: Android 端测试 Whisper -- Android手机(Qualcomm GPU)部署音频大模型
android·智能手机·whisper·qualcomm
梦想平凡15 小时前
PHP 微信棋牌开发全解析:高级教程
android·数据库·oracle
元争栈道15 小时前
webview和H5来实现的android短视频(短剧)音视频播放依赖控件
android·音视频
阿甘知识库16 小时前
宝塔面板跨服务器数据同步教程:双机备份零停机
android·运维·服务器·备份·同步·宝塔面板·建站
元争栈道16 小时前
webview+H5来实现的android短视频(短剧)音视频播放依赖控件资源
android·音视频
MuYe17 小时前
Android Hook - 动态加载so库
android
居居飒17 小时前
Android学习(四)-Kotlin编程语言-for循环
android·学习·kotlin
Henry_He20 小时前
桌面列表小部件不能点击的问题分析
android