Android基础高频面试题汇总
1.Activity生命周期
onCreate() 创建活动,做一些数据初始化操作onStart() 由不可见变为可见
onResume() 可以与用户进行交互,位于栈顶
onPause() 暂停,启动或恢复另一个活动时调用
onStop() 停止,变为不可见
onDestroy() 销毁
onRestart() 由停止状态变为运行状态
2.Service生命周期
onCreate()首次创建服务时,系统将调用此方法。如果服务已在运行,则不会调用此方法,该方法只调用一次。
onStartCommand()
当另一个组件通过调用startService()请求启动服务时,系统将调用此方法。
onDestroy()
当服务不再使用且将被销毁时,系统将调用此方法。
onBind()
当另一个组件通过调用bindService()与服务绑定时,系统将调用此方法。
onUnbind()
当另一个组件通过调用unbindService()与服务解绑时,系统将调用此方法。
onRebind()
当旧的组件与服务解绑后,另一个新的组件与服务绑定,onUnbind()返回true时,系统将调用此方法。
3.Service启动方式
1.startService①.定义一个类继承service
②.在manifest.xml文件中配置该service
③.使用context的startService(intent)启动该service
④.不再使用时,调用stopService(Intent)停止该服务
2.bindService
①.创建bindService服务段,继承自service并在类中,创建一个实现binder接口的实例对象并提供公共方法给客户端调用
②.从onbind()回调方法返回此binder实例
③.在客户端中,从onserviceconnected()回调方法接收binder,并使用提供的方法调用绑定服务
4.Activity的启动方式
①.standard模式a.Activity的默认启动模式
b.每启动一个Activity就会在栈顶创建一个新的实例。例如:闹钟程序
缺点:当Activity已经位于栈顶时,而再次启动Activity时还需要在创建一个新的实例,不能直接复用。
②.singleTop模式
特点:该模式会判断要启动的Activity实例是否位于栈顶,如果位于栈顶直接复用,否则创建新的实例。 例如:浏览器的书签
缺点:如果Activity并未处于栈顶位置,则可能还会创建多个实例。
③.singleTask模式
特点:使Activity在整个应用程序中只有一个实例。每次启动Activity时系统首先检查栈中是否存在当前Activity实例,如果存在
则直接复用,并把当前Activity之上所有实例全部出栈。例如:浏览器主界面
④.singleInstance模式
特点:该模式的Activity会启动一个新的任务栈来管理Activity实例,并且该势力在整个系统中只有一个。无论从那个任务栈中 启动该Activity,都会是该Activity所在的任务栈转移到前台,从而使Activity显示。主要作用是为了在不同程序***享一个Activity
5.Touch事件传递机制
在我们点击屏幕时,会有下列事件发生:Activity调用dispathTouchEvent()方法,把事件传递给Window;
Window再将事件交给DecorView(DecorView是View的根布局);
DecorView再传递给ViewGroup;
Activity ——> Window ——> DecorView ——> ViewGroup——> View
事件分发的主要有三个关键方法
dispatchTouchEvent() 分发
onInterceptTouchEvent() 拦截 ,只有ViewGroup独有此方法
onTouchEvent() 处理触摸事件
Activity首先调用dispathTouchEvent()进行分发,接着调用super向下传递
ViewGroup首先调用dispathTouchEvent()进行分发,接着会调用onInterceptTouchEvent()(拦截事件)。若拦截事件返回为true,表示拦截,事件不会向下层的ViewGroup或者View传递;false,表示不拦截,继续分发事件。默认是false,需要提醒一下,View是没有onInterceptTouchEvent()方法的
事件在ViewGroup和ViewGroup、ViewGroup和View之间进行传递,最终到达View;
View调用dispathTouchEvent()方法,然后在OnTouchEvent()进行处理事件;OnTouchEvent() 返回true,表示消耗此事件,不再向下传递;返回false,表示不消耗事件,交回上层处理。
6.介绍下实现一个自定义View的基本流程
①.自定义View的属性 编写attr.xml文件②.在layout布局文件中引用,同时引用命名空间
③.在View的构造方法中获得我们自定义的属性 ,在自定义控件中进行读取(构造方法拿到attr.xml文件值)
④.重写onMesure
⑥.重写onDraw
7.Android中的动画有哪些
逐帧动画(Frame Animation)加载一系列Drawable资源来创建动画,简单来说就是播放一系列的图片来实现动画效果,可以自定义每张图片的持续时间
补间动画(Tween Animation)
Tween可以对View对象实现一系列动画效果,比如平移,缩放,旋转,透明度等。但是它并不会改变View属性的值,只是改变了View的绘制的位置,比如,一个按钮在动画过后,不在原来的位置,但是触发点击事件的仍然是原来的坐标。
属性动画(Property Animation)
动画的对象除了传统的View对象,还可以是Object对象,动画结束后,Object对象的属性值被实实在在的改变了
8.ANR是什么?怎样避免和解决ANR
Application Not Responding,即应用无响应出现的原因有三种:
a)KeyDispatchTimeout(5 seconds)主要类型按键或触摸事件在特定时间内无响应
b)BroadcastTimeout(10 seconds)BoradcastReceiver在特定的时间内无法处理
c)ServiceTimeout(20 seconds)小概率类型Service在特定的时间内无法处理完成
避免ANR最核心的一点就是在主线程减少耗时操作。通常需要从那个以下几个方案下手:
a)使用子线程处理耗时IO操作
b)降低子线程优先级,使用Thread或者HandlerThread时,调用Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND)设置优先级,否则仍然会降低程序响应,因为默认Thread的优先级和主线程相同
c)使用Handler处理子线程结果,而不是使用Thread.wait()或者Thread.sleep()来阻塞主线程
d)Activity的onCreate和onResume回调中尽量避免耗时的代码
e)BroadcastReceiver中onReceiver代码也要尽量减少耗时操作,建议使用intentService处理。intentService是一个异步的,会自动停止的服务,很好解决了传统的Service中处理完耗时操作忘记停止并销毁Service的问题
9.如何优化ListView
①Item布局,层级越少越好,使用hierarchyview工具查看优化。②复用convertView
③使用ViewHolder
④item中有图片时,异步加载
⑤快速滑动时,不加载图片
⑥item中有图片时,应对图片进行适当压缩
⑦实现数据的分页加载
10.设备横竖屏切换的时候,生面周期的变化
不设置Activity的android:configChanges时,切屏会重新调用各个生命周期,切横屏时会执行一次,切竖屏时会执行两次设置Activity的android:configChanges=”orientation”时,切屏还是会重新调用各个生命周期,切横、竖屏时只会执行一次
设置Activity的android:configChanges=”orientation|keyboardHidden”时,切屏不会重新调用各个生命周期,只会执行onConfigurationChanged方法
11.RecyclerView和ListView的区别
RecyclerView可以完成ListView,GridView的效果,还可以完成瀑布流的效果。同时还可以设置列表的滚动方向(垂直或者水平);RecyclerView中view的复用不需要开发者自己写代码,系统已经帮封装完成了。
RecyclerView可以进行局部刷新。
RecyclerView提供了API来实现item的动画效果。
在性能上:
如果需要频繁的刷新数据,需要添加动画,则RecyclerView有较大的优势。
如果只是作为列表展示,则两者区别并不是很大。
12.Android异步消息处理机制
异步消息处理机制主要是用来解决子线程更新UI的问题主要有四个部分:
①. Message (消息)
在线程之间传递,可在内部携带少量信息,用于不同线程之间交换数据
可以使用what、arg1、arg2字段携带整型数据
obj字段携带Object对象
②. Handler (处理者)
主要用于发送和处理消息,sendMessage()用来发送消息,最终会回到handleMessage()进行处理
③. MessageQueue (消息队列)
主要存放所有通过Handler发送的消息,它们会一直存在于队列中等待被处理
每个线程只有一个MessageQueue
④. Looper (循环器)
调用loop()方法后,会不断从MessageQueue 取出待处理的消息,然后传递到handleMessage进行处理
13.图片加载框架有哪些?他们之间的区别是什么?
ImageLoader :优点:
① 支持下载进度监听;
② 可以在 View 滚动中暂停图片加载;
③ 默认实现多种内存缓存算法这几个图片缓存都可以配置缓存算法,不过 ImageLoader 默认实现了较多缓存算法,如 Size 最大先删除、使用最少先删除、最近最少使用、先进先删除、时间最长先删除等;
④ 支持本地缓存文件名规则定义;
缺点:
缺点在于不支持GIF图片加载, 缓存机制没有和http的缓存很好的结合, 完全是自己的一套缓存机制
Picasso:
优点:
① 自带统计监控功能,支持图片缓存使用的监控,包括缓存命中率、已使用内存大小、节省的流量等。
② 支持优先级处理
③ 支持延迟到图片尺寸计算完成加载
④ 支持飞行模式、并发线程数根据网络类型而变,手机切换到飞行模式或网络类型变换时会自动调整线程池最大并发数。
⑤ “无”本地缓存。Picasso 自己没有实现本地缓存,而由okhttp 去实现,这样的好处是可以通过请求 Response Header 中的 Cache-Control 及 Expired 控制图片的过期时间。
缺点:不支持GIF,默认使用ARGB_8888格式缓存图片,缓存体积大。
Glide:
优点:
① 图片缓存->媒体缓存 ,支持 Gif、WebP、缩略图。甚至是 Video。
② 支持优先级处理
③ 与 Activity/Fragment 生命周期一致,支持 trimMemory
④ 支持 okhttp、Volley。Glide 默认通过 UrlConnection 获取数据,可以配合 okhttp 或是 Volley 使用。实际 ImageLoader、Picasso 也都支持 okhttp、Volley。
⑤ 内存友好,内存缓存更小图片,图片默认使用默认 RGB565 而不是 ARGB888
缺点:清晰度差,但可以设置
Fresco:
优点:
① 图片存储在安卓系统的匿名共享内存, 而不是虚拟机的堆内存中,所以不会因为图片加载而导致oom, 同时也减少垃圾回收器频繁调用回收Bitmap导致的界面卡顿,性能更高.
② 渐进式加载JPEG图片, 支持图片从模糊到清晰加载
③ 图片可以以任意的中心点显示在ImageView, 而不仅仅是图片的中心.
④ JPEG图片改变大小也是在native进行的, 不是在虚拟机的堆内存, 同样减少OOM
⑤ 很好的支持GIF图片的显示
缺点:
框架较大, 影响Apk体积,使用较繁琐
14.网络框架有哪些?他们之间的区别是什么?
Xutils这个框架非常全面,可以进行网络请求,可以进行图片加载处理,可以数据储存,还可以对view进行注解,使用这个框架非常方便,但是缺点也是非常明显的,使用这个项目,会导致项目对这个框架依赖非常的严重,一旦这个框架出现问题,那么对项目来说影响非常大的
OKhttp
Android开发中是可以直接使用现成的api进行网络请求的。就是使用HttpClient,HttpUrlConnection进行操作。okhttp针对Java和Android程序,封装的一个高性能的http请求库,支持同步,异步,而且okhttp又封装了线程池,封装了数据转换,封装了参数的使用,错误处理等。API使用起来更加的方便。但是我们在项目中使用的时候仍然需要自己在做一层封装,这样才能使用的更加的顺手。
Volley
Volley是Google官方出的一套小而巧的异步请求库,该框架封装的扩展性很强,支持HttpClient、HttpUrlConnection, 甚至支持OkHttp,而且Volley里面也封装了ImageLoader,所以如果你愿意你甚至不需要使用图片加载框架,不过这块功能没有一些专门的图片加载框架强大,对于简单的需求可以使用,稍复杂点的需求还是需要用到专门的图片加载框架。Volley也有缺陷,比如不支持post大数据,所以不适合上传文件。不过Volley设计的初衷本身也就是为频繁的、数据量小的网络请求而生。
Retrofit
Retrofit是Square公司出品的默认基于OkHttp封装的一套RESTful网络请求框架,RESTful是目前流行的一套api设计的风格, 并不是标准。Retrofit的封装可以说是很强大,里面涉及到一堆的设计模式,可以通过注解直接配置请求,可以使用不同的http客户端,虽然默认是用http ,可以使用不同Json Converter 来序列化数据,同时提供对RxJava的支持,使用Retrofit + OkHttp + RxJava + Dagger2 可以说是目前比较潮的一套框架,但是需要有比较高的门槛。
Volley VS OkHttp
Volley的优势在于封装的更好,而使用OkHttp你需要有足够的能力再进行一次封装。而OkHttp的优势在于性能更高,因为 OkHttp基于NIO和Okio ,所以性能上要比 Volley更快。IO 和 NIO这两个都是Java中的概念,如果我从硬盘读取数据,第一种方式就是程序一直等,数据读完后才能继续操作这种是最简单的也叫阻塞式IO,还有一种是你读你的,程序接着往下执行,等数据处理完你再来通知我,然后再处理回调。而第二种就是 NIO 的方式,非阻塞式, 所以NIO当然要比IO的性能要好了,而 Okio是 Square 公司基于IO和NIO基础上做的一个更简单、高效处理数据流的一个库。理论上如果Volley和OkHttp对比的话,更倾向于使用 Volley,因为Volley内部同样支持使用OkHttp,这点OkHttp的性能优势就没了, 而且 Volley 本身封装的也更易用,扩展性更好些。
OkHttp VS Retrofit
毫无疑问,Retrofit 默认是基于 OkHttp 而做的封装,这点来说没有可比性,肯定首选 Retrofit。
Volley VS Retrofit
这两个库都做了不错的封装,但Retrofit解耦的更彻底,尤其Retrofit2.0出来,Jake对之前1.0设计不合理的地方做了大量重构, 职责更细分,而且Retrofit默认使用OkHttp,性能上也要比Volley占优势,再有如果你的项目如果采用了RxJava ,那更该使用 Retrofit 。所以这两个库相比,Retrofit更有优势,在能掌握两个框架的前提下该优先使用 Retrofit。但是Retrofit门槛要比Volley稍高些,要理解他的原理,各种用法,想彻底搞明白还是需要花些功夫的,如果你对它一知半解,那还是建议在商业项目使用Volley吧。