Android 一些面试问题收集
695486662
8年前
<h2><strong>前言</strong></h2> <p>因为最近换工作,所以需要面试,但是面试了3家只有一个offer,只是可能因为工资问题最终还是需要继续面试,同时感觉每次面试都不做任何准备,不看面试题,不去温习一下书本,感觉临场表现可能的确不行吧,所以本文主要记录在面试中被遇到的一些问题和一些我觉得的答案,以做记录,不过通过三次面试感觉有时候面试多点也好,毕竟一般公司都会问你公司所在乎的问题(反正我之前面试别人就是这样),所以很多时候吧面试的问题拿来学习,也是一种不错的办法,同时也请教一下,怎么样才能增加面试机会啊,投了几天简历了,才收到4个面试通知(其中2个直接邮件通知,因为预约的时间相同,所以只去了一家),在boss直聘上问也没人回答,甚至看都不看,这是什么鬼?</p> <h2><strong>正文</strong></h2> <p>好了下面就是面试中遇到的一些问题了</p> <h3><strong>1.网络优化</strong></h3> <p>问题:有没有做过网络优化,比如信号不好和手机网络状态频繁变化的情况下做了什么优化 <strong>答案:</strong></p> <p><strong>底层优化:</strong></p> <p>1、 <strong>IP访问</strong> 通过IP和域名结合访问方法,因为域名解析也需要一定的时间,所以直接通过IP访问会比域名要更快,当然因为IP随时可能会变,所以我们存储的IP是一个动态IP,一旦IP发生改变请求失败时,就通过解析域名获取新的IP,通过新的IP来访问</p> <p>2、 <strong>链接复用</strong> 可以节省连接建立时间,如开启 keep-alive,Http 1.1 默认启动了 keep-alive,对于 Android 来说默认情况下 HttpURLConnection 和 HttpClient 都开启了 keep-alive,检查keep-alive是否开业也很简单,直接用抓包软件对请求抓包,如果请求头是否有Connection: keep-alive,如果有则说明已经开启了</p> <p>3、 <strong>请求合并</strong> 简单来说越少请求接口越好,如果一个接口能把相关必要的数据一起获取下来,就不用别个数据去调用一个接口了,我之前是试过一个首页调用了8个接口才把数据完全拿到,虽然这样对于接口本身来说业务分离的比较好,但是对于客户端来说这样的设计明显不合理,而且多次请求也会增加服务器压力</p> <p>4、 <strong>请求压缩</strong></p> <p>a)对于 POST 请求,Body 和接口返回的数据可以做 Gzip 压缩,当然开启了Gzip可能需要服务器配合</p> <p>b)请求头压缩,具体可以搜索SPDY ,因为我对这一块也不是很了解</p> <p><strong>应用层优化</strong></p> <p>1、 <strong>请求失败重复请求</strong> 简单来说就是给定一个可以出错的次数,如果在指定次数中都失败了,那么则确定请求失败,当然要注意的几点就是一定要给定合理的链接超时限制,否则如果超时时间过短,网速慢的情况下在多次请求都到达不了,但是太长,网速慢的请求下就要等很久才能有结果反馈(主要是针对失败的反馈)</p> <p>2、 <strong>网络请求失败的处理</strong> 主要是针对网络请求失败做一些处理,比如显示网络请求失败的界面,点击可以重试</p> <p>3、 <strong>缓存</strong> 对于及时性不是很高或者没有网络的情况下,可以使用缓存来减少网络访问次数和加快数据展示速度,当然值得注意的是,如果界面对数据实时性要求特别高,还是不建议用缓存,如支付等界面</p> <p>4、 <strong>断点</strong> 对于下载来说,处理好断点下载是很必要的,毕竟移动网络并不稳定,所以如果能断点下载,对于流量和电量都是一个很好的优化,同时上传也可以做断点上传,不过一定要确定好的就是被上传的源文件未被修改,同时断点上传也需要服务器的支持</p> <h3><strong>2.电量优化</strong></h3> <p>首先分析APP真正耗电的地方:Android手机大量的电主要消耗在网络、传感器,当然如果是游戏程序还主要消耗在CPU和GPU上面,当然我们只是开发APP应用,所以一般来说CPU和GPU不会消耗过多电量,除非你用了需要很大计算量的自定义控件(我曾经写了一个自定义控件,在OnGlobalLayoutListener中没有异常监听,而我的控件又放在ListView中,导致此监听一直被执行,同时适配器也一直调用getItemCount的方法,虽然没有调用getView,但是一直让CPU处理计算状态,感觉肯定会加大电量消耗),所以我们主要从这几个方面来入手解决电量优化的问题</p> <p>1、 <strong>网络优化</strong> 这个可以直接参考上面的网络优化,当然也有一个问题,那就是我们还需要在请求网络的时候判断网络的状态,如果网络是不可用状态,就不用再去发起网络请求了</p> <p>2、 <strong>服务优化</strong> 很多程序会有一个服务定时去更新服务器数据,一般来说是用开启一个线程无限循环的去更新,然后休眠线程,到时在去开启,当然如果是每次间隔比较长,那么就可以通过使用AlarmManager来实现定时调用线程,因为AlarmManager是系统原生底层的东西,消耗是非常少的。不过如果本身间隔很短,比如10几秒,那么就不用使用AlarmManager了,毕竟使用AlarmManager本身也会带来一定消耗,就像你为了防止UI线程卡顿启动另外一个线程来执行几十毫秒的操作,可能你启动线程的时候,这个操作就已经完成了,所以这个一定要根据自己的需求,来确定到底使用哪种办法</p> <p>3、 <strong>内存优化</strong> 这个就很简单了,主要是针对一些大内存的优化,比如bitmap、文件流、游标这些用完就释放掉</p> <p>4、 <strong>传感器优化</strong> 如果APP对定位要求不是特别高,那么则可以使用wifi和移动网络cell定位即可,同时一般APP只需要简单定位,定位完成就可以关闭掉定位了,其他传感器也同理。</p> <p>3.解决小米、魅族、华为等手机从系统层拦截推送</p> <p>这个我还没有想出什么好的答案。。。</p> <h3><strong>3.屏幕适配</strong></h3> <p>1、 <strong>使用百分比</strong> 使用百分比布局很多时候能解决一些简单的布局适配</p> <p>2、 <strong>layout文件夹</strong> 主要是建立layout文件夹,可以为平板和手机分别建立布局,也可以用来适配横竖屏</p> <p>3、 <strong>values文件夹</strong> 可以为不同尺寸和不同分辨率不同屏幕密度来建立文件夹,屏幕适配的主要方式</p> <p>4、 <strong>9.png</strong> 可以拉伸的图片文件</p> <p>5、 <strong>自定义控件</strong> 有时候我们只能确定一个控件的宽度,但是高度却是按照一定比例出来的,这时候可以考虑用自定义控件实现,通过比例计算出高度,因为如果在布局中写死宽高还需要为每个屏幕来进行适配,而在代码中获取宽度来计算高度也有一定问题毕竟控件的宽高好绘制好了才能获取,当获取成功后再修改高度,会造成闪烁,所以通过自定义控件在onMeasure中计算并修改就不会有闪烁问题,而且性能会更好</p> <p>6、 <strong>使用不同的图片</strong> 针对不同的屏幕密度使用不同的图标</p> <h3><strong>4.Handler机制</strong></h3> <p>handler机制的4个主要组件</p> <p>1、 <strong>Looper</strong> 一个线程可以产生一个Looper对象,用它来管理此线程中的消息队列(MessageQueue),无限循环从消息队列中获取消息进行处理,如果没有消息则进入等待状态</p> <p>2、 <strong>handler对象</strong> 与Looper进行沟通和处理消息的对象,可以把消息push进消息队列,同时一旦消息的执行到了,Looper会从消息队列中取出消息,先判断消息是不是底层(ndk)消息,如果是就交给底层实现,如果不是则根据消息的属性获取发送的handler,调用handler的handlerMessage方法,处理消息</p> <p>3、 <strong>MessageQueue</strong> 消息队列,用来存放需要处理的消息,保存在ThreadLocal中,所以只有线程被销毁时,才会释放</p> <p>4、 <strong>Thread</strong> 可以是UI线程,UI线程默认会初始化好MessageQueue,也可以是其他线程,除了HandlerThread已经实现好之外,其他线程需要手动调用Looper.prepare方法手动初始化好,然后调用Looper.loop循环获取消息</p> <h3><strong>5.布局优化</strong></h3> <p>1、 <strong>include</strong> 把多个界面相同的布局抽离出来一个布局文件,使用include标签导入要引用的界面布局中,这样能加快很多开发速度, 注意 这里主要是针对开发速度有加快效果,对运行速度没有什么卵用</p> <p>2、 <strong>viewstub</strong> viewstub作用跟include差不多,都是引入一个布局,不同点在于viewstub主要导入一开始并不会显示的布局,只会在特定情况下显示的布局,比如网络连接失败,显示的提示界面,所以一开始viewstub引入的布局是不会解析的,需要解析时在java中通过(ViewStub)findViewById(id)找到ViewStub,通过stub.inflate()展开ViewStub,然后得到子View</p> <p>3、 <strong>merge</strong> 在使用了include后可能导致布局嵌套过多,多余不必要的layout节点,从而导致解析变慢,当被引用的布局能确定引用布局引用处的父布局,同时也没有margin和padding等属性时,可以使用merge减少一层布局嵌套</p> <p>4、 <strong>减少嵌套层次</strong> 其实只要不怕麻烦,RelativeLayout可以减少很多布局嵌套,当然也要在RelativeLayout和LinearLayout做出取舍,有些简单的布局,只有2层的话那么用RelativeLayout和LinearLayout的层次是一样的,所以要根据具体情况做出取舍</p> <p>5、 <strong>减少控件使用</strong> 据我所知,差不多的控件都是支持上下左右图标的,所以如果出现左边一个图标中间文本右边图标的控件,可以使用一个TextView就能实现,而不用使用一个ViewGroup,然后再用2个图标一个文本控件,一个控件也有劣势,那就是适配,因为图标的大小不好控制</p> <p>6、 <strong>用SurfaceView或TextureView代替普通View</strong> 如果是有需要大量绘制的控件,可以使用SurfaceView和TextureView来代替,因为这2个控件是在非UI线程进行绘制的</p> <p> </p> <p>来自:http://www.raye.wang/2016/09/13/android-yi-xie-mian-shi-wen-ti-shou-ji/</p> <p> </p>