怎么准备Android面试?
49 个回答
在收藏的同时,麻烦顺手点个赞,谢谢啦!!
最近看到很多人都在找工作, 而且很多人都感觉今年找工作比去年难很多, 竞争力也增加不少, 因此激发我整理这份资料, 希望能帮到正在找或者准备找工作的童鞋们.
首先我们能否获得一个面试机会, 那肯定是从简历开始, 简历需要做好功夫, 一份好的简历才足够吸引企业得到面试机会, 接着就是面试了, 面试前必须要先做好准备, 多看一下前辈们总结面试题, 有哪一方面不足的地方赶紧补充一下, 还有要了解一下你即将面试那家公司.
教你写简历
面试题
- 国内一线互联网公司内部面试题库
- Android 开发工程师面试指南
- 一个五年Android开发者百度、阿里、聚美、映客的面试心经
- 整理常见 Android 面试问题
- 2016 Android 某公司面试题
- 面试后的总结
- Android面试题整理
- Android interview questions for 2-5 yrs experienced
- Android interview questions
- 40 个 Android 面试题
- Android 名企面试题及涉及知识点整理
做题
看完面试题之后那就来做一下面试题目吧, 目前找到两个网站
- SillGun(国外网站, 自备梯子)
- 牛客网-专业IT笔试面试备考平台
聊面试
(帅张)
stormzhang跟你谈一下面试那些事儿
知乎讨论
互联网招聘平台
感谢
非常感谢上面分享面试资料以及面试经验的的前辈们!
有前辈在前面带路, 我们后辈真心感到幸福.
祝福
最后祝正在找工作的的童鞋们, 马到成功, 心想事成, 事事如意!
关于我
欢迎关注我
Freelander (G军仔) · GitHub以及
G军仔的微博如果感觉知乎的排版很难看,欢迎移步到 简书
不知道你是不是指的纯技术方面的准备,如果是的话,我就提供一些拙见,大部分算是一些开发知识死角或者tips吧,权当抛砖引玉了:)
下面的回答建立在JAVA基础(看着《JAVA核心技术 vol1》目录能梳理一遍JAVA常见知识点)和Android基础都过关的情况下。
一、JAVA SE
1、JAVA标准容器
可能受一些网上流传的各种demo的影响,大多数Android开发者最拿手的就是ListView(RecycleView)+BaseAdapter+ArrayList三剑客,但是要知道ArrayList还有两个亲戚,一个是近亲CopyOnWriteArrayList,另外是远房LinkedList、CurrentHashMap。CopyOnWriteArrayList的效率比ArrayList略有下降,空间利用率也下降了很多,但是CopyOnWriteArrayList是线程安全的,CopyOnWriteArrayList和ArrayList对尾的操作都为O(1),但是其他位置的删除,插入操作很增加很大的时间复杂度,涉及到一次内存搬移过程,不过random access效率很高;LinkedList的随即插入和删除性能很高。
tips:数组复制,请使用System.arrayCopy或Arrays.copyOf 实现,且在JAVA中后者基于前者实现。
2、JAVA并发
1、ThreadPoolExecutor,JAVA并发的核心线程池框架,不过它的构造函数非常复杂:
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
Executors.defaultThreadFactory(), defaultHandler);
}
所以有一个方便我们使用的工厂类,Executors,可以创建4种类型的ThreadPool:
- 固定线程数量的线程池:Executors.newFixedThreadPool(int size);
- 单线程异步队列:Executors.newSingleThreadExecutor();
- 周期性调度:Executors.newSingleThreadScheduledExecutor();
- 多线程周期性调度:Executors.newScheduledThreadPool(1);
说到ThreadPoolExecutor的构造函数,它的最后一个参数BlockingQueue<Runnable>来自于包java.util.concurrent,ArrayBlockingQueue、LinkedBlockingQueue、SynchronousQueue、PriorityBlockingQueue和这个包里面其他的类也要过一遍。
workQueue一定要用有界队列!设想一个极端情景,假设每个TaskWork都运行10s(更确切的说,IO等待10s),而ThreadPool在10s内接收到了1000个这样的TaskWork,如果我们使用了无界队列,队列的大小必然会急速增长直至进程Crash,但是如果我们使用了有界队列,假设队列长度为128,当TaskWork超过128,我们会有另外的线程帮忙处理,那系统的负载就可能降下来了。
上面说到了任务池的创建,那里面的任务是什么?从哪儿来呢?里面的任务是FutureTask<T>,构造函数的参数是一个Callable对象,而我们真正的任务就在Callable对象里面的call方法,FuterTask执行实际任务后会在主线程调用done函数,最后通过ExecutorService的submit方法将FutureTask提交到任务池。发一段伪代码:
public class SomeCallable implements Callable<String> {
public SomeCallable() {
}
@Override
public String call() throws Exception {
// some heavy work consting amounts of time
return "result";
}
}
FutureTask<String> futureTask = new FutureTask<String>(new SomeCallable()) {
@Override
protected void done() {
String result = get();
//dosth to result
}
};
ExecutorService executor = Executors.newFixedThreadPool(1);
executor.submit(futureTask);
2、一个线程sleep的小坑,我相信很多朋友都写过这样的代码:
public void run() {
try{
Thread.sleep(1000);
} catch (InterruptedException ie){
ie.printStackTrace();
}
}
但是设想一下,如果我们的线程在执行sleep之前就被interrupt了呢,别以为不可能,ThreadPoolExecutor框架就是通过对所有的Thread进行interrupt来取消所有线程,这是我们上述代码就会抛出异常。所以良好的实践应该是:
public void run() {
while (!Thread.currentThread().isInterrupted()) {
try{
Thread.sleep(1000);
} catch (InterruptedException ie){
ie.printStackTrace();
}
}
}
3、会用wait/notify来实现最简单的生产者-消费者模式。
生产者/消费者问题的多种Java实现方式4、ThreadLocal变量的理解/定义。ThreadLocal在Android中的应用,最典型的应用就是在android的messengeQueue-Looper模型中,Handler如何找到当前线程的Looper呢?我们平常直接在UI线程中new Handler()就可以了,里面就是mainLooper,但是Android怎么确定的UIx线程中new Handler()里面是mainLooper呢,答案就是通过将Looper作为ThreadLocal变量。以及ThreadLocal基本的实现原理(在线程对象里面有一个inner static class)。
5、JAVA的heap/stack的理解,可能会和多线程一起考察,
blogspot.com 的页面6、ConcurrentHashMap的实现,
blogspot.com 的页面7、 JAVA的Reflection,Android内部很多东西都是基于Reflection实现,比如我们经常用的属性动画,就是通过属性名称找到属性的getter方法名,进而通过反射调用。不过对于日常开发的话,Reflection有两个作用,一是在一些情形下(特别是对属性的操作,包括更改、比较,比如我们可以定义一个通用的Collections.sort)可以提高代码复用度,二是可以做一些比较hack的事情,比如使用一些internal class,内部的AIDL等,修改一些internal类的static value。
二、Android
1、预防内存泄漏!擅用WeakReference<T>!
所有从类外部传来的对象(特别对于Context,View,Fragmet,Activity对象),如果要将其放进类内部的容器对象或者静态类中引用,请一直用WeakReference包装!比如在TabLayout的源码中,在TabLayoutOnPageChangeListener中,就为TabLayout做了WeakReference wrap。
2、Android IPC,Binder的理解,理解Binder的引用和实体,知道所谓的客户端和服务端分别代表什么意思,懂得ServiceManger对每个Service注册和根据服务名来getService的基本原理,这些没多少坑,但是非常庞杂,建议阅读《深入理解Android vol1》Chapter 6,
深入理解Android (豆瓣)。
会写AIDL,会用Messenger夸进程传递信息,具体的实践:
Android实战技术:IPC方式简介教程。
3、Activity的简要绘制(创建)过程 ,Activity本质是为了Window(PhoneWindow)服务,
onAttach:建立mwindow对象->setContentView:创建DecorView,在DecorView中根据Activity的风格来 创建Title(ActionBar),TitleContent(ActionBar下面的内容,内部资源id为android:id="@android:id/content")->mWindow.addView(mDecorView),将创建好的DecorView添加进window,addview时创建一个RootView,也就是我们的R.layout.activity_main的母布局,然后对子控件递归遍历发送绘图消息,子控件收到消息后 执行onMeasure->onLayout->onDraw,这时,我们就可以得到各控件的尺寸信息。
4、 在onCreate中获得视图的尺寸信息,注意到我们上面说,母控件通过遍历向子控件发送dispatchView信息来使子控件绘图,当然,我们也可以在(setContentView)这之后在子控件上post一个Runnable到控件的runnable队列中去,在其中自然可以获得正确的尺寸。
5、关于View的点点滴滴。
基础:自定义单一View,换句话说,叫自定义UI,就是仅仅在OnDraw里面做了文章,比如仪表盘,圆形头像,自定义属性
->中级:自定义View与其他系统Wdiget协同工作,比如继承LinearLayout写一个自定义的TabLayout来与ViewPager协同工作,处理事件(滑动、点击、屏幕手势)分发,处理滑动事件冲突,这个阶段才可以被称之为自定义Widget
->进阶:突破Activity,直接向Window添加、删除、更新View,理解WindowManager仅仅是个引用,真正的工作在WindowManagerService里面完成。
6、图片加载框架,熟悉并实践过基本的缓存算法LruCache、DiskLruCache,对Bitmap重采样以降低OOM的几率,熟读一款中规中矩的图片加载框架如Universal Image Loader的源码,并能将各种策略总结。
7、SurfaceView的实践,SurfaceView最常见的一个使用情境是在我们的界面之上绘制各种动画,但是有一个问题,在布局发生改变时,SurfaceView会出现部分屏幕变黑的情况,包括但不限于在ViewPager、DrawerActivity中使用SurfaceView,需要知道这个问题的解决方案。
7、熟练使用ContentProvider,并懂得大概原理(很惭愧,我对Provider没做过深入理解)
8、Activity的几种FLAG和LauchMode分别代表的意义,以及使用场景。
9、知道65535 dex-merge问题是怎么回事
10、熟悉使用Android开发者选项功能,比如最常用的 布局边界显示、过度绘制检测、UI绘制速度检测、Surface更新时闪烁、严格模式、CPU利用率展示、不保持Activity。
三、拓展(上面这些都真正透了,就没有大的漏洞了)
1、事件流编程,EventBus、RxJava。
2、Kotlin语言。
3、DataBinding,Google的这个MVVM框架实现的很完全,很强大,包括像Angular中自定义directive/filter的类似feature。
4、知道Volley,okHttp他们的应用场景。
5、熟悉一些ORM,包括现在新出的非基于SqlLite的数据库:Realm,
Realm is a mobile database: a replacement for SQLite & Core Data6、Android对Vector Icon的支持
7、Android L新特性,Palette、CoordinatorLayout自定义Behavior等