前台运行页面,用户可见、可操作。不能进行耗时操作。5s后会产生ANR
onCreate()-onStart()-onResume()-onPause()-onStop()-onDestroy()-onRestart()
onCreate:用户首次创建activity时
onStart:可见,无法与用户交互,没有焦点,用来做一些动画的初始化
onResume:当activity位于前台可供用户操作时,此时activity位于栈顶。可用来视频的继续播放
onPause:当另一个activity覆盖当前的activity时,可见,无法与用户交互。按回退键,再次执行onResume()
onStop:不可见,在系统内存紧张的情况下,有可能会被系统进行回收。所以可做资源回收工作。
onDestroy:可通过finish()销毁activity时
onRestart:app从后台返回前台时
standard(默认模式):
无论当前要打开的activity实例是否在栈顶,总是new activity实例。各个实例可以属于不同的 task,一个 task 中也可以存在多个实例。
singleTop:
当前要打开的activity实例存在于栈顶时,会复用该activity实例。否则new activity实例。
singleTask:
当前要打开的activity实例只要存在该栈中,就会复用该activity实例,同时位于该activity实例上面的其他activity实例都会被移出该栈,这个时候按返回键,别移出的activity页面将不再显示,除非重新打开该activity页面创建实例。
singleInstance:
当前要打开的activity实例只要存在于整个手机的堆中,就会复用。否则会在堆中创建新的实例
转载:详细解读activity启动流程中的各种进程的作用
1、减少onCreate()时间,减少初始化的操作,避免耗时操作
2、布局文件优化。减少层级结构、多使用include、merge等标签复用布局
3、在启动过程中有时会出现白屏、闪屏等情况,自定义一个主题在AndroidManifest.xml中设置上
答:会走onNewIntent->onStart->onResume
/***************************************************************************/
1、可以在程序运行时动态的切换(添加、替换、隐藏),并且比activity流畅,提高性能
2、可以动态创建不同尺寸的页面,也容易适配平板
3、依赖于activity,可以重用
4、可以传值也可以接受回传
onAttach()-onCreate()-onCreateView()-onActivityCreated()
-onStart()-onResume()-onPause()-onStop()
-onDestroyView()-onDestroy()-onDetach()-onRestart()
如果你不是手动开启回退栈,它是直接销毁再重建,但如果将Fragment任务添加到回退栈,它就有了类似Activity的栈管理方式。
/***************************************************************************/
后台运行服务,不提供页面呈现。不能进行耗时操作。20s后会产生ANR
1、BindService实现serviceConnection接口
重写onServiceConnected(判断是否连接上,需返回一个IBinder实例)和onServiceDisconnected(只在Service 被破坏了或者被杀死的时候调用)方法
2、广播+startService
HandlerThread:轻量级异步类,继承Thread,内部封装了Looper。因为子线程中没有Looper需要自己手动创建。
IntentService:Service+HandlerThread,自动开启线程,可以执行一些耗时任务,用完自动停止。防止出现ANR错误
service的优先级
1、前台进程
2、可见进程
3、服务进程
4、后台进程
5、空进程
【1】提高优先级我们可以使用startForeground()方法将Service设置为前台进程。
【2】双进程守护
创建主服务——创建守护服务
在继承service重载onStartCommand方法中返回各个参数的意义
START_STICKY:在Service被关闭后,重新开启Service
START_NOT_STICKY:服务被异常杀掉后,系统将会被设置为started状态,系统不会重启该服务,直到startService(Intent intent)方法再次被调用。
START_REDELIVER_INTENT:重传Intent,使用这个返回值时,如果在执行完onStartCommand后,服务被异常kill掉,系统会自动重启该服务,并将Intent的值传入。
START_STICKY_COMPATIBILITY:START_STICKY的兼容版本,但不保证服务被kill后一定能重启。
【3】继承JobService来实现应用退出后重启service,类似守护进程
【4】保证Service在开机后自动启动
注册广播——开机启动广播
/***************************************************************************/
主要用在多个进程间存储和读取数据
fileProvider继承自ContentProvider
/***************************************************************************/
不能进行耗时操作。10s后会产生ANR
多个进程都可以接收到
只能在本进程内接收到
在AndroidManifest.xml文件中注册。
静态注册的广播,即使Activity销毁了,仍然可以收到广播。即使杀死进程,仍然可以收到广播
java动态代码注册
动态注册的广播会受Activity的生命周期的影响, 当Activity销毁的时候,广播就失效了
Context.sendOrderedBroadcast()来发送一条有序的广播。从优先级高的开始,依次往下广播。获取上个广播返回的结果getResult()
用Context.sendBroadcast()来发送一条无序广播。没有getResult()方法
/***************************************************************************/
1、域名解析
2、TCP三次握手
3、建立连接后发起请求
4、服务端响应请求,返回给浏览器数据
5、浏览器解析html代码,同时请求资源(图片)
6、浏览器进行渲染
7、TCP四次挥手
/***************************************************************************/
关于 HTTP 请求报文和响应报文的格式这里就不再过多介绍了,简单说,HTTP 协议是以 ASCII 码传输,建立在 TCP/IP 协议之上的应用层规范。规范把 HTTP 请求分为三个部分:请求行、请求头、请求体。类似于:
<空格> <协议版本号> <回车> <换行符>
<请求头>
<请求体>
Volley VS OkHttp
Volley 的优势在于封装的更好,而使用 OkHttp 你需要有足够的能力再进行一次封装。而 OkHttp 的优势在于性能更高,因为 OkHttp 基于 NIO 和 Okio ,所以性能上要比 Volley更快。
Retrofit是在okHttp基础上封装好的,当然Retrofit更好一些。
主流网络架构
Retrofit + OkHttp + RxJava + Dagger2
/***************************************************************************/
1、json-lib(原生)
需要依赖很多jar包,对于复杂类型的bean的转换也很容易出错,pass
2、jackson
优点:依赖的jar包较少,简单易用,性能较高,社区比较活跃,更新速度快。
缺点:全部解析。无论是json转bean,对于复杂的数据类型,容易出错。bean转json不是标准的json格式数据。依赖包较大
3、Goolge的Gson
优点:按需解析,无需jar包,直接导入依赖,前提是需要创建好对应的bean。无论是json转bean,还是bean转json都无可挑剔。
缺点:性能比fastJson差点
4、阿里的fastJson
优点:按需解析,无需jar包,直接导入依赖,性能最好的json解析框架
缺点:bean转json有时会出现一些问题。
总结
1、可以考虑Gson与fastJson一起使用
在解析(json转bean)时用fastJson,在需要bean转json时使用Gson
2、数据量小时采用Gson,大采用fastJson
3、依赖包体积由小到大:Gson
1、Glide
优点:1、可以绑定生命周期,不仅可以传入Context还可以传入Activity和Fragment。
2、Glide加载的是与控件大小一样尺寸的图片即RGB_565,减小内存的开销
缺点 :体积大
2、Picasso
优点:体积小
缺点:1、加载的是全尺寸即ARGB_8888,内存开销较大
2、生命周期只能传入Context
3、Fresco
优势:在5.0的系统下,它会将图片放在一个特别的内存区域(Ashmem区),当图片不显示的时候,占用的内存会自动释放,减少了oom情况的发生
缺点:在5.0系统以后,系统默认将图片储存在Ashmem区域,导致优势全没
一级缓存:手机的运行内存
二级缓存:手机的磁盘(文件)
三级缓存:网络加载(流)
首先会先从一级缓存中加载,如果没有再从二级缓存中加载,还没有去网络缓存中加载,没有就请求接口得到数据
LruCache策略:在一级缓存中通常会设置一个储存容量最大值,一旦达到这个容量,就要进行释放一些使用次数较少的图片,达到避免产生oom的特殊情况
Picasso能做的Glide也都可以,并且Glide可以加载GIF动态图。Glide适用处理一些较大的图片流。
1、获取到图片的宽高,在使用SubsamplingScaleImageView框架(底层基于BitmapRegionDecoder)进行图片分段显示
2、压缩显示。设置固定宽高尺寸
/***************************************************************************/
1、最简单的dp适配
描述:不能很好的适配平板之类的宽屏
2、宽高限定符
描述:按一定的宽高,分段适配,不是很精确,需要增加很多的文件
3、最小宽度限定符
描述:按一定的宽,分段适配,精确,需要增加很多的文件
4、鸿洋的按屏幕的宽高比,动态修改视图宽高
描述:如果是自定义的view也会有所影响
5、今日头条保持dp(设计图总宽)不变,动态改变density(1dp占当前多少像素)px = density * dp
描述:全局修改 density,对于第三方布局有所影响
今日头条的AndroidAutoSize
/***************************************************************************/
1、RecyclerView设置横向滑动时,item居中,带有惯性
new LinearSnapHelper().attachToRecyclerView(mRecyclerView);
2、RecyclerView设置横向滑动时,item居中,效果类似ViewPager
new PagerSnapHelper().attachToRecyclerView(mRecyclerView);
3、ScrollView嵌套RecyclerView滑动冲突
1)代码设置
mRecyclerView.setHasFixedSize(true);确保每个item的宽高都是一定的,减少计算每个item的宽高
mRecyclerView.setNestedSrollingEnabled(false);阻止本身的滑动
2)业务设置
根据滑动的方向判断哪个事件消费,onInterceptTouthEvent()进行事件拦截
4、数据优化
1)分页加载,将数据缓存,提高二次加载的速度。
2)对于新增与删除的数据通过DiffUtil来进行局部刷新DiffUtil用来判断新数据与旧数据的差别,从而进行局部刷新
5、布局优化
1)减少item的绘制层级
2)共用RecycledViewPool线程池
3)RecyclerView数据预取
4)加大RecyclerView的缓存用空间换时间,提高流畅度
5)处理刷新时屏幕闪烁((DefaultItemAnimator)mRecyclerView.getItemAnimator()).setSupportsChangeAnimations(false);
/***************************************************************************/
1)没有使用的图片,没有进行释放
2)非静态内部类和匿名内部类持续持有外部类,导致外部类无法被GC回收
问题:比如Handler、AsycnTask等。
解决:1、改为静态内部类+软引用>弱引用>虚引用
2、Handler:removeCallbacksAndMessages(null)
3)静态变量引用内部类
问题:静态对象引用了方法内部类,方法内部类也是持有Activity实例的,会导致Activity泄漏
解决:就是通过在onDestory方法中置空static变量
4)使用较多的单例模式
问题:单例模式的生命周期与程序的生命周期一致,不能传入activity的生命周期
解决:传入application的生命周期getApplicationContext()
5)关闭activity时广播未取消注册
解决:在activity的onDestroy()方法中取消注册广unregisterReceiver()
6)弱网进行网络请求
问题:在弱网情况下就会导致接口回调缓慢,这时用户很可能就会退出Activity不在等待,但是这时网络请求还未结束,回调接口为内部类依然会持有Activity的对象,这时Activity就内存泄漏的,并且如果是在Fragment中这样使用不仅会内存泄漏还可能会导致奔溃。
解决:这类异常的原理和非静态内部类相同,所以可以通过【static内部类+弱引用进行处理。】由于本例是通过Retrofit进行,还可以【在onDestory进行call.cancel进行取消任务,】也可以避免内存泄漏。
7)Rxjava
问题:consumer这个为内部类,如果异步任务没有完成Activity依然是存在泄漏的风险的。
解决:RxJava有取消订阅的方法,在activity的onDestroy()方法中
if (disposable!=null && !disposable.isDisposed()){
disposable.dispose();
}
8)service用完也要停止服务
stopself();
/***************************************************************************/
1、可以在一个APP内做到免安装运行另一个app内的activity
2、hook插桩动态将只注册没有具体类的activity替换为另一个app内的实体activity
3、可以做到类似热更新
4、子moduel可单独运行,也可插到宿主上运行
1、按业务分不同的library或module,可以设置参数true或false更改为module或library,module可以单独运行,library不可单独运行,但是最终发布的时候是将这些组件(library)合并统一成一个apk
2、组件之间的跳转用Router框架
/***************************************************************************/
原理:在一个数组中存着.dex文件,将新类转换成.dex文件并在加载之前经信的.dex文件放在数组第一位,开始加载时会先加载新类,就不会再加载旧类,完成了修改更新
热更新框架对比
方案对比 | Sophix | Tinker | nuwa | AndFix | Robust | Amigo |
类替换 | yes | yes | yes | no | no | yes |
So替换 | yes | yes | no | no | no | yes |
资源替换 | yes | yes | yes | no | no | yes |
全平台支持 | yes | yes | yes | no | yes | yes |
即时生效 | 同时支持 | no | no | yes | yes | no |
性能损耗 | 较少 | 较小 | 较大 | 较小 | 较小 | 较小 |
补丁包大小 | 小 | 较小 | 较大 | 一般 | 一般 | 较大 |
开发透明 | yes | yes | yes | no | no | yes |
复杂度 | 傻瓜式接入 | 复杂 | 较低 | 复杂 | 复杂 | 较低 |
Rom体积 | 较小 | Dalvik较大 | 较小 | 较小 | 较小 | 大 |
成功率 | 高 | 较高 | 较高 | 一般 | 最高 | 较高 |
热度 | 高 | 高 | 低 | 低 | 高 | 低 |
开源 | no | yes | yes | yes | yes | yes |
收费 | 收费(设有免费阈值) | 收费(基础版免费,但有限制) | 免费 | 免费 | 免费 | 免费 |
监控 | 提供分发控制及监控 | 提供分发控制及监控 | no | no | no | no |
阿里的Sophix收费的阈(yu`)值
同一个账号中多个app合计的月活跃设备在10万以下免费,对于项目初期够用了
1、Sophix比较简单,而且对代码无侵入,好维护好操作易上手;(采用新理念性能消耗低)
Tinker接入很复杂,代码入侵,性能消耗很高,要合成资源,而且不支持即时生效
我的建议
我建议用Sophix,性能消耗低,支持即时生效,最主要的是对代码无侵入,便于代码的维护,以后的版本迭代,新功能的接入都不收影响。而且免费阈值对项目初期够用了。
原理:通过生成差分包的供下载,再合并达到更新的方式
详情:https://www.jianshu.com/p/f1f9d1c8bb4e
/***************************************************************************/
在子线程与主线程之间通讯。在子线程中发送消息,在主线程中处理消息。
1、Handler.sendMessage()发送message到MessageQueue队列中(通过enqueueMessage()加入到链表对应的位置)
2、Looper通过loop()开始不停的从MessageQueue中取出message(MessageQueue.next()不是消息阻塞,是异步阻塞IO)
3、调用message绑定的Handler对象(disptchMessage())交给发送该消息的Handler处理
4、如果是post发送的消息,直接在post()括号中new一个匿名Runnable处理事件。否则会调用我们复写的handlerMessage()进行处理
5、处理完成后会调用Message.recycle()将message放入对象池中,等待下次复用。
6、三者就形成了一个闭环
/***************************************************************************/
这里我主要写一下插值器与估值器
根据时间流逝的百分比计算出当前属性值改变的百分比。确定了动画效果变化的模式,如匀速变化、加速变化等等。View动画和属性动画均可使用。常用的系统内置插值器:
1、线性插值器(LinearInterpolator):匀速动画
2、加速减速插值器(AccelerateDecelerateInterpolator):动画两头慢中间快
3、减速插值器(DecelerateInterpolator):动画越来越慢
根据当前属性改变的百分比计算出改变后的属性值。针对于属性动画,View动画不需要类型估值器。常用的系统内置的估值器:
1、整形估值器(IntEvaluator)
2、浮点型估值器(FloatEvaluator)
3、Color属性估值器(ArgbEvaluator)
/***************************************************************************/
activity创建一个window,在window上展示view
/***************************************************************************/
区别 | Serializable | Parcelable |
所属API | JAVA API | Android SDK API |
原理 | 序列化和反序列化过程需要大量的I/O操作 | 序列化和反序列化过程不需要大量的I/O操作 |
开销 | 开销大 | 开销小 |
效率 | 低 | 很高 |
使用场景 | 序列化到本地或者通过网络传输 | 内存序列化 |
Seralizable
Seralizable相对Parcelable而言,好处就是非常简单,只需对需要序列化的类class执行就可以,不需要手动去处理序列化和反序列化的过程,但需要进行大量的IO操作
Parcelable
1、Parcelable是android特有的序列化API,它的出现是为了解决Serializable在序列化的过程中消耗资源严重的问题,但是因为本身使用需要手动处理序列化和反序列化过程,会与具体的代码绑定,使用较为繁琐。
2、而Parcelable依赖于Parcel,Parcel的意思是包装,实现原理是在内存中建立一块共享数据块,序列化和反序列化均是操作这一块的数据,如此来实现。
/***************************************************************************/
反应快、稳定、省电、apk体积小
1、反应快
1)布局优化:减少层级嵌套。避免页面结构复杂化。include、marge复用布局。
2)数据优化:避免在onCreate()中初始化大量数据。请求大量数据时分页加载
3)内存优化:避免在主线程中进行耗时操作,可以采用异步执行。减少内存的占用,将无用的图片、变量和对象进行释放,可以采用静态内部类+软引用/弱引用。
4)启动优化:
app启动流程:
1、Launcher所在的进程通过ActivityManagerProxy(代理对象)将工作交给ActivityManagerService,它来启动app并保存首先要启动activity
2、如果已经启动,就直接开启,否则就通过Zygote进程fork自身,启动一个新进程创建ActivityThread,启动其中的main函数(该线程相当于主线程)
3、在主线程中,将首先要启动activityd给到ActivityManagerService,
4、ActivityThread随后依次调用Looper.prepare()和Looper.loop()来开启消息循环.
5、通过ActivityThread把新建的进程和Application绑定,然后加载app的classes到内存中
6、启动 Activity。
【1】闪屏页优化
在AndroidManifest.xml中自定义一个全局主题,将闪屏那个页面替换自己的logo,通过属性android:windowBackground这样打开桌面图标会马上显示logo,不会出现黑/白屏,直到Activity启动完成,替换主题,logo消失,但是总的启动时间并没有改变。
【2】MultipDex优化
multiDexEnabled true:表示app内的方法数可以突破65536,一个dex装不下,用多个dex来装。MultipDex主要为了支持5.0以下的手机
Android 5.0以下,ClassLoader加载类的时候只会从class.dex(主dex)里加载,ClassLoader不认识其它的class2.dex、class3.dex、…,当访问到不在主dex中的类的时候,就会报错:Class NotFound xxx
如果虚拟机本身就支持加载多个dex文件,那就啥都不用做;如果是不支持加载多个dex(5.0以下是不支持的),则走到 doInstallation 方法。是比较耗时的。
一种是直接在闪屏页开个子线程去加载dex,难维护,不推荐;
ContentProvider初始化太早了,如果不在主dex中,还没启动闪屏页就已经crash了
一种是今日头条的方案,在单独一个进程加载dex,加载完,主进程再继续。
在另一个进程中加载dex,加个弹窗加载中,在视觉上会感觉启动变快了,其实时间没什么变化
【3】第三方库懒加载
第三方框架初始化可以在用到时在进行初始化,也就是懒加载。没有必要一定在application中进行加载。【异步进行加载】待确定
【4】卡顿优化
VSYNC 这个概念出来很久了,Vertical Synchronization,就是所谓的“垂直同步”。在 Android 中也沿用了这个概念,我们也可以把它理解为“帧同步”。为了保证 CPU、GPU 生成帧的速度和 Display 刷新的速度保持一致。
Android 系统每 16ms(更准确的是大概16.6ms) 就会发出一次 VSYNC信号触发 UI 渲染更新。大约屏幕一秒刷新60次,也就是说要求 CPU 和 GPU 每秒要有处理 60 帧的能力,一帧花费的时间在 16ms 内。如果超出这个时间就回出现卡顿。
卡顿产生的原因
1、布局页面复杂:渲染时间增加
2、过度绘制:绘制了多重背景或者绘制了不可见的UI元素.
3、主线程的复杂运算,耗时运算
4、频繁的GC:执行 GC 操作的时候,任何线程的任何操作都会需要暂停,等待 GC 操作完成之后,其他操作才能够继续运行, 故而如果程序频繁 GC, 自然会导致界面卡顿
解决:尽量不要在循环中大量的使用局部变量。防止同时创建大量的对象或变量
内存泄漏检测工具:LeakCanary
2、稳定
1、也就是不崩溃,可以进行try/catch进行捕获,最好是全局捕获线程异常,全局监控
2、避免产生ANR无响应,就是避免在主线程中执行耗时任务。
3、LMK:android的沙箱机制,每个应用程序都运行在一个独立的进程中,各自拥有独立的Dalvik虚拟机实例,系统默认分配给虚拟机的内存是有限度的。当系统内存太低依然会触发LMK(Low Memory Killer)机制,即出现闪退、崩溃现象。Android4.0以后,可以通过在application节点中设置属性android:largeHeap=”true”来设置最大可分配多少内存空间就可以突破一定限制。
3、省电
1、减少浮点运算
2、使用 Job Scheduler 管理后台任务。
4、apk体积小
1、开启混淆、压缩、去除多余的资源
2、压缩图片
3、避免引入无用的第三方库
/***************************************************************************/
1、不可逆: MD5、sha1
概念:没有办法逆向回推(MD5目前可以暴力解开)
2、对称加密: DES、AES(建议使用)
概念:用同一个密钥对数据进行加密/解密
对比:DES的密钥长度是56位,不安全。AES的密钥长度最少是128位,建议使用256位
3、非对称加密: RSA
概念:用公钥加密,用私钥解密。注意密钥长度不要低于512位,建议使用2048位的密钥长度
结合使用
1、用AES对数据进行加密
2、用RSA对AES的密钥进行加密
3、用https://…进行请求
/***************************************************************************/
AIDL是Android Interface Definition Language 的缩写。意思是Android接口定义语言。
1、服务端:服务端就是你要连接的进程。他提供给客户端一个Service,在这个Service中监听客户端的连接请求,然后创建一个AIDL接口文件,里面是将要实现的方法,注意这个方法是暴露给客户端的的。最后在Service中实现这个AIDL接口即可(这里是接口的具体实现)。服务端的职责是提供连接和自身
2、客户端:客户端首先需要绑定服务端的Service,绑定成功后,将服务端返回的Binder对象转换成AIDL接口所属的类型,最后调用AIDL的方法就可以了。可以看到,客户端还是比较简单的,负责连接和调用。
想让自己的Aapp得到Bapp数据,就需要选定Bapp作为服务端,Aapp作为客户端,一个服务端可以对应多个客户端。
具体创建一个.aidl文件,通过AIDL 接口进行通讯。 但是这个 AIDL 接口和普通接口不一样,其内部仅支持六种数据类型:
1、基本数据类型
2、String和CharSequence
3、List 接口(会自动将List接口转为 ArrayList),且集合的每个元素都必须能够被 AIDL 支持
4、Map 接口(会自动将 Map 接口转为 HashMap),且每个元素的 key 和 value 都必须被 AIDL 支持
5、Parcelable 的实现类
6、AIDL 接口本身
为保护进程不受其他进程破坏和干扰,Linux中的进程都是相对独立的,而起一个进程的内存空间被分为用户空间和内核空间,并且两者也都是相对隔离的
两次拷贝:第一次拷贝是将数据从Aapp的用户空间拷贝到内核缓存区,第二次是从内核空间(包含着内核缓存区)拷贝到Bapp的用户空间
binder的一次拷贝:将数据从Aapp的用户空间拷贝到内核缓存区,内核缓存区与数据接收缓存区存在着映射关系,而数据接收缓存区与Bapp的用户空间存在着映射关系,从而实现传递数据
性能
socket和管道数据拷贝需要两次,binder只拷贝一次,内存共享不需要拷贝,采用映射,但实现起来难度高,复杂性大,安全性也不高。
安全性
传统的通讯方式对于通讯双方并没有做出严格的验证,比如socket和ip需要手动填写,很容易进行伪造。binder机制从协议本身就支持对通讯双方做身份校验,从而提高了安全性。
/***************************************************************************/
v6.0:新增9个危险权限组,如果申请的权限属于其中的危险权限时,不仅需要静态注册,还需要动态申请,当用户同意其中一组中的一个权限,那么这个组内的其他权限也会默认同意。
v7.0:
1、在7.0之后,不支持在项目中传递file://类型的uri
解决:使用FileProvider进行uri转换成content://类型
2、引入V2签名方式,更加安全,在7.0以下会显示未安装
v8.0(Oreo ):
1、通知渠道:可以将自己不感兴趣的通知关掉,相当于分类
方法:先创建通知渠道,再创建通知,传入chnnelId,否则通知将不会显示
2、权限修改:修改了一下6.0的错误,只有当用户使用到已经同意的权限组中的权限时,才会默认同意当前一个权限,而不是刚开始将一组权限都默认立刻同意
3、静态广播无法正常接收:引入了新的广播接收器限制,静态广播将无法使用,只能使用动态广播
4、非全面屏透明页面无法设置方向
5、安装apk权限:需要声明一下添加未知应用的权限:
v9.0(pis):9.0以及以上版本采用androidx包,
1、9.0以后限制了明文流量的网络请求,最好采用https方式请求
在 res 下新建一个 xml 目录,然后创建一个名为:network_security_config.xml 文件 ,该文件内容如下:
然后再AndroidManifest,application标签中加入
android:networkSecurityConfig="@xml/network_security_config"
2、刘海屏的适配
v10.0(Q):
1、暗黑模式:Android Q 的暗黑模式和 Android Pie 的暗黑模式不同,在 Android Q 中,暗黑模式适用于任何地方,如果应用不支持暗黑模式,那么系统将自动设置一个暗黑模式。
2、隐私增强
3、超级锁定模式:开启飞行模式关闭所有的传感器
4、限制程序访问剪贴板:新的权限将阻止随机的后台应用程序访问剪贴板内容
5、应用程序降级:当对商店更新后的版本后悔时,可以“回到过去”即回滚到旧版。
第一种: HandlerThread
它是在一个线程中,把不同地方的任务,有序的放在消息队列中,Loop()循环取出任务,执行完当前任务才会继续执行下一个任务,HandlerThread就相当于一个线程,同步
第二种: AsyncTask
与第一种一样,但是多了任务执行进度的回调监听,AsyncTask 就相当于是一个线程,同步
class DownloadTask extends AsyncTask//可以传入三个参数,重写方法
第三种: Executors是基于ThreadPoolExecutor的封装
Executors.newFixedThreadPool()
创建一个定长的线程池,每提交一个任务就创建一个线程,直到达到池的最大长度,这时线程池会保持长度不再变化
Executors.newCachedThreadPool()
创建一个可缓存的线程池,如果当前线程池的长度超过了处理的需要时,它可以灵活的回收空闲的线程,利用空闲的线程去执行其他任务,不会增加新的线程。当需要增加时,它可以灵活的添加新的线程,而不会对池的长度作任何限制
Executors.newScheduledThreadPool()
创建一个定长的线程池,而且支持定时的以及周期性的任务执行,类似于Timer
Executors.newSingleThreadExecutor()
创建一个单线程化的executor,它只创建唯一的worker线程来执行任务
Executors适用于多任务异步执行
ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
for (int i = 0; i < 30; i++) {
cachedThreadPool.execute(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName());
}
});
}
第四种: IntentService
IntentService继承自Service,是一个经过包装的轻量级的Service,用来接收并处理通过Intent传递的异步请求。客户端通过调用startService(Intent)启动一个IntentService,利用一个work线程依次处理顺序过来的请求,处理完成后自动结束Service。
适用于后台执行的单个任务