Android常规问题总结

xiaoxiao2021-02-28  71

1、HashMap原理,hash冲突怎么解决?hashmap原理

HashMap的工作原理

HashMap基于hashing原理,我们通过put()和get()方法储存和获取对象。当我们将键值对传递给put()方法时,它调用键对象的hashCode()方法来计算hashcode,让后找到bucket位置来储存值对象。当获取对象时,通过键对象的equals()方法找到正确的键值对,然后返回值对象。HashMap使用链表来解决碰撞问题,当发生碰撞了,对象将会储存在链表的下一个节点中。 HashMap在每个链表节点中储存键值对对象。

当两个不同的键对象的hashcode相同时会发生什么? 它们会储存在同一个bucket位置的链表中。键对象的equals()方法用来找到键值对。

HashMap是基于hashing的原理,我们使用put(key, value)存储对象到HashMap中,使用get(key)从HashMap中获取对象。当我们给put()方法传递键和值时,我们先对键调用hashCode()方法,返回的hashCode用于找到bucket位置来储存Entry对象。

“当两个对象的hashcode相同会发生什么?” 因为HashMap使用链表存储对象,这个Entry(包含有键值对的Map.Entry对象)会存储在链表中。

“如果两个键的hashcode相同,你如何获取值对象?” 找到bucket位置之后,会调用keys.equals()方法去找到链表中正确的节点,最终找到要找的值对象。

“如果HashMap的大小超过了负载因子(load factor)定义的容量,怎么办?”默认的负载因子大小为0.75,也就是说,当一个map填满了75%的bucket时候,和其它集合类(如ArrayList等)一样,将会创建原来HashMap大小的两倍的bucket数组,来重新调整map的大小,并将原来的对象放入新的bucket数组中。这个过程叫作rehashing,因为它调用hash方法找到新的bucket位置。

“你了解重新调整HashMap大小存在什么问题吗?"可能产生条件竞争(race condition),因为如果两个线程都发现HashMap需要重新调整大小了,它们会同时试着调整大小。在调整大小的过程中,存储在链表中的元素的次序会反过来,因为移动到新的bucket位置的时候,HashMap并不会将元素放在链表的尾部,而是放在头部,这是为了避免尾部遍历(tail traversing)。如果条件竞争发生了,那么就死循环了。这个时候,你可以质问面试官,为什么这么奇怪,要在多线程的环境下使用HashMap呢?:)

“为什么String, Interger这样的wrapper类适合作为键?” String, Interger这样的wrapper类作为HashMap的键是再适合不过了,而且String最为常用。因为String是不可变的,也是final的,而且已经重写了equals()和hashCode()方法了。如果两个不相等的对象返回不同的hashcode的话,那么碰撞的几率就会小些,这样就能提高HashMap的性能。

“我们可以使用自定义的对象作为键吗?” 这是前一个问题的延伸。当然你可能使用任何对象作为键,只要它遵守了equals()和hashCode()方法的定义规则,并且当对象插入到Map中之后将不会再改变了。如果这个自定义对象时不可变的,那么它已经满足了作为键的条件,因为当它创建之后就已经不能改变了。

2、webView相关,java和js交互,本地缓存,图片点击、图片缓存策略。

WebView所有问题总结

3、TCP/UDP三次握手,四次挥手内容,以及原因。

点击打开链接

三次握手: 建立一个TCP连接时,需要客户端和服务端总共发送3个包以确认连接的建立,在Socket编程中,这一过程由客户端执行connect来触发

第一次握手:Client将标志位SYN置为1,随机产生一个值seq=X,并将该数据包发送给Server, Client进入SYN_SENT状态,等待Server确认。第二次握手:Server收到数据包后由标志位SYN=1知道Client请求建立连接,Server将标志位 SYN置为1,ACK=X+1,随机产生一个值seq=Y,并将该数据包发送给Client以确认连接请求 ,Server进入SYN_RCVD状态。第三次握手:Client收到确认后,检查ACK是否为X+1,SYN是否为1,如果正确则将标志位ACK 置为Y+1,并将该数据包发送给Server,Server检查ACK是否为Y+1,如果正确则 连接建立成功,Client和Server进入ESTABLISHED状态,完成三次握手,随后Client与Server之间可以 开始传输数据了。 四次挥手 : 终止TCP连接,就是指断开一个TCP连接时,需要客户端和服务端总共发送4个包以确认连接的断开。 在Socket编程中,这一过程由客户端或服务端任一方执行close来触发

第一次挥手:Client发送一个FIN =M,用来关闭Client到Server的数据传送,Client进入 FIN_WAIT_1状态第二次挥手:Server收到FIN后,发送一个ACK= M+1,Server进入CLOSE_WAIT状态。第三次挥手:Server发送一个FIN =N,用来关闭Server到Client的数据传送,Server进入LAST_ACK 状态。第四次挥手:Client收到FIN后,Client进入TIME_WAIT状态,接着发送一个ACK = N+1给Server,Server进入CLOSED状态,完成四次挥手。 另外也可能是同事发起主动关闭的情况。

为什么建立连接是三次握手,而关闭连接却是四次挥手呢? 答:因为服务端在LISTEN状态下,收到建立连接请求的SYN报文后,把ACK和SYN放在一个报文里 发送给客户端。而关闭连接时,当收到对方的FIN报文时,仅仅表示对方不再发送数据了但是还 能接收数据,己方也未必全部数据都发送给对方了,所以己方可以立即close,也可以发送一些 数据给对方后,再发送FIN报文给对方来表示同意现在关闭连接,因此,己方ACK和FIN一般都会 分开发送。

4、java内存回收机制

Java 内存分配与回收原理

5、ThreadLocal原理及使用

ThreadLocal是java中的一个线程数据存储类,在每一个线程Thread中都存在一个ThreadLocal.Values values的变量,values中存在一个table数组,所有的数据都存储在这个数组中,也就是说每一个线程都有这么一个数组涌来存放数据,不同线程的数据互不干扰。

6、进程线程的区别,一个应用是否能有多个进程?

andorid:process

7、四种启动模式;怎么用java改变启动模式(flag)

8、IntentFilter相关,包括action、category、data等的配置,scheme,用浏览器怎么能够打开某个应用的某个activity

9、Activity的生命周期,包括Activity非正常关闭,数据的保存。

10、数据库相关,基本的增删改查等方法;数据库升级,旧数据如何保存;数据库的事物如何使用

db.insert/delete/update/query,其中insert和update用到ContentValues存储健值对,query会返回一个Cursor对象,最后需要关闭cursor对象,防止内存泄漏。

数据库事务:事务的特性可以保证某一系列操作要么全部完成,要么一个都不会完成。

db.beginTransaction db.setTransactionSuccessfuldb.endTransaction

常用的sql语句:

建表语句:"create table Book(id integer primary key autoincrement, name text,author text, pages integer, price real)"

插入语句:"insert into Book(name, author,pages,price) values (?,?,?,?)" , new String[]{"Thinking in java", "Bruce", "400", "20.0"}

删除语句:"delete from Book where pages > ?', new String[]{"500"}

更新语句:"update Book set price = ? where name =? ",new String[]{"15.2", "Thinking in java"}

查询语句:"select * from Book",null

表重新命名:"alert table Book rename to Book2"

复制表中的数据到另一个表中:"insert into Book select id ,name from Book2"

删表语句:"drop table if exits Book"

11、广播、Service

12、进程间通信,AIDL

13、View的分发机制

14、自定义View,自定义View的分类(继承现有控件、组合控件、重写onDraw)

15、include、merge、viewStub标签

16、层级优化的东西

点击打开链接

17、动画相关

Android中的动画机制

18、常见的内存泄漏,context相关的泄漏,使用什么工具。

内存泄漏的优化分为两个方面:

一个是在开发过程中避免写出有内存泄漏的代码,另一方面是通过一些分析工具比如MAT来找出潜在的内存泄漏继而解决。

19、对继承的理解

Java继承的理解

继承就是子类继承父类的属性和方法,使得子类对象具有父类的特征和行为,或子类从父类继承方法,使得子类具有父类相同的行为。

20、binder

Android中的Binder机制

21、EventBus

22、悬浮窗

WindowManager

23、(byte为例)整数的原码、反码、补码都相等,负数的反码等于原码除符号位外各位取反,补码等于反码加一,0的补码为0000 0000,-128的补码为1000 0000,也就是本身。所有的运算在内存中都是以补码的方式进行的。

项目相关:

一、Reader

1、WebView的问题WebView所有问题总结

2、滑动冲突点击打开链接

3、数据库

4、ListViewAndroid中ListView的使用及优化

二、Map

1、Crash相关Android稳定性专题之Crash

当crash发生时,系统会kill掉正在执行的程序,现象是闪退或者提示用户程序已停止运行。更糟糕的是,当用户发生crash的时候,开发者却无法得知程序为何crash,即便开发人员想去解决这个crash,但是由于无法知道用户当时的crash信息,所以往往也无能为力。幸运的是,Android提供了处理这类问题的方法,在Thread中存在一个setDefaultUncaughtExceptionHandler:

public static void setDefaultUncaughtExceptionHandler(UncaughtExceptionHandler handler) { Thread.defaughtUncaughtExceptionHandler = handler; }

当发生crash的时候,系统就会回调UncaughtExceptionHandler的uncauthtException方法,在uncauthtException方法中就可以获取到一场信息,可以选择把异常信息存储到sd卡中,然后在合适的时机通过网络将crash信息上传到服务器,这样开发人员就可以分析用户crash的场景而在后面的版本中修复此类crash。

另外Native层crash信息可以用谷歌的开源项目BreakPad来收集。

2、crash问题举个例子?

主要看data/system/dropbox中的文件,根据堆栈信息找到问题代码的位置。

crash一般是由于空指针、数组越界或者在子线程中更细UI等造成的。

3、ANR相关Android稳定性专题之ANR

简单的说,就是主线程(UI线程)被耗时操作阻塞,无法及时完成工作,导致了ANR。

类型 触发时间 是否需要与APP交互 Input Dispatching 5s 是 Service Foreground 20s 否 Broadcast Foreground 10s 否 Broadcast Background 60s 否

主线程中执行了耗时操作,比如: 网络访问数据库读写文件读写复杂的耗时算法wait()、sleep()、join()、等线程操作 其他线程或进程占用了CPU资源,导致主线程无法获取CPU资源多线程发生死锁,主线程一直无法获取锁,造成阻塞

4、举个例子?

当一个进程发生ANR的时候,会在data/anr目录下生成一个traces.txt文件,同过分析这个文件就能定位出ANR的原因。

通过traces文件的代码栈发现有这么一行内容:

-waiting to lock <xxxxxx> (a com.xx.XxxActivity)held by tid=11(Thread-13248)

可以看得出主线程在方法function1中等待一个锁<xxxxxx>,这个锁的内容是一个XxxActivity的对象,并且这个锁已经被线程id为11的线程持有了,因此需要再看一下线程11的情况。

在线程11中此刻正在执行耗时方法function2方法,这个时候发现在function2和function1方法都加了synchronized关键字,表面它们在竞争同一个锁,即当前Activity的对象锁,这样以来ANR的原因就明确了,经研究发现子线程中的锁事没有必要的,去掉即可修复这个问题。

5、性能优化工具

TraceView:点击打开链接 

UI渲染与卡顿原理

转载请注明原文地址: https://www.6miu.com/read-27639.html

最新回复(0)