(一)
接触 Android 开发也有一段时间了,前段时间便开始想抽空整理一些知识点,通过笔记整理的方式减少自己重复学习的时间成本和提高自身的效率。
目前先是总结了部分 Android 的知识点,这就是本文的主要分享内容。想特意申明的一点是,这个总结更多的是从本人自己的编程基础和侧重点出发,所以在内容上会有选择性的忽略以及侧重点,参考的博客和图文有很多,没办法一一列出,如果有引用不当的部分会立即删除,望大家见谅。 知识点目录可以再右边侧边栏查看跳转。
另外,之后会整理的知识点还会有 java、Android 源码、其他的一些计算机基础以及常见的面试题等几个部分,往后的一个月时间里会陆续补充更新,在 Github 上创建了项目,想关注的欢迎 star 。
Android复习资料
Android复习资料——Java知识点汇总(一)
进程和线程
当某个应用组件启动且该应用没有运行其他任何组件时,Android 系统会使用单个执行线程为应用启动新的 Linux 进程。默认情况下,同一应用的所有组件在相同的进程和线程(称为“主”线程)中运行。
各类组件元素的清单文件条目、、 和 —均支持 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、服务进程
正在运行已使用 startService() 方法启动的服务且不属于上述两个更高类别进程的进程。
4、后台进程
包含目前对用户不可见的 Activity 的进程(已调用 Activity 的 onStop() 方法)。通常会有很多后台进程在运行,因此它们会保存在 LRU (最近最少使用)列表中,以确保包含用户最近查看的 Activity 的进程最后一个被终止。
5、空进程
不含任何活动应用组件的进程。保留这种进程的的唯一目的是用作缓存,以缩短下次在其中运行组件所需的启动时间。 为使总体系统资源在进程缓存和底层内核缓存之间保持平衡,系统往往会终止这些进程。
多进程
如果注册的四大组件中的任意一个组件时用到了多进程,运行该组件时,都会创建一个新的 Application 对象。对于多进程重复创建 Application 这种情况,只需要在该类中对当前进程加以判断即可。
public class MyApplication extends Application {
@Override
public void onCreate() {
Log.d("MyApplication", getProcessName(android.os.Process.myPid()));
super.onCreate();
}
/**
* 根据进程 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;
}
}
复制代码
进程存活
OOM_ADJ
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/rootdir/init.rc文件中设置
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唤醒
粘性服务&与系统服务捆绑
线程
应用启动时,系统会为应用创建一个名为“主线程”的执行线程( UI 线程)。 此线程非常重要,因为它负责将事件分派给相应的用户界面小部件,其中包括绘图事件。 此外,它也是应用与 Android UI 工具包组件(来自 android.widget 和 android.view 软件包的组件)进行交互的线程。
系统不会为每个组件实例创建单独的线程。运行于同一进程的所有组件均在 UI 线程中实例化,并且对每个组件的系统调用均由该线程进行分派。 因此,响应系统回调的方法(例如,报告用户操作的 onKeyDown() 或生命周期回调方法)始终在进程的 UI 线程中运行。
Android 的单线程模式必须遵守两条规则:
不要阻塞 UI 线程
不要在 UI 线程之外访问 Android UI 工具包
为解决此问题,Android 提供了几种途径来从其他线程访问 UI 线程:
Activity.runOnUiThread(Runnable)
View.post(Runnable)
View.postDelayed(Runnable, long)
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 网络数据交换
AIDL
Android Interface Definition Language
新建AIDL接口文件
// RemoteService.aidl
package com.example.mystudyapplication3;
interface IRemoteService {
int getUserId();
}
复制代码
创建远程服务
public class RemoteService extends Service {
private int mId = -1;
private Binder binder = new IRemoteService.Stub() {
@Override
public int getUserId() throws RemoteException {
return mId;
}
};
@Nullable
@Override
public IBinder onBind(Intent intent) {
mId = 1256;
return binder;
}
}
复制代码
声明远程服务
复制代码
绑定远程服务
public class MainActivity extends AppCompatActivity {
public static final String TAG = "wzq";
IRemoteService iRemoteService;
private ServiceConnection mConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
iRemoteService = IRemoteService.Stub.asInterface(service);
try {
Log.d(TAG, String.valueOf(iRemoteService.getUserId()));
} catch (RemoteException e) {