Android 小知识点记录(二)

1.关于十进制移动上篇里说过,加强理解此处再粘贴一个例子:
(((oxf0ff&0x000f)|0x00f0)<<1)/(4>>1) = 255 即 0x00ff

                                                                                      // f0ff
        int i = 0xF0FF & 0x000F;                       // 0x000F   十六进制下也可以用   // 000f  的方式竖向计算.因为换成二进制之后..只不过是向左移动了四位.运算模式和规则没变.结果不变
        int i1 = i | 0x00F0;                           // 0x00FF
        int i2 = i1 << 1 / 2;                          // 0x00FF   移位符号永远是相对于二进制来说. 不能理解成在十六进制下的移位置运算
        Log.d("fssssss", "onCreate: "+i2);

        int i3 = 0x0F0 >>  1;   //120
        Log.d("fsssssssss", "onCreate: "+i3);
  1. 关于启动模式:
    使用Intent.FLAG_ACTIVITY_CLEAR_TOP + Intent.FLAG_ACTIVITY_SINGLE_TOP时调用了onNewIntent方法,复用了MainActivity,说明他们可以实现和singleTask一样的效果

Intent.FLAG_ACTIVITY_CLEAR_TOP 不等同于singleTask 启动模式,因为不会调用onNewIntent

3.能用思考和分析规避的的问题,避免用体力和bug 去尝试

  1. 装饰者和代理模式很像,只是结构上,但是功能上代理是为了访问控制(访问被代理 对象) 装饰者是为了增强功能

5.关于postInvalidate() requestLayout()
requestLayout() 只是通知父容器位置变化,重新进行measure 和layout 不会重新绘制ondraw
postInvalidate() 不关心位置变化,不走measure 和layout 只走ondraw

  1. SharePreferance 是否是线程安全的?
    SharedPreferences是线程安全的,它的内部实现使用了大量synchronized关键字SharedPreferences不是进程安全的第一次调用getSharedPreferences会加载磁盘 xml 文件(这个加载过程是异步的,通过new Thread来执行,所以并不会在构造SharedPreferences的时候阻塞线程,但是会阻塞getXxx/putXxx/remove/clear等调用),但后续调用getSharedPreferences会从内存缓存中获取。 如果第一次调用getSharedPreferences时还没从磁盘加载完毕就马上调用 getXxx/putXxx, 那么getXxx/putXxx操作会阻塞,直到从磁盘加载数据完成后才返回所有的getXxx都是从内存中取的数据,数据来源于SharedPreferences.mMapapply同步回写(commitToMemory())内存SharedPreferences.mMap,然后把异步回写磁盘的任务放到一个单线程的线程池队列中等待调度。apply不需要等待写入磁盘完成,而是马上返回commit同步回写(commitToMemory())内存SharedPreferences.mMap,然后如果mDiskWritesInFlight(此时需要将数据写入磁盘,但还未处理或未处理完成的次数)的值等于1,那么直接在调用commit的线程执行回写磁盘的操作,否则把异步回写磁盘的任务放到一个单线程的线程池队列中等待调度。commit会阻塞调用线程,知道写入磁盘完成才返回MODE_MULTI_PROCESS是在每次getSharedPreferences时检查磁盘上配置文件上次修改时间和文件大小,一旦所有修改则会重新从磁盘加载文件,所以并不能保证多进程数据的实时同步从 Android N 开始,,不支持MODE_WORLD_READABLE & MODE_WORLD_WRITEABLE。一旦指定, 直接抛异常

  2. 方法时间性能优化
    android.os.Debug.startMethodTracing(String traceName);
    android.os.Debug.stopMethodTracing();

    《Android 小知识点记录(二)》 微信截图_20190123201312.png

8.关于切换语言 导致栈内activity 重新创建的问题
如果栈里有两个activity 如果切换语言导致界面重新创建 , 则两个activity 创建时间是不同的,系统只会在activity 变为可见的时候重新创建,如果在A1 oncreate 中启动了A2 A1 onActivityResult 中finish() A1
那么 栈内A1 A2 的情况下,切换语言,a2 finish 生命周期如下
A1 onDestroy A1onCreate (先重新创建)
A1onActivityResult (中执行finish)
A2 onCreate (由此可见,是A2 先创建,为了resume 做好准备之后A1才销毁的)
A1 stop destory
A2 resume()

《Android 小知识点记录(二)》 微信截图_20190130171528.png

9.HTTP 和HTTPS

《Android 小知识点记录(二)》 微信图片_20190222155949.jpg

《Android 小知识点记录(二)》 微信图片_20190222155956.jpg

  1. tcp 三次握手四次挥手 http://www.cnblogs.com/zmlctt/p/3690998.html

1.为什么建立连接协议是三次握手,而关闭连接却是四次握手呢?

这是因为服务端的LISTEN状态下的SOCKET当收到SYN报文的连接请求后,它可以把ACK和SYN(ACK起应答作用,而SYN起同步作用)放在一个报文里来发送。但关闭连接时,当收到对方的FIN报文通知时,它仅仅表示对方没有数据发送给你了;但未必你所有的数据都全部发送给对方了,所以你可能未必会马上会关闭SOCKET,也即你可能还需要发送一些数据给对方之后,再发送FIN报文给对方来表示你同意现在可以关闭连接了,所以它这里的ACK报文和FIN报文多数情况下都是分开发送的。

2.为什么TIME_WAIT状态还需要等2MSL后才能返回到CLOSED状态?

这个问题可以参考《unix 网络编程》(第三版,2.7 TIME_WAIT状态)。

TIME_WAIT状态由两个存在的理由。

(1)可靠的实现TCP全双工链接的终止。

这是因为虽然双方都同意关闭连接了,而且握手的4个报文也都协调和发送完毕,按理可以直接回到CLOSED状态(就好比从SYN_SEND状态到ESTABLISH状态那样);但是因为我们必须要假想网络是不可靠的,你无法保证你最后发送的ACK报文会一定被对方收到,因此对方处于LAST_ACK状态下的SOCKET可能会因为超时未收到ACK报文,而重发FIN报文,所以这个TIME_WAIT状态的作用就是用来重发可能丢失的ACK报文。

(2)允许老的重复的分节在网络中消逝。

假 设在12.106.32.254的1500端口和206.168.1.112.219的21端口之间有一个TCP连接。我们关闭这个链接,过一段时间后在 相同的IP地址和端口建立另一个连接。后一个链接成为前一个的化身。因为它们的IP地址和端口号都相同。TCP必须防止来自某一个连接的老的重复分组在连 接已经终止后再现,从而被误解成属于同一链接的某一个某一个新的化身。为做到这一点,TCP将不给处于TIME_WAIT状态的链接发起新的化身。既然 TIME_WAIT状态的持续时间是MSL的2倍,这就足以让某个方向上的分组最多存活msl秒即被丢弃,另一个方向上的应答最多存活msl秒也被丢弃。 通过实施这个规则,我们就能保证每成功建立一个TCP连接时。来自该链接先前化身的重复分组都已经在网络中消逝了。

  1. 为什么不能用两次握手进行连接?

1.为什么建立连接协议是三次握手,而关闭连接却是四次握手呢?

这是因为服务端的LISTEN状态下的SOCKET当收到SYN报文的连接请求后,它可以把ACK和SYN(ACK起应答作用,而SYN起同步作用)放在一个报文里来发送。但关闭连接时,当收到对方的FIN报文通知时,它仅仅表示对方没有数据发送给你了;但未必你所有的数据都全部发送给对方了,所以你可能未必会马上会关闭SOCKET,也即你可能还需要发送一些数据给对方之后,再发送FIN报文给对方来表示你同意现在可以关闭连接了,所以它这里的ACK报文和FIN报文多数情况下都是分开发送的。
2.为什么TIME_WAIT状态还需要等2MSL后才能返回到CLOSED状态?

这个问题可以参考《unix 网络编程》(第三版,2.7 TIME_WAIT状态)。

TIME_WAIT状态由两个存在的理由。

(1)可靠的实现TCP全双工链接的终止。

这是因为虽然双方都同意关闭连接了,而且握手的4个报文也都协调和发送完毕,按理可以直接回到CLOSED状态(就好比从SYN_SEND状态到ESTABLISH状态那样);但是因为我们必须要假想网络是不可靠的,你无法保证你最后发送的ACK报文会一定被对方收到,因此对方处于LAST_ACK状态下的SOCKET可能会因为超时未收到ACK报文,而重发FIN报文,所以这个TIME_WAIT状态的作用就是用来重发可能丢失的ACK报文。

(2)允许老的重复的分节在网络中消逝。

假 设在12.106.32.254的1500端口和206.168.1.112.219的21端口之间有一个TCP连接。我们关闭这个链接,过一段时间后在 相同的IP地址和端口建立另一个连接。后一个链接成为前一个的化身。因为它们的IP地址和端口号都相同。TCP必须防止来自某一个连接的老的重复分组在连 接已经终止后再现,从而被误解成属于同一链接的某一个某一个新的化身。为做到这一点,TCP将不给处于TIME_WAIT状态的链接发起新的化身。既然 TIME_WAIT状态的持续时间是MSL的2倍,这就足以让某个方向上的分组最多存活msl秒即被丢弃,另一个方向上的应答最多存活msl秒也被丢弃。 通过实施这个规则,我们就能保证每成功建立一个TCP连接时。来自该链接先前化身的重复分组都已经在网络中消逝了。

  1. 为什么不能用两次握手进行连接?

我们知道,3次握手完成两个重要的功能,既要双方做好发送数据的准备工作(双方都知道彼此已准备好),也要允许双方就初始序列号进行协商,这个序列号在握手过程中被发送和确认。
现在把三次握手改成仅需要两次握手,死锁是可能发生的。作为例子,考虑计算机S和C之间的通信,假定C给S发送一个连接请求分组,S收到了这个分组,并发 送了确认应答分组。按照两次握手的协定,S认为连接已经成功地建立了,可以开始发送数据分组。可是,C在S的应答分组在传输中被丢失的情况下,将不知道S 是否已准备好,不知道S建立什么样的序列号,C甚至怀疑S是否收到自己的连接请求分组。在这种情况下,C认为连接还未建立成功,将忽略S发来的任何数据分 组,只等待连接确认应答分组。而S在发出的分组超时后,重复发送同样的分组。这样就形成了死锁。

    原文作者:fushuang
    原文地址: https://www.jianshu.com/p/179812be8864
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞