1、自我介绍
建议事先打个腹稿。不要念简历,主要介绍自己的经历,让自己脱颖而出。首先贴标签,讲故事,谈愿景。标签:给自己贴的标签要有点特色。看着像是缺点,细想还是有点。讲故事:举例说明。
2、项目介绍
技术难点,亮点。这个在平时的开发过程中要做好总结。面试随便哪一些来讲就可以了。我就是因为平时没有总结,所以在面试前要事先整理一下。
2、Java基础
建议事先复习Java基础。
(1)hashMap,hashTable,ConcurrentHashMap,LinkedHashMap
HashMap是用散列表存储键-值对,允许NULL键和NULL值,非线程同步,无序map;HashTable线程同步,不允许NULL键和NULL值,已废弃,可用ConcurrentHashMap代替;ConcurrentHashMap线程安全,引入“分段锁”概念,通过将整个map分为多个segment(类似HashTable)可以提供相同的线程安全,效率默认提供16倍;LinkedHashMap是HashMap + LinkedList,有序的map,LinkedList可以维护元素的先后顺序,可以实现LRU算法缓存。详细介绍请查看:
HashMap、LinkedHashMap、TreeMap、Hashtable、HashSet和ConcurrentHashMap区别
(2)序列化的方法:serializable和parcelable的优缺点
序列化的主要目的是将数据转换成可以存储或传输的形式的过程。serializable可以将数据持久化,是通过IO流的形式将数据写入硬盘。parcelable性能强于serializable,效率高,但是无法很好的将数据进行持久化。详细介绍请看:
Android中Serializable和Parcelable序列化对象详解
(3)ThreadLocal和Volatile的区别
Volatile可以看做是一个轻量级的synchronize,它的开销比synchronize低,使用成本更小,但是不具备操作的原子性。ThreadLocal并不是用来解决在多线程并发环境下资源的共享问题的,而是用来提供线程内的局部变量。ThreadLocal变量属于线程内部管理。详细介绍请看:
并发编程之ThreadLocal、Volatile、synchronized、Atomic关键字扫盲
(4)如何确定线程的执行顺序
运行子线程是,调用join方法:让主线程等待子线程运行结束后再继续运行。详细介绍请查看:
如何控制线程执行的顺序?
3、Android四大组件
(1)Activity的启动模式
Activity有四种启动模式:standard、singleTop、singleTask、singleInstance。standard是Activity的默认启动模式,没启动一个Activity就回在栈顶创建一个新的实例,缺点是当Activity已经在栈顶时,再次启动Activity还需要创建一个新的实例;singleTop模式会判断要启动的Activity实例是否位于栈顶,如果位于栈顶则直接复用,否则创建新的实例,缺点是如果Activity并未处于栈顶位置,则可能还会创建多个实例;singleTask模式使Activity在整个应用中只有一个实例,每次启动Activity时系统首先检查栈中是否存在当前Activity实例,如果有则直接复用,并把当前Activity之前的所有实例全部出栈;singleInstance模式会启动一个新的任务来管理Activity实例,并且该实例在整个系统中只有一个,无论在哪个任务栈中启动该Activity,都会是该Activity所在的任务栈转移到前台,主要目的是为了在不同的程序中共享一个Activity。详细介绍请查看:
Android基础之Activity的生命周期
Android基础之Activity四种启动模式和task相关
(2)service的启动模式
service的主要作用:在后台执行计算任务,执行结果可以跟外界通信。启动方式有两种:startService()和bindService()。startService多次启动时,onCreate()调用一次,onStartCommand()调用多次,只会创建一个实例,只需要调用一次stopService(),不能进行通信。bindService启动的服务是绑定状态,可以通信,多次调用时onCreate()方法调用一次,onBind()调用一次。停止的服务用unBindService()。服务可以执行耗时操作吗?答案是不能,超过20s就回出现ANR。详细介绍请查看:
Android基础之四大组件-详解Service
(3)Broadcast Receiver
Broadcast Receiver的主要作用是消息的传递,监听APP的广播并相应。应用场景有①多线程通信、②Android不同组件间的通信(包含应用内/应用外)。使用观察者模式,将发送和接受解耦。
有两种注册方式:静态注册、动态注册。静态注册在AndroidManifest中注册,不需要启动应用也可以接受到相应的广播。动态注册需要通过Context.registerReceiver()来注册。详细介绍请查看:
Android基础之四大组件-BroadcastReceiver解析
(4)Content provider
主要作用:作为一个平台,提供数据的共享,并且提供数据的增删改查,主要应用于应用间的数据共享。
Android基础之四大组件-ContentProvider(内容提供者)
4、常用的架构,例如:MVC,MVP,MVVM等。
MVC最核心就是通过Control层来进行调控。Model主要是对数据的操作,View层主要是各种组件和自定义View,Control则主要是Activity。通过Control调控,将View展示和Model操作分离,但是两者还是有交互,有一定的耦合。另外,Activity除了负责业务逻辑处理还要承载View,处理UI视图显示,所以会比较臃肿。
MVP是对MVC的一种改良模式。Presenter层隔断了View层和Model层,降低了耦合度。Activity不再同时承载Control和UI显示,只单独负责View展示。缺点就是Presenter层左右View层和Model层的桥梁,会很臃肿。而且基本上每个Activity要有相应的Presenter来处理。
MVVM将Presenter替换成了ViewModel,并通过双向的数据绑定来实现视图和数据的交互。简化了开发,数据和视图只需要进行一次绑定即可。缺点就是实现方式还比较不完善规范。详细介绍请查看:
关于MVC,MVP,MVVM的一点总结和思考
Android App的设计架构:MVC,MVP,MVVM与架构经验谈
5、常见的设计模式,理解手写单例模式、工厂模式等
简单说一下单例模式,单例模式可以分为懒汉式和饿汉式。懒汉式在加载类时,不进行初始化;饿汉式在加载类时进行初始化,所以速度会比较慢,但获取对象的速度比较快。
常见的几种单例模式
6、图片缓存与优化(三级缓存)
为了避免OOM,应增加程序的可用内存,并及时回收不使用的对象,降低内存使用。可以从以下几个方面进行考虑:
①处理图片,如剪切、压缩图片。根据控件大小来裁剪图片减少内存浪费。使用缩略图提高加载速度,如果是Bitmap,可以通过设置采样率,减少BitMap的像素。
②使用缓存机制。缓存可以提高加载速度,减少不必要的流量消耗。常用的缓存机制有三级缓存:内存、本地和网络。优先加载内存缓存,如果加载不到则加载文件缓存,若还是加载不到,则网络请求,然后将请求到的数据保存到内存和本地中。内存缓存可以用LRUCashe实现,本地缓存可以实现DisLURCashe,网络请求可以借助第三方框架,例如Volley。
③自定义堆内存的大小。如在AndroidManifest的Application节点下加入Android:largeHeap="true"
④使用第三方开源图片框架,比如Picasso、Glide等。他们在图片的异步加载、缓存、内存管理和优化有很好的处理。详细介绍请看:
Android图片缓存分析与优化
7、内存泄漏及优化方案
内存泄漏: 如果一个无用对象(不需要再使用的对象)仍然被其他对象持有引用,造成该对象无法被系统回收,以致该对象在堆中所占用的内存单元无法被释放而造成内存空间浪费。常见的内存泄漏有:
①单例导致内存泄漏。
②静态变量导致内存泄漏。
③非静态内部类导致内存泄漏。
④未取消注册或回调导致内存泄漏。详细介绍请查看:
Android内存优化——常见内存泄露及优化方案
8、内存优化之Bitmap
对于BitMap的优化可以从一下几个方面进行考虑:
①及时回收BitMap的内存。
②捕获异常。
③缓存常用的BitMap对象。
④压缩图片。详细介绍请查看:
关于Bitmap的内存优化
9、介绍使用过的开源库
这个早面试前将自己平时开发使用过的、比较熟悉的开源库整理一下就可以了。
10。算法,理解了解常用的排序算法
有的公司会考查一些算法。所以最好提前复习下常用的算法。这里简单的介绍下冒泡排序。
原理:比较两个相邻的元素,将值大的元素交换至右端。
void bubble_sort(int arr[], int len) {
int i, j, tmpValue;
for (i = 0; i < len - 1; i++) { //外层循环控制趟数,总趟数为len-1
for (j = 0; j < len - 1 - i; j++) { //内层循环为当前i趟数 所需要比较的次数
if (arr[j] > arr[j + 1]){
tmpValue = arr[j];
arr[j]= arr[j + 1];
arr[j + 1]= tmpValue;
}
}
}
}
如果传入的数组是已经排序好的,使用上述方式冒泡排序就变成做无用功了,所以可以进一步优化冒泡排序。优化后代码如下:
void bubble_sort(int arr[], int len) {
int i, j, tmpValue, flag;
for (i = 0; i < len - 1; i++) { //外层循环控制趟数,总趟数为len-1
flag = 0; //假设每次进入都是无序的
for (j = 0; j < len - 1 - i; j++) { //内层循环为当前i趟数 所需要比较的次数
if (arr[j] > arr[j + 1]){
tmpValue = arr[j];
arr[j]= arr[j + 1];
arr[j + 1]= tmpValue;
flag = 1;
}
if(flag == 1)
break;
}
}
}
当然冒泡排序还可以进一步进行优化。这里就不再进行介绍了。
11、JNI使用的理解
JNI的具体使用如果有疑问,可以查看:
JNI详解---从不懂到理解
12、介绍强引用、弱引用、软引用的区别
强引用,如果引用存在,垃圾回收器永远不会回收;软应用,只有软引用的对象,在内存空间不足时,垃圾回收器会进行回收;弱引用,如果对象只有弱引用,一旦被垃圾回收器发现,会被回收。
Java 关于强引用,软引用,弱引用和虚引用的区别与用法
15、C相关知识点:野指针、内存的分配方式、堆栈和堆内存的区别
野指针:野指针指向一个已删除的对象或未申请访问受限内存区域的指针。
内存的分配方式:静态存储区分配、栈区分配、堆区分配。
静态存储区分配:此时的内存在程序编译的时候已经分配好,并且在程序的整个运行期间都存在。全局变量,static变量等在此存储。
栈区分配:相关代码执行时创建,执行结束时被自动释放。局部变量在此存储。栈内存分配运算内置于处理器的指令集中,效率高,但容量有限。
堆区分配:动态分配内存。用new/malloc时开辟,delete/free时释放。生存期由用户指定,灵活。但有内存泄露等问题。
了解更多Android干货帖,请关注微信公众号:小牛安卓干货铺: