面试题
-
如何处理后台的Activity被系统回收问题?如何实现Android进程保活?
系统回收情况:activity处于栈底,当内存不足的时候会被系统回收
解决:可以使用onSaveInstanceState()方法来保存数据,然后再onCreate()方法中来恢复保存的数据源
进程保活:- 使用监听广播方式将进程
- 提高Service的优先级
- 使用双Service拉起
- 双进程挂起
-
如何理解内存泄漏与内存溢出?简述Android中造成内存泄漏的原因?如何解决?
- 内存泄露:程序在申请内存后,无法释放已经申请的空间,,完全无用的对象,无法被GC回收
- 内存溢出:在程序申请内存时,没有足够的内存空间供其使用
- 内存泄露的原因:单例模式
- 解决方法:
- 改进成使用内部类+弱引用
- 在Activity的的onDestory中移除myHandtrer中的所有message
-
MVC MVP MVVM原理和区别?
- MVC原理,Model View Controller,当用户出发事件的时候,view层会发送指令到controller层,接着controller去通知model层更新数据,model层更新完数据以后直接显示在view层上
- MVP原理:Model-View-Presenter,Model提供数据,View负责显示,Controller/Presenter负责逻辑的处理。
- MVVM原理:Model-View-ViewModel,ViewModel 将其中的View 的状态和行为抽象化,将视图 UI 和业务逻辑分开,它可以取出 Model 的数据同时帮忙处理 View 中由于需要展示内容而涉及的业务逻辑。
区别:MVP中view层和model层不再相互可知,完全的解耦,取而代之的presenter层充当了桥梁的作用,用于操作view层发出的事件传递到presenter层中,presenter层去操作model层,并且将数据返回给view层;view层和presenter层的通信,可以通过接口实现
MVVM:ViewModel可以理解成是View的数据模型和Presenter的合体,ViewModel和View之间的交互通过Data Binding完成,而Data Binding可以实现双向的交互,View的变动,自动反映在 ViewModel。这就使得视图和控制层之间的耦合程度进一步降低,关注点分离更为彻底,同时减轻了Activity的压力。 -
什么是协程?谈谈对进程共享和线程安全的认识。
协程是比线程更小的一种施行单位,可以理解为轻量级的线程
进程共享:进程共享资源,包括软件资源和硬件资源
线程安全:在拥有共享资源的多条线程并行执行的程序中,线程安全的代码会通过同步机制保证各个线程都可以正常且正确的执行,不会出现数据污染等意外情况。 -
如何打包apk?如何对apk瘦身?
如何打包:
- appt将资源文件打包为R.java
- aidl文件转为java文件
- javac对java文件进行编译生成.calss文件
- 将.class转化为dex文件
- 整合资源文件,打包为apk
apk瘦身
- 压缩图片
- 使用webp图片格式
- 使用Android Lint分析去除无用资源
- 使用AndResGuard
-
对比分析RecyclerView和ListView的性能?如何对两者进行优化?
性能分析:
- 布局效果上:RecyclerView的布局效果更多,ListView中效较少
- 代码编写上:RecyclerView中的ViewHolder的编写更规范化,复用item更方便,需要设置LayoutManager
- 空数据处理上:ListView 提供了setEmptyView 来处理 Adapter 中数据为空的时候所展示的界面,RecyclerView中没有这类API
- HeaderView 和 FooterView:ListView中提供了这两种视图,好处在于当指向在ListView的头部或者尾部添加一个View的时候,不会影响到Adapter的编写;RecyclerView中没有这类视图控件
- 局部刷新:ListView中的notifyDataSetChanged() 会重绘每个item,整体刷新;RecyclerView.Adapter中的notifyItemChanged可以实现单个item的刷新
- 对Item操作时的动画效果:ListView没有这类API,RecyclerView在对item做操作的时候可以实现一些动画效果
优化:
- ListView:当 convertView 为空时,用 setTag()方法为每个 View 绑定一个存放控件的ViewHolder 对象。 当 convertView 不为空, 重复利用已经创建的 view 的时候,使用 getTag()方法获取绑定的 ViewHolder 对象,这样就避免了 重复的使用findViewById
- RecyclerView:recyclerView.setHasFixedSize(true);如果设置了setHasFixedSize(true):由于item的宽高都是固定的,adapter的内容改变时,RecyclerView不会整个布局都重绘; 使用getExtraLayoutSpace为LayoutManager设置更多的预留空间; 避免创建过多对象
-
Android中如何实现和处理线程并发与线程同步问题?
线程并发:
- 使用AsyncTask 或者 Thread+ handler方式
线程同步处理:
- synchronized实现同步;
- volatile实现同步:
- 重入锁同步:ReentrantLock类是可重入、互斥、实现了Lock接口的锁, 它与使用synchronized方法和快具有相同的基本行为和语义,并且扩展了其能力。
- ThreadLocal同步:如果使用ThreadLocal管理变量,则每一个使用该变量的线程都获得该变量的副本,副本之间相互独立,这样每一个线程都可以随意修改自己的变量副本,而不会对其他线程产生影响。
- Atomic同步
- 使用阻塞队列实现线程同步
-
项目中常用的设计模式有哪些?简述其原理。
- 单例模式:某个类只能生成一个实例,该类提供了一个全局访问点供外部获取该实例,其拓展是有限多例模式。
- 工厂模式:出现了大量的产品需要创建,并且具有共同的接口时,可以通过工厂方法模式进行创建。
- 建造者模式:将各种产品集中起来进行管理,用来创建复合对象
- 原型模式:是将一个对象作为原型,对其进行复制、克隆,产生一个和原对象类似的新对象
- 适配器模式:适配器模式将某个类的接口转换成客户端期望的另一个接口表示,目的是消除由于接口不匹配所造成的类的兼容性问题。
- 装饰模式:给一个对象增加一些新的功能,而且是动态的,要求装饰对象和被装饰对象实现同一个接口。
- 代理模式:为某对象提供一种代理以控制对该对象的访问。
- 外观模式:外观模式就是将类和类的关系放在一个Facade类中,降低了类类之间的耦合度,该模式中没有涉及到接口
-
Bitmap如何处理大图,如一张30M的大图,如何预防OOM?
- 根据图片数据选择合适的解码方式,
- 解析的时候先通过BitmapFactory.decodeStream方法,创建出一个bitmap,再调用setImageBitmap或setImageResource或BitmapFactory.decodeResource将其设为ImageView的 source。
-
Android为每个应用程序分配的内存大小是多少?能不能自己分配定额内存?如何实现多进程开发?App中唤醒其他进程的实现方式有哪些?
- Android的各个厂家的系统会对默认内存值进行修改,Google原生系统正常分配的内存最多为16M.
- 可以自己分配定额内存,在AndroidManifest.xml文件中设置了android:largeheap = "true"时,最多申请更多的内存。当超过这个值时就会出现OOM。但并不是系统有多少内存,就可以申请多少内存,而是有限制的。
- 实现多进程开发:四大组件在AndroidManifest.xml文件中有个属性android:process,可以通过这个来指定组件所处的进程,因为默认是应用的主进程,所以指定后,系统会在启动这个组件的时候,先创建这个进程,再创建该组件,从而实现多进程开发。
- 唤醒进程的方式:
1 通过intent唤醒,需要修改AndroidManifest.xml文件,添加android:exported=”true”
2 通过uri唤起app
3 直接通过包名唤醒