Android开发面试:架构设计和网络知识答案精解

目录

架构设计

编程思想

六大设计原则

重构-Code Smell

AOP

设计模式

创建型5个

行为型11个

结构型7个

编程范式

MVC

MVP

MVVM

MVI

模块化

组件化

插件化、热修复

Jectpack

网络

网络基础

TCP/UDP协议

Http/Https协议

Socket通信


架构设计

编程思想

六大设计原则

  1. SOLID分类:单一职责原则、开闭原则、里氏替换原则、最少知道原则、接口隔离原则、依赖倒置原则
  2. Single Responsibility Principle:不能有多个导致类变更的原因。一个类中应该是一组相关性很高的函数、数据的封装。一个类只负责一个职责。这个原则不仅仅适用于类,对于接口和方法也适用,而且接口和方法的单一职责更容易实现。实际开发中,这是一个备受争议却又及其重要的原则。——单一职责原则
  3. Open Closed Principle:软件中的对象(类、模块、函数等)应该对扩展开放,对修改关闭(勃兰特·梅耶认为,类只应该因错误而被修改)。也就是应该通过扩展来实现变化,而不是通过修改已有的代码来实现改变。例如,现在业务需求有改变,所有书均打七折。有三个方法可以解决这个问题:第一种方法:修改接口。增加一个方法getOffPrice专门进行打折处理。第二种方法:修改实现类,在实现类里修改getPrice方法。第三种方法:重新扩展一个类继承NovelBook,重新复写getPrice方法。根据对扩展开放对修改关闭原则我们应该选择第三种解决方法。但实际开发中,修改原有代码、扩展代码(通过继承的方式来升级、维护原有系统)往往是同时存在的。——开闭原则
  4. Liskov Substitution Principle:就是只要父类出现的地方子类就可以出现,且替换成子类也不会出现任何错误或者异常;但是反过来,有子类出现的地方,父类不一定可以适用。也就是说,子类可以扩展父类的功能,但不能改变父类原有的功能。①子类可以实现父类的抽象方法,但不能覆盖父类的非抽象方法。②子类可以有自己的个性,所以子类出现的地方父类就不一定适用。③实现父类的方法时,形参的类型可以被放大。④实现父类的方法时,返回值的类型可以缩小。通过里氏替换来达到对扩展开放,对修改关闭的效果。——里氏替换原则
  5. Law of Demeter:也叫最少知道原则。一个对象应该对其他对象有最少的了解。低耦合、高内聚。——迪米特法则
  6. Interface Segregation Principle:客户端不应该依赖它不需要的接口。接口/抽象中的方法尽量少。单一职责原则是按照职责(业务逻辑)进行划分接口的,而接口隔离原则则是按照实现类对方法的使用来划分的。可以说,接口隔离原则更细一些。①接口尽量小。根据具体业务把一个接口按照接口隔离原则细化成更多的接口。但是在此基础之上必须不能违背单一职责原则。②接口要高内聚。就是说,在接口内部实现的方法,不管怎么改,都不会影响到接口外的其他接口或是实现类,只能影响它自己。③定制服务。定制服务就是单独为一个个体提供服务,即只提供访问者需要的方法。④接口设计是有限度的。接口设计越小越好,但是结构同时会变得复杂,维护也变得难了。因此就要把握住这个度。——接口隔离原则
  7. Dependence Inversion Principle:面向接口/抽象编程。①模块间的依赖关系通过接口和抽象类产生,实体类之间不直接发生依赖关系。②接口和抽象类不依赖于实现类。③实现类依赖接口或者抽象类。模块间的依赖通过抽象发生,实现类之间不发生直接的依赖关系,其依赖关系是通过接口或抽象类产生的。——依赖倒置原则

重构-Code Smell

  1. 《重构:改善既有代码的设计》在该书的第3章“代码的坏味道”中,收录了Kent Beck关于重构时机的理解——Code Smell,如果尿布臭了,就换掉它。 Code Smell的22种代码坏味道如下
  2. Duplicated Code。a、同一个class内的两个函数含有相同的表达式。——需要Extract Method,提炼出重复代码,然后让两个地点都调用被提炼出来的那一段代码。b、两个互为兄弟的subclass内含相同的表达式,要避免这种情况——需要两个class都使用Extract Method,把Extract的Method推入superclass内。c、两个毫不相干的classes内出现Duplicate Code,你应该考虑对其中一个使用Extract Class,将重复代码提炼到一个独立class中,然后在另一个class内使用这个新class。——重复代码
  3. Long Method。应该积极地分解函数。a、每当感觉需要注释来说明点什么的时候,就把需要说明的东西封装成一个函数,并以用途(而非实现手法)命名。b、条件表达式和循环常常也是提炼的信号。——过长函数
  4. Large Class。应该重新抽象。大类就是你把太多的责任交给了一个类。——过大的类
  5. Long Parameter List。使用已有对象封装参数,或者制造一个参数对象。——过长参数列
  6. Divergent Change。一个类受到多种变化的影响。将对象拆分成多个对象,这么一来每个对象就可以只因一种变化而需要修改。——发散式变化
  7. Shotgun Surgery。这正好和上面相反。一种变化引发多个类相应修改。把需要修改的代码放进同一个类。——霰弹式修改
  8. Feature Envy。如果一个类的方法频繁用get 方法存取其他类的状态进行计算,那么你要考虑把行为移到涉及状态数目最多的那个类。有时候方法中只有一部分受这种依恋之苦,那就封装那部分把它带去梦中家园。有时候一个函数往往会用到几个类的功能,那就把这个函数放在拥有最多被此函数使用的数据的类中去。——依恋情节
  9. Data Clumps。将几个数据封装成对象。某些数据通常像孩子一样成群玩耍,一起出现在很多类的成员变量中,一起出现在许多方法的参数中,这些数据或许应该自己独立形成对象。一旦拥有新对象,就可以着手寻找Feature Envy。——数据泥团
  10. Primitive Obsession。将几个有关联的基本数据封装成对象。面向对象的新手通常习惯使用几个原始类型的数据来表示一个概念。譬如对于范围,他们会使用两个数字。对于Money,他们会用一个浮点数来表示。因为你没有使用对象来表达问题中存在的概念,这使得代码变的难以理解,解决问题的难度大大增加。好的习惯是扩充语言所能提供原始类型,用小对象来表示范围、金额、 转化率、邮政编码等等。——基本类型偏执
  11. Switch Statement。使用多态替换。少用switch语句,从本质上说,switch语句的问题在于重复。——switch惊悚现身
  12. Parallel Inheritance Hierarchies。可以让一个继承体系的实例引用另一个继承体系的实例。并行的继承层次是shotgun surgery 的特殊情况。每当你为某个类增加一个子类,必须也为另一个类相应增加一个子类。——平行继承体系
  13. Lazy Class。删除。某个类没有做足够的工作,请让这个类庄严赴义吧。——冗赘类
  14. Speculative Generality。删除。一个类实现了从未用到的功能和通用性。通常这样的类或方法唯一的用户是test case。不要犹豫,删除它。但如果它们的用途是帮助测试用例检测正当功能,当然必须刀下留人。——夸夸其谈未来性
  15. Temporary Field。抽象成类。一个对象的属性可能只在某些情况下才有意义。这样的代码将难以理解。专门建立一个对象来持有这样的孤儿属性,把只和他相关的行为移到该类。最常见的是一个特定的算法需要某些只有该算法才有用的变量。——令人迷惑的暂时字段
  16. Message Chain。提炼函数、隐藏分派。消息链发生于当一个客户向一个对象要求另一个对象,然后客户又向这另一对象要求另一个对象,再向这另一个对象要求另一个对象,如此如此。先观察消息链最终得到的对象是用来干什么的,看看能否以Extract Method把使用该对象的代码提炼到一个独立函数中,再运用Move Method把这个函数推入消息链。如果这条链上的某个对象有多位客户打算航行此航线的剩余部分,就加一个函数来做这件事。——过度耦合的消息链
  17. Middle Man。删除。对象的基本特性之一就是封装,而你经常会通过分派去实现封装。但是这一步不能走得太远,如果你发现一个类接口的一大半方法都在做分派,你可能需要移去这个中间人。——中间人
  18. Inappropriate Intimacy。划清界限,拆散,合并,单向联系。某些类相互之间太亲密,它们花费了太多的时间去专研别人的私有部分。对人类而言,我们也许不应该太假正经,但我们应当让自己的类严格遵守禁欲主义。——狎昵关系
  19. Alternative Classes with Different Interfaces。重命名,合并。做相同事情的方法有不同的函数签名,一致把它们往类层次上移,直至协议一致。——异曲同工的类
  20. Incomplete Library Class。使用装饰模式来包装类。要建立一个好的类库非常困难。我们大量的程序工作都基于类库实现。然而,如此广泛而又相异的目标对库构建者提出了苛刻的要求。库构建者也不是万能的。有时候我们会发现库类无法实现我们需要的功能。而直接对库类的修改有非常困难。这时候就需要用各种手段进行重构。——不完美的库类
  21. Data Class。将相关操作封装进去,减少public成员变量。对象包括状态和行为。如果一个类只有状态没有行为,那么肯定有什么地方出问题了。——纯稚的数据类
  22. Refused Bequest。用代理替代继承。超类传下来很多行为和状态,而子类只是用了其中的很小一部分。这通常意味着你的类层次有问题。——被拒绝的遗赠
  23. Comments。人们常把注释当做除臭剂来使用,经常觉得要写很多注释表示你的代码难以理解。当你感觉需要撰写注释时,请先尝试重构。——过多的注释
  24. 设计模式是你希望到达的目标,重构则是到达之路

AOP

  1. OOP与AOP:OOP(面向对象编程,是一种典型的纵向编程方式,更多关注的是对象Object本身的功能,对象之间的功能联系往往不会考虑那么详细)、AOP(面向切面编程,切面,也叫横向,和OOP一样,是一种程序设计思想,通过预编译方式和运行期动态代理,实现程序功能的统一维护,横切关注点是一个抽象的概念,它是指那些在项目中贯穿多个模块的业务,AOP在将横切关注点与业务主体进行分类,从而提高程序代码模块化程度,将涉及到众多模块的某一类功能进行统一管理)
  2. AOP好处:就拿添加调用日志举例,AOP的好处在于:a、类更专注于它的职责(核心代码中不用包含日志调用代码);b、修改工作量更小(只需要修改相应的配置文件和日志的实现);c、解耦(App不依赖于具体日志框架,在处理Log标签的地方统一Log框架即可;实现AOP的同时需要依赖注入,这又会减少模块间依赖)
  3. AOP实现:运行时切入(epic框架、Dexposed)、编译时切入(APT——Java编译之前处理注解生成代码、ApsectJ——Java编译阶段修改Java代码、Javassist/ASM——Java编译之后对class字节码进行修改)
  4. APT:Annotation Processing Tool,注解处理器,是一种处理注解的工具,在编译时扫描、解析、处理注解,生成.java文件(它会对源代码文件进行检测,找出用户自定义的注解,根据注解、注解处理器和相应的APT工具自动生成代码——这段代码是根据用户编写的注解处理逻辑去生成的,最终将生成的新的源文件与原来的源文件共同编译(注:APT并不能对源文件进行修改操作,只能生成新的文件))
  5. 注解实现AOP:DataBinding、Dagger2、ButterKnife、EventBus3、DBFlow、AndroidAnnotation,为什么这些框架注解实现AOP要使用APT?(Android注解解析框架主要两种实现方法:a、一种是运行期通过反射去解析当前类,注入相应要运行的方法;b、另一种就是APT,在编译期生成类的代理类,在运行期直接调用代理类的代理方法)如果不使用APT基于注解动态生成java代码,那么就需要在运行时使用反射或者动态代理,导致App性能下降
  6. ASM与epic:ASM(是一个Java字节码层面的代码分析及修改工具,利用class被打包为dex前的间隙,插入ASM相关逻辑对class文件进行操纵行操纵,可以实现动态生成类,或者基于现有的类进行功能扩展)、epic(ART中函数的调用约定,去修改函数的内容,将函数前两条指令修改为跳转到自定义逻辑,从而实现对任意方法的Hook)
  7. hook:反射/动态代理(作用于Java层,虚拟机提供的标准编程接口,可靠性较高。如:用动态代理构造出一个代理对象,然后用反射API去替换进程中对象,从而达到hook目的,对Java Framework API修改常用这种方法,修改ActivityThread、当前进程的系统调用)、JNI Hook(Java层与Native之间的函数)、ClassLoader修改(通过修改ClassLoader加载Java class的Path路径达到目的,常见应用场景:一些热修复技术,稳定性高,不过需要提前编译好修改后的class去替换,灵活性低)、Xposed(这类hook技术原理都是去修改ART/Dalvik虚拟机,大量的一些自动化测试、动态调试都采用这个方法)

设计模式

创建型5个

  1. 分类:单例模式、工厂方法模式、抽象工厂模式、原型模式、建造者模式
  2. 单例模式:定义(确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例。即:让整个生命周期内只有一个实例)、使用场景(a、一个类专门提供一些公共功能供别人调用,而本身并不会处理业务逻辑,那么创建多个实例,会消耗内存,造成不必要的开销,此时需要单例;b、如果创建一个对象需要消耗的资源过多,如要访问IO和数据库等资源,这时就要考虑使用单例模式)、实现方式(a、懒汉式-非线程安全,双重校验锁-线程安全,静态内部类-线程安全,饿汉式-线程安全,枚举-线程安全,容器实现-非线程安全;b、不管以哪种形式实现单例模式,它们的核心原理都是将构造函数私有化,并且通过静态方法获取一个唯一实例,在这个获取过程中必须保证线程安全、防止反序列化导致重新生成实例对象的问题)、优点(a、减少内存开销;b、减少系统性能开销;c、避免对资源的重复占用;d、优化和共享资源访问)、缺点(a、不容易扩展,基本只能通过修改代码去扩展;b、如果持有了context就容易引发内存泄漏,建议使用ApplicationContext)
  3. 工厂方法模式:定义(定义一个用于创建对象的接口,让子类决定实例化哪个类)、使用场景(复杂对象创建可以使用工厂模式,用new就可以完成对象创建就无需使用工厂模式)、小结(a、降低对象之间耦合性;b、其依赖于抽象架构,将实例化任务交给子类去完成,有非常好扩展)
  4. 抽象工厂模式:定义(为创建一组相关或是相互依赖的对象提供一个接口,而不需要指定它们具体类,是围绕一个超级工厂创建其他工厂)、使用场景(一个对象族有相同约束时可以使用抽象工厂模式,能解决接口选择问题(比如Android和iOS是不同系统但有相同的电话、短信等软件;比如Android中的主题修改,多套主题,不同按钮弹窗样式))、小结(很好做到了接口与实现分离,客户端面向接口接口编程;但类比较多,每增加一个工厂会对应增加具体多种产品类;而且扩展性不好,每当增加一个产品类就需要修改抽象工厂,所有具体工厂也要修改)
  5. 原型模式:定义(用原型模式指定创建对象的种类,并通过复制这些原型创建新的对象,简单来说就是对象的克隆,我们称将要被克隆的对象为原型)、使用场景(a、类初始化或new一个新对象,需要消耗非常多资源时,可以考虑使用原型设计模式提升对象创建的效率——因为通过原型复制的方式不会执行构造方法,避免了初始化占有的时间和空间;b、一个对象需要提供给其他对象访问,并且该对象希望对外是只读的情况时,可以考虑使用原型模式通过返回一个对象拷贝的形式实现只读限制——保护性拷贝)、实现方式(new或clone)、深浅拷贝问题(注意对于非基本数据类型的引用类型的浅拷贝问题,由于指向的同一堆对象内存地址,修改一处后多处引用会存在联动问题;一般建议原型模式尽量使用深拷贝,避免对原型对象造成副作用)、小结(原型设计模式是在内存中二进制流的拷贝,要比直接new一个对象性能好很多;不过这既是它的优点亦是它的缺点,因为直接在内存中拷贝,构造函数不会执行,这是个需要注意的问题)
  6. 建造者模式:定义(将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示)、使用场景(a、初始化一个对象特别复杂时(如:参数较多,且很多参数都具有默认值);b、相同的方法,不同的执行顺序,产生不同的事件结果时;c、产品类非常复杂,或者产品类中的调用顺序不同产生了不同的作用,这个时候使用建造者模式非常合适)、小结(Builder模式在Android开发中也较为常用,通常作为配置类的构建器将配置的构建和表示分离开来,同时也是将配置从目标类中隔离出来,避免过多的setter方法;Builder模式比较常见的实现形式是通过调用链实现,这样使得代码更简洁、易懂)、优点(良好的封装性,使用建造者模式可以使客户端不必知道产品内部组成的细节;建造者独立,容易扩展)、 缺点(会产生多余的Builder对象以及Director对象,消耗内存 )

行为型11个

  1. 分类:观察者模式、策略模式、模板方法模式、命令模式、迭代器模式、中介者模式、备忘录模式、解释器模式、状态模式、责任链模式、访问者模式
  2. 策略模式:定义(策略模式定义了一系列的算法,并将每一个算法封装起来,而且使他们可以互相替换,让算法独立于使用它的客户而独立变化)、使用场景(a、飞机、火车、汽车等每一种出行方式都是一个策略;b、商场打折,买2送1、买1件打88折等促销方式;c、总的来说,使用继承违背常理(狗继承动物,让它飞就太天真了)时,使用实现繁琐(猴鸡狗猪都会叫,他们都各自实现叫的方法太累了)时,此时可以考虑组合(也就是策略模式的表现形式))、设计原则(a、找出应用中可能需要变化之处,把它们独立出来,不要和那些不需要变化的代码混在一起;b、针对接口编程,而不是针对实现编程;c、开闭原则:对扩展开放、对修改关闭)、优点(a、结构清晰明了、使用简单直接;b、耦合度相对较低,扩展性好;c、操作封装也更为彻底,数据更为安全)、缺点(策略类会增多,并且所有策略类都需要对外暴露)
  3. 状态模式:定义(当一个对象的内在状态改变时允许改变其行为,这个对象看起来好像修改了它的类)、使用场景(a、一个对象的行为取决于它的状态,并且它必须在运行时根据状态改变它的行为;b、代码中包含大量与对象状态有关的条件语句,如:一个操作中含有庞大的多分支语句(ifelse或switchcase),且这些分支依赖于该对象的状态)、小结(状态模式和策略模式结构几乎完全一样,但它们目的和本质却完全不一样)、优点(将繁琐的状态判断转换成结构清晰的状态族,在避免代码膨胀的同时也保证了可扩展性与可维护性)、缺点(增加系统类和对象的个数)

结构型7个

  1. 分类:适配器模式、装饰模式、代理模式、组合模式、桥接模式、外观模式、享元模式

编程范式

  1. 分类:命令式编程(面向过程、面向对象)、声明式编程(函数式编程、逻辑式)、响应式编程
  2. 理解:a、命令式编程(Imperative):详细的命令机器怎么(How)去处理一件事情以达到你想要的结果(What),如C、C++、Java等;b、声明式编程(Declarative):只告诉你想要的结果(What),机器自己摸索过程(How),是在命令式编程之上的抽象,如SQL、HTML、正则表达式等,Kotlin支持函数式编程;c、响应式编程(Reactive):是一种通过异步和数据流来构建事务关系的编程模型,基于观察者模型并提供了非阻塞、异步的特性,RxJava使得Java平台也有了能够实现响应式编程的框架

MVC

  1. 缺点:a、XML做为View层,控制能力太差;b、View与Model存在耦和;c、Activity既作为Control也作为View,违背单一职责原则、最少知道原则,当业务逻辑复杂时导致Activity臃肿、代码量庞大
  2. 小结:MVC是MVP、MVVM、MVI的爹

MVP

  1. 优点:a、解耦View与Model,分离View和业务逻辑;b、Activity只负责显示,代码变得更加简洁,提高代码阅读性;c、方便对业务做单测,直接对presenter
  2. 缺点:a、presenter复用性不强;b、持有View引用导致内存泄漏;c、随着业务逻辑的增加,导致View的接口变得庞大
  3. 如何避免内存泄漏:在Activity销毁时释放presenter,presenter把View置为null,取消网络请求等;使用Lifecycle
  4. 接口比较多怎么处理:将通用接口抽象出来放在基类,非通用接口采用继承方式

MVVM

  1. 理解:在MVC思想上实现了数据驱动UI。View产生事件,使用ViewModel进行逻辑处理后,通知Model更新数据,Model把更新的数据给ViewModel, ViewModel通过LiveData自动通知View更新界面,实现数据驱动UI,只要LiveData的数据修改UI能自动响应更新
  2. 优点:a、解耦更彻底,viewmodel不持有view;b、viewmodel复用性更强;c、没有内存泄漏;d、数据驱动解决MVP接口庞大问题
  3. 缺点:a、ViewModel和View通信更困难,可能通过LiveEventBus实现;b、为保证对外暴露的LiveData是不可变的,需要添加不少模板代码并且容易遗忘;c、View层与ViewModel层的交互比较分散零乱,不成体系

MVI

  1. 理解:在MVC基础上实现了响应式编程(Reactive)范式。安卓官方的compose框架、微信小程序、Flutter、React、鸿蒙UI的开发框架,都是使用响应式开发框架。Model:与MVVM中的Model不同的是,MVI的Model主要指UI状态(State),例如页面加载状态、控件位置等都是一种UI状态;View:与其他MVX中的View一致,可能是一个Activity或者任意UI承载单元,MVI中的View通过订阅Intent的变化实现界面刷新;Intent:此Intent不是Activity的Intent,用户的任何操作都被包装成Intent后发送给Model层进行数据请求
  2. 优点:a、强调数据单向流动,很容易对状态变化进行跟踪和回溯;b、使用ViewState对State集中管理,只需要订阅一个ViewState便可获取页面的所有状态,相对MVVM减少了不少模板代码;c、ViewModel通过ViewState与Action通信,通过浏览ViewState和Aciton定义就可以理清ViewModel的职责,可以直接拿来作为接口文档使用
  3. 缺点:a、所有的操作最终都会转换成State,所以当复杂页面的State容易膨胀;b、state是不变的,因此每当state需要更新时都要创建新对象替代老对象,这会带来一定内存开销

模块化

  1. 原本一个App模块承载所有功能,而模块化就是拆分成多个模块放在不同Module,每个功能的代码都在自己所属module中添加
  2. 通常还会有一个通用基础模块module_common,提供BaseActivity/BaseFragment、图片加载、网络请求等基础能力,然后每个业务模块都会依赖这个基础模块
  3. 多个模块中肯定会有页面跳转、数据传递、方法调用等情况,所以必然存业务模块间的依赖关系,这样模块间高耦合度加上代码量变大,就会严重影响团队开发效率及质量

组件化

  1. 什么是组件化:去除模块间耦合,使每个业务模块可以独立当做App存在,对于其他模块没有直接依赖关系,此时业务模块就成为了业务组件,除了业务组件还有包括功能组件,模块化到组件化的过程可以看作从业务导向到功能导向的过程
  2. 组件化优点:a、加快编译速度(每个业务功能都是一个单独工程,可独立编译运行,拆分后代码量较少,编译速度变快);b、 提高协作效率(解耦使得组件之间彼此互不打扰,组件内部代码相关性极高;团队中每个人有自己的责任组件,不会影响其他组件;降低团队成员熟悉项目的成本,只需熟悉责任组件即可;对测试来说,只需重点测试改动的组件,而不是全盘回归测试)
  3. 组件化方案:基础组件层(包含一些基础库以及对基础库的封装,如图片加载、网络请求、日志框架、数据存储等)、功能组件层(包含一些简单的功能组件,如视频组件、支付组件等)、MiddleWare中间件层、业务组件层、App壳工程

插件化、热修复

  1. 什么是插件化:所谓插件化,就是让应用不必再像原来一样把所有内容都放在一个Apk中,可以把一些功能和逻辑单独抽出来放在插件Apk中,然后主Apk做到按需调用,主要是一种动态加载四大组件的技术
  2. 插件化优点:a、减少主Apk体积、65535问题(在Dalvik字节码规范里方法个数超过了65535,但在art虚拟机上已不存在此问题),让应用更轻便;b、让用户不用重新安装Apk就能升级应用功能,减少发版本频率,增加用户体验
  3. 插件化框架:a、最早的插件化框架(2012年大众点评的屠毅敏就推出了AndroidDynamicLoader框架);b、主流的插件化方案(滴滴任玉刚的VirtualApk、 腾讯的Shadow、Small框架、爱奇艺的Qigsaw、Google AAB)
  4. 插件化流程:插件化技术为了解决类加载和资源加载的问题,主要是动态加载的过程,包括以下几步:a、把可执行文件(.so/dex/jar/apk等)拷贝到应用App内部;b、加载可执行文件,更换静态资源;c、调用具体方法执行业务逻辑
  5. 插件化原理:主要方案就是先在AndroidManifest.xml中注册一个Activity来进行占坑,用来通过AMS校验,接着在合适的时机用插件Activity替换占坑Activity。类加载原理、资源加载原理(反射调用AssetManager的addAssetPath)、Activity加载原理(代理:dynamic-load-apk采用(通过代理的Activity去执行插件中的Activity,加载对应生命周期);Hook:主流(Hook IActivityManager或Hook Instrumentation))

Jectpack

  1. DataBinding之ViewBinding和DataBinding区别:a、目的不同(ViewBinding的出现仅仅是为了帮开发人员省去写findViewById的步骤;而DataBinding是用于绑定数据的,能够把视图的数据和代码变量绑定起来,并且实现自动更新。这个特性使得DataBinding能和MVVM框架进行很好的配合);b、 初始化方式不同(ViewBinding通过生成的Binding类的inflate方法来加载布局,然后还需要用Activity的setContentView()方法来绑定;而Databinding则是通过DataBindingUtil.setContentView()来绑定的);c、包含关系(DataBinding也有ViewBinding的功能,也可以省去findViewById()方法)
  2. ViewModel:ViewModel旨在以生命周期方式存储和管理用户界面相关数据,可以用来管理Activity和Fragment中的数据,还可以拿来处理Fragment与Fragment之间通信等
  3. LiveData
  4. Lifecycle

网络

网络基础

  1. 计算机网络体系结构是什么:计算机网络体系结构分为3种,OSI体系结构7层(物理层、链路层、网络层、传输层、会话层、表示层、应用层)——概念清楚理念完整但复杂不实用、TCP/IP体系结构4层(网络接口层、网际层IP、运输层TCP/UDP、应用层HTTP)——是Internet核心协议并被广泛应用于局域网和广域网、五层体系结构(物理层、链路层、网络层、运输层、应用层)——目的是为了学习和讲解计算机原理
  2. 在浏览器中输入url地址到显示主页过程(一个网页请求过程):a、浏览器DNS获取域名对应IP(DNS查找过程包括浏览器缓存、路由器缓存和DNS缓存),并向Web服务器发送Http请求(请求会带上cookie);b、服务器处理请求,发回一个HTML响应;c、浏览器开始显示HTML
  3. 一次网络请求中的协议:DNS(获取域名对应IP地址)、TCP(与服务器建立TCP连接)、IP(建立TCP连接时,需要发送数据,发送数据在网络层使用IP协议)、OPSF(IP数据包在路由器之间,路由选择使用OPSF协议)、ARP(路由器在与服务器通信时,需要将IP地址转换为MAC地址,需要使用ARP协议)、HTTP(在TCP建立完成后,使用HTTP协议访问网页)
  4. IP地址分类:A类1-126(0+7位网络号+24位主机号)、B类128-191(10+14位网络号+16位主机号)、C类192-223(110+21位网络号+8位主机号)、D类224-239(1110+多播地址)、E类240-255(1111+保留为今后使用),区别在于网络号 & 主机号占的字节数不同
  5. 特殊IP地址:0.0.0.0(表示网络上本机地址)、255.255.255.255(为广播地址)、127.0.0.0(不会出现在网络上的环路自检地址,表示任意主机本身)、主机号全为0(本网络本身)、主机号全为1(本网络广播地址)
  6. ICMP报文:定义(Internet Control Message Protocol,网际控制报文协议,属于IP层协议)、作用(更有效地转发IP数据包,提高交付成功的机会)、分类(ICMP差错报告报文和ICMP询问报文)、主要应用(PING分组网间探测;Traceroute跟踪1个分组从源点到终点的路径,拿到所有路由器IP)
  7. PING原理:应用层利用IP层的ICMP协议包来侦测另一个主机是否可达,不经过传输层,具体过程是:a、用类型码为0的ICMP发请求;b、受到请求的主机则用类型码为8的ICMP回应;c、ping程序来计算间隔时间,并计算有多少个包被送达,用户就可以判断网络大致的情况
  8. 路由器与交换机区别:路由器(属于网络层,识别IP地址以及根据IP地址转发数据包,维护着路由表并基于路由表进行最佳路径选择)、交换机(属于数据链路层,识别MAC地址以及根据MAC地址转发数据帧,维护着桥表并根据桥表上MAC地址和端口的对应关系进行数据帧转发)
  9. Cookie与Session区别:Cookie(是客户端机制,存储量少(一个站点最多20个Cookie,单个Cookie数据不超过4K),不安全(可分析存放在本地的Cookie和进行Cookie欺骗),损耗低,主要存放设备配置信息)、Session(是服务器机制,存储量多,安全,损耗高(当访问增多时比较占用服务器性能),主要存放重要信息)

TCP/UDP协议

  1. 三次握手过程:a、客户端发送连接请求报文段;b、服务端发送连接确认报文段;c、客户端发送连接确认报文段
  2. 四次挥手过程:a、客户端发送连接释放报文段;b、服务端发送连接释放确认报文段;c、服务端发送释放连接的报文段;d、客户端发送释放连接确认报文段
  3. 全双工通信:TCP是全双工通信(通信双方的应用进程在任何时候都能发送数据)
  4. 为什么TCP建立连接需三次握手:防止服务器端因接收了早已失效的连接请求报文,从而一直等待客户端请求,最终导致形成死锁、浪费资源
  5. 为什么TCP释放连接需四次挥手:为了保证通信双方都能通知对方去释放、断开连接
  6. 为什么客户端关闭连接前要等待2MSL时间:MSL(Maximum Segment Lifetime,报文段最大生存时间,它是任何报文段被丢弃前在网络内最长时间),a、保证TCP协议的全双工连接能够可靠关闭;b、保证这次连接的重复数据段从网络中消失(客户端发送了最后1个连接释放请求确认报文后,再经过2MSL时间,则可使本连接持续时间内所产生的所有报文段都从网络中消失)
  7. TCP无差错传输:a、采用一些可靠传输协议,使得出现差错时,让发送方重传差错数据,即出错重传(自动重传协议);b、当接收方来不及接收收到的数据时,可通知发送方降低发送数据的效率,即速度匹配(流量控制和拥塞控制协议)
  8. TCP/IP协议通信过程:对应着数据入栈过程(HTTP-TCP-IP-以太网,数据发送方每层不断地封装首部与尾部,添加一些传输信息,确保能传输到目的地)与数据出栈过程(数据接收方每层不断地拆除首部与尾部,得到最终传输数据)
  9. TCP与UDP区别:TCP(是面向连接的可靠性字节流传输,传输效率慢所需资源多,应用于要求通信数据可靠的场景,如:Http、FTP、SMTP/POP邮件协议、Telnet远程终端接入协议等)、UDP(是面向无连接的不可靠数据报文段传输,传输效率快所需资源少,应用于要求通信速度快的场景,无拥塞控制,如:DNS、SNMP网络管理协议、NFS远程文件服务器协议、TFTP文件传输协议等)

Http/Https协议

  1. 工作方式:a、服务器不断监听TCP 80端口;b、客户端发起连接请求;c、双方建立TCP连接;d、客户端发送页面请求(Http请求报文);e、服务端返回页面请求的响应;f、关闭TCP连接
  2. Http1.1与Http1.0区别:a、引入持久连接,在同一个TCP连接中可传送多个HTTP请求和响应;b、多个请求和响应可同时进行、可重叠;c、引入更加多请求头和响应头
  3. Http与Https区别:Http在应用层,数据不加密明文传输,不安全,80端口,不需要CA申请证书;Https在传输层,对数据SSL加密、身份认证,安全,443端口,需要CA申请证书
  4. URL简介:统一资源定位符,<协议>://<主机>:<端口>/<路径>,如:https://blog.csdn.net/Agg_bin
  5. 请求报文:请求行(请求方法(定义对请求对象的操作)+资源路径(URL中请求地址部分)+协议版本(定义Http版本号),如:GET /Agg_bin HTTPS)、请求头(声明报文部分信息)、请求体(存放需发送给服务器的信息,GET请求无请求体)
  6. 响应报文:状态行(协议版本(服务器Http版本号)+状态码(200/404/500)+状态信息(请求成功/Not Found/服务器内部错误),如:HTTP/1.1 202 Accepted)、响应头(最后发送一个空白行表示头信息发送结束)、响应体(Content-Type请求头定义的格式数据)
  7. 请求方法GET与POST:GET(传输参数直接加在URL后,URL长度受限最长2048字符;浏览器中可见,安全性差;应用于数据小量或不敏感,请求数据)、POST(传输参数不受限;请求参数封装在Http请求数据中,且浏览器中无缓存,安全性好;应用于大量或数据敏感,提交数据)
  8. 常用请求/响应头:Content-Type(请求/响应体类型,如application/json)、Content-Length(请求/响应体长度,单位字节)、Cache-Control(资源缓存有效期,如no-cache或max-age=XX)、User-Agent(请求头用户标识,如OS和浏览器的类型和版本)、Host(请求的主机和端口号)、Cookie(请求头已有的Cookie)、Date(响应头服务器日期)、Last-Modified(响应头该资源最后被修改时间)、Set-Cookie(响应头设置Cookie)
  9. Http处理长连接方式:Http1.1默认保持长连接,数据传输完成后TCP连接不断开,继续使用该通道传输数据;如果不是长连接方式,那么服务端向客户端发送完请求数据后就要关闭TCP连接。Http头部字段Connection(a、Connection:close表示不使用长连接;b、Connection:Keep-Alive Keep-Alive:max=20表示连接失败次数超过20则断开;c、Connection:Keep-Alive Keep-Alive:time=20表示连接失败超时时间超过20则断开)、Keep-Alive机制(Keep-Alive开启后,TCP层将定时发送相应KeepAlive探针检测连接可用性)、结束长连接(使用长连接后,客户端和服务端可通过如下2种方式知道本次传输结束,a、判断传输数据是否达到Content-Length指示大小;b、若chunked编码数据在最后有一个空chunked块,则表明本次传输数据结束)

Socket通信

  1. Socket是什么:Socket不是一种协议,是应用层与TCP/IP 协议族通信的中间软件抽象层,表现为一个封装了 TCP/IP协议族的编程接口,属于传输层(主要解决数据如何在网络中传输),Socket能让我们在Andorid平台上通过TCP/IP协议进行开发
  2. Socket实现原理: 流套接字(streamsocket,基于TCP协议,采用流的方式提供可靠字节流服务)、数据报套接字(datagramsocket,基于UDP协议,采用数据报文提供数据打包发送服务)
  3. Socket基于TCP协议使用步骤:a、创建客户端和服务端连接(Socket socket = new Socket("192.168.1.08", 1080); socket.isConnected()));b、接受服务端数据(BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream())); br.readLine());c、发送数据到服务端(OutputStream os = socket.getOutputStream(); os.write(("Agg"+"\n").getBytes("utf-8")); os.flush())数据结尾加上换行符才可让服务器端的readline()停止阻塞;d、断开客户端和服务端连接(os.close(); br.close(); socket.close())
  4. Socket与Http协议对比:Socket(属于传输层,因为TCP/IP协议属于传输层,主要解决数据如何在网络中传输;采用服务器主动通信,有需要就发送数据)、Http协议(属于应用层,解决的是如何包装数据;采用客户端主动通信,请求-响应方式)

 架构设计

编程思想

六大设计原则

重构-Code Smell

AOP

设计模式

创建型5个

行为型11个

结构型7个

编程范式

MVC

MVP

MVVM

MVI

模块化

组件化

插件化、热修复

Jectpack

网络

网络基础

TCP/UDP协议

Http/Https协议

Socket通信


Android开发面试系列文章:


猜你喜欢

转载自blog.csdn.net/Agg_bin/article/details/129432725
今日推荐