双非实习生如何拿到阿里P7Android技术Offer:是运气使然吗

前言

想进阿里,其实获得面试机会的方法除了校招和社招之外,还有第三种途径就是内推。

当然内推的前提是你得是只千里马,其次你要在阿里找到能认识你才能的伯乐。

当然“事在人为”,当你正真成为技术千里马时,找寻伯乐也不会成为难事。

今天就为大家分享来自通过内推方式拿到阿里offer的同学的心得。

前面的一段时间和大家分享了许多文章,一部分文章是关于校招,另外一部分是关于社招的面试经验,社招往往比校招的要求更加严格,相比之下也更难。

其实在阿里,除了校招和社招这两种招聘方式之外还有第三种,就是内推

所谓内推,就是在公司或者企业里,有了解或者熟悉你的人,并且认为你有担任某些技术人员的能力,直接跨过招聘网站将你的简历交给面试官的一种工作的推荐方式。

BAT都是存在内推的,在某乎上有篇文章有不少可以参考的意见,其中几点我觉得能让我们更加了解阿里的内推:

  • 其一是内推与非内推的本质区别在于:内推的同学大多可以知道你被推荐的部门和团队。所以如果你有心,你可以了解到更多,甚至团队的成员、老大、研究方向,甚至当前的任务排期,这是所谓知彼。
  • 其二是内推的职位往往是有需求的,如果能在面试过程中,回答问题的时候,能向所推荐的团队的研究方向和任务靠拢是会给面试官很大的好感和惊喜,特别是如果你的面试官恰好是那个团队的成员的时候。当然前提是你确实有些实力,不然果断点到为止,别往枪口撞。

那么问题来了,怎么才能认识肯给你提供内推机会的人呢?这一点尤为重要

  • 首先第一你要是一匹千里马才行,技术能力还是第一位的,阿里招聘每一位工程师都是因为认为你对于企业是有价值的,只有我们能力足够优秀才行,否则就是给你机会,你也无法把握。
  • 其次么,那就是你要认识伯乐。认识伯乐的方式有很多,如果你是应届生,可以找在阿里工作的学长(可以通过老师,要是通过比赛或者项目认识就更好了),如果是已经工作几年的同学,也可以找曾经的同学,甚至你都可以加阿里的员工群,直接找群主或者管理员(真的有童鞋这样成功了)。总之,只要你是千里马,就一定能找到伯乐。

今天和大家分享的就是一位获得内推并且成功拿到阿里offer的童鞋关于找工作的准备过程以及面试经历:

我的故事

从来没有想到自己的求职之路会这么顺利, 第一次投阿里就拿到了offer, 以前一直都是做好被刷的准备的…

4月31号晚上收到了来自阿里的正式offer, 签下录取意向书, 粗略算了一下, 从2014年9月份正式入学进入计算机系到2017年4月签下阿里offer, 大约两年半的时间, 这期间有很多人值得感谢: 昊哥,、张雄、李老师…

发生了很多事儿,从最初的懵懵懂懂到后来的立志进入像阿里一样的一线互联网企业, 从对计算机一窍不通到有自己的目标和兴趣爱好, 从不知道技术博客是啥到个人博客的访问量超过40W… 也学习了很多内容。

昊哥一直想让我写下这次面试的经过, 同时也记录一下这一年来准备招聘的过程, 很多有意思的事儿如果现在不写下来以后很快就忘了, 何况看了这么多的面试经验, 现在到了"回馈社会”的时候了。

由于很多朋友和大学学弟对我找工作的准备过程以及面试经历比较感兴趣, 我就分别谈一下自己的这两段经历吧:

养兵千日

我是在2015年11月份中旬遇到昊哥的, 当时昊哥刚刚拿下阿里巴巴的offer, 意气风发。

我越俎代庖请昊哥给我们做讲座的详细经过在此就不再赘述了,不过后来我又找了昊哥好几次, 聊了很多, 也收获很多, 下定决心一定要进入阿里之类的一线互联网公司, 后来磊哥也鼓励并帮助我进入阿里。

因此, 我一直把磊哥当成为命里的贵人。

如果一个本科生能够把基础打得比较坚实再加上稍稍一点儿运气, 拿下技术工程师offer是不在话下的。

如果你实力够强的话, 那一点儿运气也不需要。

在此我引用一句学长关于面试的总结:

“面试 = 运气*(50-n)/100 + 实力*(50+n)/100, n=f(x),x即实力,n与x成正比关系,这就意味着: 你实力越强,对运气的依赖性越低,所以实力才是非常重要的一个环节.”,

下面分别介绍一下我所准备的内容:

用兵一时

4月7号(2016年)昊哥把我的简历推到YunOS

4月12(周二)晚七点参加一面

4月13(周三)下午三点参加二面

隔了一周4月20号(周三)晚八点参加三面

4月24号(周日)参加四面

4月30号收到offer

我从来没有想到这次面试会这么顺利,很早以前我就做好了前几家面试会被打击的准备, 而且这次面试又是这么仓促。

从简历推上去到真正面试只有三四天的准备时间, 还要一直提心吊胆不知道啥时候一个电话打来就要面试,终于在昊哥的一顿催促之下, 阿里那边的人在我返校之后的第五天晚上,开始了面试。

只记得部分题目了,顺手也把解析写出来,方便大家学习。

一面

  • 如何正确使用Handler?

Handler的工作是依赖于Looper的,而Looper(与消息队列)又是属于某一个线程(ThreadLocal是线程内部的数据存储类,通过它可以在指定线程中存储数据,其他线程则无法获取到),其他线程不能访问。因此Handler就是间接跟线程是绑定在一起了。因此要使用Handler必须要保证Handler所创建的线程中有Looper对象并且启动循环。因为子线程中默认是没有Looper的,所以会报错。正确的使用方法是:

  • 自定义控件优化方案
  1. 为了加速你的view,对于频繁调用的方法,需要尽量减少不必要的代码。先从onDraw开始,需要特别注意不应该在这里做内存分配的事情,因为它会导致GC,从而导致卡顿。在初始化或者动画间隙期间做分配内存的动作。不要在动画正在执行的时候做内存分配的事情。
  2. 你还需要尽可能的减少onDraw被调用的次数,大多数时候导致onDraw都是因为调用了invalidate().因此请尽量减少调用invaildate()的次数。如果可能的话,尽量调用含有4个参数的invalidate()方法而不是没有参数的invalidate()。没有参数的invalidate会强制重绘整个view。
  3. 另外一个非常耗时的操作是请求layout。任何时候执行requestLayout(),会使得Android UI系统去遍历整个View的层级来计算出每一个view的大小。如果找到有冲突的值,它会需要重新计算好几次。另外需要尽量保持View的层级是扁平化的,这样对提高效率很有帮助。如果你有一个复杂的UI,你应该考虑写一个自定义的ViewGroup来执行他的layout操作。与内置的view不同,自定义的view可以使得程序仅仅测量这一部分,这避免了遍历整个view的层级结构来计算大小。这个PieChart 例子展示了如何继承ViewGroup作为自定义view的一部分。PieChart 有子views,但是它从来不测量它们。而是根据他自身的layout法则,直接设置它们的大小。
  • 谈谈你对Java三大特性的理解

(1)封装

封装最好理解了。封装是面向对象的特征之一,是对象和类概念的主要特性。

封装,也就是把客观事物封装成抽象的类,并且类可以把自己的数据和方法只让可信的类或者对象操作,对不可信的进行信息隐藏。

(2)继承

面向对象编程 (OOP) 语言的一个主要功能就是“继承”。继承是指这样一种能力:它可以使用现有类的所有功能,并在无需重新编写原来的类的情况下对这些功能进行扩展。

通过继承创建的新类称为“子类”或“派生类”。

被继承的类称为“基类”、“父类”或“超类”。

继承的过程,就是从一般到特殊的过程。

(3)多态

多态性(polymorphisn)是允许你将父对象设置成为和一个或更多的他的子对象相等的技术,赋值之后,父对象就可以根据当前赋值给它的子对象的特性以不同的方式运作。简单的说,就是一句话:允许将子类类型的指针赋值给父类类型的指针。

实现多态,有二种方式,覆盖,重载。

覆盖,是指子类重新定义父类的虚函数的做法。

重载,是指允许存在多个同名函数,而这些函数的参数表不同(或许参数个数不同,或许参数类型不同,或许两者都不同)。

  • 谈谈Android的事件分发机制

(1)事件的传递流程:
Activity(PhoneWindow)->DecorView->ViewGroup->View。

(2)事件分发过程中三个重要的方法:
dispatchTouchEvent()、onInterceptTouchEvent()、onTouchEvent();

(3)事件传递规则:
一般一次点击会有一系列的MotionEvent,可以简单分为:down->move->….->move->up,当一次event分发到ViewGroup时,ViewGroup收到事件后调用dispatchTouchEvent,在dispatchTouchEvent中先检查是否要拦截,若拦截则ViewGroup处理事件,否则交给有处理能力的子容器处理。

  • Android动画有几种,谈谈对其的理解
  1. 视图动画。视图移动、view真真的位置并未移动。
  2. 帧动画。就和放电影一样,一帧一帧的播
  3. 属性动画。视图移动、其位置也会随着移动。
  4. 触摸返回动画。发生触摸事件时有反馈效果。比如波纹效果
  5. 揭露动画。从某一个点向四周展开或者从四周向某一点聚合起来。
  6. 转场动画 & 共享元素。比如切换activity。共享元素一般我们使用在转换的前后两个页面有共同元素时。
  7. 视图状态动画。就是 View 在状态改变时执行的动画效果
  8. 矢量图动画。在图片的基础上做动画。
  9. 约束布局实现的关键帧动画。就是给需要动画效果的属性,准备一组与时间相关的值。关键的几个值。
  • Android 内存泄漏的原因以及解决方案

1、内存泄漏指对象不再使用,本该被回收,却因为有其他正在使用的对象持有该对象的引用,而无法被JVM回收

2、内存泄漏的影响:

  1. 应用可用内存减少,增加堆内存压力
  2. 频繁触发GC,会降低了应用的性能
  3. 到一定程序会导致内存溢出错误

3、Android开发中常见内存泄漏及解决办法

  1. 静态变量生命周期与应用的生命周期一样,如果静态变量持有某个Activity的上下文,则对应Activity无法释放,导致内存泄漏(单例模式) 解决办法:使用Application的上下文
  2. 匿名内部类与非静态内部类因为都会持有外部类引用,当执行异步操作易导致内存泄漏 解决办法:将非静态内部类转为静态内部类+WeakReferenct的方式
  3. Handler消息队列存在延时消息导致内存泄漏 在onDestroy方法中调用Handler相应的方法移除回调和删除消息
  4. 各种注册的监听器忘记移除导致内存泄漏 解决办法:在onDestroy方法中取消注册
  5. 资源对象未关闭导致内存泄漏,如(IO,数据库,Bitmap等) 解决办法:及时关闭资源
  6. 属性动画未取消导致内存泄漏(如无限轮播图效果) 解决办法:onDestroy方法中取消动画
  7. 其他解决办法:使用AAC框架

4、内存泄漏排查工具: AS Monitor,MAT,LeakCanary

5、扩展: Java内存管理,GC

  • HashMap和Hashtable的区别

HashMap是map接口的子类,是将键映射到值的对象,其中键和值都是对象,并且不能包含重复键,但可以包含重复值。HashMap允许null key和null value,而hashtable不允许。

HashMap是Hashtable的轻量级实现(非线程安全的实现),他们都完成了Map接口,由于非线程安全,效率上可能高于Hashtable。

HashMap把Hashtable的contains方法去掉了,改成containsvalue和containsKey。

Hashtable继承自Dictionary类,而HashMap是Java1.2引进的Map interface的一个实现。

Hashtable的方法是Synchronize的,而HashMap不是,在多个线程访问Hashtable时,不需要自己为它的方法实现同步,而HashMap 就必须为之提供外同步。但是如果使用Java 5或以上的话,可以用ConcurrentHashMap代替Hashtable。

Hashtable和HashMap采用的hash/rehash算法都大概一样,所以性能不会有很大的差。

  • ScrollView嵌套ListView的解决方案及其原理

自定义ListView 解决:重写其中的onMeasure()方法

原因: ScrollView默认把Childview设置为UNSPEFEIED模式,而该模式下的ListView给自己的测量的高度就是第一个item的高度.原理:

int expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2, MeasureSpec.AT_MOST);

这个方法的作用是根据大小和模式来生成一个int值,这个int值封装了模式和大小信息.

首先MeasureSpec类是View的一个静态内部类,MeasureSpec类封装了从父布局到子布局传递的布局需求. 每个MeasureSpec对象代表了宽度和高度的要求.

MeasureSpec用int类型表示,前2位代表模式,后30位代表大小. 第一个参数

Integer.MAX_VALUE >> 2:Integer.MAX_VALUE

获取到int的最大值,但是表示大小的值size是int数值的底30位,所以把这个值右移两位,留出高两位表示布局模式. 此时这个值仍旧是一个30位所能表示的最大数,用该数作为控件的size,应该足够满足控件大小的需求. 第二个参数MeasureSpec.AT_MOST:表示这个控件适配父控件的最大空间.

(以下三种仅供参考,不推荐使用)

1.手动设置ListView高度

2.使用单个ListView取代ScrollView中所有内容

3.使用LinearLayout取代ListView

  • 谈谈RecyclerView的性能和优化

  • 升级 RecycleView 版本到 25.1.0 及以上使用 Prefetch 功能,可参考 RecyclerView 数据预取。

  • 如果 Item 高度是固定的话,可以使用 RecyclerView.setHasFixedSize(true); 来避免 requestLayout 浪费资源;

  • 设置 RecyclerView.addOnScrollListener(listener); 来对滑动过程中停止加载的操作。

  • 如果不要求动画,可以通过 ((SimpleItemAnimator) rv.getItemAnimator()).setSupportsChangeAnimations(false);把默认动画关闭来提升效率。

  • 对 TextView 使用 String.toUpperCase 来替代 android:textAllCaps=“true”。

  • 对 TextView 使用 StaticLayout 或者 DynamicLayout 的自定义 View 来代替它。

  • 通过重写 RecyclerView.onViewRecycled(holder) 来回收资源。

  • 通过 RecycleView.setItemViewCacheSize(size); 来加大 RecyclerView 的缓存,用空间换时间来提高滚动的流畅性。

  • 如果多个 RecycledView 的 Adapter 是一样的,比如嵌套的 RecyclerView 中存在一样的 Adapter,可以通过设置 RecyclerView.setRecycledViewPool(pool); 来共用一个 RecycledViewPool。

  • 对 ItemView 设置监听器,不要对每个 Item 都调用 addXxListener,应该大家公用一个 XxListener,根据 ID来进行不同的操作,优化了对象的频繁创建带来的资源消耗。

  • 通过 getExtraLayoutSpace 来增加 RecyclerView 预留的额外空间(显示范围之外,应该额外缓存的空间),如下所示:

  • 数据处理和视图加载分离

从远端拉取数据肯定是要放在异步的,在我们拉取下来数据之后可能就匆匆把数据丢给了 VH 处理,其实,数据的处理逻辑我们也应该放在异步处理,这样 Adapter 在 notify change 后,ViewHolder 就可以简单无压力地做数据与视图的绑定逻辑,比如:

mTextView.setText(Html.fromHtml(data).toString());

这里的 Html.fromHtml(data)方法可能就是比较耗时的,存在多个 TextView 的话耗时会更为严重,这样便会引发掉帧、卡顿,而如果把这一步与网络异步线程放在一起,站在用户角度,最多就是网络刷新时间稍长一点。

  • 数据优化

分页拉取远端数据,对拉取下来的远端数据进行缓存,提升二次加载速度;对于新增或者删除数据通过 DiffUtil 来进行局部刷新数据,而不是一味地全局刷新数据。

  • 布局优化

  • 其他

(1)减少过渡绘

制减少布局层级,可以考虑使用自定义 View 来减少层级,或者更合理地设置布局来减少层级,不推荐在 RecyclerView 中使用 ConstraintLayout,有很多开发者已经反映了使用它效果更差,相关链接有:Is ConstraintLayout that slow?、constraintlayout 1.1.1 not work well in listview。

(2)减少 xml 文件 inflate 时间

这里的 xml 文件不仅包括 layout 的 xml,还包括 drawable 的 xml,xml 文件 inflate 出 ItemView 是通过耗时的 IO 操作,尤其当 Item 的复用几率很低的情况下,随着 Type 的增多,这种 inflate 带来的损耗是相当大的,此时我们可以用代码去生成布局,即 new View() 的方式,只要搞清楚 xml 中每个节点的属性对应的 API 即可。

(3)减少 View 对象的创建

一个稍微复杂的 Item 会包含大量的 View,而大量的 View 的创建也会消耗大量时间,所以要尽可能简化 ItemView;设计 ItemType 时,对多 ViewType 能够共用的部分尽量设计成自定义 View,减少 View 的构造和嵌套。

new LinearLayoutManager(this) {
    @Override
    protected int getExtraLayoutSpace(RecyclerView.State state) {
        return size;
    }
};

前面的这几个问题比较简单, 回答的都比较流畅, 估计面试官打算在最后一题发难吧, 最后一个系统设计题难度陡然提高, 一下子就没了感觉,

这个问题纠缠了十多分钟, 直到现在这道题我直到现在这道题我仍然不知道该如何解决.

二面

  • 谈谈你对Java中hash码的理解

在Java中,哈希码代表了对象的一种特征,例如我们判断某两个字符串是否==,如果其哈希码相等,则这两个字符串是相等的,其次,哈希码是一种数据结构的算法,常见的哈希码的算法有:

Object类的HashCode,返回对象的内存地址经过处理后的结构,由于每个对象的内存地址都不一样,所以哈希码也不一样。

String类的HashCode,根据String类包含的字符串的内容,根据一种特殊的算法返回哈希码,只要字符串的内容相同,返回的哈希码也相同。

Integer类:返回的哈希码就是integer对象里所包含的那个整数的数值。 例如:Integer i1=new Integer(100) i1.hashCode的值就是100,由此可见两个一样大小的Integer对象返回的哈希码也一样。

  • 简述一下类加载过程

(1)加载

加载,是指Java虚拟机查找字节流(查找.class文件),并且根据字节流创建java.lang.Class对象的过程。这个过程,将类的.class文件中的二进制数据读入内存,放在运行时区域的方法区内。然后在堆中创建java.lang.Class对象,用来封装类在方法区的数据结构。

类加载阶段: (1)Java虚拟机将.class文件读入内存,并为之创建一个Class对象。

(2)任何类被使用时系统都会为其创建一个且仅有一个Class对象。

(3)这个Class对象描述了这个类创建出来的对象的所有信息,比如有哪些构造方法,都有哪些成员方法,都有哪些成员变量等。

(2)链接

链接包括验证、准备以及解析三个阶段。 (1)验证阶段。主要的目的是确保被加载的类(.class文件的字节流)满足Java虚拟机规范,不会造成安全错误。

(2)准备阶段。负责为类的静态成员分配内存,并设置默认初始值。

(3)解析阶段。将类的二进制数据中的符号引用替换为直接引用。

说明: 符号引用。即一个字符串,但是这个字符串给出了一些能够唯一性识别一个方法,一个变量,一个类的相关信息。

直接引用。可以理解为一个内存地址,或者一个偏移量。比如类方法,类变量的直接引用是指向方法区的指针;而实例方法,实例变量的直接引用则是从实例的头指针开始算起到这个实例变量位置的偏移量。

举个例子来说,现在调用方法hello(),这个方法的地址是0xaabbccdd,那么hello就是符号引用,0xaabbccdd就是直接引用。 在解析阶段,虚拟机会把所有的类名,方法名,字段名这些符号引用替换为具体的内存地址或偏移量,也就是直接引用。

(3)初始化

初始化,则是为标记为常量值的字段赋值的过程。换句话说,只对static修饰的变量或语句块进行初始化。

如果初始化一个类的时候,其父类尚未初始化,则优先初始化其父类。 如果同时包含多个静态变量和静态代码块,则按照自上而下的顺序依次执行。

  • 谈谈四种GC算法
  1. 标记—清除 Mark-Sweep 过程:标记可回收对象,进行清除 缺点:标记和清除效率低,清除后会产生内存碎片
  2. 复制算法 过程:将内存划分为相等的两块,将存活的对象复制到另一块内存,把已经使用的内存清理掉 缺点:使用的内存变为了原来的一半 进化:将一块内存按8:1的比例分为一块Eden区(80%)和两块Survivor区(10%) 每次使用Eden和一块Survivor,回收时,将存活的对象一次性复制到另一块Survivor上,如果另一块Survivor空间不足,则使用分配担保机制存入老年代
  3. 标记—整理 Mark—Compact 过程:所有存活的对象向一端移动,然后清除掉边界以外的内存
  4. 分代收集算法 过程:将堆分为新生代和老年代,根据区域特点选用不同的收集算法,如果新生代朝生夕死,则采用复制算法,老年代采用标记清除,或标记整理

记得当时二面面试官打电话过来的时候还在上课, 跟老师匆匆说明情况之后就找了一间空教室开始面试

与一面面试官的和蔼不同, 二面面试官刚开始问的问题就咄咄逼人(相对较难),而且在我回答问题时还曾经不止一次被他打断.

由于题目相对较难(也可能是我自己水平不足)感觉需要思考一段时间才能回答, 而且有好几个问题是我以前没有接触过的, 我只能凭自己的理解去回答

面试还未结束, 我就感觉这次面试的结果有点儿悬, 可能过不了这一关了… 但当时心里倒是很坦然

由于刚开始就没有打算能够通过, 因此也就没有那种"天生我材必有用”或那种"此处不留爷,自有留爷处,处处不留爷, 爷去投八路”的气概

只是觉得过不了就过不了,大不了从头再来.面试到最后, 我问面试官是哪个部门的,

回答说是"阿里***”(此处就不透露了哈)部门,突然感觉今天被虐成渣不怨了, 心想如果这次面试通不过, 下次直接投其他部门, 不投这个了, 后来跟同学说起这个想法,他说我是被虐疯了.

二面结束之后给昊哥发了一短信, 跟他说今天面试感觉不是太好.估计通不过了, 磊哥却说面试应该不会就此停下, 但是可能会中间再加一轮技术面, 由原来的三面变成四面

原因是在我一面试结束时问了一下面试官对我的评价, 面试官除了说我真正的项目经验不足之外又说"大三能够有这样的扎实的基础已经相当不错了”, 褒奖之意溢于言表, 估计面试官给的评价应该不错

因此如果二面面试官给个中评的话,那我就应该能够顺利的进入HR终面, 但如果是差评的话, 那就估计还要再加一轮技术面, 给出一个最终的技术评价.果不其然, 在等了一周之后, 三面来了…

三面:

在三面正式开始之前, 我先问了一句是技术面还是HR面,

"是技术面”.

内心顿时紧张起来,但面试官告诉我不用紧张,放松就好,只是聊一下我这边的具体情况, 果然三面30多分钟基本上都是处于比较轻松的氛围之中.

  • Final,Finally,Finalize的区别

final 用于声明属性,方法和类,分别表示属性不可变,方法不可覆盖,类不可继承。 内部类要访问局部变量,局部变量必须定义成final类型.

finally是异常处理语句结构的一部分,表示总是执行。

finalize是Object类的一个方法,在垃圾收集器执行的时候会调用被回收对象的此方法,可以覆盖此方法提供垃圾收集时的其他资源回收,例如关闭文件等。 JVM不保证此方法总被调用

  • 四种LaunchMode及其使用场景

standard 模式 这是默认模式,每次激活Activity时都会创建Activity实例,并放入任务栈中。使用场景:大多数Activity。

singleTop 模式 如果在任务的栈顶正好存在该Activity的实例,就重用该实例( 会调用实例的 onNewIntent() ),否则就会创建新的实例并放入栈顶,即使栈中已经存在该Activity的实例,只要不在栈顶,都会创建新的实例。使用场景如新闻类或者阅读类App的内容页面。

singleTask 模式 如果在栈中已经有该Activity的实例,就重用该实例(会调用实例的 onNewIntent() )。重用时,会让该实例回到栈顶,因此在它上面的实例将会被移出栈。如果栈中不存在该实例,将会创建新的实例放入栈中。使用场景如浏览器的主界面。不管从多少个应用启动浏览器,只会启动主界面一次,其余情况都会走onNewIntent,并且会清空主界面上面的其他页面。

singleInstance 模式 在一个新栈中创建该Activity的实例,并让多个应用共享该栈中的该Activity实例。一旦该模式的Activity实例已经存在于某个栈中,任何应用再激活该Activity时都会重用该栈中的实例( 会调用实例的 onNewIntent() )。其效果相当于多个应用共享一个应用,不管谁激活该 Activity 都会进入同一个应用中。使用场景如闹铃提醒,将闹铃提醒与闹铃设置分离。singleInstance不要用于中间页面,如果用于中间页面,跳转会有问题,比如:A -> B (singleInstance) -> C,完全退出后,在此启动,首先打开的是B。

  • 如何减小apk安装包体积

1.代码混淆 minifyEnabled true

2.资源压缩 1)shrinkResources true 2)微信的AndResGuard

3.图片压缩 1)tinypng 2)svg 3)webp

4.so库配置 只保留两个abi平台,即armeabi和armeabi-v7a

5.dex优化 Facebook的redex

  • 对未来有什么打算,
  • 对杭州有什么印象
  • 有没有女朋友,
  • 有没有在杭州长期居住的打算
  • 如果我去杭州的话, 我女朋友怎么办等等

由于面试官很健谈, 后来又聊起了逻辑思维与追求完美的话题,

总的来说, 这一面并不如前两面那样技术氛围浓厚, 面试官也特别和蔼(由于面试官在正式面试之前曾经放过我鸽子, 面试开始时面试官竟然忍不住给我道歉,真是受宠若惊了…),

后来面试官把他的两个联系方式都留给了我, 让我有什么就可以直接联系他, 后来在收到offer后联系团队时还跟面试官通过几次电话,

求面试官老师帮忙, 面试官老师在百忙之中还帮我联系HR , 告诉我该如何更快的融入团队… 说实话, 真的非常感谢这位面试官.

四面

  • 谈谈你的职场规划

主要看的是面试者对自己的定位,这样便于让企业去识别这个人的培养方向。问完这个问题会有第二个问题你有没有想过如何达成你的目标,这个通常看面试者的规划能力,说的越详细越好。

有目标并有清晰规划的人,通常这类人自驱力比较强的人。一般没有明确目标和清晰规划的人我是不会招的。

还有企业文化,通常我问面试者是否认同我们的企业文化,不认同技术再好也不行。

  • 为什么不打算读研了
  • 在大学期间遇到的最大的困难是什么, 是怎么解决的
  • 除了上课,在大学里其他的时间都在干嘛等等

四面是HR面, 万万没想到的是HR老师竟然在周天下午打电话过来, 当时刚刚打完羽毛球, 上气不接下气的接了HR的电话, 然后直接开始面试

这次面试基本没问技术方面的问题, 由于我说了我的博客, 因此HR老师也看了一下我的博客, 见访问量还比较高, 我谦虚的说"可能是由于写的东西都比较基础, 因此看的人比较多吧

总的来说, 这次面试虽然不涉及技术, 但大部分问题都是不太好答的, 因此, 在此建议大家在日常生活中对生活多一些思考, 不仅仅是为了应付HR, 更要活的明白一些.

四面结束之后, 自我感觉不错, 果不其然在第二周的周一, 收到offer通知, 知道自己的阿里面试算是可以告一段落了.

小Tips

在每次面试快要结束时, 面试官都会让你问他/她一个或几个问题, 或者你自己主动问个问题,

在这儿我比较推荐的一个问题是

"在您看来, 在阿里(当然是目标公司)如果要胜任一份工程师的工作, 他/她需要怎么样的能力或素质, 或者说如果我还想继续应聘这个工作, 我还需要做那些努力”,

这个问题暗含了三层意思:

  • 一是对我这次面试结果的询问
  • 二是我该如何努力弥补自己的不足
  • 三是表达了你对这份工作的渴望,希望能够胜任或者获得这份工作.

我在四次面试中都主动或被动的问到了这个问题, 四面的面试官各自给出了自己的答案, 虽然答案各异, 但是综合起来能够得出一个对自己综合评价

同时,也能够知道为接下来迎接下一轮面试或者参加工作该做哪方面的努力, 因此我感觉这个问题还是比较好的。

最后

分享一份大佬收录整理的Android学习PDF+架构视频+源码笔记高级架构技术进阶脑图、Android开发面试专题资料,高级进阶架构资料

这些都是我现在闲暇还会反复翻阅的精品资料。里面对近几年的大厂面试高频知识点都有详细的讲解。相信可以有效的帮助大家掌握知识、理解原理。

当然你也可以拿去查漏补缺,提升自身的竞争力。

如果你有需要的话,可以点击获取

喜欢本文的话,不妨顺手给我点个赞、评论区留言或者转发支持一下呗~

猜你喜欢

转载自blog.csdn.net/ajsliu1233/article/details/108674274