先自我介绍一下,小编浙江大学毕业,去过华为、字节跳动等大厂,目前阿里P7
深知大多数程序员,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年最新Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上Android开发知识点,真正体系化!
由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新
如果你需要这些资料,可以添加V获取:vip204888 (备注Android)
正文
1.我们是否可以把每件要做的事情抽象成一个节点,每个节点只关心自己的任务是否完成,它并不知道它是第几个,也不知道它前面或者后面的是谁.
2.每个节点统一由一个流来管理,它作为全局统筹者,可以控制从任意节点开始、控制整个流的开启与结束等,每个节点的顺序由流来管理.
实现:
带着以上设计思路,我对代码做了一下重构,代码变成了这样:
public class AfterActivity extends AppCompatActivity {
private static final int REQUEST_CODE_H5 = 1;
/**
- 初次广告弹框
*/
private static final int NODE_FIRST_AD = 10;
/**
- 初次进入h5页
*/
private static final int NODE_CHECK_H5 = 20;
/**
- 初次进入的注册协议
*/
private static final int NODE_REGISTER_AGREEMENT = 30;
private WorkFlow workFlow;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
startWorkFlow();
}
private void startWorkFlow() {
workFlow = new WorkFlow.Builder()
.withNode(getFirstAdNode())
.withNode(getShowRegisterAgreementNode())
.withNode(getShowH5Node())
.create();
workFlow.start();
}
private WorkNode getFirstAdNode() {
return WorkNode.build(NODE_FIRST_AD, new Worker() {
@Override
public void doWork(final Node current) {
Utils.fakeRequest(“http://www.api1.com”, new HttpCallBack() {
@Override
public void onOk() {
new AlertDialog.Builder(AfterActivity.this)
.setTitle(“这是一条有态度的广告”)
.setPositiveButton(“我看完了”, null)
.setOnDismissListener(new DialogInterface.OnDismissListener() {
@Override
public void onDismiss(DialogInterface dialogInterface) {
//仅仅只需关心自己是否完成,下一个节点会自动执行
current.onCompleted();
}
}).create().show();
}
@Override
public void onFailure() {
//仅仅只需关心自己是否完成,下一个节点会自动执行
current.onCompleted();
}
});
}
});
}
private WorkNode getShowRegisterAgreementNode() {
return WorkNode.build(NODE_REGISTER_AGREEMENT, new Worker() {
@Override
public void doWork(final Node current) {
Utils.fakeRequest(“http://www.api2.com”, new HttpCallBack() {
@Override
public void onOk() {
new AlertDialog.Builder(AfterActivity.this)
.setTitle(“这是注册协议”)
.setPositiveButton(“我看完了”, null)
.setOnDismissListener(new DialogInterface.OnDismissListener() {
@Override
public void onDismiss(DialogInterface dialogInterface) {
current.onCompleted();
}
}).create().show();
}
@Override
public void onFailure() {
current.onCompleted();
}
});
}
});
}
private WorkNode getShowH5Node() {
return (WorkNode.build(NODE_CHECK_H5, new Worker() {
@Override
public void doWork(final Node current) {
Utils.fakeRequest(“http://www.api3.com”, new HttpCallBack() {
@Override
public void onOk() {
startActivityForResult(new Intent(AfterActivity.this, TestH5Activity.class), REQUEST_CODE_H5);
}
@Override
public void onFailure() {
current.onCompleted();
}
});
}
}));
}
@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
switch (requestCode) {
case REQUEST_CODE_H5:
workFlow.continueWork();
break;
default:
break;
}
}
}
经过上述重构,现在的首页流程:
-
进入首页要做的几件事之间相互无关联,它们的位置可以任意切换,只需改变id大小便可轻松调整它们的执行顺序.
-
想要加入或者插入节点无需改动原有逻辑.
实现思路
设计每个工作节点
1.我希望每个任务间彼此独立,只关心自己的事情是否完成,我把它抽象成一个节点,每个节点只有自己的节点id 和 完成的方法:
public interface Node {
/**
- 节点id
- @return 当前节点id
/
int getId();
/* - 任务完成时触发
*/
void onCompleted();
}
至于为什么要提供id,后面会讲到.
我们再来看看它的实现类WorkNode的核心代码:
public class WorkNode implements Node {
/**
- 节点id
*/
private int nodeId;
/**
- 节点工作者
*/
private Worker worker;
private WorkCallBack callBack;
public static WorkNode build(int nodeId, Worker worker) {
return new WorkNode(nodeId, worker);
}
/**
- @param worker 调用者传入,即真正执行要做的事情
*/
public WorkNode(int nodeId, Worker worker) {
this.nodeId = nodeId;
this.worker = worker;
}
/**
- 由workFlow来决定调用
- @param callBack 当调用onCompleted 之后回调给WorkFlow
*/
void doWork(WorkCallBack callBack) {
this.callBack = callBack;
worker.doWork(this);
}
@Override
public int getId() {
return nodeId;
}
@Override
public void onCompleted() {
if (null != callBack) {
callBack.onWorkCompleted();
}
}
interface WorkCallBack {
/**
- 当前任务完成
*/
void onWorkCompleted();
}
}
构造方法中传入了节点id,和Worker, 这个Worker的doWork方法的实现就是我们这个节点真正要做的事情:
public interface Worker {
/**
- 执行任务
- @param current 当前节点
*/
void doWork(Node current);
}
至此我们回看下demo中对WorkNode的构建:
private WorkNode getFirstAdNode() {
return WorkNode.build(NODE_FIRST_AD, new Worker() {
@Override
public void doWork(final Node current) {
Utils.fakeRequest(“http://www.api1.com”, new HttpCallBack() {
@Override
public void onOk() {
new AlertDialog.Builder(AfterActivity.this)
.setTitle(“这是一条有态度的广告”)
.setPositiveButton(“我看完了”, null)
.setOnDismissListener(new DialogInterface.OnDismissListener() {
@Override
public void onDismiss(DialogInterface dialogInterface) {
//仅仅只需关心自己是否完成,下一个节点会自动执行
current.onCompleted();
}
}).create().show();
}
@Override
public void onFailure() {
//仅仅只需关心自己是否完成,下一个节点会自动执行
current.onCompleted();
}
});
}
});
}
是不是很清晰?
节点只需要关心自己是否做完了,调用完onCompleted之后,一切与我无关了,后续做什么就交给WorkFlow去处理了.
那节点的doWork方法是什么时候被调用的呢? 它内部是怎么安排工作的呢?,我们来设计WorkFlow.
设计工作流:
首先作为所有节点的管理者,当然要把它们存下来,用什么数据结构来存呢?回顾一下我的需求: 可以灵活控制节点的执行顺序, so…经过反复筛选,我最终选择了SparseArray来存放我们所有的节点,因为我们为每个节点提供id作为key:
一来可以提高代码可读性。
二来,SparseArray内部是数组实现的,而且是按照key的大小升序排列的,基于这个特性,我们只需要改变定义Key值的大小关系就可以改变它们在数组中的顺序。
我们再来看看用SparseArray来实现的WorkFlow:
public class WorkFlow {
private SparseArray flowNodes;
public WorkFlow(SparseArray flowNodes) {
this.flowNodes = flowNodes;
}
/**
- 开始工作,默认从第一个节点
*/
public void start() {
startWithNode(flowNodes.keyAt(0));
}
/**
- 基于某个节点Id 开始工作
- @param startNodeId 节点id
*/
public void startWithNode(int startNodeId) {
final int startIndex = flowNodes.indexOfKey(startNodeId);
WorkNode startNode = flowNodes.valueAt(startIndex);
startNode.doWork(new WorkNode.WorkCallBack() {
@Override
public void onWorkCompleted() {
findAndExecuteNextNodeIfExist(startIndex);
}
});
}
private void findAndExecuteNextNodeIfExist(int startIndex) {
final int nextIndex = startIndex + 1;
final WorkNode nextNode = flowNodes.valueAt(nextIndex);
if (null != nextNode) {
nextNode.doWork(new WorkNode.WorkCallBack() {
@Override
public void onWorkCompleted() {
findAndExecuteNextNodeIfExist(nextIndex);
}
});
}
}
}
我们在demo中调用的start()的方法,其实内部调用的是 startWithNode 方法,这个方法接收一个参数 startNodeId ,也就是我们构建节点的id,我们在 SparseArray 中找到节点,直接开始执行。
当我们在节点内部调用完 onCompleted 方法之后, 会直接回调 onWorkCompleted 方法,此时我们再看看是否有下一个节点,当有下一个节点之后,一直递归到下一个没有节点为止。
至此,我们原理基本分析完成,通过内部 SparseArray的设计,我们可以灵活从任意节点开始执行,外部的WorkFlow就是一个全局的管理者,我们可以拓展很多其他功能,比如 continueWork() :当我们在节点以外希望让流程继续执行下去的时候(参考Demo的 onActivityResult), revert():回退到上一节点 等等。
总结
- WorkFlow,很好的接耦了各个次序任务直接的相互依赖,提高了开发效率。
- 它也很好的提高了代码的可维护性和可读性,非常便于后来新次序任务的拓展。
最后对于程序员来说,要学习的知识内容、技术有太多太多,要想不被环境淘汰就只有不断提升自己,从来都是我们去适应环境,而不是环境来适应我们!
最后
总而言之,Android开发行业变化太快,作为技术人员就要保持终生学习的态度,让学习力成为核心竞争力,所谓“活到老学到老”只有不断的学习,不断的提升自己,才能跟紧行业的步伐,才能不被时代所淘汰。
在这里我分享一份自己收录整理上述技术体系图相关的几十套腾讯、头条、阿里、美团等公司20年的面试题,把技术点整理成了视频和PDF(实际上比预期多花了不少精力),包含知识脉络 + 诸多细节,由于篇幅有限,这里以图片的形式给大家展示一部分。
还有高级架构技术进阶脑图、Android开发面试专题资料,高级进阶架构资料 帮助大家学习提升进阶,也节省大家在网上搜索资料的时间来学习,也可以分享给身边好友一起学习。
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
需要这份系统化的资料的朋友,可以添加V获取:vip204888 (备注Android)
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
图片转存中…(img-bk4DdU6k-1713665902733)]
[外链图片转存中…(img-ALGnVCaD-1713665902733)]
还有高级架构技术进阶脑图、Android开发面试专题资料,高级进阶架构资料 帮助大家学习提升进阶,也节省大家在网上搜索资料的时间来学习,也可以分享给身边好友一起学习。
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
需要这份系统化的资料的朋友,可以添加V获取:vip204888 (备注Android)
[外链图片转存中…(img-2fAaY1zJ-1713665902733)]
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!