跨进程通讯
文件形式,但是并发读写会有问题
Bundle可传输基本数据及实现Parcelable,Serializeable接口的类
Messenger可以跨进程传递message,他的底层是aidl
Binder机制,利用linux层的管道来跨进程传递数据
ContentProvider,底层其实也是Binder来跨进程传递数据
建立Socket连接也可以
注意.SharePreferences会在内存中有缓存,不适合夸进程
1.png
线程通信
- 共享变量(内存)
2.handler
3.view.post(runnable) (主线程在ViewRootImpl中创建一个handler,通过DecorView传遍view树.)
4.Activity.runOnUiThread(本质是主线程创建一个handler,用这个handler发送runnable)
view相关
1.pnggetX,getY,返回相当于View左上角的x.y坐标
getRawX,getRawY返回相对于手机屏幕左上角的x,y坐标
view的滑动方式
通过view本身的scrollTo/scrollBy方式.只能改变view内容的位置,不能改变view的位置
通过动画给view施加平移效果,其实是改变view的translationX和translationY属性来改变view的位置,
通过改变view的layoutparams是view重新布局.
事件分发的大概解释
一般情况,一个事件序列只能被一个view所拦截处理,既他处理了down事件后,move,up都会自动由他处理. 如果他不处理down事件,他就不能在处理这一事件序列的其他事件,而是交给他父view处理.
onTouchListener优先级高于onTouchEvent.
viewgroup分发事件时,根据子view是否在执行动画,及点击事件坐标是否落在子元素的区域内判断
viewgroup内部有链表结构的mFistRouchTarget存放处理点击事件的子view
测量view宽高的四种方法 (通过调用view.getMeasureHeight|view.getMeasureWidth)
1.Activity/view#onWindowFocusChanged.
这个方法被调用是view已经被初始化完毕.但这个方法会被掉用多次,activity的窗口得到和失去焦点的时候都会调用.
2.view.post(runnable)
把一个runnable发送到消息队列的尾部,执行这个runnable时,view以及准备好
3.ViewTreeObserver.addOnBloballLayoutListener(listener).在listener回调函数里获取,次方法会被回调多次.所以应该在listener中移除他自己.
4.view.measure(width,height) 这个方法有局限性.view是match_parent时无法获得.
RemoteViews详解
1.pngaction的使用,利用了命令模式.就是把请求封装成命令.从而让你使用不同的请求把客户端参数化.
RemoteViews内部有个mActions的arraylist,每次把命令封装成action后添加到这里边
action实现了parcelable接口,系统会把action夸进程传输到远程进程,然后远程进程会调用action的apply.reply方法.apply是加载布局并更新界面,reply只会更新界面.apply.方法里真正改变了view的某些属性.
Window 和WindowManager
window是抽象类,具体实现是phonewindow. window 是view的直接管理者.所有的视图都是附加在window上的.
windowmanager是访问window的入口.而windowmanager的实现是WindowManagerService中,WindowManager和WindowManagerService的交互是一个Ipc过程.
window中窗口分三层.应用window在1-99层,子window在1000-1999,系统window在2000-2999.对应windowmanager.layoutparams的type参数.
windowmanager的常用功能大体是addView,updateView.removeView,Windowmanager的本地代理类是WindowmanagerGlobal,
这个类会持有Window的View,ViewRootImpl,Layoutparams三个集合,windowmanagerGlobal的addview方法会创建一个ViewRootImpl与view绑定,
Window是一个抽象概念,每个Window都对应一个View和一个ViewRootImpl,Window和View通过ViewRootImpl建立联系.
activity的创建过程中.调用attach方法里会创建window并把activity设置为window的callback回调.
view创建并添加过程.
- activity的attach方法会创建window的实际类phoneWindow,并把activity设为phoneWindow的Callback回调.
- activity的setcontentView方法会调用phoneWindow.setContentView,PhoneWindow的内部类DecorView会创建同时创建Window.LayoutParams. DecorView是系统view树的跟节点.activity的layout会设置给DecorView的子视图contentView.
- activity的onResume被调用后,会调用makeViisble,这方法中通过WindowManager.addView把Decorview添加进去.
- WindowManager的真正操作类是WindowManagerGolbal,WindowManagerGlobal的addView方法会为DecorView创建ViewRootImpl.同时把ViewRootImpl和View绑定起来.然后调用ViewRootImpl的setView方法.
- ViewRootImpl的setView方法内部会调用scheduleTraversals重绘界面.和mWindowSession.addToDisplay,这个方式内部调用WindowManagerServices的addView 方法,跨进程添加window.
- Wms会为每个应用保留一个独立的mWindoSession.
Toast过程
- toast中有两个ipc过程,第一类是Toast访问NotificationManagerService,第二类是NotificationManagerServices回调Toast里的TN接口.
- toast的大致原理是toast的show方法,会把toast和TN统一发送到NotificationManagerService远程服务,该服务负责所有toast的排队显示,他内部有个mToastQueue的ArrayList来保存所有的toast.
3.NotificationMangerService调用showNextToastLocked来显示Toast,当轮到那个Toast显示的时候.NotificationManagerService会回调该Toast的TN中的show方法.TN运行在Binder线程池中,所以要通过Handler将其切换到发送Toast的线程.
4.Toast的TN有两个方法,hide和show,这两个方法是NMS以夸进程的方式调用的,所以他们运行在Binder线程池中,需要利用Handlr.这两个方法会把Toast添加,移除出WindowManger.
handler原理
- ThreadLocal原理.每个线程内部都有一个ThreadLocal.Map对象.这个对象用来存储键值队.通过ThreadLocal像保存线程的数据时.其实是把数据保存在了线程自己中,只是以这个ThreadLocal的hashcode作为数据的key.下次取出时,还是根据这个ThreadLocal的hash值取出数据.意思就是.一个Thread可以对应多个ThreadLocal对象来保存数据.但是一个ThreadLocal对象只能在一个线程中保存一个数据.对于handler来说,保存的就是lopper.
- lopper的prepare()方法主要是创建消息队列,并保存在ThreadLocal中
- looper.quit会调用MessageQueue的quit方法.然后MwssageQueue会返回一个null的msg,然后lopper就结束loop循环.
- MessageQueue的next方法会阻塞,当没有新消息或者当前时间还没到下一个消息执行时,会通过nativePollOnce(ptr, nextPollTimeoutMillis);方法阻塞,而在enqueueMessage时如果发现在阻塞,会调用nativeWake方法来唤醒next方法.
- lopper中取出message后,通过调用message.target.dispatchMessage方法.此时的target就是我们发送消息的handler.然后handler的dispatchMessage方法就会被调用.
进程知识
-
1.jpg
主线程主要负责Activity/Service等组件的生命周期以及UI相关操作都运行在这个线程; 另外,每个App进程中至少会有两个binder线程 ApplicationThread(简称AT)和ActivityManagerProxy(简称AMP)
- IntentService内部采用HandlerThread来执行任务,当任务执行完毕后IntentService会自动退出.他是一种服务,不容易被系统杀死从而可以尽量保证任务的执行.
- AsyncTask会把paramss参数封装成一个RutureTask类,起到runnable的作用,AsyncTask有两个线程池,SerialExecutor线程池用于任务的排队.THREAD_POOL_EXECUTOR用于真正执行任务.而InternalHandler则把线程结果传递给主线程,因为InternalHandler继承子Handler且是static,他需要主线程的lopper,而静态对象会在类加载的时候初始化,所以要求AsyncTask必须在主线程中加载.而AsyncTask的任务是串行执行.
- HandlerThread 是一个可以使用Handler的Thread,他内部的run方法用过Lopper.prepare封装了消息队列
- IntentService 封装了HandlerThread 和Handler.他是抽象类,任务执行后会自动停止.本质是外界通过startSevice,然后IntentService的onCreate中创建Handler和HandlerThread,然后在onstart中把intent封装成message通过Handler发送到HandlerThread的Looper中,Lopper的回调执行到Hanlder的handleMessage是会回调抽象方法onHandleIntent,子类实现这个方法用来执行异步操作.该方法执行完成后会调用stopSelf(int),等所有的msg都执行完成后,IntentService自动关闭.由此可见.IntentService是通过Handler执行异步任务的,而且多个任务是串行执行.
优化
- BitmapFactory.Options来缩放图片.设置不同的inSampleSize(采样率)来调整bitmap的大小和imageview相接近.需要通过inJustDecodeBounds来获得图片原始大小.在根据imageview的大小来调整采样率inSampleSize.
2.内存泄漏
1.静态集合类引起内存泄露,主要是hashmap,Vector等,如果是静态集合 这些集合没有及时setnull的话,就会一直持有这些对象
2.对于hashMap,hashcode修改后,就没有办法remove了
3.observer 我们在使用监听器的时候,往往是addxxxlistener,但是当我们不需要的时候,忘记removexxxlistener,就容易内存leak,广播没有unregisterrecevier
4.各种数据链接没有关闭,数据库contentprovider,io,sokect等。cursor
5.java中的内部类(匿名内部类),会持有宿主类的强引用this
6.handler持有外部的引用.
7.是new Thread这种,后台线程的操作,当线程没有执行结束时,activity不会被回收
okhttp
大致框架- 用户使用OkHttp进行各种设置,发起各种网络请求。每个OkHttpClient内部都维护了属于自己的任务队列,连接池,Cache,拦截器等,所以在使用OkHttp作为网络框架时应该全局共享一个OkHttpClient实例。
- 用户的每一个网络请求都是一个Call实例。Call本身只是一个接口,定义了Call的接口方法,实际执行过程中,OkHttp会为每一个请求创建一个RealCall,每一个RealCall内部有一个AsyncCall:AsyncCall是一个有名字的线程.每一个Call就是一个线程,而执行Call的过程就是执行其execute方法的过程
- Dispatcher是OkHttp的任务队列,其内部维护了一个线程池,当有接收到一个Call时,Dispatcher负责在线程池中找到空闲的线程并执行其execute方法。
- RealConnection描述一个物理Socket连接,连接池中维护多个RealConnection实例。由于Http/2支持多路复用,一个RealConnection可以支持多个网络访问请求,所以OkHttp又引入了StreamAllocation来描述一个实际的网络请求开销(从逻辑上一个Stream对应一个Call,但在实际网络请求过程中一个Call常常涉及到多次请求。如重定向,Authenticate等场景。所以准确地说,一个Stream对应一次请求,而一个Call对应一组有逻辑关联的Stream),一个RealConnection对应一个或多个StreamAllocation,所以StreamAllocation可以看做是RealConenction的计数器,当RealConnection的引用计数变为0,且长时间没有被其他请求重新占用就将被释放.
5.okhttp先把请求封装成RealCall,然后在执行RealCall.enqueue时4,进一步封装为AsyncCall.并加入HttpClient的任务队列中.到时候会执行AsyncCall的execute方法.execute通过getResponseWithInterceptorChain方法获取返回的response. getResponseWithInterceptorChain构建了一个拦截器链,通过依次执行该拦截器链中的每一个拦截器最终得到服务器返回
6.所以整个RealInterceptorChain执行链就在拦截器与拦截器链中交替执行,最终完成所有拦截器的操作。这也是OkHttp拦截器的链式执行逻辑。而一个拦截器的intercept方法所执行的逻辑大致分为三部分:
在发起请求前对request进行处理
调用下一个拦截器,获取response
对response进行处理,返回给上一个拦截器
所以是最后的拦截器最先获得网络相应response.但是最先的拦截器最先对请求request进行封装.
- RetryAndFollowUpInterceptor 在网络请求失败后进行重试,在要求重定向时直接发起新的请求
- BridgeInterceptor 设置各种header,设置gzip压缩,并自动解压response
- CacheInterceptor 当网络请求有符合要求的Cache时直接返回Cache,内容有改变时更新当前cache,当前cache失效,删除
- ConnectInterceptor 调用streamAllocation.connection() 为当前请求找到合适的连接
- CallServerInterceptor负责向服务器发起真正的访问请求,并在接收到服务器返回后读取响应返回
- Dispatcher 内部有两个循环异步队列,readyAsyncCalls,runningAsyncCalls.执行异步任务时,如果所有请求小于64且单个host小于5.就加入runningAsyncCallss.并执行任务,不满足就加入等待队列readyAsyncCalls.
- 任何RealCall的execute执行到最后的finally都要调用Dispatcher的finished方法.finished方法会调用promoteCalls从readyAsyncCalls里取出等待线程放入runningAsyncCallss并执行.如果readyAsyncCalls也为空则回调空闲通知回调线程idleCallback. 这里最出彩的地方就是在try/finally中调用了Dispatcher.finished函数,可以主动控制等待队列的移动,而不是采用锁或者wait/notify,极大减少了编码复杂性
网友评论