巩固一下 Android知识

TCP和 UDP

tcp 的三次握手和四次挥手,三次握手是保证让服务器和客户端正常建立通道,而不是接收到失效的客户端请求而在等待,四次挥手就是取消释放资源
三次:1 请求服务器 发送报文字段, 请求说我需要请求
2 服务器确认下,返回确认信息 回答我可以了
3 客户端收到了,确认后再次返回确认,进行连接

释放的四次握手
第一次握手: A发送释放信息到B;(发出去之后,A->B发送数据这条路径就断了)
第二次握手: B收到A的释放信息之后,回复确认释放的信息:我同意你的释放连接请求
第三次握手: B发送“请求释放连接“信息给A
第四次握手: A收到B发送的信息后向B发送确认释放信息:我同意你的释放连接请求

udp 告诉,不可靠,不阻塞 不安全, 适合搞直播,丢包部分数据也可以.

TCP与UDP区别总结:
1、TCP面向连接(如打电话要先拨号建立连接);UDP是无连接的,即发送数据之前不需要建立连接
2、TCP提供可靠的服务。也就是说,通过TCP连接传送的数据,无差错,不丢失,不重复,且按序到达;UDP尽最大努力交付,即不保 证可靠交付
3、TCP面向字节流,实际上是TCP把数据看成一连串无结构的字节流;UDP是面向报文的UDP没有拥塞控制,因此网络出现拥塞不会使源主机的发送速率降低(对实时应用很有用,如IP电话,实时视频会议等)
4、每一条TCP连接只能是点到点的;UDP支持一对一,一对多,多对一和多对多的交互通信
5、TCP首部开销20字节;UDP的首部开销小,只有8个字节
6、TCP的逻辑通信信道是全双工的可靠信道,UDP则是不可靠信道

SharedPreferences 相关

是个轻量级的存储类,可以存基本类型数据,本质是写到了硬盘上的一个xml文件,从 data 包名的路径直接能进去找到,随便一个 Root 过的手机就能读取数据,安全性较低。
翻看源码是其本质都是存储为了 String 类型保存,所以我们可以封装一下更方便用,object 类型可以转 json 格式来上传, getSharedPreferences 是走 IO,但是 get 方法的方法 是从内存读,没有再就会创作一个新的 xml
写的过程 put 方法可以看自己需求,是否需要同步 用 apply 或者 commit 方法 apply 高效一下,走异步

消息队列机制 Looper Handler

主要是用于子线程发消息通知UI 线程进行 UI 的更新,UI 线程不能做一些耗时操作,所以用这个方式来传递消息,做一些延时或者定时的操作
ui 线程中的 handler sendMessage 消息 what 携带信息,或者 Runnable 携带一系列操作
然后重写 hander 的 handlerMessage 方法来获取信息,再做相关的操作
子线程是没有 Looper 的
原理就是 UI 线程中 有个 Looper 和 MessageQueue ,Looper 是一个轮询状态,sendMessage 的消息 会被加到队列里, 当 MessageQueue 是空的时候线程会阻塞, Looper.perprea() Looper.loop()

创建 Looper 的同时构造器里会创建一个队列

handler 像个驾驶员 looper 是个车库管理员,MessageQueeu 是个车库,message 是个车
handler 发消息,处理消息 ,looper 管理 MessageQueue 队列给对应的Handler

应用启动时,会开启一个主线程(UI线程),并且启动消息循环,应用不停地从该消息队列中取出、处理消息达到程序运行的效果。Looper对象封装了消息队列,Looper对象是ThreadLocal的,不同线程之间的Looper对象不能共享与访问。而Handler通过与Looper对象绑定来实现与执行线程的绑定,handler会把Runnable(包装成Message)或者Message对象追加到与线程关联的消息队列中,然后在消息循环中挨个取出消息,并且处理消息。当Handler绑定的Looper是主线程的Looper,则该Handler可以在handleMessage中更新UI,否则更新UI则会抛出异常!
其实我们可以把Handler、Looper、Thread想象成一个生产线,工人(搬运工)相当于Handler,负责将货物搬到传输带上(Handler将消息传递给消息队列);传送带扮演消息队列的角色,负责传递货物,货物会被挨取出,并且输送到目的地 ( target来处理 );而货物到达某个车间后再被工人处理,车间就扮演了Thread这个角色,每个车间有自己独立的传送带,车间A的货物不能被车间B的拿到,即相当于ThreadLocal( 车间独有 )。

AsyncTask 异步操作

怎么用

三个泛型参数 五个方法 execute
param 是输入的参数
progress 是进度
result 是结果 要输出的类型

doInBackground <T,E,R> 三个泛型
onPostExecute 结果

本质上

子线程和主线程的消息交互, 内部维护了一个handler 和 message 消息机制,只是更方便调用,让我们把注意力集中在各自线程的 操作
维护了一个并发线程池

WorkerRunnable futrueTask
阻塞队列 128 维护了一个线程池 现在版本是根据 cpu 核心数走的,大于 2 小于 4 理想状态是 核心-1目前是并发

线程池 ThreadPoolExecutor, ExecutorService 五个参数

我们用线程池 是因为 线程的创建 运行和销毁是资源消耗很大的,所以我们需要建立一个线程池来维护一下,优化我们的程序
官方提供了 可以用的几个模板的线程池 循环 ,设置最大数的,自动调整的,我们也可以自定义一个线程池,传入最大核心线程数,线程上线,存活时间 和任务队列(有多种类型), 比如我们可以用有序队列,自定义 类 实现 Comparable runnable 自定义一些自己想要的优先级,来完成 线程池的定制
还有一些拓展方法,before after terminated 的方法来做些
shutdowm 和 shutdownNow now会尝试停止正在运行的,shutdown 不会
asyncTask里面就是两个线程池 一个单线程的复用的,一个多线程并发的,可以自己指定用哪个

Context 上下文

Context一共有三种类型,分别是Application、Activity和Service
可以开 Activity Service 弹出弹窗 吐 Toast 操作数据库等等 但是安全机制保护 需要有 Activity 才可以操作的 比如开 activity和Dialog

LocalBroadcastManager和 BroadCastReceiver

用法区别不大 local 其实内部维护的是 handle 消息机制, 应用内应该更好些,BroadCastReceiver 用的比较宽泛 应用程序间相互通信,监听系统状态

实际开发 我还用到 eventBus

bindler。。。。。

Activity 的 四种启动

standard 标准的栈堆模式,先进后出
singeTask 有就复用,并把自己上面的其他的压出
singeInstance 单独开展开启
singeTop 栈顶是 就不会在开启了

四种状态,有焦点,可视无焦点 ,后台,待用

资源加载机制 用于换肤 语言包

getResource 编译的时候 会产生一个资源的表,AssetManager管理的 ,所有 content调用的都是一个资源表 ,可以用在换肤和更改语言包

setContontView

调用的是 windows 里的方法 把我们的布局 注入一个 FrameLayout,会创建一个根布局 、、、

HashMap和 ArrayMap

  1. 数据结构
    ArrayMap和SparseArray采用的都是两个数组,Android专门针对内存优化而设计的
    HashMap采用的是数据+链表+红黑树
  2. 内存优化
    ArrayMap比HashMap更节省内存,综合性能方面在数据量不大的情况下,推荐使用ArrayMap;
    Hash需要创建一个额外对象来保存每一个放入map的entry,且容量的利用率比ArrayMap低,整体更消耗内存
    SparseArray比ArrayMap节省1/3的内存,但SparseArray只能用于key为int类型的Map,所以int类型的Map数据推荐使用SparseArray;
  3. 性能方面:
    ArrayMap查找时间复杂度O(logN);ArrayMap增加、删除操作需要移动成员,速度相比较慢,对于个数小于1000的情况下,性能基本没有明显差异
    HashMap查找、修改的时间复杂度为O(1);
    SparseArray适合频繁删除和插入来回执行的场景,性能比较好
  4. 缓存机制
    ArrayMap针对容量为4和8的对象进行缓存,可避免频繁创建对象而分配内存与GC操作,这两个缓存池大小的上限为10个,防止缓存池无限增大;
    HashMap没有缓存机制
    SparseArray有延迟回收机制,提供删除效率,同时减少数组成员来回拷贝的次数
  5. 扩容机制
    ArrayMap是在容量满的时机触发容量扩大至原来的1.5倍,在容量不足1/3时触发内存收缩至原来的0.5倍,更节省的内存扩容机制
    HashMap是在容量的0.75倍时触发容量扩大至原来的2倍,且没有内存收缩机制。HashMap扩容过程有hash重建,相对耗时。所以能大致知道数据量,可指定创建指定容量的对象,能减少性能浪费。
  6. 并发问题
    ArrayMap是非线程安全的类,大量方法中通过对mSize判断是否发生并发,来决定抛出异常。但没有覆盖到所有并发场景,比如大小没有改变而成员内容改变的情况就没有覆盖
    HashMap是在每次增加、删除、清空操作的过程将modCount加1,在关键方法内进入时记录当前mCount,执行完核心逻辑后,再检测mCount是否被其他线程修改,来决定抛出异常。这一点的处理比ArrayMap更有全面。

死锁

死锁就是进程各种占有资源等待对方消息的情况,通俗的说就是一双筷子一人一根都在等对方用完,实际上只有一根筷子是用不完的,只能一直在手上。

解决方案 1线程加锁,保证两根筷子被同一人拿到,2 是加死锁超时,超时会释放资源,3 是使用死锁检测工具,检测到了对应处理。

Activity 的生命周期

onCreate() 生成
onStart() 可见
onResume() 可操作
onPause()
onStop()
onDestroy()

onCreate():进行布局的初始化,当需要用到数据库时对数据进行绑定等操作,
onStart():当activity处于可见之前调用onStart方法
onResume():当程序呈现在我们面前,并且能够与使用者进行交互
onStop():当activity不可见时调用
onRestart():当activity被执行onStop方法后,如果activity还行继续运行,就会执行onRestart方法
onPause():当现在的activity被其他的activity覆盖时,此时被覆盖的activity执行onPause方法,onPause()方法中由于我们的activity被其他activity覆盖,因此我们需要保存被覆盖的activity的数据,当程序再次运行时这些信息不会丢失。并且在onPause()中不能执行耗时的方法,如下载文件等,在onPause()方法中运行的程序一定很快,这样其他的activity才能尽快展现在我们面前。
onDestory():当activity不需要时调用,用于释放资源
从图中可以看的出来,一个Activity被创建后,就会调用3个方法,onCreate()、onStrart()、onResume()。那么这三个方法何时被调用,用来干嘛呢?
onCreate()方法,当一个Activity第一次被创建时首先被执行。此方法中,设置一些静态的的配置。例如加载布局文件设置应用标题,为按钮添加监听器等……
onStrart()方法,当一个Activity界面可见的时候执行。即,当用户可以看到应用界面的时候执行该方法。
onResume()方法,当我们的Activity获得用户焦点的时候执行。即,当前Activity可操作的时候,界面按钮可点可使用。
onPause()方法,如果在执行一个 Activity的时候,有另外一个Activity再被建立的时候,首先调用第一个Activity的onPause()方法。例如当我们在玩游戏的时 候,突然来电话了,电话应用的Activity被建立。此时需要先执行游戏Activity的onPause()方法。用来存储游戏的数据和当前状态。简e799bee5baa6e79fa5e98193e59b9ee7ad9431333335343438 单的说,如果当前应用被迫停止,去执行其它Activity,onPause()方法被调用。
onStop()方法,当前的Activity被迫停止,且新的Activity把原来的Activity完全遮挡住了,会调用第一个Activity的onStop()方法。
onRestart()方法,当接完电话了,需要返回继续游戏,用来执行第一个Activity的onRestart()方法。因为第一个Activity已经被建立,无需在创建。此方法用来释放onPause()方法存储的临时数据。
onDestrory()方法,返回到了游戏界面的Activity,打电话的Activity被销毁了,执行onDestrory()方法。
什么样的activity会被android系统杀死呢?
程序十分的费资源而此时系统又急需要资源,此时这个activity就会被杀死掉。那么如果activity在onStop()时被杀死了,那么就不会执行onDestory()方法了,类似在onPause()时被杀死,onStop()和onDestory()也都不会被执行了。当需要保存用户数据时我们应该在onPause()中进行保存。通常情况下,onCreate()、onStart()、onRestart()、onResume()不会被系统杀死,但是如果其中执行的程序太耗时的话还是会被系统杀死。

Activity 界面显示

可以先从 Activity 里开始看 我们看到的就是第一个生命周期 onCreate()方法 在里面调用了 setContentView()

contentView 里面是创建 Window,还有内部类 DecorView 注入了我们 xml 的布局 ,在此之后 我们才能 fbc 在此之前能设置 Windows 设置

层级基本就是
activity --phonewindow–decorView --{
title 和 ContentView
}

LayoutInflater

注入一个布局,把我们的 xml 文件转换成 java 的代码,其实本质上的 setContentView 方法内部也是 用的这个, xml 进行解析,用根节点的创建对应的 view 获取 xml 中配置的参数设置到 对应的 view 里、

而且是没有父布局的 根布局的 的 layout 参数都无效, 但是我们activity 自动填入的 xml 确实可以生效的,翻看代码 里面会发现其实是程序加了一个 父布局。

Activity 启动流程面试回答

Activity的启动过程,我们可以从Context的startActivity说起,其实现是ContextImpl的startActivity,然后内部会通过Instrumentation来尝试启动Activity,这是一个跨进程过程,它会调用ams的startActivity方法,当ams校验完activity的合法性后,会通过ApplicationThread回调到我们的进程,这也是一次跨进程过程,而applicationThread就是一个binder,回调逻辑是在binder线程池中完成的,所以需要通过Handler H将其切换到ui线程,第一个消息是LAUNCH_ACTIVITY,它对应handleLaunchActivity,在这个方法里完成了Activity的创建和启动,接着,在activity的onResume中,activity的内容将开始渲染到window上,然后开始绘制直到我们看见。——任玉刚大佬

Android 8.0 通知引入了渠道概念

我们创建的时候 可以把自己app 中的通知进行分级,然后用户选择对应的渠道进行,屏蔽或者操作。 用户可以给渠道定级别!、

Android 10 作用域存储

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
智能台灯智能台灯智能台灯智能台灯智能台灯智能台灯智能台灯智能台灯智能台灯智能台灯智能台灯智能台灯智能台灯智能台灯智能台灯智能台灯智能台灯智能台灯智能台灯智能台灯智能台灯智能台灯智能台灯智能台灯智能台灯智能台灯智能台灯智能台灯智能台灯智能台灯智能台灯智能台灯智能台灯智能台灯智能台灯智能台灯智能台灯智能台灯智能台灯智能台灯智能台灯智能台灯智能台灯智能台灯智能台灯智能台灯智能台灯智能台灯智能台灯智能台灯智能台灯智能台灯智能台灯智能台灯智能台灯智能台灯智能台灯智能台灯智能台灯智能台灯智能台灯智能台灯智能台灯智能台灯智能台灯智能台灯智能台灯智能台灯智能台灯智能台灯智能台灯智能台灯智能台灯智能台灯智能台灯智能台灯智能台灯智能台灯智能台灯智能台灯智能台灯智能台灯智能台灯智能台灯智能台灯智能台灯智能台灯智能台灯智能台灯智能台灯智能台灯智能台灯智能台灯智能台灯智能台灯智能台灯智能台灯智能台灯智能台灯智能台灯智能台灯智能台灯智能台灯智能台灯智能台灯智能台灯智能台灯智能台灯智能台灯智能台灯智能台灯智能台灯智能台灯智能台灯智能台灯智能台灯智能台灯智能台灯智能台灯智能台灯智能台灯智能台灯智能台灯智能台灯智能台灯

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值