怎么准备Android面试?

大四课程结束了,准备找实习。想找Android开发,该从哪些方面开始准备?
关注者
1,785
被浏览
194,295

49 个回答

在收藏的同时,麻烦顺手点个赞,谢谢啦!!

最近看到很多人都在找工作, 而且很多人都感觉今年找工作比去年难很多, 竞争力也增加不少, 因此激发我整理这份资料, 希望能帮到正在找或者准备找工作的童鞋们.

首先我们能否获得一个面试机会, 那肯定是从简历开始, 简历需要做好功夫, 一份好的简历才足够吸引企业得到面试机会, 接着就是面试了, 面试前必须要先做好准备, 多看一下前辈们总结面试题, 有哪一方面不足的地方赶紧补充一下, 还有要了解一下你即将面试那家公司.

教你写简历

面试题

做题

看完面试题之后那就来做一下面试题目吧, 目前找到两个网站

聊面试

(帅张)

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 Data

6、Android对Vector Icon的支持

7、Android L新特性,Palette、CoordinatorLayout自定义Behavior等