百度-APP相关安卓开发
- 安卓四大组件
- activaty生命周期 启动模式
- 一个Activity的生命周期主要有四种状态:
- Activity周期
- Activity的启动模式:
- 广播接收器
- 线程
- 多线程 线程池
- 进程 线程 携程
- 进程与线程比较
- 协程与线程比较
- 进程间通信方式和区别
- Mysql和Redis区别
- TCP UDP
- TCP三次握手四次挥手
- 区别
- OOP思想
- JAVA基础知识
- 内存泄漏场景及原因
- java内部类
- hashCode和equals
- Hashmap
- 算法类 递归方式怎么优化
安卓四大组件
Android 系统的四大组件分别是:
活动(activity),用于表现功能;
当创建完毕Activity之后,调用setContentView()方法来完成界面的显示;以此来 为用户提供交互的入口。
服务(service),后台运行服务,不提供界面呈现;
广播接受者(Broadcast Receive),用于接收广播;
内容提供者(Content Provider),支持多个应用中存储和读取数据,相当于数据库。
activaty生命周期 启动模式
一个Activity的生命周期主要有四种状态:
a.运行中(Running/Active):这时Activity位于栈顶,是可见的,并且可以用户交互。
b.暂停(Paused):当Activity失去焦点,不能跟用户交互了,但依然可见,就处于暂停状态。当一个新的非全屏的Activity或者一个透明的Activity放置在栈顶,Activity就处于暂停状态;这个时候Activity的各种数据还被保持着;只有在系统内存在极低的状态下,系统才会自动的去销毁Activity。
c.停止(Stoped):当一个Activity被另一个Activity完全覆盖,或者点击HOME键退入了后台,这时候Activity处于停止状态。这里有些是跟暂停状态相似的:这个时候Activity的各种数据还被保持着;当系统的别的地方需要用到内容时,系统会自动的去销毁Activity。
d.销毁(Detroyed):当我们点击返回键或者系统在内存不够用的情况下就会把Activity从栈里移除销毁,被系统回收,这时候,Activity处于销毁状态。
Activity周期
MainActivity会经过onCreate-> onStart -> onResume三个阶段,此时若按home键或则back按键,MainActivity会经过onPause -> onStop这两个阶段,再进入此MainActivity时,会再调用onRestart -> onStart -> onResume三个阶段。
Activity的启动模式:
通过在Mainfest.xml文件活动选项的android:launchMode属性来设置Activity的启动模式,各值对应模式如下:
1.standard模式:每次启动该活动时,都会在栈顶创建一个新的实例。 2.singTop模式(栈顶复用模式):在启动活动时,如果栈顶活动是该活动的实例,则不再创建新的实例,而是复用该实例对象;反之,则创建一个新的实例。
3.singTask模式(栈内单例模式):在启动活动时,如果任务栈中存在该活动的实例,则将其置于栈顶;反之,则创建一个新的实例。
4.sing Instance模式:这个模式是在整个Android系统中,只能启动或者存在一个活动对象。在启动该活动时,如果Android系统中没有该活动实例,则创建一个新的任务栈,再创建该活动的实例;反之,则复用已存在的实例对象
广播接收器
广播接收器是对发送出来的广播进行过滤接受并响应的一类组件。可以使用广播接收器来让应用对一个外部时间做出响应。例如,当电话呼入这个外部事件到来时,可以利用广播接收器进行处理。当下载一个程序成功完成时,仍然可以利用广播接收器进行处理。广播接收器不NotificationManager来通知用户这些事情发生了。广播接收器既可以在AndroidManifest.xml中注册,也可以在运行时的代码中使用Context.registerReceive()进行注册。
广播接收者的注册有两种方法,分别是程序动态注册(在运行时的代码中使用Context.registerReceive()进行注册)和AndroidManifest文件中进行静态注册。
线程
多线程 线程池
多线程-线程池
进程 线程 携程
安卓实现多线程
进程是一个“执行中的程序”。
线程是操作系统能够进行运调度的最小单位。
协程(coroutine)是一种程序运行的方式,即在单线程里多个函数并发地执行。
进程与线程比较
线程是指进程内的一个执行单元,也是进程内的可调度实体。线程与进程的区别:
地址空间:进程有自己独立的地址空间,进程之间相互独立。线程是进程内的一个执行单元,一个进程内的所有线程共享地址空间。
一个进程内至少有一个线程,线程是一个进程中代码的不同执行路线。某进程内的线程在其它进程不可见。
资源拥有:进程之间相互独立,但同一进程下的各个线程之间共享程序的内存空间(包括代码段、数据集、堆等)及一些进程级的资源(如打开文件和信号),某进程内的线程在其它进程不可见。
线程是处理器调度的基本单位,但进程不是。
二者均可并发执行。
调度和切换:线程上下文切换比进程上下文切换要快得多。
协程与线程比较
一个线程可以多个协程,一个进程也可以单独拥有多个协程,这样python中则能使用多核CPU。
线程进程都是同步机制,而协程则是异步。
协程能保留上一次调用时的状态,每次过程重入时,就相当于进入上一次调用的状态。
进程间通信方式和区别
管道:只能单向传递,且只能在有亲缘关系的进程中使用
有名管道:也是单向传递,但可以在非亲缘进程中使用
信号量:可以用来控制多个进程对共享资源的访问
消息队列:消息队列克服了信号传递信息少、管道只能承载无格式字节流以及缓冲区大小受限等缺点;
信号:是一种操作系统通知进程某件事情已经发生的方式。
共享内存:存在于内存中,由多个进程共享的一块内存空间。
Socket:不同主机之间通信。
1.管道:速度慢,容量有限,只有父子进程能通讯
2.FIFO:任何进程间都能通讯,但速度慢
3.消息队列:容量受到系统限制,且要注意第一次读的时候,要考虑上一次没有读完数据的问题
4.信号量:不能传递复杂消息,只能用来同步
5.共享内存区:能够很容易控制容量,速度快,但要保持同步,比如一个进程在写的时候,另一个进程要注意读写的问题,相当于线程中的线程安全,当然,共享内存区同样可以用作线程间通讯,不过没这个必要,线程间本来就已经共享了同一进程内的一块内存
Mysql和Redis区别
mysql是关系型数据库,主要用于存放持久化数据,将数据存储在硬盘中,读取速度较慢。
redis是NOSQL,即非关系型数据库,也是缓存数据库,即将数据存储在缓存中,缓存的读取速度快,能够大大的提高运行效率,但是保存时间有限。
TCP UDP
TCP三次握手四次挥手
三次握手
三次握手(Three-way Handshake)其实就是指建立一个TCP连接时,需要客户端和服务器总共发送3个包。进行三次握手的主要作用就是为了确认双方的接收能力和发送能力是否正常、指定自己的初始化序列号为后面的可靠性传送做准备。实质上其实就是连接服务器指定端口,建立TCP连接,并同步连接双方的序列号和确认号,交换TCP窗口大小信息。
第一次握手:客户端给服务端发一个 SYN 报文,并指明客户端的初始化序列号 ISN。此时客户端处于 SYN_SENT 状态。
首部的同步位SYN=1,初始序号seq=x,SYN=1的报文段不能携带数据,但要消耗掉一个序号。
第二次握手:服务器收到客户端的 SYN 报文之后,会以自己的 SYN 报文作为应答,并且也是指定了自己的初始化序列号 ISN(s)。同时会把客户端的 ISN + 1 作为ACK 的值,表示自己已经收到了客户端的 SYN,此时服务器处于 SYN_RCVD 的状态。
在确认报文段中SYN=1,ACK=1,确认号ack=x+1,初始序号seq=y。
第三次握手:客户端收到 SYN 报文之后,会发送一个 ACK 报文,当然,也是一样把服务器的 ISN + 1 作为 ACK 的值,表示已经收到了服务端的 SYN 报文,此时客户端处于 ESTABLISHED 状态。服务器收到 ACK 报文之后,也处于 ESTABLISHED 状态,此时,双方已建立起了连接。
确认报文段ACK=1,确认号ack=y+1,序号seq=x+1(初始为seq=x,第二个报文段所以要+1),ACK报文段可以携带数据,不携带数据则不消耗序号。
为什么需要三次握手,两次不行吗?
弄清这个问题,我们需要先弄明白三次握手的目的是什么,能不能只用两次握手来达到同样的目的。
第一次握手:客户端发送网络包,服务端收到了。
这样服务端就能得出结论:客户端的发送能力、服务端的接收能力是正常的。
第二次握手:服务端发包,客户端收到了。
这样客户端就能得出结论:服务端的接收、发送能力,客户端的接收、发送能力是正常的。不过此时服务器并不能确认客户端的接收能力是否正常。
第三次握手:客户端发包,服务端收到了。
这样服务端就能得出结论:客户端的接收、发送能力正常,服务器自己的发送、接收能力也正常。
因此,需要三次握手才能确认双方的接收与发送能力是否正常。
四次挥手
刚开始双方都处于ESTABLISHED 状态,假如是客户端先发起关闭请求。四次挥手的过程如下:
第一次挥手:客户端发送一个 FIN 报文,报文中会指定一个序列号。此时客户端处于 FIN_WAIT1 状态。
即发出连接释放报文段(FIN=1,序号seq=u),并停止再发送数据,主动关闭TCP连接,进入FIN_WAIT1(终止等待1)状态,等待服务端的确认。
第二次挥手:服务端收到 FIN 之后,会发送 ACK 报文,且把客户端的序列号值 +1 作为 ACK 报文的序列号值,表明已经收到客户端的报文了,此时服务端处于 CLOSE_WAIT 状态。
即服务端收到连接释放报文段后即发出确认报文段(ACK=1,确认号ack=u+1,序号seq=v),服务端进入CLOSE_WAIT(关闭等待)状态,此时的TCP处于半关闭状态,客户端到服务端的连接释放。客户端收到服务端的确认后,进入FIN_WAIT2(终止等待2)状态,等待服务端发出的连接释放报文段。
第三次挥手:如果服务端也想断开连接了,和客户端的第一次挥手一样,发给 FIN 报文,且指定一个序列号。此时服务端处于 LAST_ACK 的状态。
即服务端没有要向客户端发出的数据,服务端发出连接释放报文段(FIN=1,ACK=1,序号seq=w,确认号ack=u+1),服务端进入LAST_ACK(最后确认)状态,等待客户端的确认。
第四次挥手:客户端收到 FIN 之后,一样发送一个 ACK 报文作为应答,且把服务端的序列号值 +1 作为自己 ACK 报文的序列号值,此时客户端处于 TIME_WAIT 状态。需要过一阵子以确保服务端收到自己的 ACK 报文之后才会进入 CLOSED 状态,服务端收到 ACK 报文之后,就处于关闭连接了,处于 CLOSED 状态。
即客户端收到服务端的连接释放报文段后,对此发出确认报文段(ACK=1,seq=u+1,ack=w+1),客户端进入TIME_WAIT(时间等待)状态。此时TCP未释放掉,需要经过时间等待计时器设置的时间2MSL后,客户端才进入CLOSED状态。
挥手为什么需要四次
因为当服务端收到客户端的SYN连接请求报文后,可以直接发送SYN+ACK报文。其中ACK报文是用来应答的,SYN报文是用来同步的。但是关闭连接时,当服务端收到FIN报文时,很可能并不会立即关闭SOCKET,所以只能先回复一个ACK报文,告诉客户端,“你发的FIN报文我收到了”。只有等到我服务端所有的报文都发送完了,我才能发送FIN报文,因此不能一起发送。故需要四次挥手。
区别
OOP思想
oop详细解析
JAVA基础知识
内存泄漏场景及原因
1、大量使用static
会造成一时的内存泄漏,直到程序运行完毕才会释放
这是因为静态变量的生命周期和主函数保持一致,所以尽量减少使用静态变量
2、资源未被关闭
在使用到jdbc、数据库连接、io连接等,都会进行一个jvm的分配内存
最后代码模块都会进行一个资源的关闭,如果资源未被正常关闭,内存就一直在运行,直到主函数关闭(但是并不是时时刻刻都在连接查询资源)
3、finalize导致
final是一个关键字。表示最终的。不变的
finally也是一个关键字,和try联合使用,使用在异常处理机制中
finalize()是Object类中的一个方法。作为方法名出现,finalize是标识符。这个方法是由垃圾回收器GC负责调用的
在这里插入图片描述
之所以会造成内存泄漏,是因为在垃圾回收的时候,如果重写了finalize方法而且该对象的finalize方法没有被执行过,但是进入队列之后一直没被调用就会一直占用内存空间
java内部类
内部类:一个类嵌套在另一个类的内部,称这个嵌套类为内部类.
根据定义的位置和使用的关键字的不同,可以分为以下四种内部类
1、成员内部类
2、静态内部类
3、局部内部类
4、匿名内部类
成员内部类:直接定义在类中,不加static定义的内部类就称为成员内部类 可以用private方法进行修饰
局部内部类是定义在一个方法或者一个作用域里面的类,它和成员内部类的区别在于局部内部类的访问仅限于方法内或者该作用域内;
2.局部内部类不可使用权限修饰符 静态(static)修饰符进行修饰 同局部变量相同;
3.局部内部类可以直接访问方法中的属性;
4.局部内部类 可以直接访问方法外部类中属性和方法;
5.局部内部类 创建对象 要在方法内部 局部内部类的外部声明。
匿名内部类不能定义任何静态成员、方法和类,只能创建匿名内部类的一个实例。一个匿名内部类一定是在new的后面,用其隐含实现一个接口或实现一个类。
静态内部类也是定义在另一个类里面的类,只不过在类的前面多了一个关键字static;
静态内部类是不需要依赖于外部类的,这点和类的静态成员属性有点类似,并且它不能使用外部类的非static成员变量或者方法;
hashCode和equals
equals和hashcode
Hashmap
hashmap
算法类 递归方式怎么优化
斐波那契数列-递归优化