1.静态和动态广播的区别?
生存期:静态广播的生存期可以比动态广播的长很多,因为静态广播很多都是用来对系统时间进行监听,比如我们可以监听手机开机。而动态广播会随着context的终止而终止
优先级:动态广播的优先级比静态广播高
注册:动态广播无需在AndroidManifest.xml中声明即可直接使用(用receiver注册),也即动态;而静态广播则需要,有时候还要在AndroidManifest.xml中加上一些权限的声明。静态注册是当程序关闭后,如果有广播发过来,还能启动程序。动态注册的生命周期跟程序的生命周期是一样的,程序关闭后动态注册的广播是不能在接收到广播的
动态注册的优点:在Android的广播机制中,动态注册的优先级高于静态注册的优先级,因此在必要情况下,我们需要动态注册广播接收器。
静态注册的优点:动态注册广播接收器还有一个优点就是当用来注册广播的Activity关闭后,广播也就失效了,同时反映了静态注册广播的一个优势,就是无需担心广播接收器是否关闭,只要设备处于开启状态,广播接收器就能接收。
2.一个应用是否可以有多个进程?
在AndroidManifest.xml的声明四大组件的标签中增加"android:process"属性即可,process分私有进程和全局进程,私有进程的名称前面有冒号,全局进程没有
<activity android:name=".OtherProcessActivity"
android:process=":other">
</activity>
私有进程:其它应用的组件不可以和它跑在同一个进程中
全局进程:其它应用可以通过shareUID方式和它跑在同一个进程中(相同的shareUID和签名)
ShareUID:在Android里,每个app都有一个唯一的linux user ID,因此权限就被设置成该应用程序的文件只对该用户和应用程序自身可见。假如让两个app使用相同的userID,不论是否在同一个进程,它们都能看到对方的文件,比如data目录,组件信息等。如果在同一个进程,还可以共享内存数据。
3.两个service同进程和不同进程aidl有什么区别?
4.mqtt和http的区别?
MQTT
MQTT协议是为大量计算能力有限,且工作在低带宽、不可靠的网络的远程传感器和控制设备通讯而设计的协议,它具有以下主要的几项特性:
- 使用发布/订阅消息模式,提供一对多的消息发布,解除应用程序耦合;
- 对负载内容屏蔽的消息传输;
- 使用 TCP/IP 提供网络连接;
- 有三种消息发布服务质量:
- “至多一次”,消息发布完全依赖底层 TCP/IP 网络。会发生消息丢失或重复。这一级别可用于如下情况,环境传感器数据,丢失一次读记录无所谓,因为不久后还会有第二次发送。
- “至少一次”,确保消息到达,但消息重复可能会发生。
- “只有一次”,确保消息到达一次。这一级别可用于如下情况,在计费系统中,消息重复或丢失会导致不正确的结果。
HTTP
HTTP是一个属于应用层的,基于TCP/IP通信协议来传递数据(HTML 文件, 图片文件, 查询结果等)。
通信方式
- 浏览器作为HTTP客户端通过URL向HTTP服务端即WEB服务器发送请求。Web服务器根据接收到的请求后,向客户端发送响应信息。
- HTTP之请求消息Request:请求行(request line)、请求头部(header)、空行和请求数据四个部分组成。
- HTTP之响应消息Response:HTTP响应也由四个部分组成,分别是:状态行、消息报头、空行和响应正文。
- 若connection 模式为close,则服务器会主动关闭TCP连接,客户端被动关闭连接,释放TCP连接;若connection 模式为keepalive,则该连接会保持一段时间,在该时间内可以继续接收请求;
5.fragment和activity怎么通讯?
1、通过构造器
2、通过广播
3、通过EventBus
4、通过接口回调
5、通过ViewModel
6、通过Handler
6.layout优化方法?
一. 优化Layout层级
二. 重用Layout
三. 按需加载Layout
四. 优化ListView
1.线程有哪几种状态,他们之间怎么转化?
线程的六种状态
线程的生命周期主要有以下六种
New(新创建)
Runnable(可运行)
Blocked(被阻塞)
Waiting(等待)
Timed Waiting(计时等待)
Terminated(被终止)
通过getState()方法可以查看当前线程的状态
New(新创建)
表示线程被创建但是还没有启动的状态
1、当我们用 New Thread() 新建一个线程的时候,
2、如果该线程没有被start()的方法调用运行,
3、且没有开始执行run()方法 那么该线程的状态讲究是New
Runnable(可运行)
Java 中的 Runable 状态对应操作系统线程状态中的两种状态,分别是 Running和Ready
也就是说,Java中处于Runnab1e 状态的线程有可能正在执行,也有可能没有正在执行,正在等待被分配CPU资源。
所以,如果一个正在运行的线程是Runnable状态,当它运行到任务的一半时,执行该线程的CPU被调度去做其他事情,导致该线程暂时不运行,它的状态依然不变,还是Runnable,因为它有可能随时被调度回来继续执行任务
。
阻塞状态
这三个状态我们可以统称为阻塞状态
Blocked(被阻塞)、waiting(等待)、Timed waiting(计时等待)
Blocked(被阻塞)
当线程进入到synchronized 代码块中时未能获得相应的monitor锁,此时线程从Runnable状态进入到 Blocked状态
waiting(等待)
当线程中调用了没有设置 Timeout参数的object.wait()方法
当线程调用了没有设置Timeout参数的Thread.join()方法
当线程调用了Locksupport. park()方法
Blocked与 waiting 的区别
Blocked是在等待其他线程释放monitor锁
waiting则是在等待某个条件,比如 join的线程执行完毕,或者是notify()/notifyAll()
Timed waiting(计时等待)
Timed waiting 状态与 waiting 状态非常相似,其中的区别只在于是否有时间的限制,在Timed waiting
状态时会等待超时,之后由系统唤醒,或者也可以提前被通知唤醒如notify
以下情况会让线程进入Timed waiting状态。
线程执行了设置了时间参数的Thread.sleep(long millis)方法;
线程执行了设置了时间参数的object.wait(long timeout)方法;
线程执行了设置了时间参数的Thread.join(long mi17is)方法;
线程执行了设置了时间参数的Locksupport.parkNanos(long nanos)方法和Locksupport.parkuntil(long deadline)方法。
线程状态转换
Blocked(被阻塞)转换 Runnable(可运行)状态
当线程进入到synchronized 代码块中获得相应的monitor锁,此时线程从Blocked状态进入到 Runnable状态
当线程进入到synchronized 代码块中线程被阻塞,当其获得相应的monitor锁之后,线程又会变为Runnable(可运行)状态
Waiting(等待) 和 Timed Waiting(计时等待)转换 Runnable(可运行)状态
在线程中执行 notify()和notifyAll(),
它们会先进入 Blocked状态,然后抢夺锁成功后,再回到Runnable状态。
Terminated终止状态
run()方法执行完毕,线程正常退出。
出现一个没有捕获的异常,终止了run()方法,最终导致意外终止。
2.Android提供的线程之间的交互方式有哪些?
-
Handler机制:通过Handler对象可以向其他线程发送消息或者post Runnable对象,其他线程向Handler对象发送的消息或者Runnable对象将会在Handler所在的线程中被处理。
-
AsyncTask异步任务:主要用于在后台线程执行需要一些时间完成的任务,然后将结果返回给主线程,让主线程进行更新UI操作。
-
BroadcastReceiver机制:允许一个线程(通常是主线程)注册一个BroadcastReceiver并监听某些特定操作,其他线程可以在某些状态发生改变的时候发送广播,这个广播会被BroadcastReceiver接收并处理。
-
IntentService:可以在后台线程完成一些耗时的操作,并适当地与主线程交互。
-
ThreadPoolExecutor:提供了一个线程池,可以让多个线程共享资源,减少线程的数量,提高效率。
-
Messenger机制:通过该机制,可以在不同的线程之间传递Message对象,其他线程可以在处理Message时与UI交互。
-
CompletableFuture:从Java 8开始,在Android O及更高版本中,该类可用于异步编程和多线程中的协作。它可以等待一个Future对象的结果,并且可以指定一个回调方法,在Future对象完成计算后自动调用。
3.service是否可以在主线程启动,怎么在主线程启动,怎么在其他线程启动?
在主线程中启动Service,可以使用startService()方法,这个方法是异步的,调用之后会立即返回,Service的生命周期方法会在另一个线程中执行。
在其他线程中启动Service,可以使用Context的bindService()方法,这个方法也是异步的,Service的生命周期方法会在调用线程中执行。同时需要注意的是,如果Service需要执行耗时操作,还需要创建独立的线程进行处理,避免阻塞调用线程。
4.Android 多屏幕适配的方法?
- 使用 ConstraintLayout 或者 RelativeLayout 等布局方式,避免使用绝对坐标。
- 使用dp单位代替px单位进行布局,dp会根据屏幕密度进行适配。
- 使用多套不同分辨率的图片,将其放在不同的drawable文件夹下面。
- 使用宽高百分比,让控件根据屏幕宽高进行自适应。
- 使用限制最大最小宽高的属性 max/minWidth 和 max/minHeight 属性,以确保不会出现被拉伸或压缩的情况。
- 使用 dimen.xml 统一管理所有尺寸,方便后期维护。
- 针对平板等大屏幕设备,推荐使用 Fragment 进行适配和布局。
- 最好使用 Material Design 设计规范,相对更容易适配不同的设备。
5.Android 进程间的通讯方式有哪些?
- AIDL(Android Interface Definition Language):这是一种用于定义进程间通信接口的语言。通过 AIDL,你可以定义接口并在不同的进程之间传递对象。这种方式的优点是功能强大,支持实时通信,但使用稍微复杂。
- ContentProvider:ContentProvider 是 Android 系统提供的一种数据共享方式,它可以跨进程访问其他应用程序中的数据。通过实现 ContentProvider,你可以在其他应用程序中共享你的数据,并允许其他应用程序对数据进行增、删、改操作。这种方式的优点是简单易用,但使用受限,只能根据特定规则访问数据。
- BroadcastReceiver:BroadcastReceiver 可以用于在应用程序之间发送和接收广播。当某个应用程序发出广播时,其他应用程序可以监听这些广播并接收广播数据。这种方式的优点是简单易用,但只适用于一对多的通信场景。
- Bundle:Bundle 是 Android 四大组件间进程间通信的一种方式。它可以将数据打包成一个 Bundle 对象,并通过 Intent 或其他方式传递给其他进程。这种方式的优点是简单易用,但传输的数据类型受限。
- 文件共享:文件共享也是一种进程间通信的方式,但不适合高并发场景,并且无法做到进程间的及时通信。
- Messenger:Messenger 是通过 Message 对象进行通信的一种方式。它只能传输 Bundle 支持的数据类型,不涉及方法调用,也不需要高并发。
- Socket:Socket 是网络数据交换的常用方式,也可以用于不同进程之间的通信。但这种方式需要更多的网络编程知识,并且通信双方需要建立连接。
6.Android 为什么不能在子线程更新View?
在Android中,UI操作必须在主线程中执行,因为Android UI框架不是线程安全的。如果你尝试在子线程中更新UI,可能会引起以下问题:
- 调用非UI线程会抛出android.view.ViewRootImpl$CalledFromWrongThreadException异常;
- 可能会导致UI组件状态异常或崩溃;
- 可能会导致界面卡顿甚至ANR(Application Not Responding)。
因此,为了避免这些问题,Android中规定UI操作必须在主线程中执行。你可以使用Handler、AsyncTask、runOnUiThread等方式让子线程与主线程交互,让子线程通过这些方式向主线程发送消息,然后主线程在收到消息后执行UI更新操作。
1.Handler postDelay是怎么实现的?
postDelay()
一个10秒钟的Runnable A、消息进队,MessageQueue调用nativePollOnce()
阻塞,Looper阻塞;- 紧接着
post()
一个Runnable B、消息进队,判断现在A时间还没到、正在阻塞,把B插入消息队列的头部(A的前面),然后调用nativeWake()
方法唤醒线程; MessageQueue.next()
方法被唤醒后,重新开始读取消息链表,第一个消息B无延时,直接返回给Looper;- Looper处理完这个消息再次调用
next()
方法,MessageQueue继续读取消息链表,第二个消息A还没到时间,计算一下剩余时间(假如还剩9秒)继续调用nativePollOnce()
阻塞; - 直到阻塞时间到或者下一次有Message进队;
2.MessageQueue是什么数据结构?
MessageQueue的数据结构,是一个单向链表,Message对象有个next字段保存列表中的下一个,MessageQueue中的mMessages保存链表的第一个元素。
3.广播是怎么做到多进程通讯的?
BroadcastManager(Android 4.4 及以下版本)
在 Android 4.4 及以下版本中,BroadcastManager
负责管理广播的发送和接收。它主要通过以下几个步骤实现:
- 注册广播接收器:应用程序可以通过调用
Context.registerReceiver()
方法来注册广播接收器。注册信息会被存储在BroadcastManager
中。 - 发送广播:当应用程序需要发送广播时,它会调用
Context.sendBroadcast()
或Context.sendOrderedBroadcast()
方法。这些方法会将广播传递给BroadcastManager
。 - 分发广播:
BroadcastManager
会遍历所有已注册的广播接收器,找到与广播匹配的接收器,并将广播分发给它们。这个过程是在系统级别进行的,因此可以实现跨进程通信。
BroadcastQueue(Android 5.0 及更高版本)
在 Android 5.0 及更高版本中,BroadcastQueue
取代了 BroadcastManager
,负责广播的分发。BroadcastQueue
是一个系统服务,运行在 SystemServer
进程中。它的实现方式如下:
- 注册广播接收器:应用程序仍然可以通过调用
Context.registerReceiver()
方法来注册广播接收器。但与BroadcastManager
不同的是,注册信息会被存储在系统的服务中,而不是BroadcastManager
中。 - 发送广播:当应用程序发送广播时,它会将广播传递给
ActivityManagerService
(AMS)。AMS 会将广播放入BroadcastQueue
中。 - 分发广播:
BroadcastQueue
会根据广播的优先级和其他规则,决定广播的分发顺序。然后,它会遍历所有已注册的广播接收器,将广播分发给匹配的接收器。这个过程同样是在系统级别进行的,因此可以实现跨进程通信。
4.单例模式volatile的作用?
- 保证有序性,禁止指令重排序。在执行instance = new Singleton()语句时,一共有三步操作,包括在堆中分配内存、调用构造函数进行初始化、将instance引用指向内存地址。在这三步操作中,有可能会发生指令重排序,即有两种结果可能产生:123与132。volatile关键字的作用就是防止这种情况发生,保证instance引用的初始化顺序。
- 保证共享变量对所有线程的内存可见性。在多线程环境中,如果多个线程同时操作一个变量,可能会出现内存可见性问题,即某个线程修改了变量的值之后,其他线程感知不到变量的修改。volatile关键字可以确保将变量的更新操作通知到其他线程,当变量声明为volatile后,则编译时与运行时都会注意到这个变量是共享的,因此不会将该变量上的操作与其它内存操作一起重排序。
总的来说,volatile关键字在Java单例模式中起着非常重要的作用,它可以确保单例对象的唯一性和线程安全。
5.onMeasure什么时候需要重写?
在Android开发中,onMeasure
方法是View类中的一个重要方法,用于测量视图的大小。通常情况下,你不需要经常重写onMeasure
方法,但在某些特定情况下,你可能需要重写它来自定义视图的大小测量逻辑。
以下是一些可能需要重写onMeasure
方法的场景:
- 自定义视图大小:当你创建一个自定义视图时,并且希望该视图具有特定的大小或基于其内容(如文本、图像等)的大小来测量大小时,你需要重写
onMeasure
方法。 - 动态内容大小:如果你的视图内容在运行时可能发生变化(例如,文本长度变化或图像加载后大小改变),并且这些变化会影响视图的整体大小,你可能需要重写
onMeasure
方法来重新计算大小。 - 复杂布局逻辑:在某些复杂的布局情况下,标准的布局参数(如
wrap_content
和match_parent
)可能不足以满足你的需求。例如,你可能需要基于父视图的大小或兄弟视图的大小来动态调整视图的大小。 - 性能优化:虽然不常见,但在某些情况下,重写
onMeasure
方法可能有助于提高性能。例如,如果你可以通过更精确地测量视图大小来减少不必要的布局传递,那么重写onMeasure
可能是有益的。
请注意,重写onMeasure
方法时需要谨慎,因为错误的测量逻辑可能导致视图显示不正确或引发布局问题。在重写onMeasure
时,你通常需要调用setMeasuredDimension
方法来设置视图的最终大小。此外,了解Android的布局和测量系统的工作原理对于正确实现自定义测量逻辑至关重要。
6.mvvm如何在xml中加载一个类?
7.Android系统如何加载Launcher?
8.Activity显示启动和隐式启动的区别?
9.自定义View的方法?
10.Android事件分发机制?
11.Glide原理?
12.Glide如果更换策略?