面试复习笔记:
这份资料我从春招开始,就会将各博客、论坛。网站上等优质的Android开发中高级面试题收集起来,然后全网寻找最优的解答方案。每一道面试题都是百分百的大厂面经真题+最优解答。包知识脉络 + 诸多细节。
节省大家在网上搜索资料的时间来学习,也可以分享给身边好友一起学习。
《960页Android开发笔记》
《1307页Android开发面试宝典》
包含了腾讯、百度、小米、阿里、乐视、美团、58、猎豹、360、新浪、搜狐等一线互联网公司面试被问到的题目。熟悉本文中列出的知识点会大大增加通过前两轮技术面试的几率。
《507页Android开发相关源码解析》
只要是程序员,不管是Java还是Android,如果不去阅读源码,只看API文档,那就只是停留于皮毛,这对我们知识体系的建立和完备以及实战技术的提升都是不利的。
真正最能锻炼能力的便是直接去阅读源码,不仅限于阅读各大系统源码,还包括各种优秀的开源库。
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
“espresso_core” : “androidx.test.espresso:espresso-core:${versions[“espressoVersion”]}”,
“junit” : “junit:junit:${versions[“junitVersion”]}”,
//注释处理器
“support_annotations” : “com.android.support:support-annotations:${versions[“annotationsVersion”]}”,
“design” : “com.google.android.material:material:${versions[“designVersion”]}”,
//方法数超过65535解决方法64K MultiDex分包方法
“multidex” : “androidx.multidex:multidex:2.0.0”,
//阿里路由
“arouter_api” : “com.alibaba:arouter-api:${versions[“arouterApiVersion”]}”,
“arouter_compiler” : “com.alibaba:arouter-compiler:${versions[“arouterCompilerVersion”]}”,
“arouter_annotation” : “com.alibaba:arouter-annotation:${versions[“arouterAnnotationVersion”]}”,
//黄油刀
“butterknife” : “com.jakewharton:butterknife:${versions[“butterknifeVersion”]}”,
“butterknife_compiler”: “com.jakewharton:butterknife-compiler:${versions[“butterknifeVersion”]}”
]
}
然后在project的build.gradle中引入config.gradle文件:
apply from: “config.gradle”
基础公共组件 common 将一直作为 library 存在,所有业务组件都需要依赖 common 组件。
common 组件主要负责封装公共部分,如网络请求、数据存储、自定义控件、各种工具类等,以及对第三方库进行统一依赖等。
下图是我的 common 组件的包结构图:
前文有言,common 组件还负责对第三方库进行统一依赖,这样上层业务组件就不需要再对第三方库进行重复依赖了,其 build.gradle 源码如下所示:
apply plugin: ‘com.android.library’
apply plugin: ‘com.jakewharton.butterknife’
……
dependencies {
// 在项目中的libs中的所有的.jar结尾的文件,都是依赖
implementation fileTree(dir: ‘libs’, include: [‘*.jar’])
//把implementation 用api代替,它是对外部公开的, 所有其他的module就不需要添加该依赖
api rootProject.ext.dependencies[“appcompat”]
api rootProject.ext.dependencies[“constraintlayout”]
api rootProject.ext.dependencies[“junit”]
api rootProject.ext.dependencies[“runner”]
api rootProject.ext.dependencies[“espresso_core”]
//注释处理器,butterknife所必需
api rootProject.ext.dependencies[“support_annotations”]
//MultiDex分包方法
api rootProject.ext.dependencies[“multidex”]
//Material design
api rootProject.ext.dependencies[“design”]
//黄油刀
api rootProject.ext.dependencies[“butterknife”]
annotationProcessor rootProject.ext.dependencies[“butterknife_compiler”]
//Arouter路由
annotationProcessor rootProject.ext.dependencies[“arouter_compiler”]
api rootProject.ext.dependencies[“arouter_api”]
api rootProject.ext.dependencies[“arouter_annotation”]
}
业务组件在 library 模式下,向上组合为整体性项目;在 application 模式下,可独立运行。
其 build.gradle 源码如下:
if (Boolean.valueOf(rootProject.ext.isModule_North)) {
apply plugin: ‘com.android.application’
} else {
apply plugin: ‘com.android.library’
}
apply plugin: ‘com.jakewharton.butterknife’
……
dependencies {
implementation fileTree(dir: ‘libs’, include: [‘*.jar’])
//公用依赖库
implementation project(‘:x_module_common’)
implementation project(‘:m_module_main’)
//黄油刀
annotationProcessor rootProject.ext.dependencies[“butterknife_compiler”]
//Arouter路由
annotationProcessor rootProject.ext.dependencies[“arouter_compiler”]
}
至此,组件化架构的搭建就算完成了。
可还有几个问题,是组件化开发中必须要关注的,也是项目做组件化改造时可能会遭遇的难点,我们一起来看看吧。
===============================================================================
在 common 组件中有 BaseAppliaction,提供全局唯一的 context,上层业务组件在组件化模式下,均需继承于 BaseAppliaction。
/**
- 基础 Application,所有需要模块化开发的 module 都需要继承自此 BaseApplication。
*/
public class BaseApplication extends Application {
//全局唯一的context
private static BaseApplication application;
@Override
protected void attachBaseContext(Context base) {
super.attachBaseContext(base);
application = this;
//MultiDexf分包初始化,必须最先初始化
MultiDex.install(this);
}
@Override
public void onCreate() {
super.onCreate();
initARouter();
}
/**
- 初始化路由
*/
private void initARouter() {
if (BuildConfig.DEBUG) {
ARouter.openLog(); // 打印日志
ARouter.openDebug(); // 开启调试模式(如果在InstantRun模式下运行,必须开启调试模式!线上版本需要关闭,否则有安全风险)
}
ARouter.init(application);// 尽可能早,推荐在Application中初始化
}
/**
-
获取全局唯一上下文
-
@return BaseApplication
*/
public static BaseApplication getApplication() {
return application;
}
可为不同组件设置不同的 applicationId,也可缺省,在Android Studio中,默认的 applicationId 与包名一致。
组件的 applicationId 在其 build.gradle 文件的 defaultConfig 中进行配置:
if (Boolean.valueOf(rootProject.ext.isModule_North)) {
//组件模式下设置applicationId
applicationId “com.niujiaojian.amd.north”
}
组件在 library 模式和 application 模式下,需要配置不同的 manifest.xml 文件,因为在 application 模式下,程序入口 Activity 和自定义的 Application 是不可或缺的。
在组件的 build.gradle文件 的 android 中进行 manifest 的管理:
/*
-
java插件引入了一个概念叫做SourceSets,通过修改SourceSets中的属性,
-
可以指定哪些源文件(或文件夹下的源文件)要被编译,
-
哪些源文件要被排除。
-
*/
sourceSets {
main {
if (Boolean.valueOf(rootProject.ext.isModule_North)) {//apk
manifest.srcFile ‘src/main/manifest/AndroidManifest.xml’
} else {
manifest.srcFile ‘src/main/AndroidManifest.xml’
java {
//library模式下,排除java/debug文件夹下的所有文件
exclude ‘*module’
}
}
}
}
资源名冲突问题,相信大家多多少少都遇到过,以前最常见的就是第三方 sdk 导致的资源名冲突了。
这个问题没有特别好的解决办法,只能通过设置资源名前缀 resourcePrefix
以及约束自己开发习惯进行解决。
资源名前缀 resourcePrefix
,是在 Project 的 build.gradle 中进行设置的:
/**
-
限定所有子类xml中的资源文件的前缀
-
注意:图片资源,限定失效,需要手动添加前缀
-
*/
subprojects {
afterEvaluate {
android {
resourcePrefix “${project.name}_”
}
}
}
这样设置完之后,string、style、color、dimens 等中资源名,必须以设置的字符串为前缀,而 layout、drawable 文件夹下的 shape 的 xml 文件的命名,必须以设置的字符串为前缀,否则会报错提示。
另外,资源前缀的设置对图片的命名无法限定,建议大家约束自己的开发习惯,自觉加上前缀。
建议:将 color、shape、style 这些放在基础库组件中去,这些资源不会太多,且复用性极高,所有业务组件又都会依赖基础库组件。
Butterknife 存在的问题是控件 id 找不到,只要将 R 替换为 R2 即可解决问题。
需要注意的是,在如下代码示例外的位置,不要这样做,保持使用 R 即可,如 setContentView(R.layout.b_module_north_activity_splash)
public class SplashActivity extends BaseActivity {
@BindView(R2.id.btn_toMain)
Button btnToMain;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.b_module_north_activity_splash);
ButterKnife.bind(this);
}
……
@OnClick(R2.id.btn_toMain)
public void onViewClicked() {
}
}
另外要注意的是,每一个使用 Butterknife 的组件,在其 build.gradle 的 dependencies 都要配置注解处理器处理其 compiler 库:
apply plugin: ‘com.jakewharton.butterknife’
……
dependencies {
……
annotationProcessor rootProject.ext.dependencies[“butterknife_compiler”]
}
由于业务组件间不存在依赖关系,不可以通过 Intent 进行显式跳转。
若需跳转,是要借助于路由的,我使用的是阿里的开源框架 ARouter
。
注:我在案例中只使用了 ARouter 的基础的页面跳转功能,更复杂的诸如携带参数跳转、声明拦截器等功能的使用方法,大家可到 Github 上查看其使用文档。
在每一个需要用到 ARouter 的组件的 build.gradle 文件中对其进行配置:
android {
…
defaultConfig {
…
//Arouter路由配置
javaCompileOptions {
annotationProcessorOptions {
arguments = [AROUTER_MODULE_NAME: project.getName()]
includeCompileClasspath = true
}
}
}
}
dependencies{
…
//Arouter路由
annotationProcessor rootProject.ext.dependencies[“arouter_compiler”]
}
跳转目标页面配置:
@Route(path = “/main/MainActivity”)
public class MainActivity extends BaseActivity {
……
}
跳转来源页面的跳转代码:
尾声
对于很多初中级Android工程师而言,想要提升技能,往往是自己摸索成长,不成体系的学习效果低效漫长且无助。 整理的这些架构技术希望对Android开发的朋友们有所参考以及少走弯路,本文的重点是你有没有收获与成长,其余的都不重要,希望读者们能谨记这一点。
最后想要拿高薪实现技术提升薪水得到质的飞跃。最快捷的方式,就是有人可以带着你一起分析,这样学习起来最为高效,所以为了大家能够顺利进阶中高级、架构师,我特地为大家准备了一套高手学习的源码和框架视频等精品Android架构师教程,保证你学了以后保证薪资上升一个台阶。
当你有了学习线路,学习哪些内容,也知道以后的路怎么走了,理论看多了总要实践的。
进阶学习视频
附上:我们之前因为秋招收集的二十套一二线互联网公司Android面试真题 (含BAT、小米、华为、美团、滴滴)和我自己整理Android复习笔记(包含Android基础知识点、Android扩展知识点、Android源码解析、设计模式汇总、Gradle知识点、常见算法题汇总。)
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
薪水得到质的飞跃。最快捷的方式,就是有人可以带着你一起分析,这样学习起来最为高效,所以为了大家能够顺利进阶中高级、架构师,我特地为大家准备了一套高手学习的源码和框架视频等精品Android架构师教程,保证你学了以后保证薪资上升一个台阶。
[外链图片转存中…(img-E1MjARmO-1715115894313)]
当你有了学习线路,学习哪些内容,也知道以后的路怎么走了,理论看多了总要实践的。
进阶学习视频
[外链图片转存中…(img-zHsbx7yG-1715115894314)]
附上:我们之前因为秋招收集的二十套一二线互联网公司Android面试真题 (含BAT、小米、华为、美团、滴滴)和我自己整理Android复习笔记(包含Android基础知识点、Android扩展知识点、Android源码解析、设计模式汇总、Gradle知识点、常见算法题汇总。)
[外链图片转存中…(img-dmSDSlXE-1715115894314)]
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!