Android面试问题专题分享试题集合android面试

2017最新面试题汇总

2017-06-04  本文已影响648人  goodgleCoder

RxJava的机制是什么?

RxJava是使用Java语言,以响应式编程思维来进行编程的Java类库。

Butterknife的机制是什么?

Java Annotation Processing技术,在Java代码编译成Java字节码的时候就已经处理了@Bind、@OnClick(ButterKnife还支持很多其他的注解)这些注解了。

Annotation processing 是javac中用于编译时扫描和解析Java注解的工具

Annotation processing是在编译阶段执行的,它的原理就是读入Java源代码,解析注解,然后生成新的Java代码。

新生成的Java代码最后被编译成Java字节码,注解解析器(Annotation Processor)不能改变读入的Java 类,比如不能加入或删除Java方法。

参考:ButterKnife框架原理

安卓开发常用网络请求框架OkHttp、Volley、XUtils、Retrofit对比

1.xutils

此框架庞大而周全,这个框架可以网络请求,同时可以图片加载,又可以数据存储,又可以 View 注解,使用这种框架很方便,这样会使得你整个项目对它依赖性太强,万一以后这个库不维护了,或者中间某个模块出问题了,这个影响非常大,所以在项目开发时,一般会更喜欢选择专注某一领域的框架。

2.OkHttp

Android 开发中是可以直接使用现成的api进行网络请求的,就是使用HttpClient、HttpUrlConnection 进行操作,目前HttpClient 已经被废弃,而 android-async-http 是基于HttpClient的,可能也是因为这个原因作者放弃维护。 而OkHttp是Square公司开源的针对Java和Android程序,封装的一个高性能http请求库,它的职责跟HttpUrlConnection 是一样的,支持 spdy、http 2.0、websocket ,支持同步、异步,而且 OkHttp 又封装了线程池,封装了数据转换,封装了参数使用、错误处理等,api使用起来更加方便。可以把它理解成是一个封装之后的类似HttpUrlConnection的东西,但是在使用的时候仍然需要自己再做一层封装,这样才能像使用一个框架一样更加顺手。

3.Volley

Volley是Google官方出的一套小而巧的异步请求库,该框架封装的扩展性很强,支持HttpClient、HttpUrlConnection, 甚至支持OkHttp,而且Volley里面也封装了ImageLoader,所以如果你愿意你甚至不需要使用图片加载框架,不过这块功能没有一些专门的图片加载框架强大,对于简单的需求可以使用,稍复杂点的需求还是需要用到专门的图片加载框架。Volley也有缺陷,比如不支持post大数据,所以不适合上传文件。不过Volley设计的初衷本身也就是为频繁的、数据量小的网络请求而生。

4.Retrofit

Retrofit是Square公司出品的默认基于OkHttp封装的一套RESTful网络请求框架,RESTful是目前流行的一套api设计的风格, 并不是标准。Retrofit的封装可以说是很强大,里面涉及到一堆的设计模式,可以通过注解直接配置请求,可以使用不同的http客户端,虽然默认是用http ,可以使用不同Json Converter 来序列化数据,同时提供对RxJava的支持,使用Retrofit + OkHttp + RxJava + Dagger2 可以说是目前比较潮的一套框架,但是需要有比较高的门槛。

5.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 本身封装的也更易用,扩展性更好些。

6.OkHttp VS Retrofit

毫无疑问,Retrofit 默认是基于 OkHttp 而做的封装,这点来说没有可比性,肯定首选 Retrofit。

7.Volley VS Retrofit

这两个库都做了不错的封装,但Retrofit解耦的更彻底,尤其Retrofit2.0出来,Jake对之前1.0设计不合理的地方做了大量重构, 职责更细分,而且Retrofit默认使用OkHttp,性能上也要比Volley占优势,再有如果你的项目如果采用了RxJava ,那更该使用 Retrofit 。所以这两个库相比,Retrofit更有优势,在能掌握两个框架的前提下该优先使用 Retrofit。但是Retrofit门槛要比Volley稍高些, 要理解他的原理,各种用法,想彻底搞明白还是需要花些功夫的,如果你对它一知半解,那还是建议在商业项目使用Volley吧。

总结

综上,如果以上三种网络库你都能熟练掌握,那么优先推荐使用Retrofit,前提是最好你们的后台api也能遵循RESTful的风格, 其次如果不想使用或者没能力掌握Retrofit ,那么推荐使用Volley ,毕竟Volley不需要做过多的封装,如果需要上传大数据, 那么不建议使用 Volley,该采用 OkHttp

例举一种ORM框架,说说它的优缺点。

我熟悉的两种GreenDao3和AndroidActive,GreenDao 比较常规,注解不多(我这里都是指3.0版本后,之前的版本在生存实体的时候略显麻烦。),AndroidActive 相对而言注解较多,最后的综合性能上 GreenDao 排第一毫无争议。硬要说缺点的话就是 GreenDao 体积稍大。

在非UI线程中使用Handler需要注意哪些问题?

new Thread(){

public void run(){

Looper.prepare();//给当前线程初始化Looper

Toast.makeText(getApplicationContext(),"更新UI",0).show();//Toast初始化的时候会new Handler();无参构造默认获取当前线程的Looper,如果没有prepare过,则抛出题主描述的异常。上一句代码初始化过了,就不会出错。

Looper.loop();//这句执行,Toast排队show所依赖的Handler发出的消息就有人处理了,Toast就可以吐出来了。但是,这个Thread也阻塞这里了,因为loop()是个for (;;) ...

}

}.start();

Service有哪些派生类?这些派生类的使用场景是什么?

这个问题不知道问的具体是什么,如果是要 IntentService那么可以参考官方文档的解释与使用说明: 扩展 IntentService 类

由于大多数启动服务都不必同时处理多个请求(实际上,这种多线程情况可能很危险),因此使用 IntentService 类实现服务也许是最好的选择。

IntentService 执行以下操作:

建默认的工作线程,用于在应用的主线程外执行传递给 onStartCommand() 的所有 Intent。

创建工作队列,用于将 Intent 逐一传递给 onHandleIntent() 实现,这样您就永远不必担心多线程问题。

在处理完所有启动请求后停止服务,因此您永远不必调用 stopSelf()。

提供 onBind() 的默认实现(返回 null)。

提供 onStartCommand() 的默认实现,可将 Intent 依次发送到工作队列和 onHandleIntent() 实现。

综上所述,您只需实现 onHandleIntent() 来完成客户端提供的工作即可。(不过,您还需要为服务提供小型构造函数。)

什么情况下,Activity的onNewInstent()方法会执行?Activity的启动模式相关。

当此Activity的实例已经存在,并且此时的启动模式为SingleTask和SingleInstance,另外当这个实例位于栈顶且启动模式为SingleTop时也会触发onNewInstent()。

Activity A使用startForResult启动Activity B,B什么都不做并返回A,A中的onActivityResult回调是否会执行?

startActivity()方法,最终都是调用startActivityForResult()方法。默认的requestCode = -1 resultCode = RESULT_CANCELED = 0,当你的requestCode != -1时,onActivityResult()一定会被调用。

Fragment能否不依赖于Activity存在?简析一下Fragment的栈管理。

Fragment不能独立存在,它必须嵌入到activity中,而且Fragment的生命周期直接受所在的activity的影响。

// Create new fragment and transaction

Fragment newFragment = new ExampleFragment();

FragmentTransaction transaction = getFragmentManager().beginTransaction();

// Replace whatever is in the fragment_container view with this fragment,

// and add the transaction to the back stack

transaction.replace(R.id.fragment_container, newFragment);

transaction.addToBackStack(null);

// Commit the transaction

transaction.commit();

transaction只是记录了从一个状态到另一个状态的变化过程,即比如从FragmentA替换到FragmentB的过程,当通过函数transaction.addToBackStack(null)将这个事务添加到回退栈,则会记录这个事务的状态变化过程,如从FragmentA —>FragmentB,当用户点击手机回退键时,因为transaction的状态变化过程被保存,则可以将事务的状态变化过程还原,即将FragmentB —> FragmentA.

添加到回退栈的函数:transaction.addToBackStack(null);

热修复的原理

1:JavaSisst

2:AspectJ

3:Xposef

http://mp.weixin.qq.com/s?__biz=MzA3Mjk1MjA4Nw==&mid=400452659&idx=1&sn=841b49b875ec3b307f261ed52a7d9c4e&scene=23&srcid=1119JWRt0adNwGxTHiyok460#rd

apk安装卸载的原理

安装过程:复制apk安装包到data/app目录下,解压并扫描安装包,把dex文件(dalvik字节码)保存到dalvik-cache目录,并data/data目录下创建对应的应用数据目录。

卸载过程:删除安装过程中在上述三个目录下创建的文件及目录。

Serializable 和 Parcelable 的区别

在使用内存的时候,Parcelable 类比 Serializable 性能高,所以推荐使用 Parcelable 类。

Serializable 在序列化的时候会产生大量的临时变量,从而引起频繁的 GC。

Parcelable 不能使用在要将数据存储在磁盘上的情况。尽管 Serializable 效率低点,但在这 种情况下,还是建议你用 Serializable

进程间的通信方式

1. 管道( pipe ):管道是一种半双工的通信方式,数据只能单向流动,而且只能在具有亲缘关系的 进程间使用。进程的亲缘关系通常是指父子进程关系。

2. 有名管道 (namedpipe) : 有名管道也是半双工的通信方式,但是它允许无亲缘关系进程间的 通信。

3. 信号量(semophore ) : 信号量是一个计数器,可以用来控制多个进程对共享资源的访问。它 常作为一种锁机制,防止某进程正在访问共享资源时,其他进程也访问该资源。因此,主要作为进 程间以及同一进程内不同线程之间的同步手段。

4. 消息队列( messagequeue ) : 消息队列是由消息的链表,存放在内核中并由消息队列标识符 标识。消息队列克服了信号传递信息少、管道只能承载无格式字节流以及缓冲区大小受限等缺点。

5. 信号 (sinal ) : 信号是一种比较复杂的通信方式,用于通知接收进程某个事件已经发生。

6. 共享内存(shared memory ) :共享内存就是映射一段能被其他进程所访问的内存,这段共享内 存由一个进程创建,但多个进程都可以访问。共享内存是最快的 IPC 方式,它是针对其他进程间 通信方式运行效率低而专门设计的。它往往与其他通信机制,如信号两,配合使用,来实现进程间 的同步和通信。

7. 套接字(socket ) : 套解口也是一种进程间通信机制,与其他通信机制不同的是,它可用于不同 及其间的进程通信。

说说 LruCache 底层原理

LruCache 使用一个 LinkedHashMap 简单的实现内存的缓存,没有软引用,都是强引用。如果添 加的数据大于设置的最大值,就删除最先缓存的数据来调整内存。

maxSize 是通过构造方法初始化的值,他表示这个缓存能缓存的最大值是多少。

size 在添加和移除缓存都被更新值,他通过 safeSizeOf 这个方法更新值。safeSizeOf 默认返回 1, 但一般我们会根据 maxSize 重写这个方法,比如认为 maxSize 代表是 KB 的话,那么就以 KB 为单 位返回该项所占的内存大小。

除异常外首先会判断 size 是否超过 maxSize,如果超过了就取出最先插入的缓存,如果不为空就 删掉,并把 size 减去该项所占的大小。这个操作将一直循环下去,直到 size 比 maxSize 小或者缓存 为空。

相信自己,没有做不到的,只有想不到的

如果你觉得此文对您有所帮助,欢迎入群 QQ交流群 :232203809 微信公众号:终端研发部

(欢迎关注学习和交流)

上一篇下一篇

猜你喜欢

热点阅读