Android开发
系统架构
通常来讲会被分成五层
- 系统应用层
- 应用框架层
- native库以及Android运行时
- Native C/C++ Libraries:C/C++程序库
- Dalvik虚拟机
- 硬件抽象层
- HAL
- linux内核层
- IPC(Binder)
Android文件目录结构
- assets
- 静态文件,apk所使用的各种资源,比如图片、视频等等,通过API获取
- res
- 编译后的资源文件
- lib
- so动态链接库,用于底层的一些调用
- dex
- 虚拟机可执行文件,主要逆向目标
- META-INF
- 数字签名,用于校验apk是否被篡改
- AndroidManifest.xml
- 一个应用程序的配置清单,声明权限、组件等的基本信息
- resources.arsc
- 编译后资源的位置与id之间的映射关系
Android启动流程
- [Android启动过程-万字长文(Android14) - 柳云居士 - 博客园](https://www.cnblogs.com/anywherego/p/18221943#:~:text=1 1.引导加载程序(Bootloader)启动: 当设备上电或者重启时,首先会由引导加载程序负责启动。 … 2 2.内核加载: 引导加载程序会根据预定义的配置从设备存储中加载操作系统内核。 …,6 6.启动系统服务: 在Zygote进程启动后,还会启动一系列系统服务,例如SurfaceFlinger、ActivityManager、PackageManager等。 … 7 7.启动桌面程序: 一旦系统服务启动完成,Android系统就处于可用状态。 )
APP安装过程
system/app 存放系统自带的应用程序
data/app 用户程序安装的目录
data/data 存放应用程序的数据
- 复制APK安装包到data/app目录下
- 解压并扫描安装包,把dex文件(Dalvik字节码)保存到dalvik-cache目录
- 在data/data目录下创建对应的应用数据目录
App运行流程
- BootClassLoader加载系统核心库
- PathClassLoader加载App自身dex
- 进入App自身组件开始执行
- 调用Application的attachBaseContext
- 调用Application的onCreate
Activity
简述
onCreate():
- 必须实现,当然也是对activity进行逆向的核心破局点
- Activity第一次创建时调用
onStart():Activity置于栈顶可见但无焦点状态时调用
onRestart():Activity再次回到栈顶可见时调用
onResume()【活动状态】:在Activity可见并且有焦点时调用
onPause():发生中断时(准备启动或者恢复另一个activity时)调用,进入暂停状态。可以编写一些保存现场或者释放资源的操作。【该Activity仍然用户可见】
onStop():Activity不再对用户可见时调用
onDestory():Activity销毁时调用
场景
- 打开新Activity。原Activity: onPause()–>onStop()
- 回到原Activity。onRestart()–>onStart()–>onResume()
切屏
不配置参数
- 重走生命周期
- onPause()–>onSaveInstanceState()–>onStop()–>onDestroy()–>onCreate()–>onStart()–>onRestoreInstanceState–>onResume()
- onSaveInstanceState()和onRestoreInstanceState用于Activity异常退出时候保存和恢复Activity状态
配置参数
1
2 # 选择在什么情况下不重新启动生命周期,而是执行onConfigurationChanged方法
android:configChanges = "orientation| screenSize" # 方向旋转 | 大小变化
四种启动模式
Standard
- 先进后出,Activity放入栈顶
SingleTop【栈顶复用模式/单顶模式】
- 如果当前返回栈的顶部不存在该Activity,则新建该Activity并放入栈顶
- 如果当前返回栈的顶部存在Activity的实例,则调用该实例的onNewIntent()方法向其传送Intent,不创建该Activity的新实例
SingleTask【栈内复用模式/单任务模式】
1 | // 一个栈中只有一个指定的Activity |
SingleInstance【单例模式】
- Singletask的升级版,系统直接创建一个新的返回栈并创建Activity的新实例置于新Task返回栈中
Service
Service两种启动方式
StartService方式
- 无限期运行,需要stopService或者stopSelf方法终止
- onCreate() –> onStartCommand() –> onDestroy()
1 | public class MyService extends Service { |
BindService方式
- C/S模式。service作为server,组件作为client。单个service,多个client
- client通过Ibinder接口获取service实例
- onCreate() -> onBind() -> onUnbind() -> onDestroy()
Server端
- service的onBind方法中返回IBinder类型实例(也就是service实例)
Client端
- 创建
ServiceConnection
类型实例,重写onServiceConnected()
方法和onServiceDisconnected()
方法 - 执行
onServiceConnected
回调时,通过IBinder
得到Service
实例对象 - 执行
onServiceDisconnected
回调时,client
与Service
断开连接
销毁问题
- client销毁时自动与service解除绑定
- client调用Context的unBindService()方法解除绑定
- 没有任何client与service绑定时service自动销毁
Service保活
- 自定义系统服务
- 设置成前台服务
- 注册为系统服务
- 第三方库来保活,如HelloDaemon
- 双service轮询检测互相拉起
- START_STICKY(onStartCommand方法中),kill 后会被重启(等待5秒左右),重传Intent,保持与重启前一样
进程优先级
- 前台进程
- 可见进程。对用户可见但不能交互的Activity和绑定在上面的Service
- 服务进程。startService运行的服务
- 后台进程。执行了onStop方法停止的程序。内存不够时被杀死
- 空进程
Broadcast Receiver
分类:普通、系统、有序、本地、粘滞广播
广播发送者 广播接收者 AMS(Binder机制)
- 接收者向AMS注册
- 发送者发送广播到AMS
- AMS寻找合适的广播接收者
- 广播发送到接收者的消息循环队列中
- 广播接收者拿到广播回调
onReceive()
定义广播接收类
1 | package com.example.myapplication.receiver; |
动态注册发送广播
- 非常驻、特定监听
1 | package com.example.myapplication; |
静态注册发送广播
- 常驻,时刻监听,与app是否被用户打开无关
1 | <receiver |
1 |
|
有序广播
广播设置优先级,有序接收
具体规则
- 优先级越大的接收器,越早收到有序广播
- 优先级相同,越早注册的接收器越早收到有序广播
1 | //实现广播接收的开关 |
1 | <receiver |
Content Provider
URI
content://com.carson.provider/User/1
- Schema:Android规定的URI前缀
- Authority:content provider唯一标识符
- Path:指向数据库某个表名
- ID:表中特定记录
原理
基于binder实现跨进程数据共享交换
数据共享:允许应用之间共享数据,避免直接访问文件或数据库。
统一接口:提供 CRUD(创建、读取、更新、删除)操作的标准接口。
权限控制:通过 URI 和权限管理,控制数据的访问权限。
抽象数据源:数据可以存储在 SQLite 数据库、文件、网络或其他地方,但对外提供统一访问方式。
ContentProvider:内容提供者,主要作用就是管理数据,比如最常见的增删改查操作,同时为这些数据的访问提供了统一的接口,实现进程间的数据传递和共享。
ContentResolver:内容解析者,ContentResolver可以为不同URI操作不同的ContentProvider中的数据,优点像外部进程和ContentProvider之间的中间商。
ContentObserver:内容观察者,观察ContentProvider中的数据变化,有变化时执行特定操作。
优点
相比于binder和intent,支持大批量数据在不同进程间传输
有利于业务层和访问层解耦合
Context & Intent
context
继承关系
1 | 图要是挂了就挂了 |
broadcast receiver和content provider不是继承于context,它们所拥有的context都来源于其它地方
获取&使用
获取
- Activity.this
- getApplication():获取应用实例。仅在Activity和Service可调用
- getApplicationContext():整个App的context
- view.getContext():view的context一般是view所在的Activity实例
使用
- 优先使用application context
- start activity 和 dialog必须使用activity context
num
context = Activity + Service + 1(本身)
Intent
- intent的数据传输限制大概在1M左右,超过限制会静默奔溃
显式启动
1 | Intent intent = new Intent(this, SecondActivity.class); |
隐式启动
- manifest里设置intent-fliter
- 在代码调用里通过条件匹配得到特定intent
1
2
3
4
5
6
7
8<activity android:name=".MainActivity">
//过滤器
<intent-filter>
<action android:name="com.example.demo"/>
<category android:name="android.intent.category.DEFAULT"/>
<category android:name="com.example.demo.category"/>
</intent-filter>
</activity>1
2
3
4Intent intent = new Intent();
intent.setAction(com.example.demo);
intent.addCategory(com.example.demo.category);
startActivity(intent);
组成
- componentName:目的组件
- action:用来表现意图的行动
- category:用来表现动作的类别
- data:表示与动作要操纵的数据
- type:对于data范例的描写
- extras:扩展信息
- Flags:期望这个意图的运行模式
PendingIntent
异步机制
Handler
异步消息机制,处理父子进程间消息通讯
组成
Handler:发送Message和处理Message
Message Queue:先进先出,由Looper管理
Looper:从消息队列读Message,分配给目标Handler进行处理
一个线程对应一个Looper
一个消息队列对应多个Handler
Looper.loop()不会消耗大量CPU资源或者造成应用卡死
使用Looper判断当前线程是否为主线程
1 | public boolean isMainThread() { |
HandlerThread
介绍
子线程之间通信,一个继承自Thread的Handler类
因此,如果需要在子线程中使用Handler,则考虑
- Looper.prepare() –> Looper.loop() –> 实现Handler
- 直接实现HandlerThread类
案例
1 | private static final int MSG_READ_INFO = 100; |
AsyncTask
IntentService
基于HandlerThread实现的 继承于Service 的类,适合顺序多任务、高优先级场景。如离线下载、后台下载
特性
- 可以startService启动,但是不能onBind()
- 任务完成后主动调用stopSelft()结束
- 自动创建工作线程来处理多线程任务
Fragement
生命周期
官图
对比Activity
Activity::onCreate()
- **Fragment::onAttach()**:Fragment绑定到Activity时调用
- Fragment::onCreate()
- **Fragment::onCreateView()**:创建Fragment视图时调用
- **Fragment::onActivityCreated()**:Activity的onCreated()方法返回时调用
Activity::onStart()
- Fragment::onStart()
Activity::onResume()
- Fragment::onResume()
Activity::onPause()
- Fragment::onPause()
Activity::onStop()
- Fragment::onStop()
Activity::onDestroy()
- **Fragment::onDestroyView()**:销毁Fragment视图时调用
- Fragment::onDestroy()
- **Fragment::onDetach()**:Fragment和Activity取消绑定时调用
特点
Activity的每一个生命周期都会触发Fragment同样的回调
使用
静态
布局文件xml中声明Fragment
1 | <fragment |
1 | public class MyFragment extends Fragment { |
动态
……
Fragment和Activity通信
Activity有Fragment的引用,可直接通过引用访问Fragment里的public方法
无引用,通过
getFragmentManager.findFragmentByTag()
或者findFragmentById()
得到Fragment实例Fragment中通过
getActivity()
获取绑定的Activity实例广播通信、接口交互
Bundle通信
Activity中建Bundle –> setArguments(bundle)传入Fragment –> Fragment中getArguments()接收
registerForActivityResult() + startActivityForResult + setResult
Binder & AIDL
Then Google development
SharedPreferences
- 基于key-value 键值对生成的xml文件,在/data/data/packageName/shared_prefs目录下
- 永久性存储,少量存储
1 | SharedPreferences sharedPreferences = context.getSharedPreferences(String name, int mode); |
mode
- MODE_PRIVATE:只能被本应用读写,或者有相同用户ID的应用读写;
- MODE_WORLD_READABLE:全局读
- MODE_WORLD_WRITEABLE:全局写
- MODE_MULTI_PROCESS:可以实现多进程访问SharedPreferences数据
- MODE_APPED:如果文件存在且对应的key也存在,可以在对应的value中追加新的内容
Native函数动静态注册
Java
1 | public class MainActivity extends AppCompatActivity { |
静态注册
1 | extern "C" |
动态注册
1 |
|
序列化
bundle只支持基本数据类型,因此传递对象时需要先序列化
Parcelable
把对象分解为Intent支持的类型后通过Intent传输
内存读写
Serializable
基于Java反射
磁盘读写
1 | //序列化 |
URL格式完整
- scheme:方案,访问服务器以获取资源时要使用哪种协议,如:http
- host:主机,资源宿主服务器的主机名,ip地址
- path:路径,服务端上的资源本地名,由斜杠分割开来,如:index.html
- user:password,访问资源时需要的用户名和密码,中间冒号不能丢
- port:端口,默认端口为80
- params:参数,参数为名/值对(如:name=’xiaodeng’),url可以包含多个参数字段,他们之间以及与路径的其余部分之间用‘&’分隔。
- query:查询,用字符‘?’将其与url的其他部分分割开来
- 片段(#)
- 为了引用部分资源或资源的一个片段,url支持使用片段组件来表示一个资源内部的片段
- 如:url可以指向html文档中的特定的图片或小节。
- 案例:http://www.joes-hardware.com/tools.html#drills
参考文章: