Android面试总结(Android篇)

Android相关

Activity:

OnSaveInstanceState(Bundle outState)
OnRestoreInstanceState(Bundle savedInstanceState)
横竖屏切换时设置 configchanges = "orientation | screenSize" 不会重新调用各个生命周期,会执行onConfigurationChanged方法。

启动模式:
1.标准模式 standard
2.栈顶复用模式 singleTop
如位于栈顶,不会重新创建,调用OnNewIntent,OnCreate、OnStart不会调用,如不在栈顶或栈内没有,重新创建
3.栈内复用模式 singleTask
同singleTop,如不在栈顶,会移除上面所有Activity
4.单实例模式 singleInstance
单独栈且只有一个实例,使用ApplicationContext或Service中启动时,设置FLAG_ACTIVITY_NEW_TASK,启动一个新栈

Activity启动流程:
1.Activity调用StartActivity,会调用Instrumentation的execStartActivity方法,
Instrumentation是系统用来监控Activity运行的一个类
2.通过跨进程的Binder调用进入到ActivityManagerService中,其内部会处理Activity栈
3.在ActivityManagerService中,startProcessLocked中调用process.start()方法,
并通过socket通知zygote(整个系统创建进程的核心进程,在内部会启动Dalvik虚拟机)执行fork任务,
并通过跨进程进入到新Activity的进程
4.主线程发起绑定Application,ApplicationThread将启动Activity的信息通过Handler发送给主线程,
主线程根据拿到的信息调用Instrumentation的newActivity方法创建Activity实例
5.通过Activity去performCreateActivity

Activity绘制流程:
1.在调用ActivityThread的performLaunchActivity时,创建Activity对象,并调用attach方法创建phoneWindow和windowManagerImpl,
phoneWindow代表了应用端的window,windowManagerImpl用于添加、更新、删除View
2.在OnCreate方法中调用setContentView时会在phoneWindow中新建DecorView,DecorView包含两个部分,
标题栏和内容栏,内容栏就是SetContentView设置的布局
3.在调用ActivityThread的handleResumeActivity时,会获取创建的DecorView对象,
通过WindowManagerGlobal的对象addView把所有View添加到DecorView上
ActivityThread:
handleLaunchActivity -> performLaunchActivity(创建Activity对象 ->执行Activity.attach创建phoneWindow -> 
 OnCreate,创建DecorView,添加布局 -> Onstart -> OnResume 将DecorView添加到WindowManager ->
  WindowManagerImpl.addView -> WindowManagerGlobal.addView)
ViewRootImpl:
setView -> requestLayout -> ScheduleTraversals(这里发送异步消息任务postSyncBarrier)-> 
doTraversal(移除同步屏障removeSyncBarrier)-> performTravelsals(这里会把数组队列中的Runnable,
也就是View.post的Runnable取出,然后通过handler.postDelayed加入消息队列等待执行,
因为绘制一系列操作是通过异步任务优先执行,所以此时执行的View.post一定在绘制后,所以在这里可以拿到宽高)->
 performMeasure -> performLayout -> performDraw

Fragment:

生命周期:
OnAttach -> OnCreate -> OnCreateView -> OnActivityCreate -> OnStart -> OnResume -> OnPause -> 
Onstop -> OnDestoryView -> OnDestory -> OnDetach
Activity和Fragment交互:
Handler、广播、EventBus、接口回调、Bundle/setArgments

Service

在后台长时间运行而不提供用户界面的组件
启动方式:
startService:主线程,启动它的Activity销毁不影响Service运行
OnCreate -> OnStartCommand -> OnDestory
Service首次启动会调用OnCreate、OnStartCommand,如Service已经启动,则直接调用OnStartCommand
bindService:绑定关系,如调用者销毁,Service终止
OnCreate -> OnBind -> OnUnBind -> OnDestory
首次绑定会调用OnBind,再次绑定bindService不创建新的Service,也不会调用OnBind
IntentService:内部维护一个工作线程(子线程)来处理耗时任务,当任务执行完,IntentService会自动停止。

冷启动流程:

ActivityManagerService通过socket通知zygote发送fork进程的任务,通过反射启动ActivityThread的main方法,
最后由ActivityManagerService通过AIDL告诉ActivityThread反射启动创建App实例,并依次执行 attachBaseContext、OnCreate,然后创建MainActivity。
总结:Application构造方法 -> attachBaseContext -> OnCreate -> Activity构造方法 -> OnCreate -> 
配置主题中背景等属性 -> Onstart -> OnResume -> 测量布局绘制
冷启动的优化:
1.减少在Application和第一个Activity的OnCreate中的工作量
2.不要在Application中处理耗时等操作
3.不要以静态变量的方式在Application中保存数据
4.减少布局的复杂度和深度

自定义View

动态创建View时需 View(Context context)构造器,从xml.inflate时需View(Context context, AttributeSet attr)
View的绘制流程从顶级View(DecorView)的ViewGroup开始,一层一层从ViewGroup至子View遍历测绘,
View绘制流程开始于ViewRootImpl对象的performTravelsals

MeasureSpec(测量规格):
由测量模式mode和测量大小size组成
mode:
	unspecified  无限制模式,一般系统内部使用
	exactly  精准模式  match_parent 或具体数值(100dp)
	at_most  最大模式  wrap_content 指定一个最大尺寸
View的MeasureSpec值计算取决于:View自身的布局参数(LayoutParams)和父容器的测量规格(MeasureSpec)
当父mode为exactly时:
	子View LayoutParams >= 0,那么子View的 size = 子View的值,子View的  mode = exactly;
	子View LayoutParams = match_parent,那么子View的 size = 父View的值,子View的 mode = exactly;
	子View LayoutParams = wrap_parent,那么子View的 size = 父View的值,子View的 mode = at_most
当父mode为at_most时:
	子View LayoutParams >= 0,那么子View的 size = 子View的值,子View的 mode = exactly;
	子View LayoutParams = match_parent,那么子View的 size = 父View的值,子View的 mode = at_most;
	子View LayoutParams = wrap_content,那么子View的 size = 父View的值,子View的 mode = at_most
当父mode为unspecified时:
	子View LayoutParams >= 0,那么子View size = 子View的值,子View的 mode = exactly;
	子View LayoutParams = match_parent,那么子View size = 0,子View的 mode = unspecified;
	子View LayoutParams = wrap_content,那么子View size = 0,子View的 mode = unspecified

measure -> layout -> draw
1.getWidth和getHeight在layout后才能获得,getMeasureWidth在measure后才能获得
2.onDraw中避免创建新的局部对象,会产生大量的临时对象,占用大量内存频率GC,效率降低,不能执行耗时操作,每16ms会重新绘制
3.canvas.save可以保存canvas的状态,restore恢复canvas之前保存的状态

RecyclerView和ListView

RecyclerView四级缓存:
	1.屏幕内缓存,一级缓存,缓存屏幕中显示的ViewHolder。AttachedScrap表示未与RecyclerView分离的ViewHolder列表,
	ChangedScrap表示数据已经改变的ViewHolder列表;
	2.屏幕外缓存,二级缓存,缓存滑出屏幕的ViewHolder,缓存在CachedViews里;
	3.RecyclerViewPool,三级缓存,重写getItemType,通过type来获取ViewHolder,获取的是全新的需要重新绑定数据;
	4.ViewCacheExtension,四级缓存,自定义缓存
	
ListView二级缓存:ActiveViews和ScrapViews,缓存的是itemView

区别:
	1.ListView实现分割线、header、footer、点击长按监听简单;
	2.ListView只支持竖向滑动,RecyclerView支持横竖、网格;
	3.RecyclerView局部刷新简单,使用payload参数的notifyItemChanged方法可自定义处理局部刷新(payload不为空,
	holder会放入AttachedScrap中,不会移除重新bind,payload为空,holder会放入ChangedScrap中,会移除重新bind)

线程池

1.首先判断核心线程池中的线程是否已经满,如果没满,则创建一个核心线程执行任务(注意执行这一步,要获取全局锁);
2.如果核心池中线程已满,则判断任务阻塞队列是否已满,没有满则加入阻塞队列;
3.如果任务阻塞队列已满,判断线程池中的线程数是否达到最大值,没达到则创建非核心线程执行任务;
4.否则执行饱和拒绝策略
	AbortPolicy:直接抛出异常,默认策略
	CallerRunsPolicy:用调用者所在的线程来执行任务
	DiscardOldestPolicy:丢弃阻塞队列中靠最前的任务,并执行当前任务
	DiscardPolicy:直接丢弃任务
	也可实现RejectedExecutionHandler接口,自定义饱和策略。

核心参数:
	corePoolSize:核心线程数,当线程数小于该值时,线程池会优先创建新线程来执行新任务
	maximumPoolSize:线程池所能维护的最大线程数
	keepAliveTime:空闲线程的存活时间
	unit:空闲线程存活时间的单位,是一个枚举类
	workQueue:任务队列,用于缓存来执行的任务
	threadFactory:线程工厂,设置线程名字
	handler:拒绝策略,默认AbortPolicy

线程回收策略:
	核心线程空闲线程:设置allowCoreThreadTimeout(true)
	非核心线程空闲线程:当线程空闲时间超过keepAliveTime

缓存队列:
	同步队列、有界队列、无界队列、优先级队列

提交任务:execute、submit

关闭线程池:
	shutdown:状态设为SHUTDOWN,正在执行的任务继续,没有执行则中断
	shutdownNow:状态设置STOP,正在执行被停止,没有执行则中断

创建线程池:
	Executors.newFixedThreadPool:构建包含固定线程数的线程池,空闲线程不会被回收
	Executors.newCachedThreadPool:构建线程数不定的线程池,线程数量随任务量变动,空闲线程超过60s会被回收
	Executors.newSingleThreadExecutor:构建线程数为 1 的线程池,等价于 newFixedThreadPool(1) 所构造出来的线程池
	Executors.newScheduledThreadPool:构建核心线程数为corePoolSize,可执行定时任务的线程池
	Executors.newSingleThreadScheduledExecutor:等价于newScheduledThreadPool(1)

异步任务的实现方式

1.Thread Runnable结合Handler
2.AsyncTask  doInBackgroud  onProgressUpdate  onPostExecute
3.HandlerThread:继承Thread,内部会创建Handler
4.IntentService:Service + HandlerThread的结合体
5.线程池

类加载机制:

加载:把类以流的形式加载进内存,将字节流代表的静态存储结构转化为方法区运行时的数据结构,生产class对象
验证:类进行合法性验证,类中的语法结构等
准备:给类变量分配内存
解析:对类变量、类方法的符号引用转化为直接引用
初始化:父类静态成员变量 -> 父类静态代码块 -> 子类静态成员变量 -> 子类静态代码块 -> 父类成员变量 -> 
父类非静态代码块 -> 父类构造器 -> 子类成员变量 -> 子类非静态代码块 -> 子类构造器

Java类加载器:BootStrapClassLoader、ExtendsClassLoader、应用程序类加载器
Android类加载器:BootClassLoader、UrlClassLoader、BaseDexClassLoader、PathClassLoader、DexClassLoader
PathClassLoader和DexClassLoader区别:构造器中一个Dex优化路径参数,PathClassLoader中为null,
因此PathClassLoader只能加载系统的类和已经安装的应用程序,而DexClassLoader可以加载指定路径的apk

Android打包流程:

1.经过aapt工具生成R.java文件和resources.arsc资源映射表,并编译项目中的资源
2.将项目中的java源码、R.java和 .aidl生成的java接口文件编译成 .class文件
3.将项目中编译的 .class文件和三方库的 .class文件经过dx工具生成 .dex文件
4.将 .dex文件、resources.arsc、res资源、AndroidManifest.xml打包成apk文件
5.将apk文件签名、对齐,生成签名后的apk

apk包结构:通过Android studio  Analyze  Apk查看
	lib:cpu架构的so文件,如armeabi-v7a、arm64-v8a等
	assets:能通过AssetManager获取的资源
	AndroidManifest.xml:配置清单,包含三方库
	META-INF:签名文件等
	classes.dex:能被Dalvid/ART虚拟机识别的文件格式的类
	res:资源文件
	resources.arsc:资源映射表,配合R.java完成数据提取

性能优化:

1.布局优化:减少布局层级,使用viewStub、include、merge标签等,使用ConstraintLayout
2.启动速度:异步加载
3.绘制优化:onDraw方法避免执行大量的操作
4.内存优化:防止内存泄漏,LeakCanary等三方检测工具
5.响应速度优化和ANR:避免在主线程做耗时操作
6.线程优化:不要开启大量线程,采用线程池
7.网络优化:避免过多网络请求,做好数据缓存
8.包体优化:
 	MultiDex:方法数超过65536,会拆分成多个dex文件
 	代码混淆:minifyEnabled设为true,要注意反射和gson解析的bean类,记得keep
 	统一三方库和版本
 	Lint扫描移除冗余代码、资源
 	资源优化:图片  shrinkResources设为true开启资源缩减
 	so库:优先考虑适配范围广的cpu架构,如armeabi-v7a和arm64-v8a

ANR:

Application Not Responding:应用程序无响应
Android运行时AMS和WMS会监测应用程序的响应时间,如果主线程在超时时间内对输入事件没有处理完毕,
或者对特定操作没有执行完毕就会上报ANR

ANR产生原因:	
1.Activity在5s内无法响应触摸事件或者键盘输入事件
2.BroadcastReceiver在10s内还未执行完
3.Service各个生命周期在20s内未执行完
4.ContentProvider在10s内未执行完

避免在主线程中执行耗时操作,包括:
数据库操作
初始化的数据和控件太多
加载过大数据和图片
对大数据排序和循环操作
过多的广播和滥用广播
大对象的传递和共享
网络操作

traces.txt:
Reason:ANR原因,比如BroadcastTimeout
cpu usage when ANR:CPU使用情况
线程使用信息、线程状态

内存泄漏:

内存使用完毕后无法被释放
1.非静态内部类持有外部类的引用
如非静态内部类所创建的实例是静态的,其生命周期等于应用的生命周期,当外部类销毁时无法销毁静态实例。
解决:使用静态内部类,尽量避免非静态内部类所创建的实例是静态的
2.Handler内存泄漏
使用静态内部类 + 弱引用的方式
3.Context导致内存泄漏
Application和Activity的Context生命周期不同,常见于单例
4.资源对象未关闭
如广播、文件、Bitmap、数据库、网络连接、流等
5.监听器未关闭
6.静态集合,如HashMap、LindedList
7.WebView未调用destory,可以开启新进程、AIDL等

LeakCanary监测内存泄漏
原理:Activity执行完onDestory后,将它放入WeakReference中,然后将这个WeakReference类型的Activity对象
与ReferenceQueue关联,这时再从ReferenceQueue中查看是否有该对象,如果没有,执行GC,再次查看还是没有的话判断发生了内存泄漏,
最后用haha库去分析dump出来的pref文件。注:弱引用和引用队列联合使用时,如果弱引用持有的对象被垃圾回收,
java虚拟机就会把这个弱引用加入到与之关联的引用队列中。
关键词:Refwatcher  registerActivityLifecycleCallbacks()

Leakcanary缺点:
1.只能线下监测
2.需要主动触发GC,Dump过程造成app冻结,体验不好
3.hprof文件过大,上传耗费资源

koom:
1.触发时机:使用阈值检测的方法来触发检测,将对象是否泄漏的判断延迟到解析时,性能几乎无损耗
2.Dump:Leakcanary dump过程会影响到主线程卡顿,koom利用Linux的copy-on-write机制,fork子进程Dump内存镜像

systrace:

原理:在系统的一些关键链路(system service 虚拟机 Binder驱动)插入一些信息(Label),
通过Label的开始和结束来确定某个核心过程的执行时间,然后把这些Label信息收集起来
检测UI性能:python systrace py -- time = 10  操作10s后生成HTML报告
检测卡顿丢帧:绿色圈圈正常,黄色或红色16.6ms以上帧
自定义trace标记:Trace.beginSection和Trace.endSection

内存溢出 oom:

1.内存中加载额数据量过于庞大
2.代码中存在死循环或循环产生过多重复的对象实体
3.启动参数内存值设定小

Glide缓存机制:

内存缓存:活动缓存WeakReference和内存缓存LruCache
LruCache:最少使用算法,LinkedHashMap,数组 + 双向链表,accessOrder设置缓存访问顺序,默认插入顺序,
trimToSize判断是否操过缓存数量
使用弱引用:是一个随时可能被回收的资源,强引用频繁读写会造成内存激增频繁GC,造成内存抖动
内存缓存:正在使用的图片使用弱引用,暂时不使用的使用LruCache,通过引用计数来实现,当计数为0代表不使用,会放进LruCache中
Glide如何绑定生命周期:Glide.with(context)会创建一个RequestManager,然后创建一个透明的Fragment加入到manager中,
通过Fragment来感知生命周期。(可以考虑下fragment、viewModel的生命周期如何感知)

Binder机制:

由Client、Service、ServiceManager、Binder驱动组成
客户端通过获取服务端的代理,并通过代理接口提供的方法实现进程间通信
高效:只copy一次,用户空间和内核空间只copy一次,接收方和内核空间存在内存映射(在Linux中通过系统调用mmap函数来实现内存映射)
稳定:cs结构稳定
安全:每个进程都会分配一个UID
Binder通信步骤:
1.Binder驱动在内核空间创建一个数据接收缓存区
2.在内核空间开辟一块内核缓存区,建立内核缓存区和数据接收缓存区中间的映射关系,
同时建立数据接收缓存区和接收方用户空间的内存映射关系
3.发送方通过copy-from-user函数将数据拷贝到内存缓存区,由于内存缓存区和数据接收缓存区存在映射关系,
同时和用户空间存在映射关系,相当于把数据发送到接收方用户空间

事件分发机制:

在这里插入图片描述

Activity -> ViewGroup -> View
super:调用父类方法
true:消费事件,即事件不继续往下传递
false:不消费事件,事件也不继续往下传递,交由给父控件onTouchEvent处理

down事件在哪里消费,up、move事件就传递到哪,如果up、move被父类拦截,则消费了down事件的子View就产生cancel事件,
事件最终由拦截的父View消费;
事件由ViewGroup的onTouchEvent消费,则up、move事件不会再执行ViewGroup的onInterceptTouchEvent;
想要子View消费down事件后父View不拦截up、move事件,在子View的onDispatchTouchEvent中设置 getParent().requestDisallowInterceptTouchEvent(true)

View.post 和 Handler.post的区别:

在ActivityThread.handleResumeActivity中,先执行onResume,后执行addView操作,所以在onResume无法获取宽高;
View.post内部会判断attachInfo,如果由值,和Handler.post无区别,如果没值,会把Runnable加入到一个数组队列中,
等待执行(可以了解Activity界面绘制流程,什么时候执行数据队列中的Runnable)

Serializable 和 Parcelable 区别:

Parcelable性能好,内存开销小,内存间数据传输推荐使用Parcelable;Serializable可将数据持久化保存,
保存或网络数据时使用Serializable;Parcelable数据仅在内存中存在,是通过IBinder通信;Serializable实现简单,
Parcelable需要实现writeToParcel、describeContents以及静态的Creator变量

sp 和 mmkv 区别:

sp底层是由xml文件来实现的,操作sp的过程就是xml的序列化和反序列化的过程(对象转换为字节流的过程),
xml文件是存储在磁盘中,考虑到是I/O的读取,最好不要频繁操作sp,存储大小没限制,但DVM堆内存16M
mmkv是基于mmap内存映射的key value组件,底层序列化/反序列化使用protobuf(google开发的一种轻便高效的结构化数据存储格式)实现,
性能高,稳定性强

Android进程保活:

1.提高进程的优先级,降低被杀死的概率
2.在进程被杀死后拉活

方案:
1.Activity提权(降低oom_adj的值,值越大,进程优先级越低,越容易被回收):屏幕锁屏时启动1个像素透明的Activity
2.Service提权:创建一个前台服务  startForeground
3.系统广播拉活
4.JobScheduler拉活:效果即开启一个定时器
5.推送拉活
6.双进程守护
7.Native拉活

插件化Hook原理:

startActivity时,发送要启动的Activity信息给AMS前,把这个Activity替换为一个在manifest中声明的一个Activity,
把要启动的Activity信息存放在Bundle中,AMS通知App启动Activity时,把在manifest中声明的Activity替换回来,信息在Bundle
A  start  B(未在manifest注册)
A  start  C(hook1后,C在manifest中注册,Bundle保存B的信息)
当App启动C时,hook2,把C换为B,启动B
hook使用动态代理,如果是接口可以用动态代理,如果是类可以手动写接口或cglib,用代理对象替换原始对象

动画:

补间动画(View动画):动画的对象是View、UI控件
TranslateAnimation 平移   ScaleAnimation 缩放
RotateAnimation  旋转    AlphaAnimation  透明度
AnimationSet  组合动画
帧动画:按顺序播放一组预定好的图片,系统提供AnimationDrawable,属于Drawable
属性动画:动态改变对象的属性达到动画效果
objectAnimator  valueAnimator

补间动画和属性动画的区别:
1.补间动画针对UI控件,属性动画针对对象
2.补间动画移动到位置未发生变化,属性动画会随着位置的变化而变化

View 和 SurfaceView 的区别:

1.View适用主动刷新,SurfaceView适用被动刷新
2.View在主线程,SurfaceView在子线程
3.View和宿主窗口共享一个绘图表面,SurfaceView有自己的绘图表面
4.当需要频繁刷新或展示复杂动画和视频时使用SurfaceView

如何在SurfaceView上绘制内容:获取SurfaceHolder,并通过它获取canvas进行绘制
View的绘制过程是怎样的:通过onDraw方法,并在主线程中执行
SurfaceView的使用场景:游戏开发,视频播放等性能渲染场景

协程 和 线程 的区别:

1.线程由操作系统调度,协程由代码控制,线程是抢占式的
2.线程创建和切换需要较大的系统开销
3.线程可以利用多核CPU并行,协程单线程中
4.线程适用CPU密集型的程度,协程适用于I/O密集型的任务

Okhttp:

优点:支持http2.0版本,使用连接池,减少请求延迟,响应缓存避免重复请求
执行流程:
OkHttpClient.Builder.build
Request.Builder.url.build
client.newCall(request).enqueue  异步
client.newCall(request).execute   同步

分发器Dispatcher:内部维护队列与线程池,完成请求调配
同步请求时,分发器只是放个记录,把请求记录加入到队列中
异步执行:
1.先对异步任务进行封装,把任务放到AsyncCall对象中
2.分发器把封装后的异步任务添加到等待运行的队列中
分发器维护的三个队列:等待运行的异步任务队列、正在运行的异步任务队列、同步任务队列
内部线程池为newCacheThreadPool,不限制线程数量

拦截器:完成整个请求过程
重试重定向拦截器:RetryAndFollowUpInterceptor  最大重定向次数20
桥接拦截器:BridgeInterceptor  处理请求头信息
缓存拦截器:CacheInterceptor  处理缓存,根据缓存策略从缓存中查找是否有合适的缓存response,如有,则返回,
不继续执行后面的拦截器
连接拦截器:ConnectInterceptor  维护一个连接池,找到一个合适的连接或新建一个连接并接入,获得对应的socket流
访问服务拦截器:CallServerInterceptor
自定义拦截器:应用拦截器和网络拦截器(应用拦截器在最顶端,网络拦截器在倒数第二,应用拦截器一定会被执行,网络拦截器不一定)

OkHttp请求的整体流程:
1.创建request -> OkHttpClient -> realCall
2.同步:添加同步任务,执行拦截器,访问服务器,返回response
3.异步:分发器封装任务AsyncCall,添加异步等待队列,分发任务,判断分发的任务是否能加入异步执行队列
(同时执行的任务数量不能大于64,同一主机的访问任务不能大于5)
4.加入正在执行的异步任务队列,通过线程池执行任务,通过拦截器返回response

拦截器是如何工作:采用责任链设计模式,让请求者和执行者解耦
OkHttp如何复用TCP连接:利用连接池,缓存所有有效连接对象,使用Lru清理超过5个闲置的链接
OkHttp对于网络请求都有哪些优化:
1.通过连接池减少请求延时
2.支持Gzip减少数据流量
3.缓存响应数据减少重复的网络请求
用到的设计模式:建造者模式 builder  工厂模式 call接口中  单例模式 OkHttpClicent  责任链模式 interceptor

Rxjava:

核心为订阅流程和线程切换
Observable:被观察者
Observer:观察者

Observable大致流程:
ObservableObserveOn -> ObservableSubscribeOn -> ObservableCreate -> CreateEmitter
Observer大致流程:
emitter.onNext -> subsribeOnObserver.onNext -> ObserveOnObserver.onNext -> Observer.onNext
创建Subscriber(实现了Observer接口的抽象类,多了onStart和unSubscribe方法,在subscribe过程中,
observer也会被装换成subscriber):从下往上调用Obserable对象的Subscribe方法,生成一条Subscriber对象的链

Scheduler:线程调度器
Schedulers.io:I/O操作(读写文件、数据库、网络请求),与newThread类似,区别是用一个无数量上限的线程池
Schedulers.newThread:开启新线程
Schedulers.immediate:当前线程
Schedulers.computation:固定的线程数,大小为CPU核数
AndroidSchedulers.mainThread:Android主线程

SubScribeOn:指定subscribe所在的线程,也就是call,发布事件所在的线程
ObserveOn:指定subscriber回调方法所在的线程,也就是onCompleted、onError、onNext回调的线程

各种操作符:map、flatmap
map用于普通对象的转换,如string转drawable,转换后直接回调
flatmap返回的是把每一个observable的事件整合到一个新创建的observable对象中,转换的是每一个observable事件
其他操作符:from集合  filter过滤  doOnNext处理下一个事件之前要做的是,compose与flatMap类似,转换的是整个observable数据流

总结:
1.创建observable  create/just/from等方法
2.通过filter/dobounce等操作符进行自定义事件过滤
3.通过Schedulers进行线程控制,subCribeOn和ObserveOn
4.通过map、flatmap/compose等操作符进行事件的变换
5.调用subscribe订阅事件并回调
6.解除订阅 unSubscribe,以免内存泄漏

Retrofit:

内部通过动态代理生成接口的实体对象,在invocationHandler中处理请求,通过接口和注释来描述网络请求,包括请求方式、参数类型等。
根据注解构建一个ServiceMethod对象,使用这个对象拼接网络请求的url,使用okhttp发送网络请求,
通过callAdapterFactory将网络请求的okhttpCall对象适配成方法返回类型的对象,如observable,
通过GsonConverterFactory将返回数据转换成特定格式的数据

使用的设计模式:建造者模式、代理模式、适配器模式、工厂模式

AIDL:

定义:安卓接口定义语言
内部使用Binder机制
客户端:调用远程服务
服务端:提供接口
AIDL接口:用来传递的参数,提供进程间通信
当客户端连接服务端,服务端调用onBind方法,把sub对象返回给客户端,该对象是个Binder对象,实现进程间通信
客户端通过Intent绑定Service,在onConnected中得到mBinder,当客户端调用服务端接口时,AIDL通过proxy类中的方法调用transact方法,
transact方法又去调用服务端的onTransact方法,onTransact运行在服务端的Binder线程池中

支持的数据类型:
1.Java的8种基本数据类型
2.charsequence类型,如string、spannableString等
3.ArrayList  T必须是AIDL所支持的数据类型
4.HashMap  Key、Value必须是AIDL所支持的数据类型
5.Parcelable接口的实现类
6.AIDL接口
  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值