Android基础技术核心归纳(二)

来源:互联网 发布:如何做人力资源矩阵图 编辑:程序博客网 时间:2024/06/06 01:31

 Android基础技术核心归纳(二)

转载请声明出处:http://blog.csdn.net/andrexpert/article/details/77888034

Android                                          Java                                            数据结构
Android基础技术核心归纳(一)     Java基础技术核心归纳(一)     数据结构基础知识核心归纳(一) 
Android基础技术核心归纳(二)     Java基础技术核心归纳(二)     数据结构基础知识核心归纳(二)  
Android基础技术核心归纳(三)     Java基础技术核心归纳(三)    数据结构基础知识核心归纳(三)  
Android基础技术核心归纳(四)     Java基础技术核心归纳(四)

     不知不觉又是一年的9月,今天跟一个师弟聊天,谈到了他现在面试的一些情况,突然想起自己当年也是这么走过来的,顿时感慨良多。Android/Java经验汇总系列文章,是当初自己毕业时笔试、面试和项目开发中相关的总结,虽然不是很高深的东西,也没有归纳得很全面,但是对Android、算法、Java把握个大概还是没问题,今天特意将这些文章放出来,希望能够对看到这个系列文章的毕业生朋友一点帮助吧。当然,由于受当初知识面的限制,归纳得可能不是很准确,若有疑问就留言吧,我就不细看了。

1.Android加密技术与JNI/NDK?
    在移动应用开发中, 对于数据安全传输要求非常高, 尤其是涉及到用户财产安全的时候,都会对数据进行层层加密来确保数据的安全性和完整性。 
1.Android加密简介
   Android客户端与服务器进行数据传输时,通常会对两类不同的数据使用不同的加密算法进行加密。对于只能被用户知道的密码类数据,通常是先经过不可逆加密算法,如MD5进行加密,然后再使用其他加密算法进行双重加密;对于非密码类数据,虽然这些数据很重要,但一般其他人截获了这些数据对他们意义不太大,这些数据我们一般采用可逆的加密方式加密,因为我们在服务器端还是需要这些数据的明文的。需要注意的是,可逆加密与不可逆加密都可包括对称加密和非对称加密。
2.JNI与NDK实现客户端数据加密思路

客户端:数据加密和传输     
(1)首先,使用C代码实现MD5、3DES加密算法,以便Android应用通过JNI调用so动态库(防止反编译);
(2)其次,将要传输到服务器的数据(Common 和Business 数据)转换成JSON格式;
(3)第三,调用.so动态库中的MD5算法对json数据加密得到一个哈希值,并将该哈希值赋值给
    BusinessConnection的sign属性;
(4)最后,将BuisnessConnection Bean转换成JSON数据格式字符串并格式化成UTF-8,再使用3DES对该字符串进行二次加密,得到最后的密文上传给服务器;
注意:将所有的数据封装到一个BussinessConnection Bean中,其中,Commo为基本数据、Business为上层业务数据、Sign属性是MD5哈希值校验位。
服务器:解密
(1)首先,当服务器获得数据之后,先通过3DES解密,UTF-8转码;
(2)其次,获得Commo和Business Bean的Json字符串,然后使用MD5加密获得哈希值;
(3)最后,将MD5加密后得到的哈希值与传进来的sign哈希值对比,如果哈希值一致,说明数据是完整的,传输的过程中没有被串改过。

2.对称加密与非对称加密,可逆加密与不可逆加密?
1.对称加密与非对称加密

(1)对称加密:对称加密无论是加密还是解密都是使用同一个key;
(2)非对称加密:非对称加密需要两个key,public key和private key,使用public key对数据进行加密,必须使用private key对数据进行解密。
非对称加密的过程描述如下:
    假如有A和B两个人,A要求B将一个文件经过加密后传给A。这时A(服务器)使用了密匙生成软件生成了两个key(public key和private key),首先A将public key通过网络发给了B,然后B用public key对文件进行加密后,将经过加密后的文件发给A,最后A再用private key对该文件进行解密。我们可以知道,至始至终private key都没有通过网络进行传输,因此,只要private key不泄漏,即使public key和经过加密的文件都被截获,仍然无法对该文件进行解密。因此,非对称加密较对称加密更安全。
2.可逆加密与不可逆加密
(1)可逆加密:指明文数据被加密后,能够被解密成原来的明文,常见可逆加密算法:BASE64、RSA、DES
(2)不可逆加密:不可逆加密又称为"单向加密",是指任何数据加密后只会产生唯一的一个加密串后,不能还原成原来的数据,常见不可逆加密算法:MD5、SHA、HMAC。
3.常见加密算法对称性与可逆性

注释:
    ◆ MD5(Message Digest algorithm 5,信息摘要算法)
    ◆ SHA(Secure Hash Algorithm,安全散列算法)
    ◆ HMAC(Hash Message Authentication Code,散列消息鉴别码)
    ◆ DES(Data Encryption Standard,数据加密算法)
3.Base64编码可以加密数据吗,原理是什么?
    按照RFC2045的定义,Base64被定义为:Base64内容传送编码被设计用来把任意序列的8bit字节描述为一种不易被人直接识别的形式。常见于邮件、http加密,截取http信息,比如登录操作的用户名、密码字段就是通过Base64加密的。
1.BASE64编码原理
    BASE64 的编码都是按字符串长度,以每 3 个 8 bit 的字符(即3个字符,占3个字节)为一组,然后针对每组,首先获取每个字符的ASCII 编码,然后将 ASCII 编码转换成 8 bit 的二进制,得到一组 3*8=24 bit 的字节。然后再将这 24 bit 划分为 4 个 6 bit 的字节,并在每个 6 bit 的字节前面都填两个高位 0,得到 4 个 8 bit 的字节,然后将这 4 个 8 bit 的字节转换成十进制,对照 BASE64 编码表 (下表),得到对应编码后的字符。

注:1. 要求被编码字符是8bit的,所以须在ASCII编码范围内\u0000-\u00ff,中文就不行。
  2. 如果被编码字符长度不是3的倍数的时候,则都用0代替,对应的输出字符为=
2.举例
a) 字符长度为能被3整除时:比如“Tomsa” ,其中,"Tom"为一组,"sa0"为一组:

字符--->ASCII码--->8bit字节--->6bit字节--->十进制--->Base64编码
所以,btoa('Tom') = VG9t,也就是说,“Tom”的 BASE64 编码结果为 VG9t。
b) 字符串长度不能被3整除时,比如“Lucy”,其中,"Luc"为一组,"y00"为一组:
    由于 Lucy 只有 4 个字母,所以按 3 个一组的话,第二组还有两个空位,所以需要用 0 来补齐。这里就需要注意,因为是需要补齐而出现的 0,所以转化成十进制的时候就不能按常规用 BASE64 编码表来对应,所以不是 a, 可以理解成为一种特殊的“异常”,编码应该对应“=”。


(3)BASE64加密实现
     由于Base64编码表是公开的,任何人都可以利用Base64编码表对数据进行加密和解密,即Base64的加密解密是双向的。因此,无法直接使用标准的Base64编码表对数据进行加密,但可以将Base64编码表中的64个编码随机变换顺序,然后再用新的Base64编码表对数据进行加密,这样再用标准的Base64编码表就无法对使用经过变换顺序的Base64编码表加密的数据进行解密。Android SDK提供了一个Base64类,可以直接修改该类中的Base64编码和解码表。

/**  * BASE64解密  */  public static byte[] decryptBASE64(String key) throws Exception {      return (new BASE64Decoder()).decodeBuffer(key);  }    /**  * BASE64加密  */  public static String encryptBASE64(byte[] key) throws Exception {      return (new BASE64Encoder()).encodeBuffer(key);  }
注释:Java已经将Base64编码和解码操作封装实现,即BASE64Encoder、BASE64Decoder两个类。若需要使用Base64对数据进行加密,可以直接修改封装类中的Base64编码和解码表。然后,通过调用BASE64Encoder、BASE64Decoder两个类中相应的方法即可。需要注意的是,BASE加密后产生的字节位数是8的倍数,如果不够位数以=符号填充。 
4.Android SDK支持哪几种不可逆的加密算法?
    所谓不可逆是指数据经过加密后,不能还原成原来的数据。MD5、SHA以及HMAC是单向加密,任何数据加密后只会产生唯一的一个加密串,通常用来校验数据在传输过程中是否被修改。其中HMAC算法有一个密钥,增强了数据传输过程中的安全性,强化了算法外的不可控因素。 
    在有些情况下,并不需要还原经过加密的数据。例如:在登录过程中可以对密码进行加密,这样直接比较经过加密后的字符串即可;在验证文件一致性上也可以使用不可逆的加密算法,如当在下载Video或其他文件时看到还附带一个MD码。
Android SDK支持如下3种不可逆的加密算法:
(1)MD5(message-digest algorithm 5,信息-摘要算法)
    MD5为计算机安全领域广泛使用的一种散列函数,用以提供消息的完整性保护,其产生信息摘要的原理表述如下:MD5以512位分组来处理输入的信息,且每一分组又被划分为16个32位子分组,经过一系列的处理后,算法的输出由四个32位分组组成,将这四个32位分组级联后将生成一个128位散列值。
    MD5被广泛用于各种软件的密码认证和钥匙识别上。MD5用的是哈希函数,它的典型应用是对一段信息(Message)产生信息摘要(Message-Digest),以防止被纂改;也可以用于密码登录认证;如果再有一个第三方的认证机构,用MD5还可以防止文件作者的"抵赖",这就是所谓的数字签名应用。


/**  * MD5加密  */  //surce参数是待加密的字符串,encrypt_MD5方法返回加密后的结果public String encrypt_MD5(String source) throws Exception{     MessageDigest md5 = MessageDigest.getInstance("MD5");      md5.update(source.getBytes());      return Base64.encodingToString(md5.digest(),Base64.DEFAULT);   }
注:通常不直接使用MD5加密,而是将MD5产生的字节数组交给Base64再加密,最后得到相应的字符串(密文)。
(2)SHA(Secure Hash Algorithm,安全散列算法)
     SHA1是和MD5一样流行的消息摘要算法,主要适用于数字签名标准(Digital Signature Standard,DDS)里面定义的数字签名算法(Digital Signature Algorithm,DSA)。实现原理:SHA1算法可以采用不超过2^64位的数据输入,输入被划分为512位的块,并单独处理。160位缓冲器用来保存散列函数的中间和最后结果,其中,缓冲器可以由5个32位寄存器(A、B、C、D、E)来表示。最后,产生一个160位消息摘要。
    SHA1算法产生的消息摘要(大小为160位),可以用来验证数据的完整性(或称是为了保护文件完整性的技术)。比如数据在传输的过程中很可能会发生变化,那么这时候就会产生不同的消息摘要。SHA1不可以从消息摘要中复原信息,而两个不同的消息不会产生相同的消息摘要。    
    /**      * SHA加密      */  //surce参数是待加密的字符串,encrypt_SHA方法返回加密后的结果public String encrypt_SHA(String source) throws Exception{    MessageDigest sha = MessageDigest.getInstance("SHA");    sha .update(source.getBytes());    return Base64.encodingToString(sha .digest(),Base64.DEFAULT);}  
(3)HMAC(Hash Message Authentication Code,散列消息鉴别码)
    基于密匙的Hash算法的认证协议。消息鉴别码实现鉴别的原理是:用公开函数和密匙产生一个固定长度的值作为认证标识,用这个标识鉴别消息的完整性。使用一个密匙生成一个固定大小的小数据块,即MAC,并将其加入到消息中,然后传输,接收方利用与发送方共享的密匙进行鉴别认证等。
注:单纯的以上三种加密并不可靠。


/**  * 初始化HMAC密钥  */  public static String initMacKey() throws Exception{    KeyGenerator keyGenerator = KeyGenerator.getInstance();    SecretKey secretKey = keyGenerator.generateKey();    return Base64.encodingToString(secretKey.getEncoded(),Base64.DEFAULT);}//HMAC加密public static String encrypt_HMAC(String source,String key) throws Exception{    SecretKey secretKey = new                            SecretKeySpec(Base64.decode(key,Base64.DEFAULT),"HmacMD5");    Mac mac = Mac.getInstance(secretKey.getAlgorithm());    mac.init(secretKey);    return Base64.encodeToString(mac.doFinal(source.getBytes()),Base64.DEFAULT);}//使用HMAC算法对数据进行加密try{        String key = initMacKey();        String result = encrypt_HMAC("Android面试",key);    }catch(Exception e){        e.getMessage();    }
参考:http://blog.163.com/niwei_258/blog/static/106284882010111021953260/
5.根据自己的理解描述下Android数字签名?
(1)所有的应用程序都必须有数字证书,Android系统不会安装一个没有数字证书的应用程序
(2)Android程序包使用的数字证书可以是自签名的,不需要一个权威的数字证书机构签名认证
(3)如果要正式发布一个Android ,必须使用一个合适的私钥生成的数字证书来给程序签名,而不能使用adt插件或者ant工具生成的调试证书来发布。
(4)数字证书都是有有效期的,Android只是在应用程序安装的时候才会检查证书的有效期。如果程序已经安装在系统中,即使证书过期也不会影响程序的正常功能。
   
6.Android系统中GC什么情况下会出现内存泄露呢?
    内存泄漏,指实例化的对象所占的内存得不到释放,并且随着这类对象的增多,导致内存消耗殆尽。
(1)数据库的cursor没有关闭
(2)构造adapter时,没有使用缓存contentview
    衍生listview的优化问题-----减少创建view的对象,充分使用contentview,可以使用一静态类来    
    优化处理getview的过程。通过检测getView方法中的contentview,判断是否有能够被复用且之前出现过的列表项视图。
(3)Bitmap对象不使用时采用recycle()释放内存
(4)activity中的对象的生命周期大于activity
    调试方法: DDMS==> HEAPSZIE==>dataobject==>[Total Size]
7.android中有哪几种解析xml的类,官方推荐哪种?
1.DOM解析

 (1)优点
        ◆XML树在内存中完整存储,因此可以直接修改其数据和结构.
        ◆可以通过该解析器随时访问XML树中的任何一个节点.
        ◆DOM解析器的API在使用上也相对比较简单.
(2)缺点:如果XML文档体积比较大时,将文档读入内存是非常消耗系统资源的.
(3)使用场景:DOM 是用与平台和语言无关的方式表示 XML 文档的官方 W3C 标准.DOM 是以层次结构组织的节点的集合.这个层次结构允许开发人员在树中寻找特定信息.分析该结构通常需要加载整个文档和构造层次结构,然后才能进行任何工作.DOM是基于对象层次结构的.
2.SAX解析
(1)优点: SAX 对内存的要求比较低,因为它让开发人员自己来决定所要处理的标签.特别是当开发人员只需要处理文档中所包含的部分数据时,SAX 这种扩展能力得到了更好的体现. 
(2)缺点: 用SAX方式进行XML解析时,需要顺序执行,所以很难访问到同一文档中的不同数据.此外,在基于该方式的解析编码过程也相对复杂. 
(3)使用场景:
对于含有数据量十分巨大,而又不用对文档的所有数据进行遍历或者分析的时候,使用该方法十分有效.该方法不用将整个文档读入内存,而只需读取到程序所需的文档标签处即可.
3.Xmlpull解析
    android SDK提供了xmlpull api,xmlpull和sax类似,是基于流(stream)操作文件,然后根据节点事件回调开发者编写的处理程序.因为是基于流的处理,因此xmlpull和sax都比较节约内存资源,不会象dom那样要把所有节点以对象树的形式展现在内存中.xmlpull比sax更简明,而且不需要扫描完整个流.
  
8.如何将SQLite数据库(dictionary.db文件)与apk文件一起发布?
      可以将dictionary.db文件复制到Eclipse Android工程中的res/raw目录中。所有在res/raw目录中的文件不会被压缩,当需要打开res/raw目录中的数据库文件时,需要在程序第一次启动时将该文件复制到手机内存或SD卡的某个目录中,然后再打开该数据库文件,具体步骤如下:
    (1)使用getResources().openRawResource方法获得res/raw目录中资源的 InputStream对象
    (2)将该InputStream对象中的数据写入其他的目录中相应文件中;
    (3)使用SQLiteDatabase.openCreateDatabase方法来打开任意目录中的SQLite数据库文件
 
9.Android MVC?
   MVC模式,M表示模型(Model,即数据)、V表示视图(View,即界面)、C表示控制器(Controller,用于控制M和V之间的联系),使用MVC模式可以将显示部分与数据部分分离,这样方更换视图或模型时可以不影响对方,更有利于程序的维护。Android SDK就是采用了MVC模式来展现数据和界面的关系。MVC的基本原理如下:
    通过Controller连接View和Model,也就是说,当View中显示的数据变化时(如ListView要删除某个列表项),会通知Controller,而不是直接通知Model。这时Controller接到View的通知后,会在Model中采取响应的动作(如删除数据库中的某条记录)。如果模型的数据发生变化(如插入、删除数据库中的记录),会将通知控制器,然后控制器会通知视图重新显示数据。


    在Android SDK中使用MVC模式的组件非常多。例如,所有的列表控制(ListView、Spinner、GridView等)都采用MVC模式与数据交互。在Android中的V就代表这些组件,而M则代表各种数据源以及操作数据库的库。C则代表Adapter类。Android中的Adapter类分很多程度,但都拥有共同的接口。这些Adapter类主要包括BaseAdapter、SimpleAdapter、SimpleCursorAdapter、ArrayAdapter、CursorAdapter等。它们分别对应不同的数据源,例如,ArrayAdapter对应List和数组数据源,而CursorAdapter对应Cursor对象。这些Adapter类都需要使用getView方法返回当前列表项显示的View对象。当Model发生改变时,会调用BaseAdapter.notifyDataSetChanged方法通知组件数据变化时,这是Adapter会调用getView方法用于重新显示组件中的内容。当组件中显示的数据发生变化时,如删除一个列表项,组件会通过Adapter中的方法删除Model中相应的记录,然后再调用BaseAdapter.notifyDataSetChanged方法使组件中显示的数据发生变化。总之,无论是数据变化,还是组件中显示的数据发生变化,都需要将Adapter作为桥来达到View和Model之间同步的目的。
10.Android view树的绘制流程
1.UI框架基本概念

(1)Activity:基本的页面单元,Activity包含一个Window,在Window上可以绘制各种view;
(2)Window:表示顶层窗口,管理界面的显示和事件响应。每个Activity均会创建一个PhoneWindow对象,是Activity和整个View系统交互的接口;
(3)PhoneWindow类:该类继承于Window类,PhoneWindow类内部包含了一个DecorView对象。
    PhoneWindow是把一个FrameLayout进行了一定的包装,并提供了一组通用的窗口操作接口。
(4)DecorView:是Window中View的RootView,用于设置窗口属性。
(5)View:最基本的UI组件,表示屏幕上的一个矩形区域;
    ViewRoot:它并不是一个View类型,而是一个Handler。它的主要作用是用于向DecorView分发收到的用户发起的event事件,如按键、触屏等事件;另外,与WindowManagerService交互,完成整个Activity的GUI的绘制。

2.View树绘图流程
    整个View树的绘图流程是在ViewRoot.java类的performTraversals()函数展开,该函数做的执行过程描述如下:根据之前设置的状态,判断是否需要重新计算视图大小(measure)、是否重新需要安置视图的位置(layout)、以及是否需要重绘(draw),其框架过程如下:

11.Android的Touch事件处理机制
1.介绍View树

     在Android中所有的视图都继承于View,ViewGroup也继承于View,ViewGroup和View组成了一棵树形结构,最顶层为Activity的ViewGroup,下面有若干的ViewGroup节点,每个节点之下又有若干的ViewGroup节点或者View结点。 Android的Touch事件处理分为3个层面:Activity层,ViewGroup层,View层。在View和ViewGroup中都存在dispatchTouchEvent和onTouchEvent方法,在ViewGroup中还有一个onInterceptTouchEvent方法。

2.介绍响应的回调方法

  ★事件分发:public boolean dispatchTouchEvent(MotionEvent ev)
  Touch 事件发生时 Activity 的 dispatchTouchEvent(MotionEvent ev) 方法会以隧道方式(从根元素依次往下传递直到最内层子元素或在中间某一元素中由于某一条件停止传递)将事件传递给最外层 View 的 dispatchTouchEvent(MotionEvent ev) 方法,并由该 View 的 dispatchTouchEvent(MotionEvent ev) 方法对事件进行分发。dispatchTouchEvent 的事件分发逻辑如下:
- 如果 return true,事件会分发给当前 View 并由 dispatchTouchEvent 方法进行消费,同时
   事件会停止向下传递;
- 如果 return false,事件分发分为两种情况:
(1)如果当前 View 获取的事件直接来自 Activity,则会将事件返回给 Activity 的 onTouchEvent 进行消费;
(2)如果当前 View 获取的事件来自外层父控件,则会将事件返回给父 View 的  onTouchEvent 进行消费。
-  如果返回系统默认的 super.dispatchTouchEvent(ev),事件会自动的分发给当前 View 的 
    onInterceptTouchEvent 方法(如果是ViewGroup)并继续向下传递。


★事件拦截:public boolean onInterceptTouchEvent(MotionEvent ev)
zxdfg./?>mbvcx 如果 onInterceptTouchEvent 返回 true,则表示将事件进行拦截,并将拦截到的事件交\=-632dw    1sqw590-
   当前 View 的 onTouchEvent 进行处理;(return true:当前View的onTouchEvent处理)
- 如果 onInterceptTouchEvent 返回 false,则表示将事件放行,当前 View 上的事件会被传
   递到子 View 上,再由子 View 的 dispatchTouchEvent 来开始这个事件的分发;
- 如果 onInterceptTouchEvent 返回 super.onInterceptTouchEvent(ev),事件默认不会被拦 
    截。


★事件响应:public boolean onTouchEvent(MotionEvent ev)
    在dispatchTouchEvent 返回 super.dispatchTouchEvent(ev) 并且 onInterceptTouchEvent 返回 true onTouchEvent 会被调用。onTouchEvent 的事件响应逻辑如下:
- 如果事件传递到当前 View 的 onTouchEvent 方法,而该方法返回了 false,那么这个事件当前 View 向上传递,并且都是由上层 View 的 onTouchEvent 来接收,如果传递到上面的 onTouchEvent 也返回 false,这个事件就会“消失”,而且接收不到下一次事件。
- 如果返回了 true 则会接收并消费该事件。
- 如果返回 super.onTouchEvent(ev) 默认处理事件的逻辑和返回 false 时相同。  
3.Touch事件处理流程
    Android系统中将1个down事件、n个move事件、1个up事件整体作为一次逻辑上的触控操作,Down事件已经确定了处理事件的对象,则后续的move、up事件也确定了处理事件的对象。事件是通过层级传递的,一次事件传递对应一个完整的层级关系。事件传递是从ViewGroup传递到View的,而不是反过来传递的。触摸事件发生时(ACTION_DOWN),由系统调用Activity的dispatchTouchEvent方法,分发该事件。根据触摸事件的坐标,将此事件传递给容器控件或者显示控件的dispatchTouchEvent处理,如果是容器控件则调用onInterceptTouchEvent 判断事件是由自己处理,还是继续分发给子View。此处如果容器控件不处理Touch事件,故根据事件发生坐标,将事件传递给它的直接子View(容器控件或者显示控件)。onTouch事件要先于onClick事件执行,onTouch在事件分发方法dispatchTouchEvent中调用,而onClick在事件处理方法onTouchEvent中被调用,onTouchEvent要后于dispatchTouchEvent方法的调用。其他控件事件处理过程同上。另外如果控件是clickable 表示其能处理Touch事件。

  1) Touchevent 中,返回值是 true ,则说明消耗掉了这个事件;返回super.xxx则不处理,向下传递
  2) 事件传递的两种方式:
    - 隧道方式:从根元素依次往下传递直到最内层子元素或在中间某一元素中由于某一条件停止传递。
    - 冒泡方式:从最内层子元素依次往外传递直到根元素或在中间某一元素中由于某一条件停止传递。 
  android对Touch Event的分发逻辑是View从上层分发到下层(dispatchTouchEvent函数)类似于隧道方式,然后下层优先开始处理Event(先mOnTouchListener,再onTouchEvent)并向上返回处理情况(boolean值),若返回true,则上层不再处理,类似于冒泡方式。               

参考:http://blog.csdn.net/wangjinyu501/article/details/22584465
问题:如果Down事件被截获,Android系统还能捕获到Move事件和Up事件吗?
解决:不能。

原创粉丝点击