1、简述Service的两种启动方式的区别?
Service 的启动方式分别可以调用 startService() 、 bindService() 方法,这两个启动方式的区别如下所示:
- 生命周期:startService(): 使用该方法开启 Service 时,执行的生命周期方法依次为 onCreate() 、 onStartCommand() 、 onDestroy() 。 bindService() :使用该方法开启 Service 时,执行的生命周期方法依次为: onCreate() 、 onBind() 、 onUnbind() 、 onDestroy() 。
- 停止服务的方法 startService(): 调用 stopSelf() 、 stopService() 方法停止服务。 bindService(): 调用 unbindService() 方法停止服务。
- 组件的关联 startService(): 当一个组件通过此方法开启服务时,服务与开启该组件没有关联,即使开启服务的组件被销毁,服务依旧运行。 bindService(): 当一个组件通过此方法开启服务时,服务会与该组件绑定,组件一旦被销毁,该服务也会被销毁。
2、如何保证Service不被杀死
- onStartCommand方法,返回START_STICKY 将Service设置成START_STICKY,在运行onStartCommand后Service进程被kill,那将保留在开始状态,但是不保留那些传入的intent。不久后Service就会再次尝试重新创建,因为保留在开始状态,在创建Service后将保证调用onstartCommand。如果没有传递任何开始命令给Service,那将获取到null的intent。重传intent,保持和重启前一样。 当Service因内存不足被kill,当内存还充足的时候,Service被重新创建,但是不能保证任何情况下都被重建,比如进程被干掉了。
- 提升Service优先级 在AndroidManifest.xml文件中对于intent-filter可以通过android:priority = "1000"这个属性设置最高优先级,1000是最高值,如果数字越小则优先级越低,同时适用于广播。
- 提升service进程优先级 Android中的进程是托管的,当系统进程空间紧张的时候,会依照优先级自动进行进程的回收。 Android进程的优先级从高到低依次为: 前台进程( FOREGROUND_APP) 可视进程(VISIBLE_APP ) 次要服务进程(SECONDARY_SERVER ) 后台进程 (HIDDEN_APP) 内容供应节点(CONTENT_PROVIDER) 空进程(EMPTY_APP) 当service运行在低内存的环境时,将会kill掉一些存在的进程。因此进程的优先级将会很重要,可以使用startForeground()将service放到前台状态。这样在低内存时被kill的几率会低一些。 如果在极度低内存的压力下,该service还是会被kill掉,并且不一定会restart()
- onDestroy方法里重启service 直接在onDestroy()里startService或使用service + broadcast方式,就是当service走到onDestory的时候,发送一个自定义的广播,当收到广播的时候,重新启动service; 当使用类似某某管家等第三方应用或是在setting里-应用-强制停止时,APP进程可能就直接被干掉了,onDestroy方法都进不来,所以还是无法保证。
- 监听系统广播判断Service状态 通过系统的一些广播,比如:手机重启、界面唤醒、应用状态改变等等监听并捕获到,然后判断我们的Service是否还存活,别忘记加权限。 这也能算是一种措施,不过感觉监听多了会导致Service很混乱,带来诸多不便。
- root之后将app放到system/app变成系统级应用
- 放一个像素在前台(手机QQ)
3、Android线程间通信四种方式
- 1、通过
Handler机制 主线程中定义 Handler,子线程发消息,通知 Handler 完成 UI 更新,Handler 对象必须定义在主线程中,如果是多个类直接相互调用,就不是很方便,需要传递 content 对象或者通过接口调用。另外 Handler 机制与 Activity 生命周期不一致的原因,容易导致内存泄漏,不推荐使用。- 2、
runOnUiThread()方法,用 Activity 对象的 runOnUiThread 方法更新,在子线程中通过runOnUiThread()方法更新 UI,强烈推荐使用。- 3、
View.post(Runnable r)这种方法更简单,但是需要传递更新的 view 过去,推荐使用。- 4、
AsyncTask即异步任务,是 Android 给我们提供的一个处理异步任务的类,通过此类,可以实现 UI 线程和后台线程进行通讯,后台线程执行异步任务,并把结果返回给 UI 线程。
4、Android中有哪些进程间通信方式?
RPC是一个请求响应模型,客户端发起请求,服务器返回响应。
- 1、
Binder简单易用,只能传输 Bundle 支持的数据类型,四大组件间的进程间通信;文件共享,简单易用,不适合高并发场景,并且无法做到进程间即时通信,适应于无关发的情况下,交换简单数据,对实时性要求不高的场景。 - 2、
AIDL功能强大,支持一对多实时并发通信,使用稍复杂,需要处理好线程间的关系,一对多通信且有 RPC 需求。 - 3、
Messenger功能一般,支持一对多串行通信,支持实时通信,不能很好的处理高并发的情形,不支持 RPC,由于数据通过 Message 传输,因此只能传输 Bundle 支持的数据类型,低并发的一对多实时通信,无 RPC 需求,或者无需要返回结果的 RPC 需求。 - 4、
ContentProvider支持一对多的实时并发通信,在数据资源共享方面功能强大,可通过 Call 方法扩展其它操作,可以理解为受约束的 AIDL,主要提供对数据源的 CRUD 操作,一对多的进程间数据共享。 - 5、
BroadcastReceiver操作简单,支持一对多实时通信,只支持数据单向传递,效率低且安全性不高,一对多的低频率单向通信。 - 6、
Socket功能强大,可以通过网络传输字节流,支持一对多实时并发通信,实现细节步骤稍繁琐,不支持直接的 RPC,网络间的数据交换。
5、websocket 和 http相关
- 1、什么是
websocket?websocket是HTML5的一种新协议,允许服务器向客户端传递信息,实现浏览器和客户端双工通信。
- 2、
websocket特点 (1)与http协议有良好的兼容性; (2)建立在TCP协议之上,和http协议同属应用层; (3)数据格式比较轻量,性能开销小,通信高效; (4)可以发送文本,也可以发送二进制; (5)没有同源限制,可以任意服务器通信; (6)协议标识符是ws(如果加密,则为wss),服务器网址就是URL; (7)服务器可以主动向客户端推送信息,客户端也可以主动向服务器发送信息,是真正的双向平等对话,属于服务器推送技术的一种。
- 3、
http和websocket的区别 (1)http协议是短链接,因为请求之后,都会关闭连接,下次请求需要重新打开链接; (2)websocket协议是一种长链接,只需要通过一次请求来初始化连接,然后所有请求和响应都是通过TCP链接进行通信。
6、HTTP 与 HTTPS 的区别
- 1、HTTPS 协议需要到 CA (Certificate Authority,证书颁发机构)申请证书,一般免费证书较少,因而需要一定费用。(以前的网易官网是http,而网易邮箱是 https 。)
- 2、HTTP 是超文本传输协议,信息是明文传输,HTTPS 则是具有安全性的 SSL 加密传输协议。
- 3、HTTP 和 HTTPS 使用的是完全不同的连接方式,用的端口也不一样,前者是80,后者是443。
- 4、HTTP 的连接很简单,是无状态的。HTTPS 协议是由 SSL+HTTP 协议构建的可进行加密传输、身份认证的网络协议,比 HTTP 协议安全。(无状态的意思是其数据包的发送、传输和接收都是相互独立的。无连接的意思是指通信双方都不长久的维持对方的任何信息。)
7、HTTPS 的优点
- 1、使用 HTTPS 协议可认证用户和服务器,确保数据发送到正确的客户机和服务器。
- 2、HTTPS 协议是由SSL+HTTP 协议构建的可进行加密传输、身份认证的网络协议,要比 HTTP 协议安全,可防止数据在传输过程中不被窃取、修改,确保数据的完整性。
- 3、HTTPS 是现行架构下最安全的解决方案,虽然不是绝对安全,但它大幅增加了中间人攻击的成本。
8、HTTPS 的缺点
- 1、HTTPS 协议握手阶段比较费时,会使页面的加载时间延长近。
- 2、HTTPS 连接缓存不如 HTTP 高效,会增加数据开销,甚至已有的安全措施也会因此而受到影响。
- 3、HTTPS 协议的安全是有范围的,在黑客攻击、拒绝服务攻击和服务器劫持等方面几乎起不到什么作用。
- 4、SSL 证书通常需要绑定 IP,不能在同一 IP 上绑定多个域名,IPv4 资源不可能支撑这个消耗。
- 5、成本增加。部署 HTTPS 后,因为 HTTPS 协议的工作要增加额外的计算资源消耗,例如 SSL 协议加密算法和 SSL 交互次数将占用一定的计算资源和服务器成本。
- 6、HTTPS 协议的加密范围也比较有限。最关键的,SSL 证书的信用链体系并不安全,特别是在某些国家可以控制 CA 根证书的情况下,中间人攻击一样可行。
9、TCP连接的三次握手
SYN是TCP连接的第一个包,非常小的一种数据包。
- 第一次握手 第一次握手就是客户端给服务器端发送一个报文; 这样服务端就能得出结论:客户端的发送能力、服务端的接收能力是正常的。
- 第二次握手 第二次握手就是服务器收到报文之后,会应答一个报文给客户端; 这样客户端就能得出结论:服务端的接收、发送能力,客户端的接收、发送能力是正常的。不过此时服务器并不能确认客户端的接收能力是否正常。
- 第三次握手 第三次握手就是客户端收到报文后再给服务器发送一个报文,建立连接; 这样服务端就能得出结论:客户端的接收、发送能力正常,服务器自己的发送、接收能力也正常。
TCP连接的四次挥手:
- 第一次挥手:客户端打算关闭连接,此时会发送一个 FIN 报文,之后客户端进入 FIN_WAIT_1 状态。
- 第二次握手:服务端收到该报文后,就向客户端发送 ACK 应答报文,接着服务端进入 CLOSED_WAIT 状态。
- 第三次挥手:如果服务端也想断开连接了,和客户端的第一次挥手一样,发给 FIN 报文,且指定一个序列号。此时服务端处于 LAST_ACK 的状态。
- 第四次挥手:客户端收到 FIN 之后,一样发送一个 ACK 报文作为应答,且把服务端的序列号值 + 1 作为自己 ACK 报文的序列号值,此时客户端处于 TIME_WAIT 状态。需要过一阵子以确保服务端收到自己的 ACK 报文之后才会进入 CLOSED 状态。
- 服务端收到 ACK 报文之后,就处于关闭连接了,处于 CLOSED 状态。
更加详细参考链接:www.jianshu.com/p/249178d76…
10、APK加固
- 第一点:直接对APK加固, 直接对APK加固,设置Dex函数的虚拟化保护,目前这类是安全性很高的保护方式,但是不能全选函数做虚拟化,会有性能损耗。
- 第二点:APK里so的加固, APK里so的加固,如果想要安全性比较高,用apk加固时带的压缩保护安全性不够,需要单独对so进行虚拟化保护,对so加固后,再重新打包APK。
- 第三点:资源加密。 APK里的资源也需要加密保护的,在加密APK时选择资源文件进行加固保护。
11、AIDL简述
- AIDL是一个缩写,全称是Android Interface Definition Language,也就是Android接口定义语言。
- 设计这门语言的目的是为了实现进程间通信,尤其是涉及多线程并发情况下的进程间通信。
- 我们只需要编写AIDL文件,系统就会自动为我们生成代码,大大简化了Android程序员的工作。
12、默认情况下AIDL的调用过程是同步还是异步?
同步,客户端调用远程服务的方法,被调用的方法运行在服务端的Binder线程池中,同时客户端线程会被挂起,这个时候如果服务端方法执行比较耗时,就会导致客户端线程长时间地阻塞在这里,如果这个客户端线程是UI线程的话,就到导致客户端ANR。
13、GC算法
- 标记 —清除算法
- 复制算法
- 标记-整理算法
- 分代收集算法
14、内存优化方案
我们在做内存优化时,无非有两个方向:
- 内存溢出(OOM)
- 内存泄漏(Memory Leak)
1.内存溢出(OOM) 通常在排查内存溢出相关的问题时,可以从以下几个方面入手:
- 加载了大量的Bitmap
- 创建了过多的对象
- 加载过大的对象
- 加载的资源过多,来不及释放
- 内存泄漏
总之,内存溢出的产生都是由于App申请的内存超过了应用的内存上限,这是JVM就会抛出OutOfMemoryError,从而导致应用程序的崩溃。解决内存溢出的方法主要有:
- (1)使用LruCache对图片进行缓存;
- (2)避免在for循环中创建对象;
- (3)加载大图片时使用图片压缩、图片裁剪等技术;
- (4)及时释放不再使用的对象占用的内存;
- (5)不要将Context和View存储在静态变量中。
- (6)使用内存监控机制,例如在Application或Activity中监听onTrimMemory(int level)方法的调用,根据不同的内存状态释放无用资源或者清除图片缓存等;
- (7)内存泄漏同样是内存溢出的关键因素之一,可针对内存泄漏问题进行分析并处理。
- 2.内存泄漏(Memory Leak) 通常在排查内存泄漏相关的问题时,可以从以下几个方面入手:
- 注册后未取消注册造成的内存泄漏(例如:广播)
- 静态变量持有Activity的引用
- 单例模式持有Activity的引用
- 查询数据库后没有关闭游标Cursor
- 构造Adapter时,没有使用convertView重用
- Bitmap对象不再使用时未调用recycle()释放内存
- 对象被生命周期长的对象引用(例如:Activity被静态集合引用导致Activity不能释放)
- Handler造成的内存泄漏
- 非静态的内部类中持有外部类的引用
- 匿名内部类/非静态内部类和异步线程
使用到的工具有:LeakCanary、Profiler等。
15、 内存泄漏的场景和解决办法
- 1、非静态内部类的静态实例 非静态内部类会持有外部类的引用,如果非静态内部类的实例是静态的,就会长期的维持着外部类的引用,阻止被系统回收,解决办法是使用静态内部类。
- 2、多线程相关的匿名内部类和非静态内部类 匿名内部类同样会持有外部类的引用,如果在线程中执行耗时操作就有可能发生内存泄漏,导致外部类无法被回收,直到耗时任务结束,解决办法是在页面退出时结束线程中的任务。
- 3、Handler内存泄漏 Handler导致的内存泄漏也可以被归纳为非静态内部类导致的,Handler内部message是被存储在MessageQueue中的,有些message不能马上被处理,存在的时间会很长,导致handler无法被回收,如果handler是非静态的,就会导致它的外部类无法被回收;
解决办法:1.使用静态handler,外部类引用使用弱引用处理; 2.在退出页面时移除消息队列中的消息.- 4、Context导致内存泄漏 根据场景确定使用Activity的Context还是Application的Context,因为二者生命周期不同,对于不必须使用Activity的Context的场景Dialog),一律采用Application的Context,单例模式是最常见的发生此泄漏的场景,比如传入一个Activity的Context被静态类引用,导致无法回收。
- 5、静态View导致泄漏 使用静态View可以避免每次启动Activity都去读取并渲染View,但是静态View会持有Activity的引用,导致无法回收,解决办法是在Activity销毁的时候将静态View设置为null(View一旦被加载到界面中将会持有一个Context对象的引用,在这个例子中,这个context对象是我们的Activity,声明一个静态变量引用这个View,也就引用了activity)
- 6、WebView导致的内存泄漏 WebView只要使用一次,内存就不会被释放,所以WebView都存在内存泄漏的问题,通常的解决办法是为WebView单开一个进程,使用AIDL进行通信,根据业务需求在合适的时机释放掉。
- 7、资源对象未关闭导致 如Cursor,File等,内部往往都使用了缓冲,会造成内存泄漏,一定要确保关闭它并将引用置为null。
- 8、集合中的对象未清理 集合用于保存对象,如果集合越来越大,不进行合理的清理,尤其是入股集合是静态的。
- 9、Bitmap导致内存泄漏 bitmap是比较占内存的,所以一定要在不使用的时候及时进行清理,避免静态变量持有大的bitmap对象。
- 10、监听器未关闭 很多需要register和unregister的系统服务要在合适的时候进行unregister,手动添加的listener也需要及时移除。
16、JAVA常见的8种数据结构
17、OSI模型和TCP/IP模型
18、Java 调用 Kotlin 的扩展函数
/**
* 埋点上报公共类
*/
object AdjustUtils {
}
/**
* String的扩展函数
*/
fun String.info(msg:String){
MyToash.Log("lyy","-----String的扩展函数-----:${msg}")
}
//Kotlin调用了扩展函数
"AAA".info("Kotlin调用了扩展函数")
注意: 在 Java 中调用 Kotlin 扩展,需要通过扩展所在的文件名+Kt.的方式进行调用
//JAVA调用了扩展函数
AdjustUtilsKt.info("BBBB","JAVA调用了扩展函数");
19、Kotlin 协程中的 withContext方法是串行
mainScope.launch {
withContext(Dispatchers.Main){
delay(500)
Log.d("LUO","---Main---")
}
withContext(Dispatchers.IO){
delay(300)
Log.d("LUO","---IO---")
}
withContext(Dispatchers.Default){
delay(100)
Log.d("LUO","---Default---")
}
Log.d("LUO","---外部---")
}
结果:
D/LUO: ---Main---
D/LUO: ---IO---
D/LUO: ---Default---
D/LUO: ---外部---
20、webSocket和Socket的区别
socket:翻译为套接字,socket是在应用层和传输层之间的一个抽象层,它把TCP/IP层复杂的操作抽象为几个简单的接口供应用层调用以实现进程在网络中通信。
WebSocket:协议是基于TCP的一种新的网络协议,和http协议一样属于应用层协议,是一种让客户端和服务器之间能进行双向实时通信的技术。
1、原理上的区别:
- Socket是传输控制层协议,WebSocket是应用层协议。
2、灵活运用的程度不同:
- WebSocket 更易用,而 Socket 更灵活。Socket是应用层与TCP/IP协议族通信的中间软件抽象层,它是一组接口。
3、传输层次不同:
- Socket 是传输控制层的接口。用户可以通过 Socket 来操作底层 TCP/IP 协议族通信。
21、接口和抽象类
- 定义的关键字不同。
- 子类继承或实现关键字不同。
- 类型扩展不同:抽象类是单继承,而接口是多继承。
- 方法访问控制符:抽象类无限制,只是抽象类中的抽象方法不能被 private 修饰;而接口有限制,接口默认的是 public 控制符。
- 属性方法控制符:抽象类无限制,而接口有限制,接口默认的是 public 控制符。
- 方法实现不同:抽象类中的普通方法必须有实现,抽象方法必须没有实现;而接口中普通方法不能有实现,但在 JDK 8 中的 static 和 defualt 方法必须有实现。
- 静态代码块的使用不同:抽象类可以有静态代码块,而接口不能有。
22、OKHTTP多少种拦截器
内置总共五大拦截器,还可以自定义拦截器
内置总共五大拦截器:
- RetryAndFollowUpInterceptor - 重试重定向拦截器;
- BridgeInterceptor - 桥接拦截器;
- CacheInterceptor - 缓存拦截器;
- ConnectInterceptor - 连接拦截器;
- CallServerInterceptor - 请求服务器拦截器;
OkHttp中拦截器有:自定义应用拦截器、重试重定向、桥接、缓存、连接、自定义网络拦截器、请求服务。
更详细内容查看链接:www.jianshu.com/p/0bb97161a…
23、讲述你做过的一个自定义View
更详细内容查看链接:www.jianshu.com/p/19799a344…
24、Kotlin的内联函数
inline、noinline、crossinline 使 Kotlin 中常用的三个关键字:
inline:内联,用于修饰函数。被修饰的函数称为内联函数,内联函数中的代码可以直接嵌入到调用处,从而减少方法栈的层级与函数类型对象的创建。noinline:不内联,用于修饰内联函数中的函数类型参数,关闭对函数类型参数的内联优化,从而摆脱 inline 带来的「不能把函数类型参数当对象使用」的限制。crossinline:交叉内联,用于修饰内联函数中的函数类型参数,使函数类型参数能被间接调用。
总结来说,inline 用于将函数参数内联,提高性能;noinline 用于禁止内联函数参数;crossinline 用于禁止在内联函数参数中使用 return 语句。
更详细内容查看链接: www.jianshu.com/p/206b8d578…
25、java线程池的参数解释
更详细内容查看链接:www.jianshu.com/p/b3e38df83…
26、Handler内存泄露的原因是什么?
更详细内容查看链接:www.jianshu.com/p/69b05dd1f…
27、协程请求A、B、C、同时请求,数据要统一组装怎么处理?
更详细内容查看链接:www.jianshu.com/p/cd0f78bf2…
28、你遇到印象深刻的bug
更详细内容查看链接:www.jianshu.com/p/4a1826182…
29、apply、also、let 、run、with扩展函数总结一下:
| 函数名 | 使用方法 | 返回值 | 内部持有对象 | 作用 |
|---|---|---|---|---|
| apply | info.apply{this} | 本身 | this | 1、定义一个变量在特定的作用域;2、统一判空处理; |
| also | info.also{it} | 本身 | it | 1、定义一个变量在特定的作用域;2、统一判空处理; |
| let | info.let{it} | 最后一行 | it | 1、定义一个变量在特定的作用域;2、统一判空处理; |
| run | info.run{this} | 最后一行 | this | 1、定义一个变量在特定的作用域;2、统一判空处理; |
| with | with(info) {this} | 最后一行 | this | 1、直接调用一个对象的方法或者属性,可以省略对象名 |
30、Glide 对图片加载做了以下优化:
1、图片缩放和裁剪:Glide 可以根据ImageView的尺寸自动对加载的图片进行裁剪和缩放,以适应不同大小的ImageView,避免了浪费内存和网络带宽。 2、内存和磁盘缓存机制:Glide 提供了内存缓存和磁盘缓存机制来缓存已经加载的图片,可以避免重复下载相同的图片,节省了网络资源。同时,内存缓存和磁盘缓存也可以加速图片加载过程,提高了用户体验。 3、自适应网络传输格式:Glide 会根据网络状态选择最佳的图片压缩格式,如 WebP、PNG、JPEG 等,可以有效降低图片在网络传输中的大小,减少网络流量消耗。 4、图片解码优化:在图片解码方面,Glide 使用了 Skia 和 BitmapFactory 两种解码库,并使用了多线程技术,从而快速地将图片解码为 Bitmap,提高了图片展示速度,减少了内存占用。 5、图片请求优先级设置:Glide 支持设置图片请求的优先级,以确保在并发加载大量图片时,重要的图片优先加载,提高了用户体验。