来自程序员的感叹:我怎么就没有阿里,腾讯,安卓内存监控悬浮窗
网络存储数据
网络存储方式,需要与 Android 网络数据包打交道,关于 Android 网络数据包的详细说明,请阅读 Android SDK 引用了 Java SDK 的哪些 package?。
activity 的启动模式有哪些?是什么含义?
在 Android 里,有 4 种 activity 的启动模式,分别为:
“standard” (默认)
“singleTop”
“singleTask”
“singleInstance”
它们主要有如下不同:
如何决定所属 task
“standard” 和 ”singleTop” 的 activity 的目标 task,和收到的 Intent 的发送者在同一个 task 内,除非 intent 包括参数 FLAG_ACTIVITY_NEW_TASK。
如果提供了 FLAG_ACTIVITY_NEW_TASK 参数,会启动到别的 task 里。
“singleTask” 和 ”singleInstance” 总是把 activity 作为一个 task 的根元素,他们不会被启动到一个其他 task 里。
是否允许多个实例
“standard” 和 ”singleTop” 可以被实例化多次,并且存在于不同的 task 中,且一个 task 可以包括一个 activity 的多个实例。
“singleTask” 和 ”singleInstance” 则限制只生成一个实例,并且是 task 的根元素。 singleTop 要求如果创建 intent 的时候栈顶已经有要创建的 Activity 的实例,则将 intent 发送给该实例,而不发送给新的实例。
是否允许其它 activity 存在于本 task 内
“singleInstance” 独占一个 task,其它 activity 不能存在那个 task 里;如果它启动了一个新的 activity,不管新的 activity 的 launch mode 如何,新的 activity 都将会到别的 task 里运行(如同加了 FLAG_ACTIVITY_NEW_TASK 参数)。
而另外三种模式,则可以和其它 activity 共存。
是否每次都生成新实例
“standard” 对于没一个启动 Intent 都会生成一个 activity 的新实例。
“singleTop” 的 activity 如果在 task 的栈顶的话,则不生成新的该 activity 的实例,直接使用栈顶的实例,否则,生成该 activity 的实例。
比如现在 task 栈元素为 A-B-C-D(D 在栈顶),这时候给 D 发一个启动 intent,如果 D 是 “standard” 的,则生成 D 的一个新实例,栈变为 A-B-C-D-D。
如果 D 是 singleTop 的话,则不会生产 D 的新实例,栈状态仍为 A-B-C-D。
如果这时候给 B 发 Intent 的话,不管 B 的 launchmode 是 ”standard” 还是 “singleTop” ,都会生成 B 的新实例,栈状态变为 A-B-C-D-B。
“singleInstance” 是其所在栈的唯一 activity,它会每次都被重用。
“singl
eTask” 如果在栈顶,则接受 intent,否则,该 intent 会被丢弃,但是该 task 仍会回到前台。
当已经存在的 activity 实例处理新的 intent 时候,会调用 onNewIntent() 方法 如果收到 intent 生成一个 activity 实例,那么用户可以通过 back 键回到上一个状态;如果是已经存在的一个 activity 来处理这个 intent 的话,用户不能通过按 back 键返回到这之前的状态。
说说 ContentProvider、ContentResolver、ContentObserver 之间的关系
ContentProvider 实现各个应用程序间数据共享,用来提供内容给别的应用操作。如联系人应用中就使用了 ContentProvider,可以在自己应用中读取和修改联系人信息,不过需要获取相应的权限。它也只是一个中间件,真正的数据源是文件或 SQLite 等。 ContentResolver 内容解析者,用于获取内容提供者提供的数据,通过 ContentResolver.notifyChange(uri)发出消息 ContentObserver 内容监听者,可以监听数据的改变状态,观察特定 Uri 引起的数据库变化,继而做一些相应的处理,类似于数据库中的触发器,当 ContentObserver 所观察的 Uri 发生变化时,便会触发它。
注册广播有几种方式,这些方式有何优缺点?请谈谈 Android 引入广播机制的用意。
首先写一个类要继承 BroadcastReceiver
第一种:在清单文件中声明,添加
第二种使用代码进行注册如
两种注册类型的区别是:
第一种不是常驻型广播,也就是说广播跟随程序的生命周期;
第二种是常驻型,也就是说当应用程序关闭后,如果有信息广播来,程序也会被系统调用自动运行。
=============================================================================
搭建项目的主流框架集
Dagger2+RxJava+Retrofit+MVP 是本人目前用的框架集,目前使用的很广泛, 四个相结合,组成项目的优美整体架构。 需要导入的包
dependencies { // 网络请求 compile 'com.squareup.retrofit2:retrofit:2.1.0' compile 'com.squareup.retrofit2:adapter-rxJava:2.0.1' compile 'com.squareup.retrofit2:converter-gson:2.0.0-beta4' compile 'com.squareup.retrofit2:converter-scalars:2.0.0-beta4' compile 'com.squareup.okhttp3:okhttp:3.2.0' // 注解 compile 'com.google.dagger:dagger:2.0.2' apt 'com.google.dagger:dagger-compiler:2.0.2' provided 'org.glassfish:Javax.annotation:10.0-b28' compile 'com.jakewharton:butterknife:7.0.1' // Rx compile 'io.reactivex:rxandroid:1.1.0' compile 'io.reactivex:rxJava:1.1.5' }
下面是 MVP 的架构图
如上图所示
View 与 Model 并不直接交互,而是使用 Presenter 作为 View 与 Model 之间的桥梁。
其中 Presenter 中同时持有 view 层以及 Model 层的 Interface 的引用,View 层持有 Presenter 层 Interface 的引用。当 View 层某个界面需要展示某些数据的时候,首先会调用 Presenter 层的某个接口,然后 Presenter 层会调用 Model 层请求数据。
当 Model 层数据加载成功之后会调用 Presenter 层的回调方法通知 Presenter 层数据加载完毕。
最后 Presenter 层再调用 View 层的接口将加载后的数据展示给用户。这就是 MVP 模式的整个核心过程,如果你是面试初级安卓开发,面试官应该只会让你阐述下整个调用过程,只要你能流畅的说完整个过程应该差不多了。
Dagger2 的流程图
什么是 Dagger2
Dagger2 是一个依赖注入框架,butterknife 也是一个依赖注入框架。不过 butterknife,最多叫奶油刀,Dagger2 被叫做利器啊,他的主要作用,就是对象的管理,其目的是为了降低程序耦合。
Dagger2 的优点
全局对象实例的简单访问方式
和 ButterKnife 库定义了 view,事件处理以及资源的引用一样,Dagger2 提供全局对象引用的简易访问方式。声明了单例的实例都可以使用 @inject 进行访问。比如下面的 MyTwitterApiClient 和 SharedPreferences 的实例:
public class MainActivity extends Activity { @Inject MyTwitterApiClient mTwitterApiClient; @Inject SharedPreferences sharedPreferences; public void onCreate(Bundle savedInstance) { // assign singleton instances to fields InjectorClass.inject(this); }
复杂的依赖关系只需要简单的配置
Dagger2 会通过依赖关系并且生成易懂易分析的代码。以前通过手写的大量模板代码中的对象引用将会由它给你创建并传递到相应对象中。因此你可以更多的关注模块中构建的内容而不是模块中的对象实例的创建顺序。
让单元测试和集成测试更加方便
因为依赖关系已经为我们独立出来,所以我们可以轻松的抽取出不同的模块进行测试。依赖的注入和配置独立于组件之外。因为对象是在一个独立、不耦合的地方初始化,所以当注入抽象方法的时候,我们只需要修改对象的实现方法,而不用大改代码库。依赖可以注入到一个组件中:我们可以注入这些依赖的模拟实现,这样使得测试更加简单。
作用域实例(Scoped instances)
我们不仅可以轻松的管理全局实例对象,也可以使用 Dagger2 中的 scope 定义不同的作用域。(比如根据 user session、activity 的生命周期)
什么是 Retrofit
Retrofit 是 Square 开发的一个 Android 和 Java 的 REST 客户端库。这个库非常简单并且具有很多特性,相比其他的网络库,更容易让初学者快速掌握。
怎样创建 Retrofit 实例
创建 Retrofit 实例时需要通过 Retrofit.Builder,并调用 baseUrl 方法设置 URL。
接口定义
以获取时间列表为例
public interface TimeService {> @GET("getTimes?") Call< ResponseBody > getTimes (@Query("month") String month);}
注意,这里是 interface 不是 class,所以我们是无法直接调用该方法,我们需要用 Retrofit 创建一个 TimeService 的代理对象。
TimeService timeService= createRetrofit().create(TimeService .class);
接口调用
Call<ResponseBody> mService= timeService.getTimes ("1"); mService.enqueue(new Callback<ResponseBody>() { @Override public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) { try { Log(response.body().string()); } catch (IOException e) { e.printStackTrace(); } } @Override public void onFailure(Call<ResponseBody> call, Throwable t) { t.printStackTrace(); } });
如何快速理解项目进行二次开发
当我们进入一个新公司工作,有可能接手的不是一个新项目而是维护别人开发的项目,面对庞大的项目不知从何下手。在这里我要告诉大家的是,拿到项目的时候不要盲目的进行开发而是阅读项目源码。阅读源码首先浏览项目结构,
通过这张结构图可以了解项目用的是 MVP 架构,有两个 lib 一个和 service 有关 一个和图片处理有关。然后再阅读 build.gradle 文件,里面有项目中用到的第三方库的引用地址,知道项目中用到了哪些技术,如果有不熟悉的第三方库就可以根据这个地址去查找资源熟悉调用方式项目中用到的模块,日后逐渐研究库的源码以及实现原理。等这些了解的差不多了,再看一看需求文档和设计图,对着需求走一遍流程,主要记录 activity 之间的跳转,可以画一张类之间跳转的结构图,这样整个跳转的逻辑会更清晰。
还有两个值得阅读的是:项目中的工具类和封装的组件。相信不少人遇到过,在网上找了很久的一个处理数据的方法,过了很多天发现项目的工具类中有直接就可以拿来用。封装的组件也和工具类似可以直接拿来用的,在后面的开发也提倡大家将项目组件化。
四.历年大厂面试题总结
腾讯地图
算法:非递归实现二叉树前序遍历;
手写:双重检查单例类(其中 volatile 关键字作用)
GreenDao 底层实现
binder 用处和原理
messager 用处和原理
Android 中的内存泄露
oom 原因及如何定位
如何降低程序崩溃率
okhttp 源码理解,使用拦截器的用处和好处
项目中的难点
组件化、插件化
ExoPlayer 源码
图片优化,如何压缩、如何缓存
阿里巴巴
LRUCache 原理
图片加载原理
模块化实现(好处,原因)
视频加密传输
统计启动时长,标准
如何保持应用的稳定性
ThreadLocal 原理
谈谈 classloader
动态布局
热修复、插件化
HashMap 源码, SpareArray 原理
性能优化,怎么保证应用启动不卡顿
SP 是进程同步的吗?有什么方法做到同步
介绍下 SurfView
HashMap 实现原理,ConcurrentHashMap 的实现原理
BroadcastReceiver,LocalBroadcastReceiver 区别
Bundle 机制
Handler 机制
android 事件传递机制
线程间 操作 List
App 启动流程,从点击桌面开始
动态加载
类加载器
OSGI
Https 请求慢的解决办法,DNS,携带数据,直接访问 IP
GC 回收策略
画出 Android 的大体架构图
描述清点击 Android Studio 的 build 按钮后发生了什么
大体说清一个应用程序安装到手机上时发生了什么;
对 Dalvik、ART 虚拟机有基本的了解;
Android 上的 Inter-Process-Communication 跨进程通信时如何工作的;
App 是如何沙箱化,为什么要这么做;
权限管理系统(底层的权限是如何进行 grant 的);
进程和 Application 的生命周期;
系统启动流程 Zygote 进程 –> SystemServer 进程 –> 各种系统服务 –> 应用进程
评论