第 01 期:自定义 Handler 时如何有效地避免内存泄漏问题?
非静态内部类持有外部类的引用的情况下,造成外部类在使用完成后不能被系统回收内存,从而造成内存泄漏。这里Handler
持有外部类Activity
的引用,一旦Activity
被销毁,而此时Handler
依然持有Activity
引用,就会造成内存泄漏。
1.使用静态内部类+弱引用
2.在销毁的时候将消息队列清空,优雅的使用lifecycle
来进行生命周期的控制处理
大多数其实不是惧怕内存泄漏,就算有一个Handler
能有多少,不算大问题(积少成多,方案简单,请务必解决),主要是怕使用Handler
进行了延时操作,导致在不需要的时候仍然进行逻辑的处理
第 03 期:一般什么情况下会导致内存泄漏问题?
内存泄漏:生命周期长的对象持有了生命周期短的对象的引用
内存溢出:不合理的内存占用过多,导致在需要使用内存空间的时候没有了
1.非静态内部类持有外部类的引用,这是编译器在编译的时候自动为内部类的构造方法中添加了外部类的引用。如果内部类的生命周期大于外部类就会造成内存泄漏,如Handler
(Activity
需要销毁,但是MessageQueue
中的Message
未处理完毕),Thread
(Activity
需要销毁,但是子线程未处理完毕),Ansytask
(内部开启子线程)
4.集合中的对象直接间接持有Context
1.加载超大文件 超巨图Bitmap
,进行分片加载
2.循环中创建大量对象 特别是View的绘制过程中onDraw
编码的时候就要注意,对于一些可能出现的地方多关注一点
合理使用Lifecycle来进行生命周期的控制
答:比较复杂,建议写个demo具体查看
singleTask
栈内唯一,如果有多个栈,在每个栈内唯一,而不是所有栈唯一
1.相同 此时只有一个栈
1-2 不存在B,将B添加入栈中
2.不同 此时有两个栈
2-2 不存在B,创建新栈,将B放入栈中
第 05 期:哪些情况下会导致oom问题?
第 06 期:如何实现多线程中的同步?
场景:网络请求,从多个来源请求数据,自己的数据请求A,第三方SDK的数据请求B,获取到所有数据后在进行操作,避免时间浪费,A与B进行分别进行异步请求
第 07 期:Android 补间动画和属性动画的区别?
答:补间动画只支持 平移 缩放 透明度 旋转,视觉动画,其属性不变
属性动画只要提供了set方法的属性都可以进行变化,将属性进行改变不断重新绘制从而产生的动画效果
第 08 期:ANR 出现的场景以及解决方案?
答:在主线程进行了耗时操作,例如在Service,BroadCast中进行了耗时操作,应该将耗时操作放到子线程中进行操作。
一些常见的错误操作,网络请求,数据库查询等。
曾经遇到的问题:将小区的数据(超大json文件)放在主线程中进行解析,同时使用loading动画,明显可以看到手机的动画卡顿
-
Message.obtain()
复用Message
,减少内存开销???在Message
被处理完成后就会放入消息池中,new
出来的Message
会在处理完成后不断加入消息池,obtain()
就是从消息池中获取一个消息 -
delayMillis);为什么使用
SystemClock.uptimeMillis()
系统启动时间而不是用System.currentTimeMillis()
系统当前时间?因为这个时间是单调前进的,而System.currentTimeMillis()
会因为用户修改时间或者网络校对时间而产生前进后退不可知的变化。系统启动时间在系统深度睡眠的时候才会停止,无法人为修改 - 时间准吗?不准。因为
MessageQueue
是链表形式,消息需要一个一个处理,如果在第一个消息处理的过程中进行耗时操作例如Thread.sleep(time)
,并且time时间大于delay时间,那么第二个消息会在time时间过后进行处理,此时时间不准确
- 多个Message是如何放入MessageQueue?将放入的Message按照延时时间(没有delay为0)从头放入,最后放入的在队列的第一个。
第 10 期:抽象类与接口的区别?
抽象类体现的是is 接口体现的是like
抽象类中可以包含具体方法,可以没有抽象方法
接口中不可以包含具体方法,可以没有抽象方法
BroadcastReceiver
是所有的广播接收,可以接收到自己,其他应用,系统发出的广播,支持动态注册(代码注册)和静态注册(清单文件注册),不过建议使用动态注册
LocalBroadcastReceiver
是本应用的广播接收,只能接收到自己发出的广播,相对来说效率更高,安全性更高,仅支持动态注册(代码注册),大部分可以使用Bus替代
第 12 期:请简要谈一谈单例模式?
什么是单例?怎么实现?有什么好处?使用场景?如何保证唯一性?
1)什么是单例?一种设计模式,保证了在当前进程中只有一个实例
2)怎么实现?懒汉式,饿汉式,双重校验锁式,Holder静态内部类式,枚举式
3)什么好处?保证了在当前进程中只有一个实例,避免重复创建和随意修改,并且将生命周期延长到APP的生命周期,随时获取修改
4)如何保证唯一性?由于多线程的存在,建议使用Holder静态内部类的方式进行设计单例模式,因为静态方法只有调用的时候才会创建方法所在的类,而类的创建的线程安全的
答:线程安全,SP内部使用synchronized来保证数据同步安全,进程不安全,本质上SP存储就是对文件的读写,同一个文件可以被多个进程进行修改。
commit将数据放入内存中,同步将数据写入文件有返回值true or false来判断操作是否成功
apply将数据放入内存中,异步将数据写入文件没有返回值
因为SP本质上是对文件的读写,并没有增量的概念,所以在修改的时候是全量修改,无论修改什么数据都是会将文件全部写入,这就非常不适合存储大容量数据。如果非要进行大数据修改,建议一个数据创建一个xml的SP文件,而不是只创建一个xml的SP文件存储所有
这题太难了 呜呜呜。。。
手机屏幕刷新率为60hz,约每16ms刷新屏幕一次,就意味着CPU会计算16ms中屏幕中的界面数据发生了哪些变化,然后在16ms时间到的时候进行一次刷新,如果时间到了但是CPU没有计算完成,此时就发生了卡顿现象。
1.减少界面的层级嵌套,合理的使用布局控件ConstraintLayout,特别是注意背景的使用
2.不要在主线程尽心复杂逻辑操作
3.RecyclerView在Adapter设置Item数据的时候不要进行复杂逻辑运算,可以使用变量放在每一个实体中使用lazy进行获取,这样复用的时候也只会进行一次运算,比如时间格式化,String字符串的分割,Glide如果加载的是本地图片可以去除本地缓存
第 18 期:谈谈 Android 中内存优化的方式?
第 20 期:请回答一下Android进程间的通信方式?
- 通过Intent存入Bundle数据跳转到另一个APP的页面,如跳转高德地图导航页,拨号
- 启动多进程的Service,如双进程APP保活
- 发送广播到另一个进程的广播接收者
一个进程将数据存入文件后,另一个进程去获取文件
多用于获取应用中数据,如获取通讯录
String
:使用+
进行字符串的拼接,这样产生的每一个新的字符串都会重现创建一个变量来进行存放,String
是使用final
来进行修饰的,内容无法进行变化只能重新赋值
StringBuffer
:使用append
来进行字符串的拼接,线程安全,可是在多线程中进行使用
StringBuilder
:使用append
来进行字符串的拼接,线程不安全,只能在单线程进行使用
第 22 期:请简述从点击图标开始app的启动流程?
2.system__server进程收到1中的请求后,向zygote进程发送创建新进程的请求; 7.主线程收到6中发送来的Message后,反射创建目标Activity,回调oncreate等方法,开始执行生命周期方法,我们就可以看到应用页面了。
热启动:应用还在后台存活,直接执行Activity的onResume()方法
冷启动:应用启动,初始化Application,如果有多个进程那么会多次进行Application的初始化,然后打开启动Activity进行Activity的初始化
IntentService
继承Service
,内部自行维护一个WorkerThread
,通过重写onHandleIntent
方法来进行一步操作,该方法在子线程中,在执行完后会自行调用stopSelf
方法,来关闭Service
。IntentService
可以执行多次,每次都会按照队列一个一个执行,当所有都执行完才进行stopSelf
场景:应用更新,使用IntentService
进行下载文件,然后在通知栏显示进度条通知。
目前主要是在BroadCastReceiver中进行接收广播,过滤掉不需要的广播,在极光推送中可以看到
场景,发送广播的地点只有一处,但是接受广播的地点有很多地方,不同地点需要的广播不同,但是为了方便管理之使用一种广播,这个使用就需要IntentFilter来进行Receiver的筛选,这样发送一个广播,接收者可以直接收自己想要的广播。
第 25 期:回答一下什么是强、软、弱、虚引用以及它们之间的区别?
强引用:表示该引用很重要,大部分使用中的对象都是强引用,在GC的时候不会被回收
软引用:表示该引用比较重要,只有在内存不足的时候进行GC的时候会被回收
弱引用:表示该引用不怎么重要,在任何时候GC时都会被回收
虚引用:表示一个虚假的引用,实际上并没有这个引用,在GC的时候会被回收,可以用来追踪GC调用的时机
优点:在少量异步操作的过程中使用简单
缺点:生命周期控制麻烦,如果需要使用建议添加Lifecycle
来进行控制
不建议使用,可以使用Rxjava、协程等代替
第 27 期:对于面向对象的六大基本原则了解多少?
理论知识,建议面向百度了解
所有广播需要添加动态注册 Apache HTTP 客户端弃用 一些第三方SDK会使用 在清单文件中添加
ArrayList:在内存中找到一段地址连续的空间进行存放数据 查找方便插入删除麻烦
LinkedList:在内存中任意找到一个空闲的空间进行存放数据属于双链表,查询麻烦,插入删除简单
Handler和Thread的封装 主要用于子线程和主线程的数据交互
RecyclerView优化 一句话思路 空间换取时间 使用内存空间来换取数据转化的时间
1.在Adapter中最好不要进行任何的逻辑操作,比如日期转换,字符串切割等等,可以在model内部自行添加一个参数使用
by lazy 来存储数据转换后的结果,这样数据逻辑操作就只执行一次,而不会随着数据回收重复计算
2.新增删除数据不刷线全部,而是刷新局部
3.布局优化,尽量少的布局嵌套,尽量少的控件
5.资源文件的读取,初始化的时候使用 by lazy 生成
8.在RecyclerView添加滑动监听,一些图片加载可以在RecyclerView快速滑动的时候不进行加载图片
内部的RecyclerView必定使用的都是同一个Adapter,这个时候就很有必要使用回收池了
11.对于条目点击时间不要在复用部分进行setOnClickListener,这样会重复设置点击监听,而是应该创建一个listener对象,
传入控件的id,和当前的条目position,通过id和position判断处理点击监听
视情况,例如:一个item就占据一个页面,RecyclerView滑动到第二张,此时第一张可见,RecyclerView无法找到可复用
的View,此时会重新new一个出来,滑动卡顿,第三张及以后可以找到复用的View,滑动流畅
第 36 期:谈谈自定义View的流程?
最多使用的还是组合View,因为一些界面上的元素过多,使用一个组合View将复杂界面分成一块一块,分别去处理各个模块的相关逻辑
第 38 期:谈谈线程死锁,如何有效的避免线程死锁?
在安卓开发过程中基本上不会使用到线程死锁,目前个人在工作过程中除了双重校验锁单例需要自己加锁,还有一种就是分别从不同数据源中获取数据,不过在使用Rxjava后也取消了