面试总结Android

下面是啊最近几次面试总结:
面试分类为三个方面

  • android相关
  • java相关
  • 其他

Android相关

1.四大组件及其生命周期?

2.Activity个情况下的生命周期及之间的通信?

1.a启动b,后退键再到a的生命周期流程:a.create→a.start→a.resume→a.pause→b.create→b.start→b.resume→b界面绘制→a.stop→b.pause→b.stop→b.destroy→a.restart→a.start→a.resume
2.意外销毁会调用saveInstance,重新恢复的时候回调用restoreInstance。储存数据的时候使用了委托机制,从activity→window→viewGroup→view 会递归调用save来保持本view的数据,restore则是递归恢复本view数据。我们可以在里面做一些自己需要的数据操作。

3.各种操作下Activity的生命周期变化?
`下拉状态栏是不是影响activity的生命周期?

4.Activity的启动模式?

1.standard:默认标准模式,每启动一个都会创建一个实例,
2.singleTop:栈顶复用,如果在栈顶就调用onNewIntent复用,从onResume()开始
3.singleTask:栈内复用,本栈内只要用该类型Activity就会将其顶部的activity出栈
4.singleInstance:单例模式,除了3中特性,系统会单独给该Activity创建一个栈。

A、B、C、D分别是四种Activity的启动模式,那么A->B->C->D->A->B->C->D分别启动,最后的activity栈是怎么样的?
答案是:两个栈,前台栈是只有D,后台栈从底至上是A、B、C

5.Fragment的生命周期及个情况下的变化?

6.Fragment之间的通信?

7.Fragment与Activity生命周期对比?

8.如何实现Fragment的滑动?

9.Activity怎么和Service绑定?

10.Service的启动方式及生命周期?
Q1.IntentService原理及作用是什么?
Q2.说说Activity、Intent、Service 是什么关系?
Q3.ApplicationContext和ActivityContext的区别?
Q4.AndroidService与Activity之间通信的几种方式?

1.context.startService() ->onCreate()- >onStart()->Service running→(如果调用context.stopService() )->onDestroy() ->Service shut down
    1.如果Service还没有运行,则调用onCreate()然后调用onStart();
    2.如果Service已经运行,则只调用onStart(),所以一个Service的onStart方法可能会重复调用多次。
    3.调用stopService的时候直接onDestroy,
    4.如果是调用者自己直接退出而没有调用stopService的话,Service会一直在后台运行。该Service的调用者再启动起来后可以通过stopService关闭Service。
2.context.bindService()->onCreate()->onBind()->Service running→onUnbind() -> onDestroy() ->Service stop
    1.onBind将返回给客户端一个IBind接口实例,IBind允许客户端回调服务的方法,比如得到Service运行的状态或其他操作。
    2.这个时候会把调用者和Service绑定在一起,Context退出了,Service就会调用onUnbind->onDestroy相应退出。
    3.所以调用bindService的生命周期为:onCreate → onBind(只一次,不可多次绑定) → onUnbind → onDestory。

怎么保证service不被杀死?
1.提升service优先级
2.提升service进程优先级
3.onDestroy方法里重启service

IntentService是什么?
    含有HandlerThread的Service,可以多次startService()来多次在子线程中进行 onHandlerIntent()的调用。

11.广播分类,使用方式及场景?
1.在manifest 和代码中如何注册和使用BroadcastReceiver?
2.本地广播和全局广播有什么差别?
3.BroadcastReceiver,LocalBroadcastReceiver 区别?



静态的Broadcast 和动态的有什么区别?
1.动态的比静态的安全
2.静态在app启动的时候就初始化了 动态使用代码初始化
3.静态需要配置 动态不需要
4.生存期,静态广播的生存期可以比动态广播的长很多
5.优先级动态广播的优先级比静态广播高

12.ContentProvider的理解,说说ContentProvider、ContentResolver、ContentObserver 之间的关系?

13.Handler机制和底层实现,对比Handler、Thread和HandlerThread的差别

1.MessageQueue:读取会自动删除消息,单链表维护,在插入和删除上有优势。在其next()中会无限循环,不断判断是否有消息,有就返回这条消息并移除。
2.Looper:Looper创建的时候会创建一个MessageQueue,调用loop()方法的时候消息循环开始,loop()也是一个死循环,会不断调用messageQueue的next(),当有消息就处理,否则阻塞在messageQueue的next()中。当Looper的quit()被调用的时候会调用messageQueue的quit(),此时next()会返回null,然后loop()方法也跟着退出。
3.Handler:在主线程构造一个Handler,然后在其他线程调用sendMessage(),此时主线程的MessageQueue中会插入一条message,然后被Looper使用。
4.系统的主线程在ActivityThread的main()为入口开启主线程,其中定义了内部类Activity.H定义了一系列消息类型,包含四大组件的启动停止。
5.MessageQueue和Looper是一对一关系,Handler和Looper是多对一

java的线程如何实现
1.Thread继承
2.Runnale
3.Future
4.线程池

@Looper架构及ActivityTrhead,AMS,WMS的工作区别?

HandlerThread是:MessageQueue + Looper + Handler

14.View的绘制过程,刷新机制,自定义控件原理?
@自定义view的机型适配
@Requestlayout,onlayout,onDraw,DrawChild区别与联系
@invalidate和postInvalidate的区别及使用

1.ViewRootImpl会调用performTraversals(),其内部会调用performMeasure()、performLayout、performDraw()。
2.performMeasure()会调用最外层的ViewGroup的measure()→onMeasure(),ViewGroup的onMeasure()是抽象方法,但其提供了measureChildren(),这之中会遍历子View然后循环调用measureChild()这之中会用getChildMeasureSpec()+父View的MeasureSpec+子View的LayoutParam一起获取本View的MeasureSpec,然后调用子View的measure()到View的onMeasure()→setMeasureDimension(getDefaultSize(),getDefaultSize()),getDefaultSize()默认返回measureSpec的测量数值,所以继承View进行自定义的wrap_content需要重写。
3.performLayout()会调用最外层的ViewGroup的layout(l,t,r,b),本View在其中使用setFrame()设置本View的四个顶点位置。在onLayout(抽象方法)中确定子View的位置,如LinearLayout会遍历子View,循环调用setChildFrame()→子View.layout()。
4.performDraw()会调用最外层ViewGroup的draw():其中会先后调用background.draw()(绘制背景)、onDraw()(绘制自己)、dispatchDraw()(绘制子View)、onDrawScrollBars()(绘制装饰)。
5.MeasureSpec由2位SpecMode(UNSPECIFIED、EXACTLY(对应精确值和match_parent)、AT_MOST(对应warp_content))和30位SpecSize组成一个int,DecorView的MeasureSpec由窗口大小和其LayoutParams决定,其他View由父View的MeasureSpec和本View的LayoutParams决定。ViewGroup中有getChildMeasureSpec()来获取子View的MeasureSpec。
6.三种方式获取measure()后的宽高:
    1.Activity#onWindowFocusChange()中调用获取
    2.view.post(Runnable)将获取的代码投递到消息队列的尾部。
    3.ViewTreeObservable.

15.Android Touch事件分发机制 流程?

image.png

16.AsyncTask机制,AsyncTask原理及不足,如何取消AsyncTask?

17.为什么不能在子线程更新UI?ANR产生的原因是什么?

过度绘制、卡顿优化:

1.过度绘制:
1.移除Window默认的Background:getWidow.setBackgroundDrawable(null);
2.移除XML布局文件中非必需的Background
3.减少布局嵌套(扁平化的一个体现,减少View数的深度,也就减少了View树的遍历时间,渲染的时候,前后期的工作,总是按View树结点来)
4.在引入布局文件里面,最外层可以用merge替代LinearLayout,RelativeLayout,这样把子UI元素直接衔接在include位置
5.工具:HierarchyViewer 查看视图层级
2.卡顿优化:16ms数据更新

ANR产生的原因是什么?
1.只要是主线程耗时的操作就会ARN  如io
2.broadcast超时时间为10秒  按键无响应的超时时间为5秒 前台service无响应的超时时间为20秒,后台service为200秒

18.OOM是什么?什么情况导致OOM?有什么解决避免OOM?
Oom 是否可以try catch?为什么?

1.其他线程持有一个Listener,Listener操作activity。那么在线程么有完毕的时候,activity关闭了,原本是要被回收的但是,不能被回收。
2.例如Handler导致的内存泄漏,Handler就相当于Listener。
3.在activity关闭的时候注意停止线程,或者将Listener的注册取消
3.使用弱引用,这样即使Listener持有了activity,在GC的时候还是会被回收
4.工具:LeakCanary

19.动态布局的理解?

20.Android动画?

1.动画的基本原理:其实就是利用插值器和估值器,来计算出各个时刻View的属性,然后通过改变View的属性来,实现View的动画效果。
2.View动画:只是影像变化,view的实际位置还在原来的地方。
3.帧动画是在xml中定义好一系列图片之后,使用AnimationDrawable来播放的动画。
4.View的属性动画:
1.插值器:作用是根据时间的流逝的百分比来计算属性改变的百分比
2.估值器:在1的基础上由这个东西来计算出属性到底变化了多少数值的类

21.Android个版本之间的差异,低版本SDK如何使用高版本的API?

22.描述一次网络请求的流程,HttpUrlConnection 和 okhttp关系?

实现一个网络框架(参考Volley)?
1.缓存队列,以url为key缓存内容可以参考Bitmap的处理方式,这里单独开启一个线程。
2.网络请求队列,使用线程池进行请求。
3.提供各种不同类型的返回值的解析如String,Json,图片等等。

Q1 AstncTask+HttpClient 与 AsyncHttpClient有什么区别?
Q2 谈谈对Volley的理解

23.Intente与Bundle


bundle
1.键值对储存
2.传递的数据可以是boolean、byte、int、long、float、double、string等基本类型或它们对应的数组,也可以是对象或对象数组。
3.当Bundle传递的是对象或对象数组时,必须实现Serializable 或Parcelable接口

23.TCP与UDP的区别?TCP与UDP的应用?

如何设计在 UDP 上层保证 UDP 的可靠性传输?
1.简单来讲,要使用UDP来构建可靠的面向连接的数据传输,就要实现类似于TCP协议的超时重传,有序接受,应答确认,滑动窗口流量控制等机制,等于说要在传输层的上一层(或者直接在应用层)实现TCP协议的可靠数据传输机制。
2.比如使用UDP数据包+序列号,UDP数据包+时间戳等方法,在服务器端进行应答确认机制,这样就会保证不可靠的UDP协议进行可靠的数据传输。
3.基于udp的可靠传输协议有:RUDP、RTP、UDT

24.对Bitmap的理解,针对图片的优化?

1.当使用ImageView的时候,可能图片的像素大于ImageView,此时就可以通过BitmapFactory.Option来对图片进行压缩,inSampleSize表示缩小2^(inSampleSize-1)倍。
2.BitMap的缓存:
1.使用LruCache进行内存缓存。
2.使用DiskLruCache进行硬盘缓存。
3.实现一个ImageLoader的流程:同步异步加载、图片压缩、内存硬盘缓存、网络拉取
1.同步加载只创建一个线程然后按照顺序进行图片加载
2.异步加载使用线程池,让存在的加载任务都处于不同线程
3.为了不开启过多的异步任务,只在列表静止的时候开启图片加载

25.Activity-Window-View三者的差别?

Q0.LaunchMode应用场景?

Q1.Activity栈?
···

Activity缓存方法
1.配置改变导致Activity被杀死,横屏变竖屏:在onStop之前会调用onSaveInstanceState()保存数据在重建Activity之后,会在onStart()之后调用onRestoreInstanceState(),并把保存下来的Bundle传给onCreate()和它会默认重建Activity当前的视图,我们可以在onCreate()中,回复自己的数据。
2.内存不足杀掉Activity,优先级分别是:前台可见,可见非前台,后台。
怎样退出终止App?
1.自己设置一个Activity的栈,然后一个个finish()
···
Q0.SP是进程同步的吗?有什么方法做到同步?

Q2.AndroidManifest的作用与理解?

Q2.Android重要术语解释

1.ActivityManagerServices,简称AMS,服务端对象,负责系统中所有Activity的生命周期
2.ActivityThread,App的真正入口。当开启App之后,会调用main()开始运行,开启消息循环队列,这就是传说中的UI线程或者叫主线程。与ActivityManagerServices配合,一起完成Activity的管理工作
3.ApplicationThread,用来实现ActivityManagerService与ActivityThread之间的交互。在ActivityManagerService需要管理相关Application中的Activity的生命周期时,通过ApplicationThread的代理对象与ActivityThread通讯。
4.ApplicationThreadProxy,是ApplicationThread在服务器端的代理,负责和客户端的ApplicationThread通讯。AMS就是通过该代理与ActivityThread进行通信的。
5.Instrumentation,每一个应用程序只有一个Instrumentation对象,每个Activity内都有一个对该对象的引用。Instrumentation可以理解为应用进程的管家,ActivityThread要创建或暂停某个Activity时,都需要通过Instrumentation来进行具体的操作。
6.ActivityStack,Activity在AMS的栈管理,用来记录已经启动的Activity的先后关系,状态信息等。通过ActivityStack决定是否需要启动新的进程。
7.ActivityRecord,ActivityStack的管理对象,每个Activity在AMS对应一个ActivityRecord,来记录Activity的状态以及其他的管理信息。其实就是服务器端的Activity对象的映像。
8.TaskRecord,AMS抽象出来的一个“任务”的概念,是记录ActivityRecord的栈,一个“Task”包含若干个ActivityRecord。AMS用TaskRecord确保Activity启动和退出的顺序。如果你清楚Activity的4种launchMode,那么对这个概念应该不陌生。

Q2.简述IPC?

1.ipc通信方式:binder、contentprovider、socket
2.操作系统进程通讯方式:共享内存、socket、管道

1.在Activity和Service进行通讯的时候,用到了Binder。
1.当属于同个进程我们可以继承Binder然后在Activity中对Service进行操作
2.当不属于同个进程,那么要用到AIDL让系统给我们创建一个Binder,然后在Activity中对远端的Service进行操作。
2.系统给我们生成的Binder:
1.Stub类中有:接口方法的id,有该Binder的标识,有asInterface(IBinder)(让我们在Activity中获取实现了Binder的接口,接口的实现在Service里,同进程时候返回Stub否则返回Proxy),有onTransact()这个方法是在不同进程的时候让Proxy在Activity进行远端调用实现Activity操作Service
2.Proxy类是代理,在Activity端,其中有:IBinder mRemote(这就是远端的Binder),两个接口的实现方法不过是代理最终还是要在远端的onTransact()中进行实际操作。

3.哪一端的Binder是副本,该端就可以被另一端进行操作,因为Binder本体在定义的时候可以操作本端的东西。所以可以在Activity端传入本端的Binder,让Service端对其进行操作称为Listener,可以用RemoteCallbackList这个容器来装Listener,防止Listener因为经历过序列化而产生的问题。
4.当Activity端向远端进行调用的时候,当前线程会挂起,当方法处理完毕才会唤醒。
5.如果一个AIDL就用一个Service太奢侈,所以可以使用Binder池的方式,建立一个AIDL其中的方法是返回IBinder,然后根据方法中传入的参数返回具体的AIDL。
6.IPC的方式有:Bundle(在Intent启动的时候传入,不过是一次性的),文件共享(对于SharedPreference是特例,因为其在内存中会有缓存),使用Messenger(其底层用的也是AIDL,同理要操作哪端,就在哪端定义Messenger),AIDL,ContentProvider(在本进程中继承实现一个ContentProvider,在增删改查方法中调用本进程的SQLite,在其他进程中查询),Socket

Q3.描述一次跨进程通讯

1.client、proxy、serviceManager、BinderDriver、impl、service
2.client发起一个请求service信息的Binder请求到BinderDriver中,serviceManager发现BinderDiriver中有自己的请求 然后将clinet请求的service的数据返回给client这样完成了一次Binder通讯
3.clinet获取的service信息就是该service的proxy,此时调用proxy的方法,proxy将请求发送到BinderDriver中,此时service的 Binder线程池循环发现有自己的请求,然后用impl就处理这个请求最后返回,这样完成了第二次Binder通讯
4.中间client可挂起,也可以不挂起,有一个关键字oneway可以解决这个

Q3.什么是AIDL?

Q4.AIDL解决了什么问题?

Q5.AIDL如何使用?

Q6.线程池?Android线程有没有上限?线程池有没有上限?

1.Asynctask:异步任务类,单线程线程池+Handler
2.线程池:
1.ThreadPoolExecutor:通过Executors可以构造单线程池、固定数目线程池、不固定数目线程池。
2.ScheduledThreadPoolExecutor:可以延时调用线程或者延时重复调度线程。

Q6.线程同步的问题,常用的线程同步?

1.sycn:保证了原子性、可见性、有序性
2.锁:保证了原子性、可见性、有序性
1.自旋锁:可以使线程在没有取得锁的时候,不被挂起,而转去执行一个空循环。
1.优点:线程被挂起的几率减少,线程执行的连贯性加强。用于对于锁竞争不是很激烈,锁占用时间很短的并发线程。
2.缺点:过多浪费CPU时间,有一个线程连续两次试图获得自旋锁引起死锁
2.阻塞锁:没得到锁的线程等待或者挂起,Sycn、Lock
3.可重入锁:一个线程可多次获取该锁,Sycn、Lock
4.悲观锁:每次去拿数据的时候都认为别人会修改,所以会阻塞全部其他线程 Sycn、Lock
5.乐观锁:每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据,可以使用版本号等机制。cas
6.显示锁和内置锁:显示锁用Lock来定义、内置锁用synchronized。
7.读-写锁:为了提高性能,Java提供了读
3.volatile
1.只能保证可见性,不能保证原子性
2.自增操作有三步,此时多线程写会出现问题
4.cas
1.操作:内存值V、旧的预期值A、要修改的值B,当且仅当预期值A和内存值V相同时,将内存值修改为B并返回true,否则什么都不做并返回false。
2.解释:本地副本为A,共享内存为V,线程A要把V修改成B。某个时刻线程A要把V修改成B,如果A和V不同那么就表示有其他线程在修改V,此时就表示修改失败,否则表示没有其他线程修改,那么把V改成B。
3.局限:如果V被修改成V1然后又被改成V,此时cas识别不出变化,还是认为没有其他线程在修改V,此时就会有问题
4.局限解决:将V带上版本。
5.线程不安全到底是怎么回事:
1.一个线程写,多个线程读的时候,会造成写了一半就去读
2.多线程写,会造成脏数据

Q7.多进程场景遇见过么?

Q8.Android进程分类?

Q9.进程和 Application 的生命周期?

Q10进程调度?

Q11.谈谈对进程共享和线程安全的认识

Q12.谈谈对多进程开发的理解以及多进程应用场景

Q13.什么是协程?

Q13.操作系统进程和线程的区别?

1.简而言之,一个程序至少有一个进程,一个进程至少有一个线程.
2.线程的划分尺度小于进程,使得多线程程序的并发性高。
3.另外,进程在执行过程中拥有独立的内存单元,而多个线程共享内存,从而极大地提高了程序的运行效率。
4.多线程的意义在于一个应用程序中,有多个执行部分可以同时执行。有将多个线程看做多个独立的应用,来实现进程的调度和管理以及资源分配

Q14.自定义View如何提供获取View属性的接口?

Q15.介绍下SurfView?

Q15.RecycleView的使用及与ListView的区别?

Q15.LruCache默认缓存大小?

Q16.ContentProvider的权限管理(解答:读写分离,权限控制-精确到表级,URL控制)

Q17.Android为什么引入Parcelable?

Q18.ListView 中图片错位的问题是如何产生的?

Q19.屏幕适配的处理技巧都有哪些?

Q20.怎么去除重复代码?

Q21.Android中开启摄像头的主要步骤?

Q22.HTTP1.0与2.0的区别?HTTP与HTTPS的区别以及如何实现安全性?

1.ARP协议:在IP以太网中,当一个上层协议要发包时,有了该节点的IP地址,ARP就能提供该节点的MAC地址。
HTTP HTTPS的区别:
1.HTTPS使用TLS(SSL)进行加密
2.HTTPS缺省工作在TCP协议443端口
3.它的工作流程一般如以下方式:
1.完成TCP三次同步握手
2.客户端验证服务器数字证书,通过,进入步骤3
3.DH算法协商对称加密算法的密钥、hash算法的密钥
4.SSL安全加密隧道协商完成
5.网页以加密的方式传输,用协商的对称加密算法和密钥加密,保证数据机密性;用协商的hash算法进行数据完整性保护,保证数据不被篡改
3.http请求包结构,http返回码的分类,400和500的区别
1.请求:请求行、头部、数据
2.返回:状态行、头部、数据
1.包结构:
2.http返回码分类:1到5分别是,消息、成功、重定向、客户端错误、服务端错误
4.Tcp
1.fin-c = x , 表示现在需要关闭c到s了。ack-c = y,表示上一条s的消息已经接收完毕
2.ack-s = x + 1,表示需要关闭的fin-c消息已经接收到了,同意关闭
3.fin-s = y + 1,表示s已经准备好关闭了,就等c的最后一条命令
4.ack-c = y + 1,表示c已经关闭,让s也关闭
1.三次握手:防止了服务器端的一直等待而浪费资源,例如只是两次握手,如果s确认之后c就掉线了,那么s就会浪费资源
1.syn-c = x,表示这消息是x序号
2.ack-s = x + 1,表示syn-c这个消息接收成功。syn-s = y,表示这消息是y序号。
3.ack-c = y + 1,表示syn-s这条消息接收成功
1.可靠连接,三次握手,四次挥手
2.四次挥手:TCP是全双工模式
3.滑动窗口,停止等待、后退N、选择重传
4.拥塞控制,慢启动、拥塞避免、加速递减、快重传快恢复

TCP与UDP区别总结:
1、TCP面向连接(如打电话要先拨号建立连接);UDP是无连接的,即发送数据之前不需要建立连接
2、TCP提供可靠的服务。也就是说,通过TCP连接传送的数据,无差错,不丢失,不重复,且按序到达;UDP尽最大努力交付,即不保   证可靠交付
3、TCP面向字节流,实际上是TCP把数据看成一连串无结构的字节流;UDP是面向报文的
  UDP没有拥塞控制,因此网络出现拥塞不会使源主机的发送速率降低(对实时应用很有用,如IP电话,实时视频会议等)
4、每一条TCP连接只能是点到点的;UDP支持一对一,一对多,多对一和多对多的交互通信
5、TCP首部开销20字节;UDP的首部开销小,只有8个字节
6、TCP的逻辑通信信道是全双工的可靠信道,UDP则是不可靠信道

Q23.谈谈你对WebSocket的理解?WebSocket与socket的区别?

Q24.谈谈你对安卓签名的理解。请解释安卓为啥要加签名机制?

Q25.App 是如何沙箱化,为什么要这么做?

Q26.谈谈对java状态机理解

Q27.Fragment如果在Adapter中使用应该如何解耦?

Q28.Binder机制及底层实现

Q29.对于应用更新这块是如何做的?(解答:灰度,强制更新,分区域更新)?

Q30.AlertDialog,popupWindow,Activity区别?

1.Window用于显示View和接收各种事件,Window有三种类型:应用Window(每个Activity对应一个Window)、子Window(不能单独存在,附属于特定Window)、系统window(Toast和状态栏)
2.Window分层级,应用Window在1-99、子Window在1000-1999、系统Window在2000-2999.WindowManager提供了增删改View三个功能。
3.Window是个抽象概念:每一个Window对应着一个View和ViewRootImpl,Window通过ViewRootImpl来和View建立联系,View是Window存在的实体,只能通过WindowManager来访问Window。
4.WindowManager的实现是WindowManagerImpl其再委托给WindowManagerGlobal来对Window进行操作,其中有四个List分别储存对应的View、ViewRootImpl、WindowManger.LayoutParams和正在被删除的View
5.Window的实体是存在于远端的WindowMangerService中,所以增删改Window在本端是修改上面的几个List然后通过ViewRootImpl重绘View,通过WindowSession(每个应用一个)在远端修改Window。
6.Activity创建Window:Activity会在attach()中创建Window并设置其回调(onAttachedToWindow()、dispatchTouchEvent()),Activity的Window是由Policy类创建PhoneWindow实现的。然后通过Activity#setContentView()调用PhoneWindow的setContentView。

Q31.Application 和 Activity 的 Context 对象的区别?

Q32.如何导入外部数据库?
Q33.LinearLayout、RelativeLayout、FrameLayout的特性及对比,并介绍使用场景。?
Q34.回调的原理并谈谈对接口与回调的理解?

序列化的作用,以及Android两种序列化的区别?
差值器
估值器
Android中数据存储方式?

(三)数据库
sqlite升级,增加字段的语句
数据库框架对比和源码分析
数据库的优化
数据库数据迁移问题

(四)算法
排序算法有哪些?
最快的排序算法是哪个?
手写一个冒泡排序
手写快速排序代码
快速排序的过程、时间复杂度、空间复杂度
堆排序过程、时间复杂度及空间复杂度
写出你所知道的排序算法及时空复杂度,稳定性
二叉树给出根节点和目标节点,找出从根节点到目标节点的路径
给阿里2万多名员工按年龄排序应该选择哪个算法?
GC算法(各种算法的优缺点以及应用场景)?

1.搜索算法:
    1.引用计数
    2.图搜索,可达性分析
2.回收算法:
    1.标记清除复制:用于青年代
    2.标记整理:用于老年代
3.堆分区:
    1.青年区eden 80%、survivor1 10%、survivor2 10%
    2.老年区
4.虚拟机栈分区:
    1.局部变量表
    2.操作数栈
    3.动态链接
    4.方法返回地址
5.GC Roots:
    1.虚拟机栈(栈桢中的本地变量表)中的引用的对象
    2.方法区中的类静态属性引用的对象
    3.方法区中的常量引用的对象
    4.本地方法栈中JNI的引用的对象

蚁群算法与蒙特卡洛算法
子串包含问题(KMP 算法)写代码实现
一个无序,不重复数组,输出N个元素,使得N个元素的和相加为M,给出时间复杂度、空间复杂度。手写算法
(五)插件化、模块化、组件化、热修复、增量更新、Gradle

对热修复和插件化的理解
插件化原理分析
模块化实现(好处,原因)
热修复,插件化?

热修复:Andfix为例子

1.大致原理:apkpatch将两个apk做一次对比,然后找出不同的部分。可以看到生成的apatch了文件,后缀改成zip再解压开,里面有一个dex文件。通过jadx查看一下源码,里面就是被修复的代码所在的类文件,这些更改过的类都加上了一个_CF的后缀,并且变动的方法都被加上了一个叫@MethodReplace的annotation,通过clazz和method指定了需要替换的方法。然后客户端sdk得到补丁文件后就会根据annotation来寻找需要替换的方法。最后由JNI层完成方法的替换。
2.无法添加新类和新的字段、补丁文件很容易被反编译、加固平台可能会使热补丁功能失效

插件化框架描述:dynamicLoadApk为例子
1.可以通过DexClassLoader来对apk中的dex包进行加载访问
2.如何加载资源是个很大的问题,因为宿主程序中并没有apk中的资源,所以调用R资源会报错,所以这里使用了Activity中的实现ContextImpl的getAssets()和getResources()再加上反射来实现。
3.由于系统启动Activity有很多初始化动作要做,而我们手动反射很难完成,所以可以采用接口机制,将Activity的大部分生命周期提取成接口,然后通过代理Activity去调用插件Activity的生命周期。同时如果像增加一个新生命周期方法的时候,只需要在接口中和代理中声明一下就行。
4.缺点:
1.慎用this,因为在apk中使用this并不代表宿主中的activity,当然如果this只是表示自己的接口还是可以的。除此之外可以使用that代替this。
2.不支持Service和静态注册的Broadcast
3.不支持LaunchMode和Apk中Activity的隐式调用。

项目组件化的理解
描述清点击 Android Studio 的 build 按钮后发生了什么
(六)架构设计和设计模式

谈谈你对Android设计模式的理解
MVC MVP MVVM原理和区别
你所知道的设计模式有哪些?
谈谈对RxJava的理解
RxJava的功能与原理实现
RxJava的作用,与平时使用的异步操作来比的优缺点
说说EventBus作用,实现方式,代替EventBus的方式
Retrofit的了解?

1.动态代理创建一个接口的代理类
2.通过反射解析每个接口的注解、入参构造http请求
3.获取到返回的http请求,使用Adapter解析成需要的返回值。

从0设计一款App整体架构,如何去做?
(七)性能优化

如何对Android 应用进行性能分析以及优化?
ddms 和 traceView
性能优化如何分析systrace?
用IDE如何分析内存泄漏?
Java多线程引发的性能问题,怎么解决?
启动页白屏及黑屏解决?
启动太慢怎么解决?

(八)NDK、jni、Binder、AIDL、进程通信有关

请介绍一下NDK
什么是NDK库?
jni用过吗?
如何在jni中注册native函数,有几种注册方式?
Java如何调用c、c++语言?
jni如何调用java层代码?

(九)framework层、ROM定制、Ubuntu、Linux之类的问题

java虚拟机的特性
谈谈对jvm的理解
JVM内存区域,开线程影响哪块内存
对Dalvik、ART虚拟机有什么了解?
Art和Dalvik对比
虚拟机原理,如何自己设计一个虚拟机(内存管理,类加载,双亲委派)
谈谈你对双亲委派模型理解
JVM内存模型,内存区域
Java类加载机制?

1.加载时机:创建实例、访问静态变量或方法、反射、加载子类之前
2.验证:验证文件格式、元数据、字节码、符号引用的正确性
3.加载:根据全类名获取文件字节流、将字节流转化为静态储存结构放入方法区、生成class对象
4.准备:在堆上为静态变量划分内存
5.解析:将常量池中的符号引用转换为直接引用
6.初始化:初始化静态变量
7.书籍推荐:深入理解java虚拟机,博客推荐:Java/Android阿里面试JVM部分理解

谈谈对ClassLoader(类加载器)的理解?

1.双亲委托:一个ClassLoader类负责加载这个类所涉及的所有类,在加载的时候会判断该类是否已经被加载过,然后会递归去他父ClassLoader中找。
2.可以动态加载Jar通过URLClassLoader
3.ClassLoader 隔离问题 JVM识别一个类是由:ClassLoader id+PackageName+ClassName。
4.加载不同Jar包中的公共类:
1.让父ClassLoader加载公共的Jar,子ClassLoader加载包含公共Jar的Jar,此时子ClassLoader在加载公共Jar的时候会先去父ClassLoader中找。(只适用Java)
2.重写加载包含公共Jar的Jar的ClassLoader,在loadClass中找到已经加载过公共Jar的ClassLoader,也就是把父ClassLoader替换掉。(只适用Java)
3.在生成包含公共Jar的Jar时候把公共Jar去掉。

谈谈对动态加载(OSGI)的理解
内存对象的循环引用及避免
内存回收机制、GC回收策略、GC原理时机以及GC对象
垃圾回收机制与调用System.gc()区别
系统启动流程是什么?(提示:Zygote进程 –> SystemServer进程 –> 各种系统服务 –> 应用进程)
大体说清一个应用程序安装到手机上时发生了什么
简述Activity启动全部过程
App启动流程,从点击桌面开始
逻辑地址与物理地址,为什么使用逻辑地址?
Android为每个应用程序分配的内存大小是多少?
Android中进程内存的分配,能不能自己分配定额内存?
进程保活的方式
如何保证一个后台服务不被杀死?(相同问题:如何保证service在后台不被kill?)比较省电的方式是什么?
App中唤醒其他进程的实现方式
Q29.APK打包流程和其内容

1.流程
   1.aapt生成R文件
    2.aidl生成java文件
    3.将全部java文件编译成class文件
    4.将全部class文件和第三方包合并成dex文件
    5.将资源、so文件、dex文件整合成apk
    6.apk签名
    7.apk字节对齐
2.内容:so、dex、asset、资源文件

apk瘦身:
1.classes.dex:通过代码混淆,删掉不必要的jar包和代码实现该文件的优化
2.资源文件:通过Lint工具扫描代码中没有使用到的静态资源
3.图片资源:使用tinypng和webP,下面详细介绍图片资源优化的方案,矢量图
4.SO文件将不用的去掉,目前主流app一般只放一个arm的so包

@.Sharedpreferences源码简述

1.储存于硬盘上的xml键值对,数据多了会有性能问题
2.ContextImpl记录着SharedPreferences的重要数据,文件路径和实例的键值对
3.在xml文件全部内加载到内存中之前,读取操作是阻塞的,在xml文件全部内加载到内存中之后,是直接读取内存中的数据
4.apply因为是异步的没有返回值, commit是同步的有返回值能知道修改是否提交成功
5.多并发的提交commit时,需等待正在处理的commit数据更新到磁盘文件后才会继续往下执行,从而降低效率; 而apply只是原子更新到内存,后调用apply函数会直接覆盖前面内存数据,从一定程度上提高很多效率。 3.edit()每次都是创建新的EditorImpl对象.

58.浏览器输入地址到返回结果发生了什么

1.DNS解析
2.TCP连接
3.发送HTTP请求
4.服务器处理请求并返回HTTP报文
5.浏览器解析渲染页面
6.连接结束

59.java泛型类型擦除发生在什么时候,通配符有什么需要注意的。

1.发生在编译的时候
2.PECS,extends善于提供精确的对象 A是B的子集,Super善于插入精确的对象 A是B的超集
3.博客推荐:Effective Java笔记(不含反序列化、并发、注解和枚举)、android阿里面试java基础锦集

61.面试常考的算法

1.快排、堆排序为首的各种排序算法
2.链表的各种操作:判断成环、判断相交、合并链表、倒数K个节点、寻找成环节点
3.二叉树、红黑树、B树定义以及时间复杂度计算方式
4.动态规划、贪心算法、简单的图论
5.推荐书籍:算法导论,将图论之前的例子写一遍
62.Launcher进程启动另外一个进程的过程:启动一个app

63.开源框架源码

1.Fresco
1.mvc框架:
1.Controller控制数据显示在Hierarchy中的Drawable的显隐
2.ImagePipeline在Controller中负责进行数据获取,返回的数据是CloseableImage
3.Drawee把除了初始化之外的操作全部交给Holder去做,Holder持有Controller和Hierarchy
2.Drawable层次以及绘制:
1.如果要绘制一次Drawable就调用invalidateSelf()来触发onDraw()
2.Drawable分为:容器类(保存一些Drawable)、自我绘制类(进度条)、图形变换类(scale、rotate、矩阵变换)、动画类(内部不断刷新,进行webp和gif的帧绘制)
3.ImagePipeline返回的CloseableImage是由一个个DrawableFactory解析成Drawable的
4.webp和gif动画是由jni代码解析的,然后其他静态图片是根据不同的android平台使用BitmapFactory来解析的
3.职责链模式:producer不做操作标n,表示只是提供一个consumer。获取图片—》解码图片缓存Producer—》后台线程Producer—》client图片处理producer(n)—》解码producer(n)—》旋转或剪裁producer(n)—》编码图片内存缓存producer—》读硬盘缓存producer—》写硬盘缓存producer(n)—》网络producer提供CloseableImage《—解码图片缓存consumer《—client图片处理consumer《—解码consumer《—旋转或剪裁consumer《—编码图片内存缓存consumer《—写硬盘缓存consumer《—图片数据
4.内存缓存:
1.一个CountingLruMap保存已经没有被引用的缓存条目,一个CountingLruMap保存所有的条目包括没有引用的条目。每当缓存策略改变和一定时间缓存配置的更新的时候,就会将 待销毁条目Map中的条目一个个移除,直到缓存大小符合配置。
2.这里的引用计数是用Fresco组件实现的引用计数器。
3.缓存有一个代理类,用来追踪缓存的存取。
4.CountingLruMap是使用LinkedHashMap来储存数据的。
5.硬盘缓存:
1.DefaultDiskStorage使用Lru策略。
2.为了不让所有的文件集中在一个文件中,创建很多命名不同的文件夹,然后使用hash算法把缓存文件分散
3.DiskStorageCache封装了DefaultDiskStorage,不仅进行缓存存取追踪,并且其在内存里面维持着一个
的键值对,因为文件修改频繁,所有只是定时刷新,因此如果在内存中找不到,还要去硬盘中找一次。
4.删除硬盘的缓存只出现在硬盘数据大小超限的时候,此时同时也会删除缓存中的key,所以不会出现内存中有key,但是硬盘上没有的情况。
5.在插入硬盘数据的时候,采用的是插入器的形式。返回一个Inserter,在Inserter.writeData()中传入一个CallBack(里面封装了客户端插入数据的逻辑和文件引用),让内部实现调用CallBack的逻辑来插入文件数据,前面写的文件后缀是.temp,只有调用commit()之后才会修改后缀,让文件对客户端可见。
6.使用了java提供的FileTreeVisitor来遍历文件
6.对象池:
1.使用数组来存储一个桶,桶内部是一个Queue。数组下标是数据申请内存的byte大小,桶内部的Queue存的是内存块的。所以数组使用的是稀疏数组
2.申请内存的方式有两种 1.java堆上开辟的内存 2.ashme 的本地内存中开辟的内存
7.设计模式:Builder、职责链、观察者、代理、组合、享元、适配器、装饰者、策略、生产者消费者、提供者
8.自定义计数引用:类似c++智能指针
1.使用一个静态IdentityHashMap <储存需要被计数引用的对象,其被引用的次数>
2.用SharedReference分装需要被计数引用的对象,提供一个销毁资源的销毁器,提供一个静态工厂方法来复制自己,复制一个引用计数加一。提供一个方法销毁自己,表示自己需要变成无人引用的对象了,此时引用计数减一。
3.引用计数归零,销毁器将销毁资源,如bitmap的recycle或者是jni内存调用jni方法归还内存。
9.博客推荐:Android Fresco源码文档翻译、从零开始撸一个Fresco之硬盘缓存、从零开始撸一个Fresco之gif和Webp动画、从零开始撸一个Fresco之内存缓存、从零开始撸一个Fresco之总结

2.oKhttp:
1.同步和异步:
1.异步使用了Dispatcher来将存储在 Deque 中的请求分派给线程池中各个线程执行。
2.当任务执行完成后,无论是否有异常,finally代码段总会被执行,也就是会调用Dispatcher的finished函数,它将正在运行的任务Call从队列runningAsyncCalls中移除后,主动的把缓存队列向前走了一步。
2.连接池:
1.一个Connection封装了一个socket,ConnectionPool中储存s着所有的Connection,StreamAllocation是引用计数的一个单位
2.当一个请求获取一个Connection的时候要传入一个StreamAllocation,Connection中存着一个弱引用的StreamAllocation列表,每当上层应用引用一次Connection,StreamAllocation就会加一个。反之如果上层应用不使用了,就会删除一个。
3.ConnectionPool中会有一个后台任务定时清理StreamAllocation列表为空的Connection。5分钟时间,维持5个socket
3.选择路线与建立连接
1.连接池中已经存在连接,就从中取出(get)RealConnection,如果没有命中就进入下一步
2.根据选择的路线(Route),调用Platform.get().connectSocket选择当前平台Runtime下最好的socket库进行握手
3.将建立成功的RealConnection放入(put)连接池缓存
4.如果存在TLS,就根据SSL版本与证书进行安全握手
5.构造HttpStream并维护刚刚的socket连接,管道建立完成
1.无代理,那么在本地使用DNS查找到ip,注意结果是数组,即一个域名有多个IP,这就是自动重连的来源
2.有代理HTTP:设置socket的ip为代理地址的ip,设置socket的端口为代理地址的端口
3.代理好处:HTTP代理会帮你在远程服务器进行DNS查询,可以减少DNS劫持。
1.选择路线有两种方式:
2.建立连接
4.职责链模式:缓存、重试、建立连接等功能存在于拦截器中网络请求相关,主要是网络请求优化。网络请求的时候遇到的问题
5.博客推荐:Android数据层架构的实现 上篇、Android数据层架构的实现 下篇

3.okio
1.简介;
1.sink:自己—》别人
2.source:别人—》自己
3.BufferSink:有缓存区域的sink
4.BufferSource:有缓存区域的source
5.Buffer:实现了3、4的缓存区域,内部有Segment的双向链表,在在转移数据的时候,只需要将指针转移指向就行
2.比java io的好处:
1.减少内存申请和数据拷贝
2.类少,功能齐全,开发效率高
3.内部实现:
1.Buffer的Segment双向链表,减少数据拷贝
2.Segment的内部byte数组的共享,减少数据拷贝
3.SegmentPool的共享和回收Segment
4.sink和source中被实际操作的其实是Buffer,Buffer可以充当sink和source
5.最终okio只是对java io的封装,所有操作都是基于java io 的

你可能感兴趣的:(面试总结Android)