Android程序猿 面试秘籍

这里写图片描述

惟楚有才于斯为盛!!!

又到夏季招聘好时节了,程序员面试考核一直都是热门话题,今年也不例外。

而对于Android程序员来说,面试时候什么最重要呢?绝对是技术,如今很多企业招聘Android工程师会不仅会给一份笔试考题,还会在面试中不断的问你技术问题,从Android基础到Android项目,难度不亚于一场高考,哪怕是技术过硬的Android程序员在面试+笔记的连番炮轰下,也会蒙圈。

但是,从今天开始,各位Android程序员再也不用担心面试了,我根据自己以往的一些面试经历,总结了一些面试官面试中可能会去问的问题来给大家分享一下。做事就要做到极致,希望每位同胞们能够过五关斩六将:去到自己心仪的公司,能够拥有属于自己的那一份美好的未来.


如何对Android应用进行性能分析(★★★★)

一款App流畅与否安装在自己的真机里,玩几天就能有个大概的感性认识。不过通过专业的分析工具可以使我们更好的分析我们的应用。而在实际开发中,我们解决完当前应用所有bug后,就会开始考虑到新能的优化。

如果不考虑使用其他第三方性能分析工具的话,我们可以直接使用ddms中的工具,其实ddms工具已经非常的强大了。ddms中有traceview、heap、allocation tracker等工具都可以帮助我们分析应用的方法执行时间效率和内存使用情况。

traceview

TraceView简介

Traceview是Android平台特有的数据采集和分析工具,它主要用于分析Android中应用程序的hotspot(瓶颈)。Traceview本身只是一个数据分析工具,而数据的采集则需要使用Android SDK中的Debug类或者利用DDMS工具。

二者的用法如下:

开发者在一些关键代码段开始前调用Android SDK中Debug类的startMethodTracing函数,并在关键代码段结束前调用stopMethodTracing函数。这两个函数运行过程中将采集运行时间内该应用所有线程(注意,只能是Java线程)的函数执行情况,并将采集数据保存到/mnt/sdcard/下的一个文件中。开发者然后需要利用SDK中的Traceview工具来分析这些数据


什么情况下会导致内存泄露(★★)

Android的虚拟机是基于寄存器的Dalvik,它的最大堆大小一般是16M,有的机器为24M。因此我们所能利用的内存空间是有限的。如果我们的内存占用超过了一定的水平就会出现OutOfMemory的错误。

内存溢出的几点原因:

(1)资源释放问题

程序代码的问题,长期保持某些资源,如Context、Cursor、IO流的引用,资源得不到释放造成内存泄露。

(2)对象内存过大问题

保存了多个耗用内存过大的对象(如Bitmap、XML文件),造成内存超出限制。

(3)static关键字的使用问题

static是Java中的一个关键字,当用它来修饰成员变量时,那么该变量就属于该类,而不是该类的实例。所以用static修饰的变量,它的生命周期是很长的,如果用它来引用一些资源耗费过多的实例(Context的情况最多),这时就要谨慎对待了。

public class ClassName {  

     private static Context mContext;  

     //省略

}

以上的代码是很危险的,如果将Activity赋值到mContext的话。那么即使该Activity已经onDestroy,但是由于仍有对象保存它的引用,因此该Activity依然不会被释放。

针对static的解决方案

(1) 应该尽量避免static成员变量引用资源耗费过多的实例,比如Context。

(2) 尽量使用ApplicationContext,因为Application的Context的生命周期比较长,引用它不会出现内存泄露的问题。

(3) 使用WeakReference代替强引用。比如可以使用WeakReference mContextRef;

1.线程导致内存溢出

线程产生内存泄露的主要原因在于线程生命周期的不可控。我们来考虑下面一段代码。

这里写图片描述

这段代码很平常也很简单,是我们经常使用的形式。我们思考一个问题:假设MyThread的run函数是一个很费时的操作,当我们开启该线程后,将设备的横屏变为了竖屏,一 般情况下当屏幕转换时会重新创建Activity,按照我们的想法,老的Activity应该会被销毁才对,然而事实上并非如此。

由于我们的线程是Activity的内部类,所以MyThread中保存了Activity的一个引用,当MyThread的run函数没有结束时,MyThread是不会被销毁的,因此它所引用的老的Activity也不会被销毁,因此就出现了内存泄露的问题。

有些人喜欢用Android提供的AsyncTask,但事实上AsyncTask的问题更加严重,Thread只有在run函数不结束时才出现这种内存泄露问题,然而AsyncTask内部的实现机制是运用了ThreadPoolExcutor,该类产生的Thread对象的生命周期是不确定的,是应用程序无法控制的,因此如果AsyncTask作为Activity的内部类,就更容易出现内存泄露的问题。

针对这种线程导致的内存泄露问题的解决方案:

(1) 将线程的内部类,改为静态内部类(因为非静态内部类拥有外部类对象的强引用,而静态类则不拥有)。

(2) 在线程内部采用弱引用保存Context引用。


如何避免OOM异常(★★★★)

OOM内存溢出,想要避免OOM异常首先我们要知道什么情况下会导致OOM异常。

(1)图片过大导致OOM

Android 中用bitmap时很容易内存溢出,比如报如下错误:Java.lang.OutOfMemoryError : bitmap size exceeds VM budget。

解决方法:

方法1: 等比例缩小图片

这里写图片描述

以上代码可以优化内存溢出,但它只是改变图片大小,并不能彻底解决内存溢出。

方法2:对图片采用软引用,及时地进行recyle()操作

这里写图片描述

方法3:使用加载图片框架处理图片,如专业处理加载图片的ImageLoader图片加载框架。还有我们学的XUtils的BitMapUtils来做处理。

(2)界面切换导致OOM

一般情况下,开发中都会禁止横屏的。因为如果是来回切换话,activity的生命周期会重新销毁然后创建。

有时候我们会发现这样的问题,横竖屏切换N次后 OOM了。

这种问题没有固定的解决方法,但是我们可以从以下几个方面下手分析。

1、看看页面布局当中有没有大的图片,比如背景图之类的。

去除xml中相关设置,改在程序中设置背景图(放在onCreate()方法中):

这里写图片描述

在Activity destory时注意,drawable.setCallback(null);防止Activity得不到及时的释放。

2、跟上面方法相似,直接把xml配置文件加载成view 再放到一个容器里,然后直接调用 this.setContentView(View view);方法,避免xml的重复加载。

3、 在页面切换时尽可能少地重复使用一些代码

比如:重复调用数据库,反复使用某些对象等等……

(3)查询数据库没有关闭游标

程序中经常会进行查询数据库的操作,但是经常会有使用完毕Cursor后没有关闭的情况。如果我们的查询结果集比较小,对内存的消耗不容易被发现,只有在常时间大量操作的情况下才会出现内存问题,这样就会给以后的测试和问题排查带来困难和风险。

(4)构造Adapter时,没有使用缓存的 convertView

在使用ListView的时候通常会使用Adapter,那么我们应该尽可能的使用ConvertView。

为什么要使用convertView?

当convertView为空时,用setTag()方法为每个View绑定一个存放控件的ViewHolder对象。当convertView不为空,重复利用已经创建的view的时候,使用getTag()方法获取绑定的ViewHolder对象,这样就避免了findViewById对控件的层层查询,而是快速定位到控件。

(5)Bitmap对象不再使用时调用recycle()释放内存

有时我们会手工的操作Bitmap对象,如果一个Bitmap对象比较占内存,当它不再被使用的时候,可以调用Bitmap.recycle()方法回收此对象的像素所占用的内存,但这不是必须的,视情况而定。

(6)其他

Android应用程序中最典型的需要注意释放资源的情况是在Activity的生命周期中,在onPause()、onStop()、 onDestroy()方法中需要适当的释放资源的情况。使用广播没有注销也会产生OOM。


Android中如何捕获未捕获的异常(2016.5.5)(★★★)

UncaughtExceptionHandler

1.自定义一个Application,比如叫MyApplication继承Application实现UncaughtExceptionHandler。

2..覆写UncaughtExceptionHandler的onCreate和uncaughtException方法。

这里写图片描述

注意:上面的代码只是简单的将异常打印出来。

在onCreate方法中我们给Thread类设置默认异常处理handler,如果这句代码不执行则一切都是白搭。

在uncaughtException方法中我们必须新开辟个线程进行我们异常的收集工作,然后将系统给杀死。

  1. 在AndroidManifest中配置该Application

这里写图片描述

(二)Bug收集工具Crashlytics

Crashlytics 是专门为移动应用开发者提供的保存和分析应用崩溃的工具。国内主要使用的是友盟做数据统计。

Crashlytics的好处:

  1. 不会漏掉任何应用崩溃信息。

  2. 可以象Bug管理工具那样,管理这些崩溃日志。

  3. 可以每天和每周将崩溃信息汇总发到你的邮箱,所有信息一目了然。

使用步骤:

1.注册需要审核通过才能使用,国内同类产品顶多发个邮箱激活链接;

2.支持Eclipse、Intellij IDEA和Android Studio等三大IDE;

3.Eclipse插件是iOS主题风格UI,跟其他plugin在一起简直是鹤立鸡群;

4.只要登录帐号并选择项目,会自动导入jar包并生成一个序列号,然后在AndroidManifest.xml和启动Activity的入口添加初始化代码,可以说是一键式操作,当然要使用除错误统计外的其他功能还是得自己添加代码;

5.不像友盟等国内同类产品,将固定的序列号直接写入xml文件,而是动态自动生成的;当然这个存放序列号的xml文件也是不能修改和提交到版本控制系统的;

6.后台可以设置邮件提醒,当然这个最好不要开启,Android开发那数量惊人、千奇百怪的错误信息你懂的。

7.不仅能统计到UncaughtException这种未捕获的Crash异常信息,只要在try/catch代码块的catch中添加一行代码就能统计到任何异常;

try{ myMethodThatThrows(); }catch(Exception e){ Crashlytics.logException(e); //handle your exception here! }

相当详细的错误信息,不仅仅是简单的打印StackTrace信息;并且能看到最近一次crash的机器可用内存等信息,而不仅仅是简单统计机型和版本号。

使用连接:http://blog.csdn.net/smking/article/details/39320695


ANR是什么?怎样避免和解决ANR(★★★★★)

在Android上,如果你的应用程序有一段时间响应不够灵敏,系统会向用户显示一个对话框,这个对话框称作应用程序无响应(ANR:Application Not Responding)对话框。用户可以选择让程序继续运行,但是,他们在使用你的应用程序时,并不希望每次都要处理这个对话框。因此,在程序里对响应性能的设计很重要,这样,系统不会显示ANR给用户。

Activity 5秒 broadcast10秒

耗时的操作worker thread里面完成, handler message…AsynTask , intentservice.等…

ANR:Application Not Responding,即应用无响应

ANR一般有三种类型:

1:KeyDispatchTimeout(5 seconds) –主要类型

按键或触摸事件在特定时间内无响应

2:BroadcastTimeout(10 seconds)

BroadcastReceiver在特定时间内无法处理完成

3:ServiceTimeout(20 seconds) –小概率类型

Service在特定的时间内无法处理完成

超时的原因一般有两种:

(1)当前的事件没有机会得到处理(UI线程正在处理前一个事件没有及时完成或者looper被某种原因阻塞住)

(2)当前的事件正在处理,但没有及时完成

UI线程尽量只做跟UI相关的工作,耗时的工作(数据库操作,I/O,连接网络或者其他可能阻碍UI线程的操作)放入单独的线程处理,尽量用Handler来处理UI thread和thread之间的交互。

UI线程主要包括如下:

Activity:onCreate(), onResume(), onDestroy(), onKeyDown(), onClick()

AsyncTask: onPreExecute(), onProgressUpdate(), onPostExecute(), onCancel()

Mainthread handler: handleMessage(), post(runnable r)

查找ANR的方式: 1. 导出/data/data/anr/traces.txt,找出函数和调用过程,分析代码 2. 通过性能LOG人肉查找


Android线程间通信有哪几种方式(★★★)

共享内存(变量);

文件,数据库;

Handler;

Java里的wait(),notify(),notifyAll()


Devik进程,linux进程,线程的区别(★)

Dalvik虚拟机运行在Linux操作系统之上。Linux操作系统并没有纯粹的线程概念,只要两个进程共享一个地址空间,那么就可以认为它们是同一个进程的两个线程。Linux系统提供了两个fork和clone调用,其中,前者是用来创建进程的,而后者是用来创建线程的。

一般来说,虚拟机的进程和线程都是和目标机器本地操作系统的进程和线程一一对应的,这样的好处是可以使本地操作系统来调度进程和线程。

每个Android应用程序进程都有一个Dalvik虚拟机实例。这样做得好处是Android应用程序进程之间不会互相影响,也就是说,一个Android应用程序进程的意外终止,不会影响到其他的应用程序进程的正常运行。

每个Android应用程序进程都是由一种称为Zygote的进程fork出来的。Zygote进程是由init进程启动起来的,也就是在系统启动的时候启动的。Zygnote进程在启动的时候,会创建一个虚拟机实例,并且在这个虚拟机实例将所有的Java核心库都加载起来。每当Zygote进程需要创建一个Android应用程序进程的时候,它就通过复制自身来实现,也就是通过fork系统调用来实现。这些被fork出来的Android应用程序进程,一方面是复制了Zygote进程中的虚拟机实例,另外一方面是与Zygote进程共享了同一套Java核心库。这样不仅Android程序进程的创建很快,而且所有的应用程序都共享同一套Java核心库而节省了内存空间。


描述一下android的系统架构?

  1. android系统架构分从下往上为linux 内核层、运行库、应用程序框架层、和应用程序层。

  2. 负责硬件的驱动程序、网络、电源、系统安全以及内存管理等功能。

  3. 即c/c++函数库部分,大多数都是开放源代码的函数库,例如webkit,该函数库负责 android网页浏览器的运行,例如标准的c函数库libc、openssl、sqlite等,当然也包括支持游戏开发2dsgl和 3dopengles,在多媒体方面有mediaframework框架来支持各种影音和图形文件的播放与显示,例如mpeg4、h.264、mp3、 aac、amr、jpg和png等众多的多媒体文件格式。android的runtime负责解释和执行生成的dalvik格式的字节码。

  4. (应用软件架构),java应用程序开发人员主要是使用该层封装好的api进行快速开发。

  5. 该层是java的应用程序层,android内置的googlemaps、e-mail、即时通信工具、浏览器、mp3播放 器等处于该层,java开发人员开发的程序也处于该层,而且和内置的应用程序具有平等的位置,可以调用内置的应用程序,也可以替换内置的应用程序。


android应用对内存是如何限制的?我们应该如何合理使用内存?(2016.01.24)(★★★★)

如何限制的?

Android应用的开发语言为Java,每个应用最大可使用的堆内存受到Android系统的限制

•Android每一个应用的堆内存大小有限

•通常的情况为16M-48M

•通过ActivityManager的getMemoryClass()来查询可用堆内存限制

•3.0(HoneyComb)以上的版本可以通过largeHeap=“true”来申请更多的堆内存

•NexueHeap 512

•如果试图申请的内存大于当前余下的堆内存就会引发OutOfMemoryError()

•应用程序由于各方面的限制,需要注意减少内存占用,避免出现内存泄漏。

获取这个代码:

这里写图片描述


如何合理使用内存?

1、注意资源回收,像数据库,输入输出流,定位操作这样的对象,要在使用完及时关闭流。

2、少使用静态变量,因为系统将静态变量的优先级设定的很高,会最后回收。所以可能因为静态变量导致该回收的没有回收。而回收了不该回收的内存。

3、注意大图片的缩放,如果载入的图片很大,要先经过自己程序的处理,降低分辨率等。最好设置多种分辨率格式的图片,以减少内存消耗。

4、动态注册监听,把一些只有显示的时候才使用到的监听放进程序内部,而不是放在manifesat中去。

5、减少使用动画,或者适当减少动画的帧数。

6、注意自己的程序逻辑,在该关闭自己程序的控件的时候,主动关闭,不要交给系统去决定。(这个要自己把握好,也不是说都自己搞定,只有那些自己确定需要关闭的对象,自己将其关闭。)


AIDL 什么是AIDL以及如何使用(★★★★)

①aidl是Android interface definition Language 的英文缩写,意思Android 接口定义语言。

②使用aidl可以帮助我们发布以及调用远程服务,实现跨进程通信。

③将服务的aidl放到对应的src目录,工程的gen目录会生成相应的接口类

我们通过bindService(Intent,ServiceConnect,int)方法绑定远程服务,在bindService中有一个ServiceConnec接口,我们需要覆写该类的onServiceConnected(ComponentName,IBinder)方法,这个方法的第二个参数IBinder对象其实就是已经在aidl中定义的接口,因此我们可以将IBinder对象强制转换为aidl中的接口类。

我们通过IBinder获取到的对象(也就是aidl文件生成的接口)其实是系统产生的代理对象,该代理对象既可以跟我们的进程通信,又可以跟远程进程通信,作为一个中间的角色实现了进程间通信。


AIDL的全称是什么?如何工作?能处理哪些类型的数据(★★★)

AIDL全称Android Interface Definition Language(AndRoid接口描述语言) 是一种接口描述语言; 编译器可以通过aidl文件生成一段代码,通过预先定义的接口达到两个进程内部通信进程跨界对象访问的目的。需要完成2件事情: 1. 引入AIDL的相关类.; 2. 调用aidl产生的class.理论上, 参数可以传递基本数据类型和String, 还有就是Bundle的派生类, 不过在Eclipse中,目前的ADT不支持Bundle做为参数。


Android中的动画

[Android中的动画有哪几类,它们的特点和区别是什么(★★★)

Android中动画分为两种,一种是Tween动画、还有一种是Frame动画。

Tween动画,这种实现方式可以使视图组件移动、放大、缩小以及产生透明度的变化;

Frame动画,传统的动画方法,通过顺序的播放排列好的图片来实现,类似电影。

如何修改Activity进入和退出动画(★★)

可以通过两种方式,一是通过定义Activity的主题,二是通过覆写Activity的overridePendingTransition方法。

通过设置主题样式

在styles.xml中编辑如下代码:

这里写图片描述

添加themes.xml文件:

这里写图片描述

在AndroidManifest.xml中给指定的Activity指定theme。

覆写overridePendingTransition方法

overridePendingTransition(R.anim.fade, R.anim.hold);

属性动画,例如一个button从A移动到B点,B点还是可以响应点击事件,这个原理是什(★★)

补间动画只是显示的位置变动,View的实际位置未改变,表现为View移动到其他地方,点击事件仍在原处才能响应。而属性动画控件移动后事件相应就在控件移动后本身进行处理.

猜你喜欢

转载自blog.csdn.net/qq_36437339/article/details/80859225