转自 http://www.jianshu.com/p/5f6d79323923

一、Android系统底层研究

关于底层的知识点不是在一篇文章中能讲解清楚,参见本人的Android底层研究系列,不断更新中。

二、Android重要知识点

下面精选了较为常见的知识点,坚决杜绝简单罗列答案的方式,因为那样理解不了也记不住。所以尽量以层层递进而简单粗暴的方式来表达。耐心点看,一定能帮你应对大多数面试问题。

Tips:可以先阅读自己熟悉的知识点,然后再去看那些不太熟悉的。

1、Activity启动模式

什么是启动Activity?

一般而言是先创建一个Activity对象,然后把Activity放入一个Task堆栈里进行管理(包括切换、关闭等)。那么问题来了,如果该堆栈里已经有这个Activity对象呢,我还要不要创建一个新的对象呢?Android提供了四种选择方案:

  • 不管堆栈里有没有,都创建一个新的activity放在堆栈顶部:standard模式
  • 如果我要打开的activity正好在堆栈顶部,那就直接用它;否则也创建新的: singleTop模式
  • 这个比较霸道。即如果activity已经存在在堆栈里,那么当要打开这个activity时,就算栈的上层还有其他activity,也统统移除,成为栈顶。而如果没有,就也要创建。:singleTask模式
  • 这个更加霸道。即打开这个activity时,直接创建一个堆栈,并创建这个activity放入新堆栈中,不去和别人挤一个堆栈。以后再要打开这个activity时,直接跳转到这个新堆栈里去用。:singleInstance模式(即只创建一个实例,单独放在一个task堆栈里给别的task栈共享)

启动模式

2、Activity(或组件)通信机制

Activity(组件)之间何时需要通信?

一般当需要从一个Activity(组件)向其他的Activity(组件)传递数据时,就会涉及到通信机制。例如打开一个新的Activity并向其传递数据。

如何来通信/传递数据?

较常用的是android系统的信使:Intent
Intent的作用是,带上要传递的数据,然后出发前往指定的目的地。
那么问题来了,如果带上各种各样的数据呢?又如何导航去找到目的地呢?

如何带上各种各样的数据?

就像发信一样,你不可能把一堆凌乱的信纸直接塞给信使让人家送,而会用信封把信都装起来。
android里也一样,会把数据先打包,再给信使,这里就涉及到 bundle。对,我们把一堆凌乱的数据放在一个bundle里,然后把bundle给Intent就可以了。

 如何导航找到目的地呢?

如果你想邮寄东西有两种方式:1、在信封上写好详细地址;2、如果你想邮寄没用的棉被书籍给灾区,但你又无所谓寄给哪个灾区,你就可以写帮我随便寄到一个灾区去,然后邮局管理员会在全国范围内查询,如果查到了灾区如汶川,那就邮寄到那。
android里也一样,有显式Intent和隐式Intent,前者会指定特定组件名,如指定目标activity;后者不指定名称,只给一个描述(Intent-Filter)。然后android会依据这个描述去搜索。

但是,关于数据打包,有个问题是,如果传递普通数据可以直接放入bundle中,但 如果要传递对象呢。

如何在bundle中打包并传递对象呢!?

3、对象序列化机制

前面已经知道了,我们要在组件间通信时会先用bundle对数据打包,然后交给信使intent。那么问题来了?

bundle如何打包数据呢?

这里的数据我们分成两种,一种是原型数据,如int、string等,可以直接打包并传递。打包方式如下:

bundle.putInt("key1", 20);
bundle.putString("key2", "hello");

另一种是java对象,这是不能直接给bundle的,而要通过序列化后再给bundle,然后对象会以二进制流形式传输,直到目标组件接受到bundle后,要对该对象二进制数据反序列化才能获取真实的的对象。

那么如何对对象进行序列化呢?

两种方法。

  • 基于java语言的Serializable序列化方法:对象类要实现Serializable接口;
  • 基于android系统提出的Parcel序列化方法:实现Parcelable接口。
    只要类实现了这两个接口,就可以把对象存入bundle中:
bundle.putSerializable(Key, Object);
bundle.putParcelable(Key, Object);

那么

 这两种机制有何区别?
  • JAVA中的Serialize机制是将对象转化为字节流存储在外部设备,在需要重新生成对象(采用java反射机制)。主要用于外部设备保存对象状态,网络传输对象等场景。缺点是产生很多中间对象及造成一定的GC(垃圾回收),简而言之Serialize更慢
  • Android提供的Parcel机制是针对移动设备轻量级高效对象序列化机制。整个过程均在内存进行,不涉及外部设备,反序列化时读取的就是原对象,而不会创建新对象。简单来说Parcel更快;不过它使用复杂

这一步我们知道,要对对象进行序列化后才可以放入bundle由intent传递给其他组件,那么,

为什么需要对对象序列化后才能通过intent在组件间传递呢!?

以startActivity(intent)为例,该函数作用时从A Activity中启动B Activity,同时把数据打包给intent并传递给B。也就是说,如果intent里的数据有java对象,那就要序列化这个对象才能传递给B。
下面直接给出原因:(详细可参见从源码角度轻松学习Intent机制)
因为在启动B Activity过程中,需要离开应用程序所在进程,转而调用native方法,进入linux kernel进程中去执行activity切换的实际操作。完成后再重新把传输数据带回到应用程序进程中,对原始打包数据进行解析。
也就是说,在启动B Activity过程中,所打包的数据要经过不同进程:应用程序->linux kernel->应用程序,而java对象是无法直接在进程间传输的(见下文),所以,我们需要提前序列化java对象,才能让它经得住后面跨进程传输的考验。

4、进程间通信机制IPC

什么是进程?

简单来说,一个进程往往代表一个应用程序。操作系统会为每一个进程分配一定的内存空间等资源,然后进程就在这块内存里跑。

什么是进程间通信?

一般而言,为了保证安全,进程获得的内存空间时一块抽象的内存,然后会映射到实际的某一块物理内存,从而,每个进程都无法访问其他进程所在内存里的数据。比如手机上开了qq和某银行客户端,操作系统会为他俩创建两个独立的内存区供运行,而qq进程是无法访问到银行客户端数据的,这就保证了数据的安全性。
但是,带来的缺陷是,进程间无法直接进行数据传输,所以要引入特有的进程间通信机制。

进程间可以直接传递对象吗?

前面知道,不同进程间通信,也就意味着在两块不同的物理内存间传递数据。首先,原生的数据如int string数据是可以传递的,只要你说明这个数据时什么类型,那么就可以在目标进程里复原。但是对象数据,如果直接把对象传递过去,目标进程是无法复原的,因而也无法识别。

内存区数据通信
Android系统中不同应用程序之间通信示意图。一个进程代表一个应用程序。

进程间通信
附加:IPC机制中很重要的是Binder机制,利用Binder实现不同进程间传递。这部分内容面试一般不会问的太难。
目前本人还在整理该部分内容,继续更新中。

5、多线程管理

前面提到了进程间通信,下面讲解下Android里的多线程管理,后面会讲解线程间通信。
首先,线程基本概念此处不过多讲解,只要知道线程是轻量级进程,在有限的进程内存空间资源中去执行实际操作。

什么是Main Thread 和 Worker Thread?

当应用程序开启时会自动创建一个主线程 (Main Thread),也叫UI线程,主要功能是完成UI界面绘制和与用户交互。除主线程之外的其他线程称为子线程或Worker Thread。这些线程往往用执行耗时操作如网络通信或数据库访问等。
如果在主线程中执行耗时操作,那么在执行过程中,就无法绘制界面或响应用户操作,在用户看来就是卡顿,可能造成ANR现象,破坏用户体验。

主线程是线程不安全的

网上很多地方解释线程不安全并非解释原因,而是在‘解释’结果,即:(因为主线程是线程不安全的,所以)UI控件只能在主线程中操作,而不能在其他线程中操作,否则多个线程同时操作一个控件会出错。
这种解释不仅没解释为何主线程是线程不安全的,反而让人感觉android系统里限定了只能在主线程操作ui元素,容易误解为那不是很安全吗?
我的解释是:
首先我们是的的确确可以通过代码,在子线程里操作UI元素,然后引发程序崩溃。假设主线程是安全的,那么安全的情况是:即使我们不小心在子线程操作UI也不用担心,因为系统会屏蔽这种操作。而实际上系统并未屏蔽,只要开发者在子线程操作UI元素,很有可能会导致崩溃。所以我们才说android系统里主线程并不安全。

附加知识:什么是线程安全/不安全?
在多线程环境里,往往一段代码会被多个线程分别执行。而常见的情况是一个线程执行了该段代码的一部分后,
会被另一个线程抢走时间片又去执行这段代码,并修改其中变量。
当原线程再次回来继续运行时,其实里面的变量已经被别人改动了但它却不知,最后会导致错误。
这种线程就是不安全的。而安全的线程在执行一段代码时,只要没执行完,
其他线程就不能来执行这段代码或修改变量知道它执行完。

那么

多个线程间时如何通信的呢?

这里就涉及到另一套机制handler、looper、MessageQueue机制,在本人另一篇文章中有生动详细的描述,见Handler实现机制
简单来说,每个线程拥有上面这三个东西,如线程A想发送消息给线程B,那么在线程A中调用线程B的handler来发送消息,消息会自动发送线程B的消息队列中,同时线程B的looper在不断遍历这个队列,如果发现有新消息就会自动去处理。

常见问题:

如何避免发生ANR(Application Not Response)现象呢?

尽量在子线程中执行耗时操作(如网络请求或数据库读取等)或者资源开销较大的操作,当子线程执行完毕后,利用handler通知主线程做出更新。

6、内存管理机制

前面提到了,每个应用程序运行在独立的进程中(实际是一个独立的Dalvik进程),而且系统会为它分配固定的内存。在内存使用中常常会发生内存泄漏(memory leak)和内存溢出(OOM),其中,内存溢出非常严重,往往会导致程序崩溃。所以,合理有效的管理内存非常的重要。
详细的管理(包括面试重点:图片缓存机制)均可以参考本人另一篇文章:Android之内存管理及优化

此处不再赘述。

只说一下三种图片缓存思路:

  • LRU算法:设置缓存图片最大数量,当图片数量超过最大值久删除使用较少的图片,从而优化内存。
  • FTU算法:设置图片的缓存时限,从最后一次使用算起,当达到时限即删除。
  • FMU算法:设置固定大小的缓存空间,当达到空间限制后删除最大尺寸的图片。

快速了解Android重要机制的更多相关文章

  1. Android随笔之——Android广播机制Broadcast详解

    在Android中,有一些操作完成以后,会发送广播,比如说发出一条短信,或打出一个电话,如果某个程序接收了这个广播,就会做相应的处理.这个广播跟我们传统意义中的电台广播有些相似之处.之所以叫做广播,就 ...

  2. 理解Android安全机制

    本文从Android系统架构着手,分析Android的安全机制以SE Android,最后给出一些Android安全现状和常见的安全解决方案. 1.Android系统架构 Android采用分层的系统 ...

  3. Android渲染机制和丢帧分析

    http://blog.csdn.net/bd_zengxinxin/article/details/52525781 自己编写App的时候,有时会感觉界面卡顿,尤其是自定义View的时候,大多数是因 ...

  4. Android内存机制分析1——了解Android堆和栈

    //----------------------------------------------------------------------------------- Android内存机制分析1 ...

  5. Android反射机制实现与原理

    本文介绍Android反射机制实现与原理,在介绍之前,要和Java进行比较,所以先看下Java中的反射相关知识: 一.反射的概念及在Java中的类反射 反射主要是指程序可以访问.检测和修改它本身状态或 ...

  6. 巧用第三方快速开发Android App 热门第三方SDK及框架

    巧用第三方快速开发Android App 热门第三方SDK及框架 历经大半年的时间,终于是把这门课程给录制出来了,也就在今天,正式在慕课网上上线了 项目地址:巧用第三方快速开发Android App ...

  7. Android群英传笔记——第六章:Android绘图机制与处理技巧

    Android群英传笔记--第六章:Android绘图机制与处理技巧 一直在情调,时间都是可以自己调节的,不然世界上哪有这么多牛X的人 今天就开始读第六章了,算日子也刚好一个月了,一个月就读一半,这效 ...

  8. 【腾讯Bugly干货分享】经典随机Crash之二:Android消息机制

    本文作者:鲁可--腾讯SNG专项测试组 测试工程师 背景 承上经典随机Crash之一:线程安全 问题的模型 好几次灰度top1.top2 Crash发生场景:在很平常.频繁的使用页面,打开一个界面,马 ...

  9. Android内存机制分析2——分析APP内存使用情况

    上面一篇文章说了Android应用运行在dalvik里面分配的堆和栈内存区别,以及程序中什么代码会在哪里运行.今天主要是讲解一下Android里面如何分析我们程序内存使用情况.以便后续可以分析我们程序 ...

随机推荐

  1. php面向对象(2)值传递

    PHP中值传递方式,2中 值传递:传递的时候,拷贝的是数据本身.默认都是值传递 结果:传递完成,有了2份同样的数据,且2个变量“相互独立”,不会相互影响 引用传递:传递的时候,拷贝的是引用关系(数据的 ...

  2. 图解HTTP总结(1)——了解Web及网络基础

    Web页面不能凭空显示出来.根据Web浏览器地址栏指定的URL,Web浏览器从Web服务器端获取文件资源等信息,从而显示出Web页面. Web使用一种名为HTTP(HyperText  Transfe ...

  3. 单片机入门学习笔记8:STM32单片机使用

    经常会在某个QQ群里看见某人的QQ昵称的名字"不会32绝不改名",其实无论会不会,之后名称都改了. STM32单片机在我看来就三部分组成:各部分的初始化,中断的使用,Main函数内 ...

  4. JAVA 扫雷 程序

    文件列表 2.主程序入口 3.1部分源代码 package MineSweeper; import java.awt.BorderLayout; import java.awt.Font; impor ...

  5. POJ3682 概率DP

    King Arthur's Birthday Celebration Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 3575 ...

  6. GPIO基础知识

    STM32 GPIO入门知识 GPIO是什么? 通用输入输出端口,可以做输入,也可以做输出.GPIO端口可通过程序配置成输入或输出. 引脚和GPIO的区别和联系 STM32的引脚中,有部分是做GPIO ...

  7. 关于DIV内文字垂直居中的写法

    最近在写UI,或多或少用到了CSS,在这记录一下,今天用到的DIV内文字垂直居中的写法, 因为所做的项目都是基于WebKit内核浏览器演示的,所以我们今天采用的是-webkit-box的写法: dis ...

  8. 开启虚拟机所报的错误:VMware Workstation cannot connect to the virtual machine. Make sure you have rights to run the program, access all directories the program uses, and access all directories for temporary fil

    当我们开启虚拟机时出现错误: VMware Workstation cannot connect to the virtual machine. Make sure you have rights t ...

  9. 自己定义的TryParse()

    out 参数的练习,自己定义的TryParse()... 一开始写错了,错在:判断str[i] >= '0'&& str[i]<='9'时,把str[i]当数字去判断了.. ...

  10. 常用正则表达式 -- 费元星 java大神

    正则表达式用于字符串处理.表单验证等场合,实用高效.现将一些常用的表达式收集于此,以备不时之需. 匹配中文字符的正则表达式: [\u4e00-\u9fa5]评注:匹配中文还真是个头疼的事,有了这个表达 ...