js和java对象交互
-
获取webview控件的websetting -
设置websetting.setJavascriptEnabled( true ) -
将一个对象暴露给JavaScript:webview.addJavascriptInterface。这个对象包含了JS调用的方法,这些方法用@JavascriptInterface修饰 -
JS通过这些方法与Android交互
防止OOM
- 在代码中动态地将webview设置到布局中,而不是直接写到xml文件中;
- 在Activity的onDestory中销毁webview
线程相关
Linux线程基础
ANR
- what
- Activity 5s内无响应,BroadcastReceiver 10s内无响应
- /data/anr/traces.txt 文件记录了ANR的信息
- why
- how
耗时任务或者线程间通讯
Handler
- Handler + MessageQueue + Looper
MessageQueue本质上是一个单链表,不是Queue。采用FIFO方式管理,enqueueMessage()方法是将消息插入一条队列,next()方法是一个无限循环的方法。如果有消息,则取出,如果没有,就阻塞。
本质上是一个继承了Thread的线程类。 通过创建HandlerThread获取looper对象,传递给Handler对象,执行异步任务。在HandlerThread中通过**Looper.prepare()来创建消息队列,并通过Looper.loop()**来开启消息循环。创建HandlerThread后必须先调用start()方法,才能调用getLooper()获取Looper对象。
HandlerThread封装了Looper对象,使我们不用关心Looper的开启和释放的细节问题。如果不用HandlerThread的话,需要手动去调用Looper.prepare()和Looper.loop()这些方法。
IntentService
-
原理:IntentService是一个抽象类,封装了HandlerThread和Handler,负责处理耗时的任务。任务执行完毕后会自行停止。在onCreate()方法中开启了一个HandlerThread线程,之后通过HandlerThread的Looper初始化了一个Handler,负责处理耗时操作。通过startService()方法启动,在handler中调用抽象方法onHandleIntent(),该方法执行完成后自动调用stopself()方法停止 -
override onHandleIntent() 方法 -
优点:一方面不需要自己去创建线程,另一方面不需要考虑在什么时候关闭该Service
OOM
-
what OOM 和 内存泄漏 的区别 -
how -
静态变量持有Activity或Context对象 -
非静态内部类的实例(默认持有外部类的引用) -
资源未关闭:file、stream、bitmap等 -
Handler造成OOM -
原因:使用**(匿名)内部类**实例化handler,默认持有context引用 -
避免:静态内部类、Activity在onDestroy的时候,清空handler未处理的消息 -
WebView造成OOM
View相关
三部曲
三个核心步骤:Measure、Layout、Draw
Touch分发机制
重要
滑动冲突
简述Activity、Window、WindowManager、View、ViewRootImpl的作用和相互之间的关系
-
Activity不负责视图的控制,而是交给Window。这个Window本质上是一个PhoneWindow,被windowmanager管理。 -
Window中有decorview,decorview是当前视图的底层View,是setContentView所设置View的父View View是所有控件的基类。 -
ViewRoot对应ViewRootImpl,它是连接WindowManager和DecorView的纽带。绘制的三大流程都是在ViewRootImpl中完成的:从ViewRootImpl中的performTraversals开始,有三个方法performMeasure, performLayout, prformDraw分别对应measure,layout,draw三个流程,完成对顶级View的绘制。 -
在父View的Measure过程中,会调用子View的Measure过程,如此反复,完成对整个View树的遍历。同理,在Layout和Draw中也是如此。
RecyclerView
-
优点: -
封装了ViewHolder -
与ListView相比,耦合性更低、更加灵活:根据viewType设置不同的布局 -
设置LayoutManager,实现ListView的功能和GridView的功能(支持 LinearLayoutManager 和 GridLayoutManager) -
支持局部刷新:notifyItemChanged()方法 (Listview用的BaseAdapter只有notifyDataSetChanged()方法) -
缺点: -
使用更加复杂 -
没有onItemClickListener()、setOnItemLongClickListener()方法,只有OnItemTouchListener()方法 -
RecyclerView.Adapter -
onCreateViewHolder()方法:产生一个ViewHolder对象,该对象中封装了view -
onBindViewHolder()方法:根据传入的ViewHolder对象,显示数据 -
getItemViewType()方法:根据情况,返回不同的viewType,方便后续显示不同的布局和业务处理
IPC
Linux中IPC的方式:命名管道、信号量、共享内存
基础
- 开启多进程的方式:给四大组件在Menifest文件中,添加process属性,指定进程名称
- Android为每个进程分配一个独立的虚拟机,有不同的Application和地址空间。
- 不同进程访问同一个类的对象会有不同的副本。因此静态成员和单例模式失效、线程同步失效、sharedPreference可靠性降低。
序列化
-
Serializable接口:Java的序列化接口,使用简单,但开销大,序列化和反序列化需要大量IO操作 -
Parcelable接口:是Android的序列化方式,使用复杂,但效率高。 -
对象是不能直接跨进程传输的。对象的跨进程传输,其本质是序列化和反序列化的过程
机制:Bundle、文件共享、ContentProvider、Socket、AIDL、Messager
-
四大组件间,把数据封装到Bundle。在一个进程中开启另一个进程的Activity或者Service,就可以通过Intent把Bundle传递过去。其中,封装在Bundle中的数据需要能够被序列化 -
使用文件共享方式,多进程读写一个相同的文件,获取文件内容进行交互。 -
使用ContentProvider,常用于多进程共享数据,比如系统的相册,音乐等,我们也可以通过ContentProvider访问到 -
使用Socket传输数据。服务端(比如一个进程中运行了一个Service)创建一个ServerSocket对象,监听本地的端口;客户端(比如另一个进程中运行的Activity)通过Socket连接本地的那个接口。经过TCP的三次握手后,建立连接。接着可以发送数据。使用socket不仅可以实现进程间通信,也可以实现设备间通信。
Binder
- 基本原理:
Android特有的IPC、客户端-服务器C/S的模式、
四个角色:Client、Server、ServiceManager、BinderDriver
调用过程: 1. Server向ServiceManager注册 2. Client通过ServiceManager获取Server的代理对象 3. Client向代理对象发起请求,该请求通过BinderDriver发送给Server处理 4. Server通过BinderDriver返回处理结果
在一个应用有多个使用AIDL的场景,无需为每一个AIDL创建自己的Service。而是使用一个Service,创建并返回一个Binder连接池的Binder对象。Activity在使用AIDL的时候,可以通过该Binder连接池对象,获取不同的Binder对象(类似于工厂模式)
AIDL
-
使用流程:以Activity(进程1)和Service(进程2)通信为例 -
创建AIDL接口,Build一下,产生相关代码 -
创建IBinder实例,即实例化xxx.Stub()抽象内部类,override抽象方法 -
创建Service,在onBind()中,把上述IBinder实例返回 -
在Activity中调用bindService启动Service,然后在ServiceConnection中的onServiceConnected方法回调中获得该IBinder实例。 -
Activity调用该实例的方法,实现通信
Messager
-
一种轻量级的跨进程通讯方案,底层使用AIDL实现。 -
是一种串行的通信,即服务端需要一个一个处理消息。因此,在大量并发请求的情况下,用Messager 就不太合适。 -
使用流程:以Activity(进程1)和Service(进程2)通信为例
- 在Service中new一个Messenger(这个Messenger需要指定Handler)
- 然后在onBind函数中,返回messenger的Binder对象(messenger.getBinder())
- 在Activity中,通过bindService启动service,通过ServiceConnection获取到Binder对象。
- 通过这个Binder对象实例化一个Messenger,然后messenger.send(message)进行通信
启动流程
Android开机流程
init进程-zygote进程-SystemServer进程-各种ManagerService(AMS,PMS,WMS)- launcher程序
App启动流程
launcher-AMS-(pause)-zygote-新进程ActivityThread-(main函数)-向AMS注册-通知ActivityThread创建Activity并执行生命周期
App内Activity启动流程
Activity1-AMS-(pause)-在同一个ActivityThread-加载Activity2类,执行生命周期
ActivityManagerService 和 Instrument 的区别
性能及优化
apk包大小
1、减少不必要的jar包依赖 2、优先使用代码来设置UI效果 3、去除没用到的资源文件,压缩其他资源文件的大小,不用适配所有尺寸的设备 4、尽量重用代码,避免代码的冗余 5、限制app支持的cpu架构的数目:在当前的Android 生态系统中,让你的app支持 armabi 和 x86 架构就够了;
方法数越界 multiDex方案
-
what:dex是Android平台上(Dalvik虚拟机)的可执行文件, 相当于Windows平台中的exe文件, 每个Apk安装包中都有dex文件。 -
单个dex文件所包含的最大方法数是65536,包含Android Framwork、依赖的jar包,以及应用本身的所有方法。 -
解决方法数越界:
- 删除无用的代码和第三方库
- 采用插件化机制,动态加载dex。这是一个重量级的方案
- multiDex方案——可以从apk中加载多个dex文件
- 配置Gradle,添加 multiDexEnabled true
- 添加multiDex依赖
- 在Application中添加 MultiDex.install(this) 代码
其他
目标:
优化方案:
架构:本质上都是一种代码架构思想
MVC
其中M层处理数据,业务逻辑等;V层处理界面的显示结果;C层起到桥梁的作用,来控制V层和M层通信 视图层(View):一般采用XML文件进行界面的描述,这些XML可以理解为AndroidApp的View。 控制层(Controller):Android中由Activit、Fragment承担,负责逻辑处理 模型层(Model):提供数据,从进行数据库或者网络的操作。
缺点:在Android开发中,Activity并不是一个标准的MVC模式中的Controller,它的首要职责是加载应用的布局和初始化用户界面,接受并处理来自用户的操作请求,进而作出响应,既是view层,又是controller层。随着界面及其逻辑的复杂度不断提升,Activity类的职责不断增加,以致变得庞大臃肿。
MVP
-
MVP框架由3部分组成: -
Model:提供数据,从进行数据库或者网络的操作 -
View:对应于Activity/Fragment等View,主要负责UI显示 -
Presenter:是Model和View之间的桥梁,进行逻辑处理。View并不能直接对Model进行操作 -
优点:将在Activty中的大量逻辑操作放到Presenter控制层中,避免Activity的臃肿。 -
缺点:MVP模式需要多写许多新的接口;过于复杂的逻辑会使得Presenter臃肿 -
实现方法: -
定义IView接口,Activity实现IView接口,然后在方法中更新UI; -
在Presenter中维持IView的一个引用; -
在Activity中实例化Presenter,然后将IView的实例(即this)赋值给Presenter。 -
在Model中做具体的操作,Presenter获取具体的结果,通过调用所因为的View的方法,更新UI。
MVVM
AAC(Android Architecture Components,架构组件)
-
LiveData: -
使用观察者模式,可以与控件绑定,监听数据的改变刷新UI。 -
可以感知控件的生命周期,在控件销毁时自动取消注册,因此也不会产生内存泄漏 -
ViewModel:将视图的数据和逻辑从具有生命周期特性的实体(如 Activity 和 Fragment)中剥离开来。比如 AndroidViewModel(ViewModle的子类) -
Room:官方数据库框架,对原生的SQLite API进行了一层封装。 -
与SQLite相比:对于复杂的数据库结构,SQL使用复杂,代码冗长、管理困难;Room,使用简单、易于管理
MVVM和AAC
个人理解:MVVM是一种思想,AAC提供多种工具。利用AAC中的工具实现MVVM的思想
View:
ViewModel:
Model:
-
橘黄色框的Repository及其下都是Model层。一个Repository数据仓库负责通过不同方式获取同类型的数据。 -
数据来源有: -
本地存储数据,如数据库,文件,SharedPreferences(本质也是文件) -
内存的缓存或临时数据 -
通过各种网络协议获取的远程数据 -
ViewModel在从Repository获取数据时,不需关注数据具体是怎么来的。
响应式编程
RxJava/RxAndroid
基于观察者模式,可以方便地以流的方式处理异步事件
-
创建: Observable.create/just/from -
Schedulers线程调度
-
在不指定线程的情况下, RxJava 遵循的是线程不变的原则 -
subscribeOn(): -
指定 subscribe() 所发生的线程,即 Observable.OnSubscribe 被激活时所处的线程。或者叫做事件产生的线程。 -
subscribeOn() 的位置放在哪里都可以,但它是只能调用一次的。 -
observeOn(): -
Subscriber 所运行在的线程,或者叫做事件消费的线程。 -
指定的是它之后的操作所在的线程,以此实现线程的多次调用 -
举例:
基于观察者模式,可以方便地以流的方式处理异步事件
-
创建: Observable.create/just/from -
Schedulers线程调度
-
在不指定线程的情况下, RxJava 遵循的是线程不变的原则 -
subscribeOn(): -
指定 subscribe() 所发生的线程,即 Observable.OnSubscribe 被激活时所处的线程。或者叫做事件产生的线程。 -
subscribeOn() 的位置放在哪里都可以,但它是只能调用一次的。 -
observeOn(): -
Subscriber 所运行在的线程,或者叫做事件消费的线程。 -
指定的是它之后的操作所在的线程,以此实现线程的多次调用 -
举例:
|