Android高频面试题知识整理

mvc mvp mvvm

mvc是最基础的架构,最开始是从web引用过来的,但是在android里面,C就在activity里,activity其实是属于view层,本身是不能做大量业务逻辑处理的,mvc在安卓中就会显得笨拙,使activity变的繁杂不易维护和拓展,但是小项目又比较合适,正因为大项目使用mvc把activity作用变得不易维护所以衍生出了mvp,mvp是把activity里的业务抽出来放到 Presenter里面,把activity的位置还原到view层,去实现用户的所有操作接口,但是这里又会有个问题,presenter和activity也就是view的交互会很频繁,而这些操作都是用接口连接的,所以项目会增加很多接口文件,虽然现在有控件可以直接一键生成这样的接口,但是每次增加一个业务的时候就会比较繁琐,会写很多接口和实现类,但是总的来说用mvp在中大型项目上用的时候可能觉得麻烦一点,但是在单元测试,拓展,维护上会方便很多,而且一个presenter可以用于多个activity,可重用性更高,mvvm是改良版的mvp,它用viewmodel代替了presenter,用dadabinding 做view和viewmode的数据绑定,数据发生改变view就会跟着改变,因为livedata 生命周期通过lifecycle和activity绑定,所以一定程度上app了页面的内存泄露问题,mvvm是现在主流的架构也是Google主推的架构

多线程

http网络请求多线程,照片上传多线程,人像比对多线程 多线程主要是要处理线程之间的共享变量,比如几个线程同时请求,而请求结果需要做一个回调,每个线程请求成功需要做一个计数器,而这个计数器就是共享变量,多线程操作共享变量需要加锁synconizied,并且用volatile修饰保证变量操作的唯一性

join:调用join就是调用当前线程的wait方法,等待join线程执行完毕在调用当前线程的notify方法恢复执行,join方法必须要在线程运行之后才有效

如何保证你的线程执行完

(如何保证你的线程执行完https://blog.csdn.net/wzy_1988/article/details/46875343,用WakeLock,可以在锁屏状态下保持CPU的正常运行,这个WakeLock是用来执行一些关键代码的,用完需要释放,不然app会很耗电)后来发现是我配置的问题,rxjava和retrofit的activity生命周期配置

kotlin

很多只是写法变了,关键字变了,逻辑还是差不多的,比如switch变成了when,for循环变成for in,还有就是一些权限修饰符变了,默认权限是final,open标识可继承,可重写,增加了新的权限internal标识在当前module中使用用起来比java方便,省掉了很多代码,比如那种非空判断只需要语句中加个问号就行,逻辑都是差不多的

kotlin没有static的变量,只能用companion派生对象关键字修饰,全局静态对象用Object关键字(Util工具类)const常量

高阶函数

    forEach     遍历数组

    map    数组转换

    flatmap    多维数组转换

    let     变量定义作用域,非空判断 返回最后一行

    with    传入对象,作用域最后一行是返回值

    run    只接受lambda函数 返回最后一行

    apply,返回函数本身作用域,减少重复引用 不改变值 

tcp/ip http

这些协议原理还是很深的,首先他们的层级是不一样的,ip协议是用于网络层的,tcp是传输层,http是应用层,然后tcp又涉及到三次握手,对于这些协议我没有研究的很深,平常用的多的还是http协议,http协议是建立在tcp上的一种应用,他的特点就是每次发出请求都需要服务端回送响应,建立连接和关闭连接叫做一次连接 可以参考(https://blog.csdn.net/DavidStar1988/article/details/80400020

rxjava

rxjava的话,其实大部分的项目,可以说90%在项目里用rxjava都是用在retrofit的adapter上,因为大部分项目业务流程都比较简单,不用rxjava也就只是多几个回调方法而已,但是我用rxjava的目的主要还是那种链式编程可以使项目的逻辑变得清晰,因为很多逻辑如果嵌套太多的话时间长了维护起来会很难看懂,所以我是觉得能使逻辑变清晰的框架都适合我,rxjava关键字很多,我用的比较多的是map,和flatmap,作用就是你可以像流水线一样从Observable开始层层处理得到你想要的数据(两个都是转换数据,但是flatmap可以转换成Observable类型的数据,相当于for循环内又可以再for循环)还有很多关键字比如just,from,timer,interval,这些用到的时候不懂再去查一下很快就可以上手了,还是挺简单的

zip 合并observable

其他操作符https://blog.csdn.net/chaoyangsun/article/details/80373203

    创建类型

        concat 将Observable依次发送

        merge 交错,不按顺序发送

        ust      原样发射

        from    将数组分成单个依次发射

        Interval    间隔发射

        timer 延迟发射

    转换类型

        map 转换数据 比如给我的是url,但是我需要的是bitmap,这时候就用map

        filter 筛选,按条件筛选,比如筛选出非空的url

        flatmap    相对于map,可以多对多,比如在转换数据的集合里进行拆分

just 和from区别: just是设置什么就返回什么,from是把数组分成单独的发送
https://blog.csdn.net/moonpure/article/details/78402347

retrofit

其实retrofit不是一个网络请求库,它是一个请求库上面的一个封装,建立在okhttp上的一个库,特点就是你可以用注解去构建一个网络请求,他先是用接口去实现一个带有注解的类,然后用retrofit的create去创建一个实体,我看了一下源码,这个create里面是用了动态代理来实现的他就是通过反射在一个class方法的前后增加逻辑代码,这些逻辑代码就是用到okhttp的库,最后生成一个请求的request,里面设计感还是很强的,工厂模式,适配器模式还提供了rxjava的支持,和rxjava结合还是用的很爽的https://www.jianshu.com/p/a8b98e66b1b8

Glide

和其他图片加载框架差不多,glide都有三级缓存,但是glide比较强大的是能加载gif,还有glide的with方法传入的context会进行检查,他会添加一个隐藏的fragment来监听生命周期,达到自动回收图片的目的

Volley

volley的封装比较简单是轻量级的,volley也支持okhttp,但是volley不支持post大文件数据

Dagger

dagger是一个注解处理器,帮助项目解耦少用new关键字,和spring的作用差不多,但是他是编译期间通过apt插件预生成一些代码,而spring是在运行期间,它主要可以帮助你做一些初始化的操作,缺点就是编译时间边长了,每次运行要多很长时间https://www.jianshu.com/p/cc54c5ec9897

事件分发

image

数据库增加字段

sqllite增加字段只能重新建表,方法就是把表重命名,新建一张带有该字段的表,然后复制数据

数据库框架比较

数据库框架分为关系型数据库和对象型数据库,关系型数据库最好的库是greendao,对象型数据库比较好的也是用的最多的是realm,底层是c语言实现的,性能相对较好就是包会比较大但是业务量不大的话用android的sqlite就行了,功能简单,也方便拓展

数据库性能优化

  • 数据库操作基本由三个过程,创建事务,执行sql,提交,这三个过程,但是我们批量操作,就变成创建事务,执行n个sql,提交,这样效率会提高很多,

  • 在sql语句数量比较多的情况下,用stringbuilder代替string拼接,这样会提高空间分配效率

  • 查询时根据需要返回尽量少的字段,可以减少内存的消耗

  • 查询结束后及时关闭cursor

  • 如果条件允许的话可以在建表的时候记住columnIndex,它是一个int类型下标值,不用每次查询都去调用getColumnIndex,这个在数据量庞大的查询条件下会比较节省时间

  • 调用数据库的时候要用子线程防止卡ui,但是由于sqllite是不支持多线程并发访问的,两个线程同时插入会抛出异常,虽然是有事务控制,可以保证数据库的完整性,但是不能保证线程执行的准确性,也就是说有的线程可能会调用失败或者请求出现线程繁忙错误,所以sqlite最好保证单线程执行

  • 一般情况下,sqlite是多进程可以操作的,不会报错,但是不能保证插入顺序,原则上需要在一个进程里去操作,正确的做法是,启用一个, 单独的进程通过contentprovider或者其他ipc向其他进程提供接口,通过这个单独的进程统一操作

ipc

为什么需要多进程:

  • Android对进程的内存分配是有限的,用多进程让核心服务和UI分离,可以为用户提供更好的程序稳定性,提升用户体验 开启多进程,用多进程分担内存压力,用前台service保证adj的值最小,最不容易回收

  • 内存分配 管理内存分配的是LMK LowMemoryKiller,通过adb命令proc/pid/com_score_adj可以看到一个应用的adj值,值越大,越容易被回收,通常切换到后台会变大

  • 多进程会出现的问题:

    共享内存失效,单例,静态变量成员失效,同步锁失效,application多个,sharepreferce可靠性下降
    
  • 应用场景:

    音乐播放器,定位服务
    
  • 开启多进程的方式:在四大组件注册文件中指定 android:process

  • 多进程的通信方式:

    1. Bundle 常用于四大组件通讯

    2. 文件共享,多进程操作同一个文件交换数据 但是不支持并发

    3. Messenger 轻量级的AIDL ,需要基于Handler

    4. Socket

    5. AIDL 写aidl接口文件,在服务里通过Binder拿到接口对象传递数据,注册服务,客户端绑定服务转换aidl接口获取数据

    6. ContentProvider 例如我们的应用访问系统的通讯录数据

recycleview

嵌套scrollview卡顿,重新scrollview拦截一下事件

嵌套显示不全item,外面再包一层relativelayout 增加一个descendantfcusability属性

布局优化

  1. 避免层级太多

  2. 开发者模式查看是否过度绘制

  3. 使用include标签重用layout

  4. viewstub标签 (调用的时候才加载布局)

  5. 不要在onDraw中频繁创建对象和做耗时操作

socket

创建服务端socket连接对象,指定ip和端口号,子线程进行

监听socket流,获取服务端返回数据

发送数据也是利用InputStream的write字节

websocket

是基于类似于http的应用层协义,使用jar包WebSocketClient连接服务器

Android动画

  • view动画 移动,平移,缩放,旋转

  • drawable动画 帧动画,一帧一帧的

  • property动画 view动画升级版,可以渲染还没加载的view

Handler机制

Handler创建Looper,Looper创建MessageQueue Looper消息队列处理者用死循环不断去 MessageQueue 消息队列拿到message然后又调用handler去处理, 类似于生产者消费者https://www.jianshu.com/p/87ee9b5206df

性能优化

1 anr主线程不能处理耗时操作

2 内存溢出,bitmap优化

3 内存抖动,频繁创建临时对象

4 内存泄漏

  • 使用LeakCanary检测:

    运行后会在另外一个Leaks的app中显示,该库会监听onDistory方法,把activity实例放在弱引用里实时访问,找出内存泄露的变量和类

  • android studio app profiler工具:

    可以查看当前运行app的CPU,内存,网络的占用和消耗,可以看当前页面所在类的实例,可以调试内存泄漏和占用比例

  • webview引起的内存泄露,手动创建,手动销毁,不要在xml使用

  • 线程销毁

  • context单例引用

  • handler

  • 弱引用

  • SQLite使用完记得关闭链接

5 ui布局复杂

6 view重复绘制

7 懒加载setUserVisibleHint

https://www.jianshu.com/p/3e44250ca2de

activity启动模式

standard

   默认启动模式,start多少就开启多少

singletop

   栈顶唯一,允许有多个实例,但是不允许叠加,通知栏跳转

singleTask

   栈唯一,但是start的时候如果此activity之上有新的activity会被销毁,会调用此activity的onNewIntent方法,主界面

singleInstance

   栈唯一,一般用于系统应用,launcher

Android 678910 的差异

6.0     运行时权限,休眠模式,app进入休眠模式会断开网络,杀掉一些空置进程

7.0    分屏多任务,VR,通知栏快捷回复,优化编辑器减少安装速度,文件加密

8.0    画中画,Notifcation Dots,自适应桌面图标,后台进程限制,运行时权限优化,安装位置来源apk权限

9.0    WIFI RTT室内精准定位,凹凸屏支持,消息通知优化,多摄像头api,ImageDecoder,神经网络api,NFC api

10.0  暗黑模式,桌面模式(投影),5Gapi,折叠屏支持,手势导航,后台程序位置获取权限,神经网络1.2,文件沙盒

https://www.jianshu.com/p/88409d6f5795

activity fragment互传值

LiveData [https://www.jianshu.com/p/3e8e1fee00fc](https://www.jianshu.com/p/3e8e1fee00fc)

livedata 主要是用于activity的数据共享,比如activity和fragment,fragment和fragment之间的通讯,优点就是它自己会处理生命周期,不用担心内存泄漏,比如网络请求自动刷新ui这种

实现方式

    需要配合viewmodel使用,viewmodel 定义mutableLiveData, 用viewModelProviders.of创建实例,在fragment里用.observe绑定,最后调用mutableModel的setvalue刷新数据,就可以自动刷新

外部获取自定义view的宽高

不能直接获取,view没有进行onmeasure方法获取到是0,有两种方法

——自己调用view的onmeasure测量

——需要设置一个监听,View.ViewTreeObserver.addGlobalLayoutLinstener在这个回调里获取宽高

hashcode

hashcode是用对象的字段算出来的一个数字,用来比较两个对象是否相等,但是他需要和 equals一起使用,当hashcode相等的时候比较equals,这样比较更高效 当hashcode相等时两个对象不一定相等

StringBuffer和StringBuilder

stringbuffer是线程安全,stringbuilder不能多线程访问,但是stringbuilder速度更快,另外string因为每次都是新建对象,所以string也是线程安全

接口的意义

接口主要为了弥补类不能实现多继承的缺点,有了接口一个类可以实现多个接口的操作

内部类,静态内部类,局部内部类

内部类可以隐藏一些外部类的变量和方法,不让调用者知道

静态内部类不依赖外部对象,但是可以指向表达一种从属关系

局部类只是在方法里面使用

设计模式

  • 单例模式
  • 工厂模式(工厂方法,抽象工厂)
  • 策略模式
  • 代理模式 (动态代理静态代理)
  • 观察者模式
  • 责任链模式

模块化组件化与插件化和热修复

模块化是把基础业务分成一个模块,其他业务引用基础业务,这些模块都在同一个工程
组件化是指一个app有多个module,每个module负责一部分业务,每个业务组件可以单独打包也可以做依赖库,最后打包成为一个apk,
插件化是指一个项目分为一个宿主和多个插件,每个插件是一个apk,最后这个宿主app加载多个apk,可以实现动态加载
热修复是指为一个业务或者一个class单独进行加载,已达到修复bug的目的

排序算法

  • 冒泡排序
int a = [2,1,5,9,5]
int temp = 0;
for (int i = 0; i < a.length-1; i++) {
    for (int j = 0;j < a.length-1-i; j++) {
        if (a[j] > a[j+1]) {
            temp = a[j];
            a[j] = a[j+1];
            a[j+1] = temp;
        }
    }
}

原理,像挤跑跑一样,一个一个挤出来,第二层for循环每一次选出一个最大值,外面一层for循环控制第二层循环的排序范围

  • 选择排序


    image.png

    总结,就是把里面的循环每次找到一个最小值,外面的循环控制轮询范围

glide 和 Picasso的选择

特性 glide Picasso
gif加载 支持gif加载 不支持
生命周期 支持 不支持
内存 根据image尺寸 full 尺寸
加载时间 慢-先改变尺寸 快-直接加载到内存

图片加载时,传入Context对象或者fragment对象,glide会生成一个无UI的fragment,因为glide无法从传入的context中获取生命周期 通过这个fragment可以拿到传入context相同的生命周期,从而实现了对生命周期变化做出相同的暂停和销毁操作

总结:小项目用Picasso,功能简单,加载速度快,大项目用glide,功能配置丰富,对内存优化比较好,对于内存方面,glide会对不同尺寸的图片缓存多份缓存,
而Picasso都是同一份缓存,根据尺寸要求在内存中进行resize,所以下载速度Picasso>glide,内存加载速度glide> Picasso

activity启动过程

首先从点击桌面图标开始,launcher进程通过binder ipc向system service发起通信startActivity,system service进程的AMS(activity manager service)会判断app进程是否已经创建,若没有创建则通过binder ipc向zygote通信fork app进程, app进程会通过ipc向ams 发起通信 请求attachapplication 和得到schedulelancheractivity请求然后和主线程通信,主线程开始调用activity oncreate app正式启动

协成

什么是协成

协成是轻量级线程,建立在线程之上,和线程的区别就是它不会阻塞任务,而是挂起任务,当一个任务出现阻塞的时候这个线程会被挂起,挂起之后这个线程还可以去执行其他任务,而这个任务阻塞结束后又会被线程执行,相当于是把线程进行分段,相当于用最少的线程做更多的事情,节约资源,协成的另外一个好处就是它的调用是同步的,不需要回调函数,只需要return回结果,看上去更简洁易懂

如何开启协成
  • launch
private suspend fun getWebTime(): Long {
    var result = RequeastTest.getInstance().start()
    val name = Thread.currentThread().name
    if (!coroutines.contains(name)) {
        coroutines.add(name)
    }
    return result
}

launch() {
    //do sth
    var time = withContext(Dispather.IO){
        getWebTime()
    }
    //update UI
    
}

launch 返回的是job对象 只能控制协成状态,不能返回数据结构,异步方法需要用suspend修饰

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 157,198评论 4 359
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 66,663评论 1 290
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 106,985评论 0 237
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,673评论 0 202
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 51,994评论 3 285
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,399评论 1 211
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,717评论 2 310
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,407评论 0 194
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,112评论 1 239
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,371评论 2 241
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,891评论 1 256
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,255评论 2 250
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,881评论 3 233
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,010评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,764评论 0 192
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,412评论 2 269
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,299评论 2 260

推荐阅读更多精彩内容