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的简化代码如下

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就行了

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是跑在其他线程上的,并且在他的任务执行完毕后,就自动停止了

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();
       }
    }
}

相关推荐

  1. 【UBUNTU】手记

    2024-03-11 23:08:02       38 阅读
  2. 博客手记

    2024-03-11 23:08:02       36 阅读
  3. 博客手记

    2024-03-11 23:08:02       35 阅读
  4. 【DOCKER】手记

    2024-03-11 23:08:02       22 阅读
  5. Github 学习使用手记

    2024-03-11 23:08:02       10 阅读
  6. Android 禁用字体系统大小变化

    2024-03-11 23:08:02       38 阅读

最近更新

  1. TCP协议是安全的吗?

    2024-03-11 23:08:02       16 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2024-03-11 23:08:02       16 阅读
  3. 【Python教程】压缩PDF文件大小

    2024-03-11 23:08:02       15 阅读
  4. 通过文章id递归查询所有评论(xml)

    2024-03-11 23:08:02       18 阅读

热门阅读

  1. python Plotly可视化

    2024-03-11 23:08:02       21 阅读
  2. Android FTPServer监听摄像机文件上传处理

    2024-03-11 23:08:02       23 阅读
  3. 最短路dp,LeetCode 1976. 到达目的地的方案数

    2024-03-11 23:08:02       17 阅读
  4. python界面开发 - filedialog 文件选择对话框

    2024-03-11 23:08:02       21 阅读
  5. MySQL 建表约束

    2024-03-11 23:08:02       20 阅读
  6. Rust新手必看,大神力推的必读书籍

    2024-03-11 23:08:02       21 阅读
  7. npm使用

    2024-03-11 23:08:02       18 阅读
  8. 微信小程序使用npm、miniprogram管理

    2024-03-11 23:08:02       18 阅读
  9. 机器学习介绍

    2024-03-11 23:08:02       16 阅读
  10. Linux中PATH、LIBRARY_PATH、LD_LIBRARY_PATH的作用

    2024-03-11 23:08:02       20 阅读