主要用于实现一些不规则的效果,静态或者动态地显示一些不规则的图形,即重写 onDraw
方法。采用这种方式需要自己支持 wrap_content,并且 padding 也需要自己处理。
主要用于实现自定义布局,采用这种方式需要合适地处理 ViewGroup 的测量、布局两个过程,并同时处理子元素的测量和布局过程。
用于扩张某种已有的View的功能
用于扩张某种已有的ViewGroup的功能
进程
==
进程(Process) 是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位,是操作系统结构的基础。
当某个应用组件启动且该应用没有运行其他任何组件时,Android 系统会使用单个执行线程为应用启动新的 Linux 进程。默认情况下,同一应用的所有组件在相同的进程和线程(称为“主”线程)中运行。
各类组件元素的清单文件条目<activity>
、<service>
、<receiver>
和 <provider>
—均支持 android:process 属性,此属性可以指定该组件应在哪个进程运行。
进程生命周期
1、前台进程
托管用户正在交互的 Activity(已调用 Activity 的 onResume()
方法)
托管某个 Service,后者绑定到用户正在交互的 Activity
托管正在“前台”运行的 Service(服务已调用 startForeground()
)
托管正执行一个生命周期回调的 Service(onCreate()
、onStart()
或 onDestroy()
)
托管正执行其 onReceive()
方法的 BroadcastReceiver
2、可见进程
托管不在前台、但仍对用户可见的 Activity(已调用其 onPause()
方法)。例如,如果 re前台 Activity 启动了一个对话框,允许在其后显示上一 Activity,则有可能会发生这种情况。
托管绑定到可见(或前台)Activity 的 Service
3、服务进程
4、后台进程
onStop()
方法)。通常会有很多后台进程在运行,因此它们会保存在 LRU (最近最少使用)列表中,以确保包含用户最近查看的 Activity 的进程最后一个被终止。5、空进程
多进程
如果注册的四大组件中的任意一个组件时用到了多进程,运行该组件时,都会创建一个新的 Application 对象。对于多进程重复创建 Application 这种情况,只需要在该类中对当前进程加以判断即可。
public class MyApplication extends Application {
@Override
public void onCreate() {
Log.d(“MyApplication”, getProcessName(android.Pid()));
}
/**
根据进程 ID 获取进程名
@param pid 进程id
@return 进程名
*/
public String getProcessName(int pid){
ActivityManager am = (ActivityManager)getSystemService(Context.ACTIVITY_SERVICE);
List<ActivityManager.RunningAppProcessInfo> processInfoList = am.getRunningAppProcesses();
if (processInfoList == null) {
return null;
}
for (ActivityManager.RunningAppProcessInfo processInfo : processInfoList) {
if (processInfo.pid == pid) {
return processInfo.processName;
}
}
return null;
}
}
一般来说,使用多进程会造成以下几个方面的问题:
- 静态成员和单例模式完全失效
- 线程同步机制完全失效
- SharedPreferences 的可靠性下降
- Application 会多次创建
进程存活
| ADJ级别 | 取值 | 解释 |
| — | — | — |
| UNKNOWN_ADJ | 16 | 一般指将要会缓存进程,无法获取确定值 |
| CACHED_APP_MAX_ADJ | 15 | 不可见进程的adj最大值 |
| CACHED_APP_MIN_ADJ | 9 | 不可见进程的adj最小值 |
| SERVICE_B_AD | 8 | B List 中的 Service(较老的、使用可能性更小) |
| PREVIOUS_APP_ADJ | 7 | 上一个App的进程(往往通过按返回键) |
| HOME_APP_ADJ | 6 | Home进程 |
| SERVICE_ADJ | 5 | 服务进程(Service process) |
| HEAVY_WEIGHT_APP_ADJ | 4 | 后台的重量级进程,system/ 文件中设置 |
| BACKUP_APP_ADJ | 3 | 备份进程 |
| PERCEPTIBLE_APP_ADJ | 2 | 可感知进程,比如后台音乐播放 |
| VISIBLE_APP_ADJ | 1 | 可见进程(Visible process) |
| FOREGROUND_APP_ADJ | 0 | 前台进程(Foreground process) |
| PERSISTENT_SERVICE_ADJ | -11 | 关联着系统或persistent进程 |
| PERSISTENT_PROC_ADJ | -12 | 系统 persistent 进程,比如telephony |
| SYSTEM_ADJ | -16 | 系统进程 |
| NATIVE_ADJ | -17 | native进程(不被系统管理) |
开启一个像素的 Activity
使用前台服务
多进程相互唤醒
JobSheduler 唤醒
粘性服务 & 与系统服务捆绑
Parcelable 接口
=============
只要实现了 Parcelable 接口,一个类的对象就可以实现序列化并可以通过 Intent 和 Binder 传递。
使用示例
import android.os.Parcel;
import android.os.Parcelable;
public class User implements Parcelable {
private int userId;
protected User(Parcel in) {
userId = in.readInt();
}
public static final Creator CREATOR = new Creator() {
@Override
public User createFromParcel(Parcel in) {
return new User(in);
}
@Override
public User[] newArray(int size) {
return new User[size];
}
};
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(userId);
}
public int getUserId() {
return userId;
}
}
方法说明
Parcel 内部包装了可序列化的数据,可以在 Binder 中自由传输。序列化功能由 writeToParcel
方法完成,最终是通过 Parcel 中的一系列 write 方法完成。反序列化功能由 CREATOR 来完成,通过 Parcel 的一系列 read 方法来完成反序列化过程。
| 方法 | 功能 |
| — | — |
| createFromParcel(Parcel in) | 从序列化后的对象中创建原始对象 |
| newArray(int size) | 创建指定长度的原始对象数组 |
| User(Parcel in) | 从序列化后的对象中创建原始对象 |
| writeToParcel(Parcel dest, int flags) | 将当前对象写入序列化结构中,其中 flags 标识有两种值:0 或者 1。为 1 时标识当前对象需要作为返回值返回,不能立即释放资源,几乎所有情况都为 0 |
| describeContents | 返回当前对象的内容描述。如果含有文件描述符,返回 1,否则返回 0,几乎所有情况都返回 0 |
Parcelable 与 Serializable 对比
Serializable 使用 I/O 读写存储在硬盘上,而 Parcelable 是直接在内存中读写
Serializable 会使用反射,序列化和反序列化过程需要大量 I/O 操作, Parcelable 自已实现封送和解封(marshalled &unmarshalled)操作不需要用反射,数据也存放在 Native 内存中,效率要快很多
IPC
===
IPC 即 Inter-Process Communication (进程间通信)。Android 基于 Linux,而 Linux 出于安全考虑,不同进程间不能之间操作对方的数据,这叫做“进程隔离”。
在 Linux 系统中,虚拟内存机制为每个进程分配了线性连续的内存空间,操作系统将这种虚拟内存空间映射到物理内存空间,每个进程有自己的虚拟内存空间,进而不能操作其他进程的内存空间,只有操作系统才有权限操作物理内存空间。 进程隔离保证了每个进程的内存安全。
IPC方式
| 名称 | 优点 | 缺点 | 适用场景 |
| — | — | — | — |
| Bundle | 简单易用 | 只能传输 Bundle 支持的数据类型 | 四大组件间的进程间通信 |
| 文件共享 | 简单易用 | 不适合高并发场景,并且无法做到进程间即时通信 | 无并发访问情形,交换简单的数据实时性不高的场景 |
| AIDL | 功能强大,支持一对多并发通信,支持实时通信 | 使用稍复杂,需要处理好线程同步 | 一对多通信且有 RPC 需求 |
| Messenger | 功能一般,支持一对多串行通信,支持实时通信 | 不能很处理高并发清醒,不支持 RPC,数据通过 Message 进行传输,因此只能传输 Bundle 支持的数据类型 | 低并发的一对多即时通信,无RPC需求,或者无需返回结果的RPC需求 |
| ContentProvider | 在数据源访问方面功能强大,支持一对多并发数据共享,可通过 Call 方法扩展其他操作 | 可以理解为受约束的 AIDL,主要提供数据源的 CRUD 操作 | 一对多的进程间数据共享 |
| Socket | 可以通过网络传输字节流,支持一对多并发实时通信 | 实现细节稍微有点烦琐,不支持直接的RPC | 网络数据交换 |
Binder
Binder 是 Android 中的一个类,实现了 IBinder 接口。从 IPC 角度来说,Binder 是 Android 中的一种扩进程通信方方式。从 Android 应用层来说,Binder 是客户端和服务器端进行通信的媒介,当 bindService 的时候,服务端会返回一个包含了服务端业务调用的 Binder 对象。
Binder 相较于传统 IPC 来说更适合于Android系统,具体原因的包括如下三点:
Binder 本身是 C/S 架构的,这一点更符合 Android 系统的架构
性能上更有优势:管道,消息队列,Socket 的通讯都需要两次数据拷贝,而 Binder 只需要一次。要知道,对于系统底层的 IPC 形式,少一次数据拷贝,对整体性能的影响是非常之大的
安全性更好:传统 IPC 形式,无法得到对方的身份标识(UID/GID),而在使用 Binder IPC 时,这些身份标示是跟随调用过程而自动传递的。Server 端很容易就可以知道 Client 端的身份,非常便于做安全检查
示例&
本文发布于:2024-01-29 17:23:09,感谢您对本站的认可!
本文链接:https://www.4u4v.net/it/170652019417024.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
留言与评论(共有 0 条评论) |