Android面试

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 如何进行内存优化
  1. 对图片进行内存优化
  • 对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可以部分加载图片
  1. 使用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<Runnable> 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个标签
  • <Presence>用于确定用户状态
  • <message>消息
  • <iq>

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. 垃圾回收机制

垃圾回收机制涉及到几个回收算法

  1. 标记回收算法
    从GC Roots集合开始,将内存整个遍历一次,保留所有可以被GC Roots直接或者间接引用到的对象,其他的当作垃圾回收,这个算法会产生内存碎片。
  2. 复制算法
    将内存分为两快,每次只使用其中一块。垃圾回收时候将在使用的那一块中存活的对象复制到另一块中,之后清理这一块中的所有对象。两块内存交互角色。
  3. 标记-压缩算法
    从根节点开始对所有可达对象做一次标记,之后将存活对象压缩到内存到一端。然后清理掉边界外到所有空间。

所有新建到对象放在新生代(新生代特点是会很快回收,所以使用复制算法),当一个对象经过多次回收后依旧存活,对象会被放入老生代(采用标记-压缩算法)。

复制算法与标记-压缩算法对区别在于复制算法的复制与移动会一起执行,标记-压缩算法会分开。同时压缩阶段会暂停应用。

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生命周期

  1. startService启动
    onCreate-->onStartCommand-->onDestroy
    一旦通过这种方式开启Service,这个Service会在后台一直运行,即使创建这个Service的Activity或者Broadcast被销毁,也会一直运行下去除非手动关闭这个Service。第一次调用startService时候,onCreate方法和onStartCommand方法将依次调用,多次调用startService时候,只有onStartCommand会被调用。可以通过调用stopSelf或者其他组建调用stopService来停止这时候走onDestroy方法。
  2. 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包含了传递的信息。

19. Binder机制

20. Activity启动流程

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

推荐阅读更多精彩内容