1,Activity
1.1 生命周期
正常情况系,Activity会经历如下几个阶段:
- onCreate:表示Activity正在被创建。
- onRestart:表示Activity正在被重新启动。
- onStart:表示Activity正在被启动,这时已经可见,但没有出现在前台无法进行交互。
- onResume:表示Activity已经可见,并且处于前台。
- onPause:表示Activity正在停止(可做一次保存状态停止动画等非耗时操作)。
- onStop:表示Activity即将停止(可进行重量级回收工作)。
- onDestroy:表示Activity即将被销毁。

对于生命周期,通常还会问如下的一些问题:
- 第一次启动:onCreate->onStart->onResume;
- 打开新的Activity或者返回桌面:onPause->onStop。如果打开新的Activity为透明主题,则不会调用onStop;
- 当回到原来Activity时:onRestart->onStart->onResume;
- 当按下返回键:onPause->onStop->onDestroy
1.2 启动模式
Activity的启动模式有四种:Standard、SingleTop、SingleTask和SingleInstance。
- Standard:标准模式,也是默认模式。每次启动都会创建一个全新的实例。
- SingleTop:栈顶复用模式。这种模式下如果Activity位于栈顶,不会新建实例。onNewIntent会被调用,接收新的请求信息,不会再低啊用onCreate和onStart。
- SingleTask:栈内复用模式。升级版singleTop,如果栈内有实例,则复用,并会将该实例之上的Activity全部清除。
- SingleInstance:系统会为它创建一个单独的任务栈,并且这个实例独立运行在一个 task中,这个task只有这个实例,不允许有别的Activity 存在(可以理解为手机内只有一个)。
1.3 启动流程
在理解Activity的启动流程之前,先让我们来看一下Android系统启动流程。总的来说,Android系统启动流程的主要经历init进程 -> Zygote进程 –> SystemServer进程 –> 各种系统服务 –> 应用进程等阶段。
- 启动电源以及系统启动:当电源按下时引导芯片从预定义的地方(固化在ROM)开始执行,加载引导程序BootLoader到RAM,然后执行。
- 引导程序BootLoader:BootLoader是在Android系统开始运行前的一个小程序,主要用于把系统OS拉起来并运行。
- Linux内核启动:当内核启动时,设置缓存、被保护存储器、计划列表、加载驱动。当其完成系统设置时,会先在系统文件中寻找init.rc文件,并启动init进程。
- init进程启动:初始化和启动属性服务,并且启动Zygote进程。
- Zygote进程启动:创建JVM并为其注册JNI方法,创建服务器端Socket,启动SystemServer进程。
- SystemServer进程启动:启动Binder线程池和SystemServiceManager,并且启动各种系统服务。
- Launcher启动:被SystemServer进程启动的AMS会启动Launcher,Launcher启动后会将已安装应用的快捷图标显示到系统桌面上。
Launcher进程启动后,就会调用Activity的启动了。首先,Launcher会调用ActivityTaskManagerService,然后ActivityTaskManagerService会调用ApplicationThread,然后ApplicationThread再通过ActivityThread启动Activity,完整的分析可以参考Android 之 Activity启动流程
2,Fragment
2.1 简介
Fragment,是Android 3.0(API 11)提出的,为了兼容低版本,support-v4库中也开发了一套Fragment API,最低兼容Android 1.6,如果要在最新的版本中使用Fragment,需要引入AndroidX的包。
相比Activity,Fragment具有如下一些特点:
- 模块化(Modularity):我们不必把所有代码全部写在Activity中,而是把代码写在各自的Fragment中。
- 可重用(Reusability):多个Activity可以重用一个Fragment。
- 可适配(Adaptability):根据硬件的屏幕尺寸、屏幕方向,能够方便地实现不同的布局,这样用户体验更好。
Fragment有如下几个核心的类:
- Fragment:Fragment的基类,任何创建的Fragment都需要继承该类。
- FragmentManager:管理和维护Fragment。他是抽象类,具体的实现类是FragmentManagerImpl。
- FragmentTransaction:对Fragment的添加、删除等操作都需要通过事务方式进行。他是抽象类,具体的实现类是BackStackRecord。
2.2 生命周期
Fragment必须是依存于Activity而存在的,因此Activity的生命周期会直接影响到Fragment的生命周期。相比Activity的生命周期,Fragment的生命周期如下所示。
- onAttach():Fragment和Activity相关联时调用。如果不是一定要使用具体的宿主 Activity 对象的话,可以使用这个方法或者getContext()获取 Context 对象,用于解决Context上下文引用的问题。同时还可以在此方法中可以通过getArguments()获取到需要在Fragment创建时需要的参数。
- onCreate():Fragment被创建时调用。
- onCreateView():创建Fragment的布局。
- onActivityCreated():当Activity完成onCreate()时调用。
- onStart():当Fragment可见时调用。
- onResume():当Fragment可见且可交互时调用。
- onPause():当Fragment不可交互但可见时调用。
- onStop():当Fragment不可见时调用。
- onDestroyView():当Fragment的UI从视图结构中移除时调用。
- onDestroy():销毁Fragment时调用。
- onDetach():当Fragment和Activity解除关联时调用。
如下图所示:

下面是Activity的生命周期和Fragment的各个生命周期方法的对应关系。

2.3 与Activity传递数据
2.3.1 Fragment向Activity传递数据
首先,在Fragment中定义接口,并让Activity实现该接口,如下所示。
public interface OnFragmentInteractionListener {
void onItemClick(String str);
}
然后,在Fragment的onAttach()中,将参数Context强转为OnFragmentInteractionListener对象传递过去。
public void onAttach(Context context) {
super.onAttach(context);
if (context instanceof OnFragmentInteractionListener) {
mListener = (OnFragmentInteractionListener) context;
} else {
throw new RuntimeException(context.toString()
+ " must implement OnFragmentInteractionListener");
}
}
2.3.2 Activity向Fragment传递数据
在创建Fragment的时候,可以通过setArguments(Bundle bundle)方式将值传递给Activity,如下所示。
public static Fragment newInstance(String str) {
FragmentTest fragment = new FragmentTest();
Bundle bundle = new Bundle();
bundle.putString(ARG_PARAM, str);
fragment.setArguments(bundle);//设置参数
return fragment;
}
3, Service
3.1 启动方式
Service的启动方式主要有两种,分别是startService和bindService。
其中,StartService使用的是同一个Service,因此onStart()会执行多次,onCreate()只执行一次,onStartCommand()也会执行多次。使用bindService启动时,onCreate()与onBind()都只会调用一次。
使用startService启动时是单独开一个服务,与Activity没有任何关系,而bindService方式启动时,Service会和Activity进行绑定,当对应的activity销毁时,对应的Service也会销毁。
3.2 生命周期
下图是startService和bindService两种方式启动Service的示意图。

3.2.1 startService
- onCreate():如果service没被创建过,调用startService()后会执行onCreate()回调;如果service已处于运行中,调用startService()不会执行onCreate()方法。
- onStartCommand():多次执行了Context的startService()方法,那么Service的onStartCommand()方法也会相应的多次调用。
-
onBind():Service中的onBind()方法是抽象方法,Service类本身就是抽象类,所以onBind()方法是必须重写的,即使我们用不到。
onDestory():在销毁Service的时候该方法。
public class TestOneService extends Service{
@Override
public void onCreate() {
Log.i("Kathy","onCreate - Thread ID = " + Thread.currentThread().getId());
super.onCreate();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.i("Kathy", "onStartCommand - startId = " + startId + ", Thread ID = " + Thread.currentThread().getId());
return super.onStartCommand(intent, flags, startId);
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
Log.i("Kathy", "onBind - Thread ID = " + Thread.currentThread().getId());
return null;
}
@Override
public void onDestroy() {
Log.i("Kathy", "onDestroy - Thread ID = " + Thread.currentThread().getId());
super.onDestroy();
}
}
3.2.2 bindService
bindService启动的服务和调用者之间是典型的Client-Server模式。调用者是client,Service则是Server端。Service只有一个,但绑定到Service上面的Client可以有一个或很多个。bindService启动服务的生命周期与其绑定的client息息相关。
1,首先,在Service的onBind()方法中返回IBinder类型的实例。
2,onBInd()方法返回的IBinder的实例需要能够返回Service实例本身。
3.3 Service不被杀死
现在,由于系统API的限制,一些常见的不被杀死Service方式已经过时,比如下面是之前的一些方式。
3.3.1, onStartCommand方式中,返回START_STICKY。
调用Context.startService方式启动Service时,如果Android面临内存匮乏,可能会销毁当前运行的Service,待内存充足时可以重建Service。而Service被Android系统强制销毁并再次重建的行为依赖于Service的onStartCommand()方法的返回值,常见的返回值有如下一些。
START_NOT_STICKY:如果返回START_NOT_STICKY,表示当Service运行的进程被Android系统强制杀掉之后,不会重新创建该Service。
START_STICKY:如果返回START_STICKY,表示Service运行的进程被Android系统强制杀掉之后,Android系统会将该Service依然设置为started状态(即运行状态),但是不再保存onStartCommand方法传入的intent对象,即获取不到intent的相关信息。
START_REDELIVER_INTENT:如果返回START_REDELIVER_INTENT,表示Service运行的进程被Android系统强制杀掉之后,与返回START_STICKY的情况类似,Android系统会将再次重新创建该Service,并执行onStartCommand回调方法,但是不同的是,Android系统会再次将Service在被杀掉之前最后一次传入onStartCommand方法中的Intent再次保留下来并再次传入到重新创建后的Service的onStartCommand方法中,这样我们就能读取到intent参数。
4, BroadcastReceiver
4.1 BroadcastReceiver是什么
BroadcastReceiver,广播接收者,它是一个系统全局的监听器,用于监听系统全局的Broadcast消息,所以它可以很方便的进行系统组件之间的通信。BroadcastReceiver属于系统级的监听器,它拥有自己的进程,只要存在与之匹配的Broadcast被以Intent的形式发送出来,BroadcastReceiver就会被激活。
和其他的四大组件一样,BroadcastReceiver也有自己独立的声明周期,但是它又和Activity、Service不同。当在系统注册一个BroadcastReceiver之后,每次系统以一个Intent的形式发布Broadcast的时候,系统都会创建与之对应的BroadcastReceiver广播接收者实例,并自动触发它的onReceive()方法,当onReceive()方法被执行完成之后,BroadcastReceiver的实例就会被销毁。
从不同的纬度区分,BroadcastReceiver可以分为不同的类别。
- 系统广播/非系统广播
- 全局广播/本地广播
- 无序广播/有序广播/粘性广播
4.2 基本使用
4.2.1 注册广播
广播的注册分为静态注册和动态注册。静态注册是在Mainfest清单文件中进行注册,比如。
动态注册是在代码中,使用registerReceiver方法代码进行注册,比如。
val br: BroadcastReceiver = MyBroadcastReceiver()
val filter = IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION).apply {
addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED)
}
registerReceiver(br, filter)
4.2.2 发送广播
然后,我们使用sendBroadcast方法发送广播。
Intent().also { intent ->
intent.setAction("com.example.broadcast.MY_NOTIFICATION")
intent.putExtra("data", "Notice me senpai!")
sendBroadcast(intent)
}
4.2.3 接收广播
发送广播的时候,我们会添加一个发送的标识,那么接收的时候使用这个标识接收即可。接收广播需要继承BroadcastReceiver,并重写onReceive回调方法接收广播数据。
private const val TAG = "MyBroadcastReceiver"
class MyBroadcastReceiver : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
StringBuilder().apply {
append("Action: ${intent.action}n")
append("URI: ${intent.toUri(Intent.URI_INTENT_SCHEME)}n")
toString().also { log ->
Log.d(TAG, log)
Toast.makeText(context, log, Toast.LENGTH_LONG).show()
}
}
}
}
5, ContentProvider
ContentProvider是Android四大组件之一,不过平时使用的机会比较少。如果你看过它的底层源码,那么就应该知道ContentProvider是通过Binder进行数据共享。因此,如果我们需要对第三方应用提供数据,可以考虑使用ContentProvider实现。
6,Android View知识点
Android本身的View体系非常庞大的,如果要完全弄懂View的原理是很困难的,我们这里捡一些比较重要的概念来给大家讲解。
6.1 测量流程
Android View本身的绘制流程需要经过measure测量、layout布局、draw绘制三个过程,最终才能够将其绘制出来并展示在用户面前。
首先,我们看一下Android的MeasureSpec,Android的MeasureSpec分为3中模式,分别是EXACTLY、AT_MOST 和 UNSPECIFIED,含义如下。
- MeasureSpec.EXACTLY:精确模式,在这种模式下,尺寸的值是多少组件的长或宽就是多少。
- MeasureSpec.AT_MOST:最大模式,由父组件能够给出的最大的空间决定。
- MeasureSpec.UNSPECIFIED:未指定模式,当前组件可以随便使用空间,不受限制。
6.2 事件分发
Android的事件分发由dispatchTouchEvent、onInterceptTouchEvent和onTouchEvent三个方法构成。
- dispatchTouchEvent:方法返回值为true,表示事件被当前视图消费掉;返回为super.dispatchTouchEvent表示继续分发该事件,返回为false表示交给父类的onTouchEvent处理。
-
onInterceptTouchEvent:方法返回值为true,表示拦截这个事件并交由自身的onTouchEvent方法进行消费;返回false表示不拦截,需要继续传递给子视图。如果return super.onInterceptTouchEvent(ev), 事件拦截分两种情况:即一种是有子View的情况,另一种是没有子View的情况。
如果该View存在子View且点击到了该子View,则不拦截,继续分发
给子View 处理,此时相当于return false。如果该View没有子View或者有子View但是没有点击中子View,则交由该View的onTouchEvent响应,此时相当于return true。 - onTouchEvent:方法返回值为true表示当前视图可以处理对应的事件;返回值为false表示当前视图不处理这个事件,它会被传递给父视图的onTouchEvent方法进行处理。如果return super.onTouchEvent(ev),事件处理分为两种情况,即自己消费还是还是向上传递。
在Android系统中,拥有事件传递处理能力的类有以下三种:
- Activity:拥有分发和消费两个方法。
- ViewGroup:拥有分发、拦截和消费三个方法。
- View:拥有分发、消费两个方法。
在事件分发中,有时候会问:ACTION_CANCEL什么时候触发,触摸button然后滑动到外部抬起会触发点击事件吗,再滑动回去抬起会么?
对于这个问题,我们需要明白以下内容:
- 一般ACTION_CANCEL和ACTION_UP都作为View一段事件处理的结束。如果在父View中拦截ACTION_UP或ACTION_MOVE,在第一次父视图拦截消息的瞬间,父视图指定子视图不接受后续消息了,同时子视图会收到ACTION_CANCEL事件。
- 如果触摸某个控件,但是又不是在这个控件的区域上抬起,也会出现ACTION_CANCEL。


- ViewGroup 默认不拦截任何事件。ViewGroup 的 onInterceptTouchEvent 方法默认返回 false。
- View 没有 onInterceptTouchEvent 方法,一旦有点击事件传递给它,onTouchEvent 方法就会被调用。
- View 在可点击状态下,onTouchEvent 默认会消耗事件。
- ACTION_DOWN 被拦截了,onInterceptTouchEvent 方法执行一次后,就会留下记号(mFirstTouchTarget == null)那么往后的 ACTION_MOVE 和 ACTION_UP 都会拦截。`
6.3 MotionEvent
Android的MotionEvent事件主要有以下几个:
- ACTION_DOWN 手指刚接触到屏幕
- ACTION_MOVE 手指在屏幕上移动
- ACTION_UP 手机从屏幕上松开的一瞬间
- ACTION_CANCEL 触摸事件取消
下面是事件的举例:点击屏幕后松开,事件序列为 DOWN -> UP,点击屏幕滑动松开,事件序列为 DOWN -> MOVE -> …> MOVE -> UP。同时,getX/getY 返回相对于当前View左上角的坐标,getRawX/getRawY 返回相对于屏幕左上角的坐标。TouchSlop是系统所能识别出的被认为滑动的最小距离,不同设备值可能不相同,可通过ViewConfiguration.get(getContext()).getScaledTouchSlop() 获取。
6.4 Activity、Window、DecorView之间关系
首先,来看一下Activity中setContentView的源代码。
public void setContentView(@LayoutRes int layoutResID) {
//将xml布局传递到Window当中
getWindow().setContentView(layoutResID);
initWindowDecorActionBar();
}
可以看到, Activity的 setContentView实质是将 View传递到 Window的 setContentView()方法中, Window的 setContenView会在内部调用 installDecor()方法创建 DecorView,代码如下。
public void setContentView(int layoutResID) {
if (mContentParent == null) {
//初始化DecorView以及其内部的content
installDecor();
} else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
mContentParent.removeAllViews();
}
if (hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
...............
} else {
//将contentView加载到DecorVoew当中
mLayoutInflater.inflate(layoutResID, mContentParent);
}
...............
}
private void installDecor() {
...............
if (mDecor == null) {
//实例化DecorView
mDecor = generateDecor(-1);
...............
}
} else {
mDecor.setWindow(this);
}
if (mContentParent == null) {
//获取Content
mContentParent = generateLayout(mDecor);
}
...............
}
protected DecorView generateDecor(int featureId) {
...............
return new DecorView(context, featureId, this, getAttributes());
}
通过 generateDecor()的new一个 DecorView,然后调用 generateLayout()获取 DecorView中 content,最终通过 inflate将 Activity视图添加到 DecorView中的 content中,但此时 DecorView还未被添加到 Window中。添加操作需要借助 ViewRootImpl。
ViewRootImpl的作用是用来衔接 WindowManager和 DecorView,在 Activity被创建后会通过 WindowManager将 DecorView添加到 PhoneWindow中并且创建 ViewRootImpl实例,随后将 DecorView与 ViewRootImpl进行关联,最终通过执行 ViewRootImpl的 performTraversals()开启整个View树的绘制。
6.5 Draw 绘制流程
Android的Draw过程可以分为六个步骤:
- 首先,绘制View的背景;
- 如果需要的话,保持canvas的图层,为fading做准备;
- 然后,绘制View的内容;
- 接着,绘制View的子View;
- 如果需要的话,绘制View的fading边缘并恢复图层;
- 最后,绘制View的装饰(例如滚动条等等)。
涉及到的代码如下:
public void draw(Canvas canvas) {
...
// 步骤一:绘制View的背景
drawBackground(canvas);
...
// 步骤二:如果需要的话,保持canvas的图层,为fading做准备
saveCount = canvas.getSaveCount();
...
canvas.saveLayer(left, top, right, top + length, null, flags);
...
// 步骤三:绘制View的内容
onDraw(canvas);
...
// 步骤四:绘制View的子View
dispatchDraw(canvas);
...
// 步骤五:如果需要的话,绘制View的fading边缘并恢复图层
canvas.drawRect(left, top, right, top + length, p);
...
canvas.restoreToCount(saveCount);
...
// 步骤六:绘制View的装饰(例如滚动条等等)
onDrawForeground(canvas)
}
6.6 Requestlayout,onlayout,onDraw,DrawChild区别与联系
- requestLayout():会导致调用 measure()过程 和 layout()过程,将会根据标志位判断是否需要ondraw。
- onLayout():如果该View是ViewGroup对象,需要实现该方法,对每个子视图进行布局。
- onDraw():绘制视图本身 (每个View都需要重载该方法,ViewGroup不需要实现该方法)。
- drawChild():去重新回调每个子视图的draw()方法。
6.7 invalidate() 和 postInvalidate()的区别
invalidate()与postInvalidate()都用于刷新View,主要区别是invalidate()在主线程中调用,若在子线程中使用需要配合handler;而postInvalidate()可在子线程中直接调用。
PS:关于我

本人是一个拥有6年开发经验的帅气Android攻城狮,记得看完点赞,养成习惯,关注这个喜欢写干货的程序员。
另外耗时两年整理收集的Android一线大厂面试完整考点PDF出炉,【完整版】已更新在我的【Github】,如有面试、进阶需要的朋友们可以去参考参考,如果对你有帮助,可以点个Star哦!
地址:【https://github.com/733gh/xiongfan】
