1. Linux进程和Dalvik进程区别
- Dalvik虚拟机是运行在Linux系统上的,是Linux的一个进程。
- 每个应用程序都有一个Dalvik虚拟机。好处是一个应用程序一个进程,相互不影响。
1.1 什么是进程、什么是线程
- 一个应用程序(进程)拥有独立的内存空间
- 线程即java中的Thread类,线程共享应用程序(进程)的内存
- 一个应用程序运行在Dalvik虚拟机(Linux进程)
- 一个应用程序(进程)都必须有个主线程(UI线程)
- 一个应用程序(进程)需要拥有其他线程提高并发性(网络操作、IO、等等)
2. 什么是内存泄漏、内存溢出
- 内存泄漏:保存了不可能再被访问的引用,导致gc无法回收。
- 内存溢出:Dalvik内存耗尽,无法为新对象分配空间。
- 当某个界面存在内存泄漏,我们反复进入该界面,导致对象创建无法被回收,最终导致内存溢出。
2.1 什么情况下会发生内存泄漏
- 长期引用Activity的Context
- 不关闭IO流
- 对象过大,如XML文件、Bitmap
- static关键字标识的成员变量
- 内部类持有Activity引用
2.2 如何进行内存优化
- 对图片进行内存优化
- 对Bitmap进行等比缩放(一张图片解析成Bitmap,会导致占用内存变大,导致OOM)
- BitmapFactory.Options类的inSampleSize属性设置缩放倍数
- 设置Bitmap.Config.图片解码格式
- Bitmap.Config.RGB_565 色彩值16位 2字节
- Bitmap.Config.ARGB_4444 色彩值16位 2字节
- Bitmap.Config.ARGB_8888 色彩值32位 4字节
- Bitmap.Config.ALPHA_8 色彩值8位 1字节
- BitmapRegionDecocder可以部分加载图片
- 使用ThreadPool替代new Thread()
- 每次new Thread()都会消耗性能,单独使用Thread缺乏管理,可能无限制new Thread(),相互竞争、占用过多的系统资源导致OOM。
- 而且缺乏一些常见功能,如定时任务、定期执行、线程中断
- ThreadPool的简单使用方法
//Java自带线程池 ExecutorService cachedThreadPool = Executors.newCacheThreadPool(); ExecutorService fixedThreadPool = Executors.newFixedThreadPool(5); ExecutorService singleThread = Executors.newSingleThreadExecutor(); //使用方法 cachedThreadPool.execute(runnable); fixedThreadPool.execute(runnable); singleThread.execute(runnable);
- 自定义线程池ThreadPoolExecutor
//ThreadPoolExecutor构造函数 ThreadPoolExecutor(int corePoolSize,//核心线程数 int maximumPoolSize,//最大线程数 long keepAliveTime,TimeUnit unit,//大于corePoolSize部分的线程在执行完毕超过多少时间,杀死线程 BlockingQueue
workQueue,//任务队列 ThreadFactory threadFactory//创建线程池的工厂 )
2.3 UI Review
- 减少视图层级嵌套(可以减少内存消耗),因为视图是树状结构,并且每次渲染都会遍历一次
- include
- merge
- ViewStub
2.4 使用int而不是Integer,因为每次创建对象都要花费时间(同理 long、double、byte、char)
2.5 使用StringBuilder、StringBuffer代替String的拼接操作
- StringBuilder是非线程安全的、StringBuffer是线程安全的
2.6 ListView、RecyclerView优化
- item中有图片时候异步加载
- 快速滑动时,不加载图片
- item中对图片进行压缩
- 数据分页加载
2.7 减少不必要的static变量
2.8 Cursor及时回收
2.9 Receiver、registerReceiver和unregisterReceiver要同时出现
2.10 I/O流及时关闭
2.11 javabean尽量不要用get/set方法,直接public效率会高
2.12 for循环中不要放业务逻辑比如
for(int i=0;i < list.size();i++)
改成
int size = list.size;
for(int i=0;i < size;i++)
2.13 Android启动优化
- Application中onCreate进行第三方库初始化的时候使用异步(Thread、Service都可以)
- 启动Activity设置windowsBackground属性,进行预加载提高用户体验
3 XMPP协议(即时通讯时候用)
- XMPP消息是XML格式的,预定义了3个标签
用于确定用户状态 消息
4 微信网页登陆原理
服务器生成一个二维码(包含UUID),与浏览器创建一个长连接,微信扫描二维码调用登陆接口,并且传递用户信息和UUID给服务器,服务器进行校验。
5 第三方登陆原理
用户 第三方应用 QQ/微信
|--request_token------->|
|<--grant request_token-|
|<-redirect to auth page----|
|---authorize request_token------------------------>|
|<-acknowledge authorization------------------------|
|-redirect to-------------->|
|--access_token-------->|
|<-grant access_token---|
6 在Android应用程序中有几个Context
- Context = Activity个数 + Service个数 + Application个数
7 线程与进程区别
进程有自己的独立地址空间,每启动一个进程,系统就会为它分配地址空间,建立数据表来维护代码段、堆栈段和数据段,这种操作非常昂贵。而线程是共享进程中的数据的,使用相同的地址空间,因此CPU切换一个线程的花费远比进程要小很多,同时创建一个线程的开销也比进程要小很多。
线程之间的通信更方便,同一进程下的线程共享全局变量、静态变量等数据,而进程之间的通信需要以通信的方式(IPC)进行。不过如何处理好同步与互斥是编写多线程程序的难点。
8 Android多进程之间通信方式
Bundle、文件共享、Handler、Binder(AIDL)
9 http协议
请求:请求行、请求头部、请求数据
请求行包括请求方法(如GET、POST)、URL(如www.baidu.com)、协议版本(如HTTP/2.0)合起来就是GET www.baidu.com HTTP/2.0
请求头部包括一些控制字段(如时间、缓存控制、长连接控制)
请求数据就是POST请求时候携带的数据、如果是GET请求的话,请求数据直接在URL里面
响应:状态行、首部行、实体
状态行包括版本(如HTTP/2.0)、状态码(如200)、原因短语(如OK),合起来就是 HTTP/2.0 200 OK
首部行与请求头部类似都是一些控制字段
实体的话就是服务器处理后返回给我们的数据
HTTP协议基于TCP/IP,经历IP协议寻址、TCP协议3次握手连接上服务器。然后开始使用http协议通信,发送请求行、请求头部(发送空白行表示结束)、请求数据(头部中的Content-Length定义了长度)。接收响应行、响应头部(发送空白行表示结束)、响应数据(头部中的Content-Length定义了长度)。最后TCP四次挥手关闭断开,如果控制字段设置了keep-alive会保持连接下次复用。
10 https协议
https就是http协议加上了ssl,http协议默认端口80,https协议默认端口443。https在连接时候会进行ssl认证,客户端向服务端请求https的连接。服务器返回证书(包含公钥)给客户端;客户端认证证书没有问题之后,使用公钥对随机生成的密匙进行加密(非对称加密),然后返回给服务。之后双方通信才有随机生成的密匙进行加密(对称加密)。
非对称加密公钥加密的私钥才能解开,私钥加密的公钥才能解开,所以安全性高;但是这种方式慢。
对称加密只有一个密匙,所以安全性低;但是快。
所以https采用了服务器下发对称加密(公钥),客户端使用公钥加密了非对称加密的密匙传再给服务器,这样提高了安全性和速度。
11. TCP三次握手和四次挥手流程
三次握手:
- 客户端发送SYN报文段给服务器表示建立连接
- 服务端收到SYN报文段后开始配置TCP连接需要用到的东西,之后返回SYNAKC报文段给客户端
- 客户端收到SYNACK报文段后也开始配置TCP连接需要用到的东西,返回给ACK给服务端
四次挥手:
- 客户端发送FIN给服务端表示关闭连接,同时客户端进入等待关闭的状态
- 服务端收到FIN后返回客服端ACK,同时服务端进入等待关闭状态。客户端收到ACK后进入半关闭状态,这时候客户端还是可以接收服务端的数据。
- 服务端发送FIN给客户端表示关闭连接。服务端进入等待最后一个ACK状态。
- 客户端收到FIN返回ACK给服务端。客户端和服务端完全断开TCP连接。
为什么握手三次挥手要四次?因为FIN和ACK要分开,不像SYN和ACK那样可以同步发送。
12. 垃圾回收机制
垃圾回收机制涉及到几个回收算法
- 标记回收算法
从GC Roots集合开始,将内存整个遍历一次,保留所有可以被GC Roots直接或者间接引用到的对象,其他的当作垃圾回收,这个算法会产生内存碎片。 - 复制算法
将内存分为两快,每次只使用其中一块。垃圾回收时候将在使用的那一块中存活的对象复制到另一块中,之后清理这一块中的所有对象。两块内存交互角色。 - 标记-压缩算法
从根节点开始对所有可达对象做一次标记,之后将存活对象压缩到内存到一端。然后清理掉边界外到所有空间。
所有新建到对象放在新生代(新生代特点是会很快回收,所以使用复制算法),当一个对象经过多次回收后依旧存活,对象会被放入老生代(采用标记-压缩算法)。
复制算法与标记-压缩算法对区别在于复制算法的复制与移动会一起执行,标记-压缩算法会分开。同时压缩阶段会暂停应用。
13. Activity四种形态
- Active(Activity处于栈顶)
- Paused(可见但是不可以交互)
- Stopped(不可见,被另一个Activity完全覆盖,内存足够时候,数据、状态、变量都被保存,内存不足时候会被回收)
- killed(系统回收掉)
14. Activity启动模式
- Standard(默认启动方式,Activity可以被多次实例化,一个任务栈中有多个实例)
- SingleTop(分2种情况,如果Activity在栈顶,会复用Activity通过onNew
Intent传递Intent。如果Activity不在栈顶或者不存在时候会重新实例化) - SingleTask(会去查看当前栈种是否有Activity,如果有则会销毁这个Activity上的所有Activity,然后复用改Activity;如果没有,则实例化)
- SingleInstance(如果Activity不存在,会开启新的任务栈去实例化。如果任务栈种存在这个Activity,则会销毁他上面的所有Activity,复用这个Activity)
15. Activity生命周期
- onCreate(创建)
- onRestart(重运行,从onPause回来)
- onStart(运行)
- onRestoreInstanceState(恢复之前保存的状态)
- onResume(获取焦点)
- onPause(失去焦点)
- onSaveInstnaceState(做一些保存状态的操作)
- onStop(暂停)
- onDestroy(销毁)
16. Activity与Fragment生命周期关系
- onAttach(Fragment关联到Activity)
- onCreate(系统创建Fragment)
- onCreateView(绘制View)
- onActivityCreate(Activity的onCreate方法执行之后调用)
- onStart(运行)
- onResume(获取焦点)
- onPause(失去焦点)
- onStop(暂停)
- onDestroyView(Fragment中的布局被移除)
- onDestroy(销毁)
- onDetach(Fragment与Activity解除关系)
Activity onStart方法执行后Fragmenton开始执行Attach-->onCreate-->onCreateView-->onActivityCreate-->onStart
Activity onResume方法执行后Fragment开始执行onResume
Activity onPause方法执行后Fragment开始执行onPause
Activity onStop方法执行后Fragment开始执行onStop
Activity onDestroy方法执行后Fragment开始执行onDestroyView-->onDestroy-->onDetach
17. Service生命周期
- startService启动
onCreate-->onStartCommand-->onDestroy
一旦通过这种方式开启Service,这个Service会在后台一直运行,即使创建这个Service的Activity或者Broadcast被销毁,也会一直运行下去除非手动关闭这个Service。第一次调用startService时候,onCreate方法和onStartCommand方法将依次调用,多次调用startService时候,只有onStartCommand会被调用。可以通过调用stopSelf或者其他组建调用stopService来停止这时候走onDestroy方法。 - bindService启动
onCreate-->onBind-->onUnbind-->onDestroy
这种方法启动的Service会把Service和开启他的组件进行绑定,多次调用bindService只有第一次会触发onBind其余的不会触发。可以通过unbindService来解除绑定走onUnbind方法。多个组件都解除绑定之后会被系统销毁走onDestroy方法。
19. IntentService与Service区别
Service不是独立的线程,也不是独立的进程,他依赖于主线程即Service也会产生ANR。
IntentService继承Service,区别在于onCreate的时候IntentService创建了一个HandlerThread去执行耗时操作。
20. Service中onStartCommond四种返回值策略
- START_STICKY(系统默认的值,Service进程被杀,保留Service的状态为开始状态,但不保留传递的Intent对象,之后系统会尝试重新创建Service调用onStartCommand)
- START_NOT_STICK(Service进程被杀掉,系统不会自动启动这个服务)
- START_REDELIVER_INTENT(如果在执行完onStartCommand后被异常杀掉,则会重启并将Intent值传入)
- START_STICK_COMPATBILITY(START_STICKY的兼容版本,不保证一定重启)
18. Handler机制
Handler用来发送消息,创建的时候获取默认或者传递过来的Looper对象,并持有Looper对象包含的MessageQueue。发送消息时使用该MessageQueue对象来插入Message,并把自己分装到Message中。
Looper用来为某个线程做消息循环。Looper持有MessageQueue,循环获取Message并且使用Message封装的handler对象进行处理。如果没有Message的话就会阻塞。
Message包含了传递的信息。