Android篇:2019初中级Android开发社招面试解答(中-下半场)

213 阅读18分钟
原文链接: mp.weixin.qq.com

▲长按图片保存可分享至朋友圈

      

微信公众号:[顾林海]    

问题或建议,请关注公众号留言     

[如果你觉得对你有帮助,请点个在看]    

作者:Android的后花园

链接:https://juejin.cn/post/6844903806250008589

又到周五了,小伙伴们是不是很兴奋,阅读到底部,有红包!

性能优化

1、图片的三级缓存中,图片加载到内存中,如果内存快爆了,会发生什么?怎么处理?

参考回答:

首先我们要清楚图片的三级缓存是如何的

如果内存足够时不回收。内存不够时就回收软引用对象

2、内存中如果加载一张500*500的png高清图片.应该是占用多少的内存?

参考回答:

不考虑屏幕比的话:占用内存=500 * 500 * 4 = 1000000B ≈ 0.95MB

考虑屏幕比的的话:占用内存= 宽度像素 x (inTargetDensity / inDensity) x 高度像素 x (inTargetDensity / inDensity)x 一个像素所占的内存字节大小

inDensity表示目标图片的dpi(放在哪个资源文件夹下),inTargetDensity表示目标屏幕的dpi

3、WebView的性能优化 ?

参考回答:

一个加载网页的过程中,native、网络、后端处理、CPU都会参与,各自都有必要的工作和依赖关系;让他们相互并行处理而不是相互阻塞才可以让网页加载更快:

WebView初始化慢,可以在初始化同时先请求数据,让后端和网络不要闲着。

常用 JS 本地化及延迟加载,使用第三方浏览内核

后端处理慢,可以让服务器分trunk输出,在后端计算的同时前端也加载网络静态资源。

脚本执行慢,就让脚本在最后运行,不阻塞页面解析。

同时,合理的预加载、预缓存可以让加载速度的瓶颈更小。

WebView初始化慢,就随时初始化好一个WebView待用。

DNS和链接慢,想办法复用客户端使用的域名和链接。

推荐文章:WebView性能、体验分析与优化 https://tech.meituan.com/2017/06/09/webviewperf.html

4、Bitmap如何处理大图,如一张30M的大图,如何预防OOM?

参考回答:避免OOM的问题就需要对大图片的加载进行管理,主要通过缩放来减小图片的内存占用。

BitmapFactory提供的加载图片的四类方法(decodeFile、decodeResource、decodeStream、decodeByteArray)都支持BitmapFactory.Options参数,通过inSampleSize参数就可以很方便地对一个图片进行采样缩放

比如一张10241024的高清图片来说。那么它占有的内存为102410244,即4MB,如果inSampleSize为2,那么采样后的图片占用内存只有512512*4,即1MB(注意:根据最新的官方文档指出,inSampleSize的取值应该总是为2的指数,即1、2、4、8等等,如果外界输入不足为2的指数,系统也会默认选择最接近2的指数代替,比如2)

综合考虑。通过采样率即可有效加载图片,流程如下

将BitmapFactory.Options的inJustDecodeBounds参数设为true并加载图片

从BitmapFactory.Options中取出图片的原始宽高信息,它们对应outWidth和outHeight参数

根据采样率的规则并结合目标View的所需大小计算出采样率inSampleSize

将BitmapFactory.Options的inJustDecodeBounds参数设为false,重新加载图片

推荐文章:Android高效加载大图、多图解决方案,有效避免程序OOM https://blog.csdn.net/guolin_blog/article/details/9316683

5、内存回收机制与GC算法(各种算法的优缺点以及应用场景);GC原理时机以及GC对象

参考回答:

内存判定对象可回收有两种机制:

引用计数算法:给对象中添加一个引用计数器,每当有一个地方引用它时,计数器值就加1;当引用失效时,计数器值就减1;任何时刻计数器为0的对象就是不可能再被使用的。然而在主流的Java虚拟机里未选用引用计数算法来管理内存,主要原因是它难以解决对象之间相互循环引用的问题,所以出现了另一种对象存活判定算法。

可达性分析法:通过一系列被称为『GCRoots』的对象作为起始点,从这些节点开始向下搜索,搜索所走过的路径称为引用链,当一个对象到GC Roots没有任何引用链相连时,则证明此对象是不可用的。其中可作为GC Roots的对象:虚拟机栈中引用的对象,主要是指栈帧中的本地变量*、本地方法栈中Native方法引用的对象、方法区中类静态属性引用的对象、方法区中常量引用的对象

GC回收算法有以下四种:

分代收集算法:是当前商业虚拟机都采用的一种算法,根据对象存活周期的不同,将Java堆划分为新生代和老年代,并根据各个年代的特点采用最适当的收集算法。

新生代:大批对象死去,只有少量存活。使用『复制算法』,只需复制少量存活对象即可。

复制算法:把可用内存按容量划分为大小相等的两块,每次只使用其中的一块。当这一块的内存用尽后,把还存活着的对象『复制』到另外一块上面,再将这一块内存空间一次清理掉。实现简单,运行高效。在对象存活率较高时就要进行较多的复制操作,效率将会变低

老年代:对象存活率高。使用『标记—清理算法』或者『标记—整理算法』,只需标记较少的回收对象即可。

标记-清除算法:首先『标记』出所有需要回收的对象,然后统一『清除』所有被标记的对象。标记和清除两个过程的效率都不高,清除之后会产生大量不连续的内存碎片,空间碎片太多可能会导致以后在程序运行过程中需要分配较大对象时,无法找到足够的连续内存而不得不提前触发另一次垃圾收集动作。

标记-整理算法:首先『标记』出所有需要回收的对象,然后进行『整理』,使得存活的对象都向一端移动,最后直接清理掉端边界以外的内存。标记整理算法会将所有的存活对象移动到一端,并对不存活对象进行处理,因此其不会产生内存碎片

推荐文章:图解Java 垃圾回收机制 https://blog.csdn.net/justloveyou_/article/details/71216049

6、内存泄露和内存溢出的区别 ?AS有什么工具可以检测内存泄露

参考回答:

内存溢出(out of memory):是指程序在申请内存时,没有足够的内存空间供其使用,出现out of memory;比如申请了一个integer,但给它存了long才能存下的数,那就是内存溢出。

内存泄露(memory leak):是指程序在申请内存后,无法释放已申请的内存空间,一次内存泄露危害可以忽略,但内存泄露堆积后果很严重,无论多少内存,迟早会被占光。memory leak会最终会导致out of memory!

查找内存泄漏可以使用Android Studio 自带的AndroidProfiler工具或MAT

7、性能优化,怎么保证应用启动不卡顿? 黑白屏怎么处理?

参考回答:

应用启动速度,取决于你在application里面时候做了什么事情,比如你集成了很多sdk,并且sdk的init操作都需要在主线程里实现所以会有卡顿的感觉。在非必要的情况下可以把加载延后或则开启子线程处理

另外,影响界面卡顿的两大因素,分别是界面绘制和数据处理。

布局优化(使用include,merge标签,复杂布局推荐使用ConstraintLayout等)

onCreate() 中不执行耗时操作 把页面显示的 View 细分一下,放在 AsyncTask 里逐步显示,用 Handler 更好。这样用户的看到的就是有层次有步骤的一个个的 View 的展示,不会是先看到一个黑屏,然后一下显示所有 View。最好做成动画,效果更自然。

利用多线程的目的就是尽可能的减少 onCreate() 和 onReume() 的时间,使得用户能尽快看到页面,操作页面。

减少主线程阻塞时间。

提高 Adapter 和 AdapterView 的效率。

推荐文章:Android 性能优化之内存检测、卡顿优化、耗电优化、APK瘦身 https://blog.csdn.net/csdn_aiyang/article/details/74989318

黑白屏产生原因:当我们在启动一个应用时,系统会去检查是否已经存在这样一个进程,如果不存在,系统的服务会先检查startActivity中的intent的信息,然后在去创建进程,最后启动Acitivy,即冷启动。而启动出现白黑屏的问题,就是在这段时间内产生的。系统在绘制页面加载布局之前,首先会初始化窗口(Window),而在进行这一步操作时,系统会根据我们设置的Theme来指定它的Theme 主题颜色,我们在Style中的设置就决定了显示的是白屏还是黑屏。

windowIsTranslucent和windowNoTitle,将这两个属性都设置成true (会有明显的卡顿体验,不推荐)

如果启动页只是是一张图片,那么为启动页专一设置一个新的主题,设置主题的android:windowBackground属性为启动页背景图即可

使用layer-list制作一张图片launcher_layer.xml,将其设置为启动页专一主题的背景,并将其设置为启动页布局的背景。

推荐文章:Android启动页解决攻略 https://blog.csdn.net/zivensonice/article/details/51691136

8、强引用置为null,会不会被回收?

参考回答:

不会立即释放对象占用的内存。 如果对象的引用被置为null,只是断开了当前线程栈帧中对该对象的引用关系,而 垃圾收集器是运行在后台的线程,只有当用户线程运行到安全点(safe point)或者安全区域才会扫描对象引用关系,扫描到对象没有被引用则会标记对象,这时候仍然不会立即释放该对象内存,因为有些对象是可恢复的(在 finalize方法中恢复引用 )。只有确定了对象无法恢复引用的时候才会清除对象内存。

9、ListView跟RecyclerView的区别

参考回答:

动画区别:

在RecyclerView中,内置有许多动画API,例如:notifyItemChanged(), notifyDataInserted(), notifyItemMoved()等等;如果需要自定义动画效果,可以通过实现(RecyclerView.ItemAnimator类)完成自定义动画效果,然后调用RecyclerView.setItemAnimator();

但是ListView并没有实现动画效果,但我们可以在Adapter自己实现item的动画效果;

刷新区别:

ListView中通常刷新数据是用全局刷新notifyDataSetChanged(),这样一来就会非常消耗资源;本身无法实现局部刷新,但是如果要在ListView实现局部刷新,依然是可以实现的,当一个item数据刷新时,我们可以在Adapter中,实现一个onItemChanged()方法,在方法里面获取到这个item的position(可以通过getFirstVisiblePosition()),然后调用getView()方法来刷新这个item的数据;

RecyclerView中可以实现局部刷新,例如:notifyItemChanged();

缓存区别:

RecyclerView比ListView多两级缓存,支持多个离ItemView缓存,支持开发者自定义缓存处理逻辑,支持所有RecyclerView共用同一个RecyclerViewPool(缓存池)。

ListView和RecyclerView缓存机制基本一致,但缓存使用不同

推荐文章:【腾讯Bugly干货分享】Android ListView 与 RecyclerView 对比浅析—缓存机制https://zhuanlan.zhihu.com/p/23339185ListView 与 RecyclerView 简单对比https://blog.csdn.net/shu_lance/article/details/79566189Android开发:ListView、AdapterView、RecyclerView全面解析https://www.jianshu.com/p/4e8e4fd13cf7

10、ListView的adapter是什么adapter

参考回答:

BaseAdapter:抽象类,实际开发中我们会继承这个类并且重写相关方法,用得最多的一个适配器!

ArrayAdapter:支持泛型操作,最简单的一个适配器,只能展现一行文字〜

SimpleAdapter:同样具有良好扩展性的一个适配器,可以自定义多种效果!

SimpleCursorAdapter:用于显示简单文本类型的listView,一般在数据库那里会用到,不过有点过时,不推荐使用!

11、LinearLayout、FrameLayout、RelativeLayout性能对比,为什么?

参考回答:

RelativeLayout会让子View调用2次onMeasure,LinearLayout 在有weight时,也会调用子 View 2次onMeasure

RelativeLayout的子View如果高度和RelativeLayout不同,则会引发效率问题,当子View很复杂时,这个问题会更加严重。如果可以,尽量使用padding代替margin。

在不影响层级深度的情况下,使用LinearLayout和FrameLayout而不是RelativeLayout。

JNI

1、对JNI是否了解

参考回答:

Java的优点是跨平台,但也因为其跨平台的的特性导致其本地交互的能力不够强大,一些和操作系统相关的的特性Java无法完成,于是Java提供JNI专门用于和本地代码交互,通过JNI,用户可以调用C、C++编写的本地代码

NDK是Android所提供的一个工具集合,通过NDK可以在Android中更加方便地通过JNI访问本地代码,其优点在于

提高代码的安全性。由于so库反编译困难,因此NDK提高了Android程序的安全性

可以很方便地使用目前已有的C/C++开源库

便于平台的移植。通过C/C++实现的动态库可以很方便地在其它平台上使用

提高程序在某些特定情形下的执行效率,但是并不能明显提升Android程序的性能

2、如何加载NDK库 ?如何在JNI中注册Native函数,有几种注册方法 ?

参考回答:

    public class JniTest{

    //加载NDK库

    static{

    System.loadLirary("jni-test");

    }

    }

注册JNI函数的两种方法

静态方法

动态注册

推荐文章:注册JNI函数的两种方式https://blog.csdn.net/wwj_748/article/details/52347341Android JNI 篇 - 从入门到放弃https://www.jianshu.com/p/3dab1be3b9a4

3、你用JNI来实现过什么功能 ? 怎么实现的 ?(加密处理、影音方面、图形图像处理)

参考回答:推荐文章:Android JNI 篇 - ffmpeg 获取音视频缩略图 https://www.jianshu.com/p/411761bd5f5b

设计模式

1、你所知道的设计模式有哪些?

参考回答:

创建型模式,共五种:工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式。

结构型模式,共七种:适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式。

行为型模式,共十一种:策略模式、模板方法模式、观察者模式、迭代子模式、责任链模式、命令模式、备忘录

模式、状态模式、访问者模式、中介者模式、解释器模式。

2、谈谈MVC、MVP和MVVM,好在哪里,不好在哪里 ?

参考回答:

MVC:

视图层(View) 对应于xml布局文件和java代码动态view部分

控制层(Controller) MVC中Android的控制层是由Activity来承担的,Activity本来主要是作为初始化页面,展示数据的操作,但是因为XML视图功能太弱,所以Activity既要负责视图的显示又要加入控制逻辑,承担的功能过多。

模型层(Model) 针对业务模型,建立数据结构和相关的类,它主要负责网络请求,数据库处理,I/O的操作。

总结

具有一定的分层,model彻底解耦,controller和view并没有解耦层与层之间的交互尽量使用回调或者去使用消息机制去完成,尽量避免直接持有 controller和view在android中无法做到彻底分离,但在代码逻辑层面一定要分清业务逻辑被放置在model层,能够更好的复用和修改增加业务。

MVP

通过引入接口BaseView,让相应的视图组件如Activity,Fragment去实现BaseView,实现了视图层的独立,通过中间层Preseter实现了Model和View的完全解耦。MVP彻底解决了MVC中View和Controller傻傻分不清楚的问题,但是随着业务逻辑的增加,一个页面可能会非常复杂,UI的改变是非常多,会有非常多的case,这样就会造成View的接口会很庞大。

MVVM

MVP中我们说过随着业务逻辑的增加,UI的改变多的情况下,会有非常多的跟UI相关的case,这样就会造成View的接口会很庞大。而MVVM就解决了这个问题,通过双向绑定的机制,实现数据和UI内容,只要想改其中一方,另一方都能够及时更新的一种设计理念,这样就省去了很多在View层中写很多case的情况,只需要改变数据就行。

三者如何选择?

如果项目简单,没什么复杂性,未来改动也不大的话,那就不要用设计模式或者架构方法,只需要将每个模块封装好,方便调用即可,不要为了使用设计模式或架构方法而使用。

对于偏向展示型的app,绝大多数业务逻辑都在后端,app主要功能就是展示数据,交互等,建议使用mvvm。

对于工具类或者需要写很多业务逻辑app,使用mvp或者mvvm都可。

推荐文章:MVC、MVP、MVVM,我到底该怎么选? https://juejin.cn/post/6844903632446423054

3、封装p层之后.如果p层数据过大,如何解决?

参考回答:

对于MVP模式来说,P层如果数据逻辑过于臃肿,建议引入RxJava或则Dagger,越是复杂的逻辑,越能体现RxJava的优越性

推荐文章:(仿有道精品课)RxJava+OkHttp+Retrofit+Dagger2+MVP框架(kotlin版本) https://juejin.cn/post/6844903780715069454#comment

4、是否能从Android中举几个例子说说用到了什么设计模式 ?

参考回答:

AlertDialog、Notification源码中使用了Builder(建造者)模式完成参数的初始化

Okhttp内部使用了责任链模式来完成每个Interceptor拦截器的调用

RxJava的观察者模式;单例模式;GridView的适配器模式;Intent的原型模式

日常开发的BaseActivity抽象工厂模式

5、装饰模式和代理模式有哪些区别 ?

参考回答:

装饰器模式与代理模式的区别就在于

两者都是对类的方法进行扩展,但装饰器模式强调的是增强自身,在被装饰之后你能够在被增强的类上使用增强后的功能。

而代理模式则强调要让别人帮你去做一些本身与你业务没有太多关系的职责(记录日志、设置缓存)代理模式是为了实现对象的控制,因为被代理的对象往往难以直接获得或者是其内部不想暴露出来。

6、实现单例模式有几种方法 ?懒汉式中双层锁的目的是什么 ?两次判空的目的又是什么 ?

参考回答:

单例模式实现方法有多种:饿汉,懒汉(线程安全,线程非安全),双重检查(DCL),内部类,以及枚举

所谓双层检验锁(在加锁前后对实例对象进行两次判空的检验):加锁是为了第一次对象实例化的线程同步,而锁内还要有第二层判空是因为可能会有多个线程进入第一层if判断内部,而在加锁代码块外排队等候,如果锁内不进行第二次检验,仍然会出现实例化多个对象的情况。

推荐文章:单例模式的总结https://xxxblank.github.io/2017/09/14/singleTon/

7、用到的一些开源框架,介绍一个看过源码的,内部实现过程。

参考回答:

面试常客:Okhttp,Retrofit,Glide,RxJava,GreenDao,Dagger等

推荐文章:Android OkHttp源码解析入门教程(一)https://juejin.cn/post/1 OkHttp源码解析入门教程(二)https://juejin.cn/post/6844903765225685006

8、Fragment如果在Adapter中使用应该如何解耦?

参考回答:

接口回调

广播

点赞抽奖 明天老子不上班 Mini Program

推荐阅读

(点击标题可跳转阅读)

来自美团的Android资料

Android篇:2019初中级Android开发社招面试解答(中-上半场)

Android篇:2019初中级Android开发社招面试解答(上)

觉得本文对你有帮助?请分享给更多人


wx号:gulinhai531

顾林海公众号

不定期推出优质文

章,喜欢的朋友们

给我个好看。

好文章,我在看❤️