android 面试复习笔记

Android工程师面试问题记载

主要记录一些在面试中未完全回答正确的问题。

技术面试官考虑的是:1.技术是否过关,进来是否会拖后腿,2.技术是不是太强,进来会不会影响我当前的岗位,3.开的工资有没有我高,会不会导致我心里不平衡

老板面试官考虑的是:1.这个人进来之后能不能干活,2.能干活但是开的工资性价比怎么样,3.这个人有没有其他特点好不好相处、管理

重点考虑的是:1.岗位是否真是急着缺人,2.你的技能与其岗位是否对口

Android工程师教你如何准备面试复习

Android 性能优化最佳实践

1 、布局优化

2、绘制优化

3、内存优化

4、启动速度优化

5、包体优化

6、耗电优化

7、ListView和 Bitmap优化

8、响应速度优化

9、线程优化

10、微优化(提高代码质量)

Android Context 上下文 你必须知道的一切

《3分钟看懂Activity启动流程》

总结UI原理和高级的UI优化方式

简析Window、Activity、DecorView以及ViewRoot之间的错综关系

常用设计模式

  • 工厂模式和抽象工厂模式:注意他们的区别。

  • 责任链模式:View的事件分发和OkHttp的调用过程都使用到了责任链模式。

  • 观察者模式:重要性不言而喻。(广播、Android事件监听等等)

  • 代理模式:建议了解一下动态代理

  • 单例模式:考的少但是很常用

  • 模板模式:定义算法结构顺序

  • 装饰者模式(java的流处理使用的就是装饰者模式)

软件设计原则?

  • 单一职责原则:一个类只专注于做一件事; 高内聚,低耦合;
  • 开放-封闭原则:对拓展开放,对修改关闭(尽可能不动原有代码进行拓展);
  • 里氏代换原则:子类必须能够替换它们的基类型,基类与子类可互换,客户端没有察觉情况下;
  • 依赖倒置原则:面向接口编程,依赖于抽象而不依赖于具体。写代码时用到具体类时,不与具体类交互,而与具体类的上层接口交互。
  • 接口隔离原则:使用多个专一功能的接口比使用一个总接口总要好,但不能过渡;一个接口不能过于臃肿;
  • 迪米特法则:对象与对象之间应该使用尽可能少的方法来关联,避免千丝万缕的关系; 低耦合; 类知道其他类应尽量少;

示例

http 和 https 的区别

内存泄露检测,内存性能优化 ?

内存性能优化

  • 优先使用Parcelable序列化传输数据而不是使用Serializable序列化
  • 优化布局,减少嵌套,慎用weight属性
  • 节制地使用Service:系统会倾向于将这个Service所依赖的进程进行保留,这样就会导致这个进程变得非常消耗内存
  • 当界面不可见时释放内:在Activity中重写onTrimMemory()方法,监听TRIM_MEMORY_UI_HIDDEN
  • 当内存紧张时释放内存:onTrimMemory()方法
  • 避免在Bitmap上浪费内存:有效压缩、合理配置分辨率、使用bitmapFactory.decode方法加载bitmap。即Jni调用c底层加载优化速度
  • 谨慎使用抽象编程:抽象的编程方法需要编写额外的代码,虽然这些代码根本执行不到,但是却也要映射到内存当中,不仅占用了更多的内存,在执行效率方面也会有所降低
  • 尽量避免使用依赖注入框架:这些框架为了要搜寻代码中的注解,通常都需要经历较长的初始化过程。并且还可能将一些你用不到的对象也一并加载到内存当中
  • 使用ProGuard简化代码:除了混淆之外,它还具有压缩和优化代码的功能,ProGuard会对我们的代码进行检索,删除一些无用的代码,并且会对类、字段、方法等进行重命名
  • 使用多个进程:如音乐播放器。Service配置android:processs属性为:background就可以了

内存泄露检测

  • LeakCanary
  • 追踪内存分配
  • 查询方法执行的时间

通常判断方法是:如果方法调用次数不多,但每次调用却需要花费很长的时间的函数,可能会有问题。 如果自身占用时间不长,但调用却非常频繁的函数也可能会有问题。

Jave中的引用分为3种:

  • 强引用:引用为空的时候,Java的垃圾回收器会处理。一般来说自己写的程序大部分都是强引用。
  • 软引用:如果一个对象具有软引用,内存空间足够,垃圾回收器就不会回收它;如果内存空间不足了,就会回收这些对象的内存
  • 弱引用:是用来描述非必需对象的,当JVM进行垃圾回收时,无论内存是否充足,都会回收被弱引用关联的对象。
  • 虚引用:虚引用和前面的软引用、弱引用不同,它并不影响对象的生命周期。如果一个对象与虚引用关联,则跟没有引用与之关联一样,在任何时候都可能被垃圾回收器回收。

OOM与ANR的区别?

OOM:就是当前占用的内存加上我们申请的内存资源超过了Dalvik虚拟机的最大内存限制就会抛出。

主要是因为使用过多的内存泄漏造成的OOM。

主要原因可能有:

  1. 内部类对Activity的引用(未及时释放)
  2. 大量Bitmap使用(未及时回收)
  3. 游标cursor的使用(未关闭)
  4. 在onDraw方法里面执行大量对象的创建
  5. 不恰当的使用static关键字(堆占用内存过多)
  6. 滥用多线程

OOM:是当前占用的内存加上我们申请的内存资源超过了Dalvik虚拟机的最大内存限制;

内存抖动:是短时间内大量的对象被创建,然后又被马上释放;

内存泄漏:指无用对象持续占有内存或得不到及时释放,从而造成的内存空间的浪费,过多的内存泄漏会造成OOM.

ANR:Application not response,应用程序无响应。(android中Activity的最长执行时间是5秒,BroadcastReceiver的最长执行时间则是10秒)

布局优化?

  • 减少嵌套布局
  • 慎用weight属性
  • 重用布局文件
  • include
  • merge
  • 仅在需要时才加载布局ViewStub

Picasso、Okhttp、Retrofit、Rxjava源码的理解?

加锁机制的使用有哪些?

  • Lock : 明锁,用于处理synchronized解决不了的特殊问题下使用

  • synchronized : 同步锁,java有优化一般情况下推荐使用,锁少的情况下效率较高。(类锁、方法锁、对象锁)

  • Atomic :

      AtomicBoolean:以原子更新的方式更新boolean;
      AtomicInteger:以原子更新的方式更新Integer;
      AtomicLong:以原子更新的方式更新Long;
      
      AtomicIntegerArray:原子更新整型数组中的元素;
      AtomicLongArray:原子更新长整型数组中的元素;
      AtomicReferenceArray:原子更新引用类型数组中的元素
      
      AtomicReference:原子更新引用类型;
      AtomicReferenceFieldUpdater:原子更新引用类型里的字段;
      AtomicMarkableReference:原子更新带有标记位的引用类型;
      
      AtomicIntegeFieldUpdater:原子更新整型字段类;
      AtomicLongFieldUpdater:原子更新长整型字段类;
      AtomicStampedReference:原子更新引用类型,这种更新方式会带有版本号。
    
  • volatile修饰的变量:

多线程、加锁多线程的使用?

Executor执行器的使用多线程。

newCacheThreadPool:将为每一个任务创建一个线程,但如果已有线程是空闲的会重用已有线程(默认情况下推荐使用)

newFixedThreadPool:使用有限线程集执行所提交的任务,可控制线程最大并发数,超出的线程会在队列中等待,不会滥用可获得的资源。(资源紧张下使用)

newSingleThreadExecutor:一个单线程化的线程池,它只会用唯一的工作线程来执行任务(用于文件日志)

ForkJoinPool:优势在于,可以充分利用多cpu,多核cpu的优势,把一个任务拆分成多个“小任务”,把多个“小任务”放到多个处理器核心上并行执行。 缺点: 在执行过程中,会创建大量的子任务,导致GC进行垃圾回收,这些是需要注意的

多线程间通信的几种模式?

  1. 同步(Lock、synchronized、Atomic):这里讲的同步是指多个线程通过synchronized关键字这种方式来实现线程间的通信。(通过判断这个“共享的条件变量“是否改变了,来实现进程间的交流)
  2. while轮询的方式(通过判断这个“共享的条件变量“是否改变了,来实现进程间的交流)
  3. wait/notify机制。(通知过早,会打乱程序的执行逻辑。)
  4. 管道通信:通过管道,将一个线程中的消息发送给另一个。

java线程安全的容器有哪些?

  • 同步容器过时类:使用了synchronized

      1.Vector、Stack(Vector子类、先进后出) 
      2.HashTable
    
  • 并发容器:

      3.ConcurrentHashMap:分段
      4.CopyOnWriteArrayList:写时复制
      5.CopyOnWriteArraySet:写时复制
    
  • Queue:

      6.ConcurrentLinkedQueue:是使用非阻塞的方式实现的基于链接节点的无界的线程安全队列,性能非常好。
      (java.util.concurrent.BlockingQueue 接口代表了线程安全的队列。)
      7.ArrayBlockingQueue:基于数组的有界阻塞队列
      8.LinkedBlockingQueue:基于链表的有界阻塞队列。
      9.PriorityBlockingQueue:支持优先级的无界阻塞队列,即该阻塞队列中的元素可自动排序。默认情况下,元素采取自然升序排列
      10.DelayQueue:一种延时获取元素的无界阻塞队列。
      11.SynchronousQueue:不存储元素的阻塞队列。每个put操作必须等待一个take操作,否则不能继续添加元素。内部其实没有任何一个元素,容量是0
    
  • Deque:

      (Deque接口定义了双向队列。双向队列允许在队列头和尾部进行入队出队操作。)
      12.ArrayDeque:基于数组的双向非阻塞队列。
      13.LinkedBlockingDeque:基于链表的双向阻塞队列。
    
  • Sorted容器:

      14.ConcurrentSkipListMap:是TreeMap的线程安全版本
      15.ConcurrentSkipListSet:是TreeSet的线程安全版本
    

google混合App开源框架fluter的使用?

view事件分发拦截机制?

自定义view?

  • 集成View,重写onDraw()方法

  • 集成现有空间如TextVeiw

  • 组合View

      onMeasure()会在初始化之后调用一到多次来测量控件或其中的子控件的宽高;
      onLayout()会在onMeasure()方法之后被调用一次,将控件或其子控件进行布局;
      onDraw()会在onLayout()方法之后调用一次,也会在用户手指触摸屏幕时被调用多次,来绘制控件。
    

Android 动画?

补间动画、帧动画

Handler源码的理解?

– 功能

    ——执行计划任务 
    ——线程间通信 
    ——-确保操作始终在某个特定的线程中执行 

– 结论

    ——1在同一线程可以创建不同的handler 
    ——2handler不能直接创建在没有Looper.prapare这种函数的线程中 
    ——3通过对handler指定Looper才能在不同的线程中运行 
    ——4 一旦message被开始处理,removeMessage是无效的

跨进程通信的几种模式?

  • Activity:需要指定的是要访问的Activity所对应的Action,用在跳转拨号界面等
  • Service:通过AIDL服务,通过binder机制
  • Broadcast: 广播是一种被动跨进程通讯的方式
  • ContentProvider:通过binder机制,提供了一种在多个应用程序之间数据共享的方式

ContentProver共享数据机制?

MVC与MVP的优缺点?

MVC有助于管理复杂的应用程序,可以让开发人员单独进行某一层的开发。

优点:

1.耦合性低:M、V、C的分离所以很容易改变应用程序的数据层和业务规则

2.重用性高:允许不同样式的视图共享一个模型

3.生命周期成本低:是开发和维护用户接口的技术含量降低

4.部署快:他可以让一个开发人员专注于业务逻辑的开发,而另一个开发人员专注于界面的开发。

5.维护性高:因为M、V、C层的分离所以更易于维护和修改

缺点:

1.不适合小型和中型规模的应用程序

2.视图和控制器之间过于紧密的连接

MVP:MVP是从经典的模式MVC演变而来

特点:

MVP和MVC最大的区别就是:在MVP中View并不会直接使用Model,他们的之间的所有通信都是通过Presenter层进行,所有的交互都发生的presenter内部,在MVC中View会直接从Model中读取数据而不是通过Controller.

在MVC里,View是可以直接访问Model的,从而View里会包含Model信息,不可避免的还要包括一些业务逻辑。导致更改View也是比较困难的。

优点:

1、模型与视图完全分离,我们可以修改视图而不影响模型

2、可以更高效地使用模型,因为所有的交互都发生在一个地方——Presenter内部

3、我们可以将一个Presenter用于多个视图,而不需要改变Presenter的逻辑。这个特性非常的有用,因为视图的变化总是比模型的变化频繁。

4、如果我们把逻辑放在Presenter中,那么我们就可以脱离用户接口来测试这些逻辑(单元测试)

缺点:

由于对View的渲染放在了Presenter中,所以视图和Presenter的交互会过于频繁。一旦View需要变更,那么Presenter也需要变更了。

后台进程保活?

黑色保活:不同的app进程,用广播相互唤醒(包括利用系统提供的广播进行唤醒)

白色保活:系统应用白名单(如QQ、微信)、可见的前台服务。用在音乐播放器。

灰色保活:利用系统漏洞。

Activity的启动模式及应用?

  • standard:不管有没有已存在的实例,都生成新的实例。
  • singleTop:否有一个MainActivity实例正位于栈顶,如果有则不再生成新的,而是直接使用。
  • singleTask:如果发现有对应的Activity实例,则使此Activity实例之上的其他Activity实例统统出栈。用在主Activity
  • singleInstance:它会启用一个新的栈结构,将Activity放置于这个新的栈结构中,并保证不再有其他Activity实例进入。 用在全局拨号界面

String,Stringbuffer,Stringbuilder 区别?

String:字符串常量,字符串长度不可变。Java中String是immutable(不可变)的。

StringBuffer:字符串变量(Synchronized,即线程安全)。如果要频繁对字符串内容进行修改,出于效率考虑最好使用StringBuffer,如果想转成String类型,可以调用StringBuffer的toString()方法。可将字符串缓冲区安全地用于多个线程

StringBuilder:字符串变量(非线程安全)。在内部,StringBuilder对象被当作是一个包含字符序列的变长数组。用在字符串缓冲区被单个线程使用的时候(这种情况很普遍)

java中Serializable与Parcelable的使用

  • Serializable序列化的空接口,这个序列化很简单,类直接实现就可以了,记住要添加或者保留序列化版本号serialVersionUID,否则可能会造成反序列化失败.

  • Parcelable接口,android特有的序列化存储,传输效率高,需要实现里面的抽象方式,实现起来比较麻烦.

Java 容器(list, set, map)

  • list: 有序排列

      ArrayList               内部实现是用数组, 随机访问速度快, 删除或插入元素速度慢。
      LinkedList              内部实现是用链表, 随机访问速度慢,删除和插入元素相对较快。
      Queue(先进先出)          各种Queue以及栈的行为,有LinkedList提供支持
      Vector、Stack(先进后出)  是过去遗留下来的类,目的只是为了支持老程序,应该在编写程序时尽量避免使用它们。
    
  • Set: 默认无序排列、不接受重复元素

      HashSet: 提供最快的查询速度。为快速查找而设计,可以认为是基于哈希表的实现。 存入HashSet的元素必须定义hashCode().
      TreeSet:保持元素处于排序状态。保持次序的Set,底层为树结构(红黑树)。使用它可以从Set提取有序的序列。元素必须实现Comparable接口或者在构造TreeSet时传入Comparator参数。
      LinkedHashSet: 具有HashSet的查询速度且内部使用链表维护元素的顺序(按插入的顺序或最近最少使用顺序)
    
  • Map: 默认无序排列,键值对存储机制,Map的key不允许重复。如果是线程安全容器key-value都不可为null

      HashMap  基于散列表的实现(它取代了HashTable, HashTable是过时的类)。key、value可以为null
      TreeMap 基于红黑树的实现。查看key 或 key-value是,它们会被排序(次序由Comparator或Comparable决定),key不可为null,value可以为null
      LinkedHashMap 类似与HashMap, 但是迭代遍历时,取得“键值对”的顺序是其插入的顺序,或最近最少使用的顺序(如果在构造LiskedHashMap传入参数accessOrder=true)。比HashMap慢一点,但是在迭代访问时更快,因为它使用链表维护内部的次序。
    

Android xml解析的几种方式?

  • SAX(Simple API XML)

      SAX(Simple API for XML)解析器是一种基于事件的解析器,事件驱动的流式解析方式是,从文件的开始顺序解析到文档的结束,不可暂停或倒退。 
      优点:解析速度快,占用内存少。非常适合在Android移动设备中使用。 
      缺点:不会记录标签的关系,而要让你的应用程序自己处理,这样就增加了你程序的负担。 
      工作原理:对文档进行顺序扫描,当扫描到文档(document)开始与结束、元素(element)开始与结束、文档 (document)结束等地方时通知事件处理函数,由事件处理函数做相应动作,然后继续同样的扫描,直至文档结束。 
    
  • DOM(Document Object Model)

      DOM,即对象文档模型,它是将整个XML文档载入内存(所以效率较低,不推荐使用),每一个节点当做一个对象,结合代码分析。
      优点:由于DOM在内存中以树形结构存放,因此检索和更新效率会更高
      缺点:但是对于特别大的文档,解析和加载整个文档将会很耗资源。 当然,如果XML文件的内容比较小,采用DOM是可行的。 
      工作原理:使用DOM对XML文件进行操作时,首先要解析文件,将文件分为独立的元素、属性和注释等,然后以节点树的形式在内存中对XML文件进行表示,就可以通过节点树访问文档的内容,并根据需要修改文档。 
    
  • Pull

      PULL解析器的运行方式和SAX类似,都是基于事件的模式。不同的是,在PULL解析过程中返回的是数字,且我们需要自己获取产生的事件然后做相应的操作,而不像SAX那样由处理器触发一种事件的方法,执行我们的代码。 
      优点: PULL解析器小巧轻便,解析速度快,简单易用,非常适合在Android移动设备中使用,Android系统内部在解析各种XML时也是用PULL解析器,Android官方推荐开发者们使用Pull解析技术
    

总结:三种方式的总结比较

DOM方式最直观和容易理解,但是只适合XML文档较小的时候使用,而SAX方式更适合在移动终端系统中使用,因为相比DOM占用内存少,适合处理比较大的XML文档,最后的Pull方式使用场合和SAX类似,但是更适合需要提前结束XML文档解析的场合。

手写冒泡算法

public static void BubbleSort(int[] arr) {
    int temp;//临时变量
    for (int i = 0; i < arr.length - 1; i++) {   //表示趟数,一共arr.length-1次。
        for (int j = arr.length - 1; j > i; j--) {
            if (arr[j] < arr[j - 1]) {
                temp = arr[j];
                arr[j] = arr[j - 1];
                arr[j - 1] = temp;
            }
        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值