- 第五步,初始化
if (isDebug()) { // 这两行必须写在init之前,否则这些配置在init过程中将无效
ARouter.openLog(); // 打印日志
ARouter.openDebug(); // 开启调试模式(如果在InstantRun模式下运行,必须开启调试模式!线上版本需要关闭,否则有安全风险)
}
ARouter.init(mApplication); // 尽可能早,推荐在Application中初始化
- 第六步,使用ARouter
ARouter.getInstance().build(“/test/activity”).navigation();
传统intent的优点
-
轻量
-
简单
传统intent的缺点
-
跳转过程无法控制,一旦调用了
startActivity(Intent)
便交由系统执行,中间过程无法插手 -
跳转失败无法捕获、降级,出现问题直接抛出异常
-
显示Intent中因为存在直接的类依赖关系,导致耦合严重
startActivity(new Intent(MainActivity.this, LoginActivity.class));//强依赖LoginActivity
- 隐式Intent中会出现规则集中式的管理,导致协作困难,都需要在Manifest中进行配置,导致扩展性比较差
//隐式 比 显式更强一点,可以在两个无关子module 之间跳转,由于显式无法引入包,所以无法完成跳转
Intent intent = new Intent();
intent.setClassName(MainActivity.this,“com.cnn.loginplugin.ui.login.LoginActivity”);//设置包路径
startActivity(intent);
ARouter优点
-
模块间通信(后面讲原理)
-
支持url 跳转
build("/test/activity").navigation()
-
支持拦截器
// 比较经典的应用就是在跳转过程中处理登陆事件,这样就不需要在目标页重复做登陆检查
// 拦截器会在跳转之间执行,多个拦截器会按优先级顺序依次执行
@Interceptor(priority = 8, name = “测试用拦截器”)
public class TestInterceptor implements IInterceptor {
@Override
public void process(Postcard postcard, InterceptorCallback callback) {
…
callback.onContinue(postcard); // 处理完成,交还控制权
// callback.onInterrupt(new RuntimeException(“我觉得有点异常”)); // 觉得有问题,中断路由流程
// 以上两种至少需要调用其中一种,否则不会继续路由
}
@Override
public void init(Context context) {
// 拦截器的初始化,会在sdk初始化的时候调用该方法,仅会调用一次
}
}
- 参数注入,@Autowired注解实现,更方便,需要配合
ARouter.getInstance().inject(this);
一起使用
@Autowired
public String name;
@Autowired
int age;
// 通过name来映射URL中的不同参数
@Autowired(name = “girl”)
boolean boy;
// 支持解析自定义对象,URL中使用json传递
@Autowired
TestObj obj;
// 使用 withObject 传递 List 和 Map 的实现了
// Serializable 接口的实现类(ArrayList/HashMap)
// 的时候,接收该对象的地方不能标注具体的实现类类型
// 应仅标注为 List 或 Map,否则会影响序列化中类型
// 的判断, 其他类似情况需要同样处理
@Autowired
List list;
@Autowired
Map<String, List> map;
- 支持外部url 跳转
<data
android:host=“www.nativie.com”
android:scheme=“arouter”/>
- 简单demo,github做简单静态界面服务器,并部署到oslanka.github.io/statichtml.…
跳转登录android-ARouter
跳转登录android-ARouter 带参数
跳转android-ARouter 设置界面
跳转android-ARouter 设置界面
跳转android-ARouter 错误路径
-
拦截器(拦截跳转过程,面向切面编程)
-
什么是面向切面编程AOP?AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期间动态代理实现程序功能的统一维护的一种技术。AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率
// 拦截器会在跳转之前执行,多个拦截器会按优先级顺序依次执行
@Interceptor(priority = 8, name = “测试用拦截器”)
public class TestInterceptor implements IInterceptor {
@Override
public void process(Postcard postcard, InterceptorCallback callback) {
…
callback.onContinue(postcard); // 处理完成,交还控制权
// callback.onInterrupt(new RuntimeException(“我觉得有点异常”)); // 觉得有问题,中断路由流程
// 以上两种至少需要调用其中一种,否则不会继续路由
}
@Override
public void init(Context context) {
// 拦截器的初始化,会在sdk初始化的时候调用该方法,仅会调用一次
}
}
- 动态注册路由信息 适用于部分插件化架构的App以及需要动态注册路由信息的场景,可以通过 ARouter 提供的接口实现动态注册 路由信息,目标页面和服务可以不标注 @Route 注解,注意:同一批次仅允许相同 group 的路由信息注册
ARouter.getInstance().addRouteGroup(new IRouteGroup() {
@Override
public void loadInto(Map<String, RouteMeta> atlas) {
atlas.put(“/dynamic/activity”, // path
RouteMeta.build(
RouteType.ACTIVITY, // 路由信息
TestDynamicActivity.class, // 目标的 Class
“/dynamic/activity”, // Path
“dynamic”, // Group, 尽量保持和 path 的第一段相同
0, // 优先级,暂未使用
0 // Extra,用于给页面打标
)
);
}
});
// 构建标准的路由请求,并指定分组
ARouter.getInstance().build(“/home/main”, “ap”).navigation();
// 构建标准的路由请求,通过Uri直接解析
Uri uri;
ARouter.getInstance().build(uri).navigation();
// 构建标准的路由请求,startActivityForResult
// navigation的第一个参数必须是Activity,第二个参数则是RequestCode
ARouter.getInstance().build(“/home/main”, “ap”).navigation(this, 5);
// 指定Flag
ARouter.getInstance()
.build(“/home/main”)
.withFlags();
.navigation();
// 获取Fragment
Fragment fragment = (Fragment) ARouter.getInstance().build(“/test/fragment”).navigation();
// 对象传递
ARouter.getInstance()
.withObject(“key”, new TestObj(“Jack”, “Rose”))
.navigation();
// 使用绿色通道(跳过所有的拦截器)
ARouter.getInstance().build(“/home/main”).greenChannel().navigation();
- ARouter.init 时,通过获取
/data/app/包名/base.apk
来筛选出ARouter生成的类,如下图。
- 对于Activity类型,跳转
ARouter.getInstance().build("/login/login").navigation();
,最终执行的是,如下:
**
-
Start activity
-
@see ActivityCompat
*/
private void startActivity(int requestCode, Context currentContext, Intent intent, Postcard postcard, NavigationCallback callback) {
if (requestCode >= 0) { // Need start for result
if (currentContext instanceof Activity) {//启动context 为Activity
ActivityCompat.startActivityForResult((Activity) currentContext, intent, requestCode, postcard.getOptionsBundle());
} else {
// 启动context 为Application 时,不支持requestCode
logger.warning(Consts.TAG, “Must use [navigation(activity, …)] to support [startActivityForResult]”);
}
} else {//启动context 为Application
ActivityCompat.startActivity(currentContext, intent, postcard.getOptionsBundle());
}
if ((-1 != postcard.getEnterAnim() && -1 != postcard.getExitAnim()) && currentContext instanceof Activity) { // Old version.
((Activity) currentContext).overridePendingTransition(postcard.getEnterAnim(), postcard.getExitAnim());
}
if (null != callback) { // Navigation over.
callback.onArrival(postcard);
}
}
- 两个无关的module 如何跳转的呢?我们发现最终执行startActivity时,所用的context为Application,思路是这样的,子module启动另外无关子module时,将执行权,交还给主进程/主程序去处理
- 打开生成路由文档,AROUTER_GENERATE_DOC=“enable”,会生成arouter-map-of-xx.json和3个java文件
// 更新 build.gradle, 添加参数 AROUTER_GENERATE_DOC = enable
// 生成的文档路径 : build/generated/ap_generated_sources/(debug or release)/com/alibaba/android/arouter/docs/arouter-map-of-${moduleName}.json
android {
defaultConfig {
…
javaCompileOptions {
annotationProcessorOptions {
arguments = [AROUTER_MODULE_NAME: project.getName(), AROUTER_GENERATE_DOC: “enable”]
}
}
}
}
//ARouter映射关系如何生成?Generated出三个文件
//ARouter G r o u p Group Grouplogin
//ARouter P r o v i d e r s Providers Providersloginplugin
//ARouter R o o t Root Rootloginplugin
atlas.put(“/login/login”, RouteMeta.build(RouteType.ACTIVITY, LoginActivity.class, “/login/login”, “login”, new java.util.HashMap<String, Integer>(){{put(“password”, 8); put(“username”, 8); }}, -1, -2147483648));
//map 存映射关系
//static Map<String, RouteMeta> routes = new HashMap<>();
- 以上三个文件是如何生成的呢?APT是Annotation Processing Tool的简称,即注解处理工具,apt是在编译期对代码中指定的注解进行解析,然后做一些其他处理(如通过javapoet生成新的Java文件)ARouter使用了两个库
auto-service
javapoet
,来实现从注解到代码的注入,其中auto-service
为注解处理器的库,javapoet
为代码生成器
首先我们了解一下元注解,meta-annotation(元注解)
- @Target
TYPE, // 类、接口、枚举类
FIELD, // 成员变量(包括:枚举常量)
METHOD, // 成员方法
PARAMETER, // 方法参
CONSTRUCTOR, // 构造方法
LOCAL_VARIABLE, // 局部变量
ANNOTATION_TYPE, // 注解类
PACKAGE, // 可用于修饰:包
TYPE_PARAMETER, // 类型参数,JDK 1.8 新增
TYPE_USE // 使用类型的任何地方,JDK 1.8 新增
- @Retention
SOURCE, 只在本编译单元的编译过程中保留,并不写入Class文件中。
CLASS, 在编译的过程中保留并且会写入Class文件中,但是JVM在加载类的时候不需要将其加载为运行时可见的(反射可见)的注解==是JVM在加载类时反射不可见。
RUNTIME 在编译过程中保留,会写入Class文件,并且JVM加载类的时候也会将其加载为反射可见的注解。
-
@Documented 注解的作用是:描述在使用 javadoc 工具为类生成帮助文档时是否要保留其注解信息.
-
@Inherited 注解的作用是:使被它修饰的注解具有继承性(如果某个类使用了被@Inherited修饰的注解,则其子类将自动具有该注解)
-
通过元注解我们定义自己的注解
注解处理器是一个在javac中的,用来编译时扫描和处理的注解的工具。你可以为特定的注解,注册你自己的注解处理器。到这里,我假设你已经知道什么是注解,并且知道怎么申明的一个注解类型。
一个注解的注解处理器,以Java代码(或者编译过的字节码)作为输入,生成文件(通常是.java文件)作为输出。
-
虚处理器
AbstractProcessor
-
init(ProcessingEnvironment env)
: 【核心】
每一个注解处理器类都必须有一个空的构造函数。然而,这里有一个特殊的init()方法,它会被注解处理工具调用,并输入ProcessingEnviroment
参数。ProcessingEnviroment
提供很多有用的工具类Elements
,Types
和Filer
process(Set< ? extends TypeElement> annotations, RoundEnvironment env)
:【核心】
这相当于每个处理器的主函数main()。你在这里写你的扫描、评估和处理注解的代码,以及生成Java文件
getSupportedAnnotationTypes()
这里你必须指定,这个注解处理器是注册给哪个注解的
getSupportedSourceVersion()
用来指定你使用的Java版本。通常这里返回SourceVersion.latestSupported()
-
APT 所用的代码生成器:JavaPoet is a Java API for generating
.java
source files.(JavaPoet 是一个java api ,为了生成 .java源文件的) -
官方helloworld
MethodSpec main = MethodSpec.methodBuilder(“main”)
.addModifiers(Modifier.PUBLIC, Modifier.STATIC)
.returns(void.class)
.addParameter(String[].class, “args”)
.addStatement(“ T . o u t . p r i n t l n ( T.out.println( T.out.println(S)”, System.class, “Hello, JavaPoet!”)
.build();
TypeSpec helloWorld = TypeSpec.classBuilder(“HelloWorld”)
.addModifiers(Modifier.PUBLIC, Modifier.FINAL)
.addMethod(main)
.build();
JavaFile javaFile = JavaFile.builder(“com.example.helloworld”, helloWorld)
.build();
javaFile.writeTo(System.out);
- 通过以上可生成以下java 文件
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数Android工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!
由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新
如果你觉得这些内容对你有帮助,可以添加V获取:vip204888 (备注Android)
最后
其实Android开发的知识点就那么多,面试问来问去还是那么点东西。所以面试没有其他的诀窍,只看你对这些知识点准备的充分程度。so,出去面试时先看看自己复习到了哪个阶段就好。
下面分享的腾讯、头条、阿里、美团、字节跳动等公司2019-2021年的高频面试题全套解析,博主还把这些技术点整理成了视频和PDF(实际上比预期多花了不少精力),包含知识脉络 + 诸多细节,由于篇幅有限,下面只是以图片的形式给大家展示一部分。
知识不体系?这里还有整理出来的Android进阶学习的思维脑图,给大家参考一个方向。
一个人可以走的很快,但一群人才能走的更远。不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎扫码加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
n/13f2cb2e05a14868a3f0fd6ac81d625c.png)
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!
由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新
如果你觉得这些内容对你有帮助,可以添加V获取:vip204888 (备注Android)
[外链图片转存中…(img-u9qyU937-1712626717304)]
最后
其实Android开发的知识点就那么多,面试问来问去还是那么点东西。所以面试没有其他的诀窍,只看你对这些知识点准备的充分程度。so,出去面试时先看看自己复习到了哪个阶段就好。
下面分享的腾讯、头条、阿里、美团、字节跳动等公司2019-2021年的高频面试题全套解析,博主还把这些技术点整理成了视频和PDF(实际上比预期多花了不少精力),包含知识脉络 + 诸多细节,由于篇幅有限,下面只是以图片的形式给大家展示一部分。
[外链图片转存中…(img-UI3R2F2B-1712626717305)]
知识不体系?这里还有整理出来的Android进阶学习的思维脑图,给大家参考一个方向。
[外链图片转存中…(img-2Wd293WM-1712626717305)]
一个人可以走的很快,但一群人才能走的更远。不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎扫码加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
[外链图片转存中…(img-gHwhQcMt-1712626717306)]