1.Android系统架构
最新的Android架构官方分为5层:
Linux内核层→硬件抽象层(HAL)→系统运行库→应用程序框架→应用程序层
https://developer.android.google.cn/guide/platform/
2.Activity生命周期
- onCreate():当Activity第一次启动时调用
- onDestroy():当Activity销毁时调用
- onStart():当Activity变为可视时调用
- onStop():当Activity不可见时调用
- onResume():当Activity中的按钮可以被点击时调用
- onPause():当Activity中的按钮失去焦点,按钮不可点击时调用
- onRestart():当界面重新启动时调用
3.Activity启动和销毁的生命周期
Activity启动:
onCreate()→onStart()→onResume()
Activity销毁:
onPause()→onStop()→onDestory()
4.横竖屏切换Activity生命周期的变化
Activity生命周期会先销毁再创建
onPause()→onStop()→onDestory()→onStart()→onResume()
5.假设当前Activity为A,如果打开一个新的Activity B,那么B的onResume()和A的onPause()哪个先执行呢?
(A)onPause()→(B)onCreate()→(B)onStart()→(B)onResume()→(A)onStop()
此时退出B页面,生命周期如下:
(B)onPause()→(A)onRestart→(A)onStart→(A)onResume()→(B)onStop()→(B)onDestroy()
6.请简述一下Activity四种启动模式
在清单文件中配置Activity的launchMode属性,有以下四种:
- standard:标准模式。Activity每启动一次,往栈里添加一次
- singleTop:栈顶复用模式。启动Activity时,如果栈顶存在这个Activity,就不往栈中添加了
- singleTask:栈内复用模式。启动Activity时,如果栈中存在这个Activity,就不往栈中添加了
- singleInstance:单实例模式。启动Activity时,会启动一个新栈单独添加这个Activity
7.Android进程和线程的区别
进程:是系统进行资源分配的独立单元,为了允许多个程序同时在内存中运行,一个进程看成一个独立的程序
线程:cpu调度的基本单元,在一个进程内可以开启多个线程,实现不同的功能。
8.Android进程间通信的方式有什么?
IPC机制,是Inter—Process Communication的缩写,含义是进程间通信或者跨进程通信,是指两个进程之间进行数据交换的过程。
由于应用程序之间不能共享内存。在不同应用程序之间交互数据(跨进程通讯),在android SDK中提供了4种用于跨进程通讯的方式。这4种方式正好对应于android系统中4种应用程序组件:Activity、Content Provider、Broadcast和Service。
其中Activity可以跨进程调用其他应用程序的Activity;Content Provider可以跨进程访问其他应用程序中的数据(以Cursor对象形式返回),当然,也可以对其他应用程序的数据进行增、删、改操 作;Broadcast可以向android系统中所有应用程序发送广播,而需要跨进程通讯的应用程序可以监听这些广播;Service和Content Provider类似,也可以访问其他应用程序中的数据,但不同的是,Content Provider返回的是Cursor对象,而Service返回的是Java对象,这种可以跨进程通讯的服务叫AIDL服务。
实现跨进程的方式有很多,比如通过Intent来传递数据,共享文件和SharedPreferences,基于Binder的Message,AIDL和Socket等。
9.介绍一下Binder机制
Binder是客户端和服务端进行通信的媒介,当bindService的时候,服务端会返回一个包含服务端业务调用的Binder对象,通过这个Binder对象,客户端就可以获取服务端提供的服务或者数据,这里的服务包括普通服务和基于AIDL的服务。
10.Android线程间通信的方式有什么?
一般说线程间通信主要是指主线程(也叫UI线程)和子线程之间的通信,主要有以下方式:
- Handler机制。
- AsyncTask机制
- runOnUiThread方法
- View.post(Runnable r)方法
- 使用Rxjava
11.介绍一下Handler机制?
Handler消息机制主要的四个类的功能
- Message:信息的携带者,持有了Handler,存在MessageQueue中,一个线程可以有多个
- Hanlder:消息的发起者,发送Message以及消息处理的回调实现,一个线程可以有多个Handler对象
- Looper:消息的遍历者,从MessageQueue中循环取出Message进行处理,一个线程最多只有一个
- MessageQueue:消息队列,存放了Handler发送的消息,供Looper循环取消息,一个线程最多只有一个
12.Android中,有哪些是基于Handler来实现通信的?
答:App的运行、更新UI、AsyncTask、Glide、RxJava等
13.处理Handler消息,是在哪个线程?一定是创建Handler的线程么?
答:创建Handler所使用的Looper所在的线程
14.消息是如何插入到MessageQueue中的?
答: 是根据when在MessageQueue中升序排序的,when=开机到现在的毫秒数+延时毫秒数
15.当MessageQueue没有消息时,它的next方法是阻塞的,会导致App ANR么?
答:不会导致App的ANR,是Linux的pipe机制保证的,阻塞时,线程挂起;需要时,唤醒线程
16.子线程中可以使用Toast么?
答:可以使用,但是Toast的显示是基于Handler实现的,所以需要先创建Looper,然后调用Looper.loop。
在子线程中直接调用toast,运行会崩溃,崩溃原因如下
java.lang.RuntimeException: Can't toast on a thread that has not called Looper.prepare()
at android.widget.Toast$TN.<init>(Toast.java:426)
at android.widget.Toast.<init>(Toast.java:125)
at android.widget.Toast.makeText(Toast.java:298)
at android.widget.Toast.makeText(Toast.java:288)
是不是我们在toast show之前调用Looper.prepare()就能显示toast了呢?
new Thread(new Runnable() {
@Override
public void run() {
Looper.prepare();
Toast.makeText(SplashActivity.this, "123", Toast.LENGTH_LONG).show();
Looper.loop();
}
}).start();
运行后toast就能正常显示了
查看toast源码可以看到,toast的显示隐藏都是在一个handler中操作的,这个handler关联的正是我们toast所在的线程的looper,这就可以看出来子线程是可以更新toast的,前提是需要提供looper。
17.Looper.loop()是死循环,可以停止么?
答:可以停止,Looper提供了quit和quitSafely方法
18.Handler内存泄露怎么解决?
答: 静态内部类+弱引用 、Handler的removeCallbacksAndMessages等方法移除MessageQueue中的消息
19.onTouch和onTouchEvent有什么区别,又该如何使用?
onTouch()→onTouchEvent()→onClick()
这两个方法都是在View的dispatchTouchEvent中调用的,onTouch优先于onTouchEvent执行。如果在onTouch方法中通过返回true将事件消费掉,onTouchEvent将不会再执行。
另外需要注意的是,onTouch能够得到执行需要两个前提条件,第一mOnTouchListener的值不能为空,第二当前点击的控件必须是enable的。因此如果你有一个控件是非enable的,那么给它注册onTouch事件将永远得不到执行。对于这一类控件,如果我们想要监听它的touch事件,就必须通过在该控件中重写onTouchEvent方法来实现。
20.Android事件分发机制?
Android事件分发是先传递到ViewGroup,再由ViewGroup传递到View的。
在ViewGroup中可以通过onInterceptTouchEvent方法对事件传递进行拦截,onInterceptTouchEvent方法返回true代表不允许事件继续向子View传递,返回false代表不对事件进行拦截,默认返回false。
子View中如果将传递的事件消费掉,ViewGroup中将无法接收到任何事件。
21.Android数据存储?
- 使用SharedPreferences存储数据
- 文件存储数据
- SQLite数据库存储数据
- 网络存储数据
- 使用ContentProvider存储数据
22.Android版本之间的区别,版本适配方案?
https://blog.csdn.net/yinhaide/article/details/103295050
Android6.0,新增了动态权限,危险权限需要动态申请。Android6.0之后,Wifi的使用更加严格。需要动态获取LOCATION权限,如果还想获取Wifi列表的话还需要打开GPS(位置信息)。
Android7.0,将不允许在 App 间,使用 file:// 的方式,传递一个 File ,否者会抛出 FileUriExposedException的错误,会直接引发 Crash,解决方案就是 FileProvider,通过 content://的模式替换掉 file://,在app开发过程中需要用到FileProvider的主要有相机拍照以及图片裁剪和
调用系统应用安装器安装apk(应用升级)。Android8.0,Android 8.0之后通知权限默认都是关闭的,无法默认开启以及通过程序去主动开启,需要程序员读取权限开启情况,然后提示用户去开启。Android 8.0中,为了更好的管制通知的提醒,不想一些不重要的通知打扰用户,新增了通知渠道,用户可以根据渠道来屏蔽一些不想要的通知。Android 8.0后安装APK必须申请权限。静态广播无法正常接收,改为动态注册。
Android9.0,刘海屏API支持。限制了明文流量的网络请求,非加密的流量请求(http)都会被系统禁止掉。前台服务需要添加权限。
Android10.0,分区存储。在后台运行时访问设备位置信息需要权限,电话、蓝牙和WLAN的API需要精确位置权限。后台启动 Activity 的限制。
Android11.0,存储机制更新。权限更新
23.介绍一下Context?
Context是上下文环境,维持Android程序中各组件能够正常工作的一个核心功能类。
Context的继承结构还是稍微有点复杂的,可以看到,直系子类有两个,一个是ContextWrapper,一个是ContextImpl。那么从名字上就可以看出,ContextWrapper是上下文功能的封装类,而ContextImpl则是上下文功能的实现类。而ContextWrapper又有三个直接的子类,ContextThemeWrapper、Service和Application。其中,ContextThemeWrapper是一个带主题的封装类,而它有一个直接子类就是Activity。
那么Context到底可以实现哪些功能呢?这个就实在是太多了,弹出Toast、启动Activity、启动Service、发送广播、操作数据库等等等等都需要用到Context。由于Context的具体能力是由ContextImpl类去实现的,因此在绝大多数场景下,Activity、Service和Application这三种类型的Context都是可以通用的。不过有几种场景比较特殊,比如启动Activity,还有弹出Dialog。出于安全原因的考虑,Android是不允许Activity或Dialog凭空出现的,一个Activity的启动必须要建立在另一个Activity的基础之上,也就是以此形成的返回栈。而Dialog则必须在一个Activity上面弹出(除非是System Alert类型的Dialog),因此在这种场景下,我们只能使用Activity类型的Context,否则将会出错。
23.list和set的区别是什么?
list和set都是接口继承于Collection接口
list:元素有序,可重复
set:元素无序,元素唯一
24.res和assets的区别?
1、子目录不同
res目录只能有一层子目录,而且这些子目录必须是预定义的,如res/layout、res/values等都是合法的,而res/abc,res/xyz并不是合法的资源目录,在assets目录中可以建任意层次的子目录(只受操作系统的限制)
2、引用资源的方式不同
res目录中的所有资源都会在R类中
assets目录中的资源需要直接使用文件名来引用,getResources().getAssets().open("xyz.xml")
3、处理方式不同
res目录中的资源子目录除了raw外,其他资源目录中的资源文件都会被编译,这也是为什么
将APK文件解压后无法直接查看XML格式资源文件内容的原因。而assets与res/raw目录中的资源
文件不会做任何处理,所以将APK解压后,这两个目录中的资源文件都会保持原样.
25.h5页面和Android怎么通信?
1、webView加载页面
2、Android本地通过Java调用HTML页面中的JavaScript方法
3、js调用Android本地Java方法
4、拦截HTML页面中的点击事件
26.BLE默认限制数据传输长度是多少?
Android系统从4.3(API 18)开始支持BLE,且从5.1(API 21)才开始支持MTU修改(默认MTU仅为23字节,而且传输本身用掉3字节)。
我们需要传输 / 接收超过20字节长度的数据时,就需要在连接设备成功后通过BluetoothGatt#requestMtu(int mtu)方法进行对应的请求设置
27.Service生命周期有哪些?
onCreat() 创建服务
onStartCommand() 开始服务
onDestroy() 销毁服务
onBind() 绑定服务
onUnbind() 解绑服务
28.Service两种启动模式的区别是什么?
startService()方法启动服务,调用者与服务之间没有任何的关联,即使调用者退出了服务,服务仍然会保持运行;
bindService()方法启动服务,调用者与服务绑定在一起,调用者退出,服务也会随着退出。绑定者可以调用服务里面的方法。
29.线程的优先级如何设置
setPriority来设置线程的优先级,这个范围是 0- 10,默认为5
30.Service中的onStartCommand()方法的三种返回值的含义以及理解
在service中,onStartCommand()方法有三种返回值:
START_STICKY(常量值:1):sticky的意思是“粘性的”。使用这个返回值时,我们启动的服务跟应用程序"粘"在一起,如果在执行完onStartCommand后,服务被异常kill掉,系统会自动重启该服务。当再次启动服务时,传入的第一个参数将为null;
START_NOT_STICKY(常量值:2):“非粘性的”。使用这个返回值时,如果在执行完onStartCommand后,服务被异常kill掉,系统不会自动重启该服务。
START_REDELIVER_INTENT(常量值:3):重传Intent。使用这个返回值时,如果在执行完onStartCommand后,服务被异常kill掉,系统会自动重启该服务,并将Intent的值传入。
【备注:】
以上三种情况,可以理解为发生车祸后的人:
START_STICKY:(常量值:1)车祸后自己苏醒,但是失忆;
START_NOT_STICKY:(常量值:2)车祸后再也没有苏醒;
START_REDELIVER_INTENT:(常量值:3)车祸后自己苏醒,依然保持记忆。