Android面试题汇总

来源:互联网 发布:linux的gcc编译器 编辑:程序博客网 时间:2024/05/18 00:34

题目来源是CSDN上@xingfeng_coder的非科班生的Android秋招求职经历这篇文章。边向大佬学习边汇总,错误之处还望指正。
暂时只有部分题目,后续会慢慢更新……

1. Android进程优先级

前台进程、可见进程、服务进程、后台进程、空进程

2. 进程的服务保活

(1)系统根据资源分配情况杀死服务
onStartCommand() 方法的返回值设为 START_STICKY ,服务就会在资源紧张的时候被杀掉,然后在资源足够的时候再恢复。当然也可设置为前台服务,使其有高的优先级,在资源紧张的时候也不会被杀掉。
(2)用户通过 settings -> Apps -> Running -> Stop 方式杀死服务
用户干预,主动杀掉运行中的服务。这个过程杀死服务会通过服务的生命周期,也就是会调用 onDestory() 方法,这时候一个方案就是在 onDestory() 中发送广播开启自己。这样杀死服务后会立即启动。开启两个服务,相互监听,相互启动。服务A监听B的广播来启动B,服务B监听A的广播来启动A。
(3)用户通过 settings -> Apps -> Downloaded -> Force Stop 方式杀死服务
处理这个情况的唯一方法是屏蔽掉 force stop和 uninstall 按钮

3. HashMap在插入自定义类时,要重写哪些方法

使用HashMap,如果key是自定义的类,就必须重写hashcode()和equals()。
HashMap中,如果要比较key是否相等,要同时使用这两个函数!因为自定义的类的hashcode()方法继承于Object类,其hashcode码为默认的内存地址,这样即便有相同含义的两个对象,比较也是不相等的,例如,生成了两个“羊”对象,正常理解这两个对象应该是相等的,但如果你不重写 hashcode()方法的话,比较是不相等的!
HashMap中的比较key是这样的,先求出key的hashcode(),比较其值是否相等,若相等再比较equals(),若相等则认为他们是相等 的。若equals()不相等则认为他们不相等。

4. Touch事件分发机制

  • Touch事件分发中只有两个主角:ViewGroup和View。ViewGroup包含onInterceptTouchEvent、dispatchTouchEvent、onTouchEvent三个相关事件。View包含dispatchTouchEvent、onTouchEvent两个相关事件。其中ViewGroup又继承于View。
  • ViewGroup和View组成了一个树状结构,根节点为Activity内部包含的一个ViwGroup。
  • 触摸事件由Action_Down、Action_Move、Aciton_UP组成,其中一次完整的触摸事件中,Down和Up都只有一个,Move有若干个,可以为0个。
  • 当Acitivty接收到Touch事件时,将遍历子View进行Down事件的分发。ViewGroup的遍历可以看成是递归的。分发的目的是为了找到真正要处理本次完整触摸事件的View,这个View会在onTouchuEvent结果返回true。
  • 当某个子View返回true时,会中止Down事件的分发,同时在ViewGroup中记录该子View。接下去的Move和Up事件将由该子View直接进行处理。由于子View是保存在ViewGroup中的,多层ViewGroup的节点结构时,上级ViewGroup保存的会是真实处理事件的View所在的ViewGroup对象:如ViewGroup0-ViewGroup1-TextView的结构中,TextView返回了true,它将被保存在ViewGroup1中,而ViewGroup1也会返回true,被保存在ViewGroup0中。当Move和UP事件来时,会先从ViewGroup0传递至ViewGroup1,再由ViewGroup1传递至TextView。
  • 当ViewGroup中所有子View都不捕获Down事件时,将触发ViewGroup自身的onTouch事件。触发的方式是调用super.dispatchTouchEvent函数,即父类View的dispatchTouchEvent方法。在所有子View都不处理的情况下,触发Acitivity的onTouchEvent方法。
  • onInterceptTouchEvent有两个作用:1.拦截Down事件的分发。2.中止Up和Move事件向目标View传递,使得目标View所在的ViewGroup捕获Up和Move事件。

5. 如何实现客户端长连接的

可以通过使用第三方长连接服务或者是自己实现连接的方式;
自定义实现长连接可以通过使用NIO或者是第三方NIO框架,比如MINA实现;
长连接实现中通过心跳包的机制实现App与服务器的长时间连接;
可以通过闹钟的机制定时检测长连接服务是否可靠,长连接是否出现异常等;
为了消息的及时性,在长连接出现异常情况时可通过创建轮训服务的机制实现对消息的获取,待长连接恢复之后关闭轮训服务。

6. Activity的launchMode

  • standard模式是默认的启动模式。不管有没有已存在的实例,都生成新的实例。
  • singleTop如果发现有对应的Activity实例正位于栈顶,则重复利用,不再生成新的实例。(消息推送、登录)
  • singleTask如果发现有对应的Activity实例,则使此Activity实例之上的其他Activity实例统统出栈,使此Activity实例成为栈顶对象,显示到幕前。(浏览器)
  • singleInstance会启用一个新的栈结构,将Acitvity放置于这个新的栈结构中,并保证不再有其他Activity实例进入。

7. 转动屏幕时会发生什么

当将手机屏幕旋转时,系统会被强制重置启动onCreate方法。
不启动onCreate方法的操作:
- 修改AndroidManifest.xml
在activity属性中加入:android:configChanges=”orientation|keyboardHidden”
android:configChanges:这个方法主要是负责列出清单,当清单上用户指定的设置改变时,Activity会自己处理这些变化。
orientation:屏幕界面旋转(可能是用户手动旋转的),【注意:如果你的开发API等级等于或高于13,你还需要设置screenSize,因为screenSize会在屏幕旋转时改变】
keyboardHidden:键盘辅助功能改变
- 在相对应的Activity中继承重写onConfigurationChanged方法
- 只有一种状态

android:screenOrientation="landscape" //横屏设置android:screenOrientation="portrait" //竖屏设置

8. Service两种启动方式的区别

  • startService
    Service会经历 onCreate -> onStart,stopService的时候直接onDestroy
    如果是调用者自己直接退出而没有调用stopService的话,Service会一直在后台运行。下次调用者再起来可以stopService。
  • bindService
    Service只会运行onCreate,这个时候服务的调用者和服务绑定在一起。如果调用者退出了,Srevice就会调用onUnbind->onDestroyed被终止。并且这种方式还可以让调用方调用服务上的其他方法。

9.OkHttp和HttpUrlConnection以及Volley的区别

  • HttpUrlConnection
    这是google官方提供的用来访问网络,但是HttpUrlConnection实现的比较简单,只支持1.0/1.1,并没有上面讲的多路复用,如果碰到app大量网络请求的时候,性能比较差。HttpUrlConnection底层是用Socket来实现的。
  • Volley
    Volley是一个开源库,它只是封装了访问网络的一些操作,但是底层还是使用HttpUrlConnection。Volley只是一个引用了HttpUrlConnection,它并不关心网络连接过程,只是封装了请求的过程而已。
  • OkHttp
    OkHttp像HttpUrlConnection一样,实现了一个网络连接的过程。所以按照层级来说,OkHttp和HttpUrlConnection是一级的,用socket实现了网络连接,只是OkHttp更强大。HttpUrlConnection在IO方面用到的是InputStream和OutputStream,但是OkHttp用的是sink和source,这两个是在Okio这个开源库里的,sink相当于outputStream,source相当于是inputStream。sink和source比InputStream和OutputStream更加强大,单拿sink举例,他的子类有BufferedSink(支持缓冲)、GzipSink(支持Gzip压缩)、ForwardingSink和InflaterSink(后面这两者服务于GzipSink),source对应的也有。

10.为什么有滑动冲突?怎么处理?

http://blog.csdn.net/u010302764/article/details/72778732

11.处理页面UI刷新和网络操作

了解Epoll模型:http://www.jianshu.com/p/7bc2b86c4d89

12.对热修复的理解

主要修复方案:http://www.jianshu.com/p/d10aa991ca76
微信方案Tinker(另有与so热修复相关):http://blog.csdn.net/l2show/article/details/53187548

13.Android OOM处理

原因及应对:http://blog.csdn.net/crazy__chen/article/details/45460279

补充:
1 .静态变量导致的Memory leak
静态变量的生命周期和类是息息相关的,它们分配在方法区上,垃圾回收一般不会回收这一块的内存。所以我们在代码中用到静态对象,在不用的时候如果不赋null值,消除对象的引用的话,那么这些对象是很难被垃圾回收的,如果这些对象一多或者比较大的话,程序出现OOM的概率就比较大了。因为静态变量而出现内存泄漏是很常见的。
2. 不合理使用Context 导致的Memory leak
android 中很多地方都要用到context,连基本的Activty 和 Service都是从Context派生出来的,我们利用Context主要用来加载资源或者初始化组件,在Activity中有些地方需要用到Context的时候,我们经常会把context给传递过去了,将context传递出去就有可能延长了context的生命周期,最终导致了内存泄漏。例如我们将activty context对象传递给一个后台线程去执行某些操作,如果在这个过程中因为屏幕旋转而导致activity重建,那么原先的activity对象不会被回收,因为它还被后台线程引用着,如果这个activity消耗了比较多的内存,那么新建activity或者后续操作可能因为旧的activity没有被回收而导致内存泄漏。所以,遇到需要用到context的时候,我们要合理选择不同的context,对于android应用来说还有一个单例的Application Context对象,该对象生命周期和应用的生命周期是绑定的。选择context应该考虑到它的生命周期,如果使用该context的组件的生命周期超过该context对象,那么我们就要考虑是否可以用application context。如果真的需要用到该context对象,可以考虑用弱引用来WeakReference来避免内存泄漏。
3. 非静态内部类导致的Memory leak
非静态的内部类会持有外部类的一个引用,所以和前面context说到的一样,如果该内部类生命周期超过外部类的生命周期,就可能引起内存泄露了,如AsyncTask和Handler。因为在Activity中我们可能会用到匿名内部类,所以要小心管理其生命周期。 如果明确生命周期较外部类长的话,那么应该使用静态内部类。
4. Drawable对象的回调隐含的Memory leak
当我们为某一个view设置背景的时候,view会在drawable对象上注册一个回调,所以drawable对象就拥有了该view的引用了,进而对整个context都有了间接的引用了,如果该drawable对象没有管理好,例如设置为静态,那么就会导致Memory leak

另一篇https://www.2cto.com/kf/201611/567034.html
Android内存泄露分析利器——LeakCanary:
http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2015/0509/2854.html

14.LruCache的理解

LruCache是android提供的一个缓存工具类,其算法是最近最少使用算法。
详细解读:https://www.cnblogs.com/tianzhijiexian/p/4248677.html

15.如何设计一套图片加载框架

http://blog.csdn.net/lmj623565791/article/details/41874561
推荐看文中推荐的“Android Handler 异步消息处理机制的妙用 创建强大的图片加载类”一文

补充:
ImageLoader中的三级缓存策略

16.四大图片加载框架对比

https://www.cnblogs.com/linghu-java/p/5741358.html

17.getWidth()和getMeasuredWidth()的区别以及两者的使用场景

区别:
getWidth()获得的宽度是View在设定好布局后整个View的宽度。getMeasuredWidth()是对View上的内容进行测量后得到的View内容占据的宽度。
两者的使用场合:
getMeasuredWidth:在自定义view重写onLayout时、在我们用layoutinflater动态加载view后想获得view的原始宽度时。
getWidth:一般在view已经布局后呈现出来了,想获取宽度时。

参考http://blog.csdn.net/u011494050/article/details/39134161

18.IntentService原理

由于Service的运行依然是在用户线程(即主线程),因此如果做了过于耗时的操作的话,则可能会引起ANR(Android Not Responding)的情况。所以关于耗时的操作都需要放在子线程中去做。基于这种情况,Android自身也提供了关于Service的衍生类IntentService。IntentService保留了Service原有的特性,并且将耗时的操作都放在的子线程中,通过Handler的回调方式实现了数据的返回。

参考:http://www.jianshu.com/p/4dd46616564d

19.Android UI性能优化

1.移除不必要的background
2.使用clipRect
3.使用Hierarchy Viewer

参考http://blog.csdn.net/lmj623565791/article/details/45556391

20.Java中的反射机制

https://www.cnblogs.com/yrstudy/p/6500982.html

21.XML解析的方式

http://blog.csdn.net/isee361820238/article/details/52371342

22.在单线程模型中Message、Handler、Message Queue、Looper之间的关系

Handler定义:

一个Handler允许你发送和处理Message和Runable对象,这些对象和一个线程的MessageQueue相关联。每一个线程实例和一个单独的线程以及该线程的MessageQueue相关联。当你创建一个新的Handler时,它就和创建它的线程绑定在一起了。这里,线程我们也可以理解为线程的MessageQueue。从这一点上来看,Handler把Message和Runable对象传递给MessageQueue,而且在这些对象离开MessageQueue时,Handler负责执行他们。
Handler 即为处理者,是Message的主要处理者,负责Message的发送,Message内容的执行处理

Message定义:

Message类就是定义了一个信息,这个信息中包含一个描述符和任意的数据对象,这个信息被用来传递给Handler.Message对象提供额外的两个int域和一个Object域,这可以让你在大多数情况下不用作分配的动作。
尽管Message的构造函数是public的,但是获取Message实例的最好方法是调用Message.obtain(),或者Handler.obtainMessage()方法,这些方法会从回收对象池中获取一个。
Message即为消息,可以理解为线程间交流的信息。处理数据后台线程需要更新UI,你可以发送内含一些数据的Message给UI线程。

Message Queue定义:

这是一个包含message列表的底层类。Looper负责分发这些message。Messages并不是直接加到一个MessageQueue中,而是通过Handler关联到Looper。
你可以通过Looper.myQueue()从当前线程中获取MessageQueue
Message Queue即为消息队列,用来存放通过Handler发布的消息,按照先进先出原则执行。

每个Message Queue都会有一个对应的Handler。Handler会向Message Queue通过两种方法发送消息:
sendMessage 或 post。这两种消息都会插在Message Queue队尾并按照先进先出原则执行。

但通过这两种方法发送的消息执行的方式略有不同:
通过sendMessage发送的是一个Message对象,会被Handler的handleMessage()方法处理;
而通过post方法发送的是一个Runnable对象,则会自己执行。

Looper定义:

Looper类被用来执行一个线程中的message循环。默认情况,没有一个消息循环关联到线程。在线程中调用prepare()创建一个Looper,然后用loop()来处理messages,直到循环终止。
一个典型的带有Looper的线程实现:

class LooperThread extends Thread {      public Handler mHandler;      public void run() {          Looper.prepare();          mHandler = newHandler() {              publicvoidhandleMessage(Message msg) {                  //process incomingmessages here              }          };          Looper.loop();      }  }

Looper是每条线程里Message Queue的管家。

Android没有Global 的Message Queue,而Android 会自动替主线程(UI线程)建立Message Queue,但在子线程里并没有建立Message Queue。

所以调用Looper.getMainLooper()得到的主线程的Looper不为Null, 但调用Looper.myLooper()得到当前线程的Looper就有可能为Null。

参考:http://blog.csdn.net/isee361820238/article/details/52404165

23.对ButterKnife的理解

ButterKnife 使用注解的方式来替代繁琐的 findViewById 和注册监听器时大量的匿名内部类写法。

详解:http://www.jianshu.com/p/b8b59fb80554

24.Android机型适配

参考:http://blog.csdn.net/dfskhgalshgkajghljgh/article/details/50564682

原创粉丝点击