安卓系统分为四层:
linux内核层:为安卓设备硬件提供驱动;
系统运行库层:一些c/c++库,支持安卓系统。如sqlite支持数据库;open-gl支持3d绘图;webkit支持浏览器内核;安卓运行时库的一些核心库支持java语言编写安卓应用
应用框架层:提供安卓编码的一些api;
应用层:手机上的应用程序;
安卓的四大组件:
活动(Activity,应用中看到的东西),服务(Service,运行在后台),广播接收器(Brocast Receiver,电话,短信等),内容提供器(Content Provider,应用间共享数据)
Window是一个抽象类,提供了绘制窗口的一组通用API
phoneWindow是window的具体继承实现类,phoneWindow内部包含了一个DecorView对象
view被添加到屏幕的过程:
创建一个DecorView,是一个顶层布局容器,继承自FrameLayout,是phoneWindow内部持有的一个实例对象,是所有应用层的顶层view。
setContentView(id) 调用时解析xml文件,然后将视图添加到FrameLayout中
Activity:
Activity状态:
活动状态,位于栈顶的页面;
暂停状态,非栈顶,但可见;
停止状态,非栈顶,不可见,其成员变量和状态可能会被系统回收;
销毁状态,从栈中移除,系统会回收掉。
Activity生命周期:
onCreate():页面第一次创建的时候调用,完成页面布局,初始化工作,事件绑定等;
onStart(): 页面由不可见到可见状态调用;
onResume(): 页面已经可以和用户交互;----requestLayout()布局的绘制流程,并会checkThread()。在检查线程方法调用之后,就不可以在子线程中更新UI了。
onPause(): 即将进入或者加载另一个页面,可释放一些资源,如:文件句柄,定时器,sqlite的操作等;
onStop(): 页面完全不可见的时候调用;
onDestroy(): 页面被销毁的时候调用;
onRestart(): 页面重新变为可见的时候调用;
onSaveInstanceState(Bundle bundle): 通过bundle保存当前activity的变量或者数据信息,在onCreate中取出来。
getTaskId() 任务id。一个task表示的是启动一个app,并在app的activity做跳转,以及跳转到另一个app页面的跟踪记录。
activity的lauchmode:1、standard,标准加载模式,正常的任务栈
2、singleTop,如果activity在栈顶,则调用onNewIntent(),如果不在栈顶,则类同standard,放入栈顶中
3、singleTask, 整个activity任务栈中,会只有一个activity,重复的activity只会调用onNewIntent(),如果当前activity不是栈顶,则栈顶的activity会调用onDestroy()
4、singleInstance, 类似于singleTask,但会生成一个task任务栈。
一个app启动的时候,会自动启动一个主线程,然后调用ActivityThread的main函数,调用Looper.prepareMainLooper()创建一个Looper对象,并调用Looper.loop()处理消息队列和用户实践。ActivityThread就是一个普通的class,并非一个thread类。ActivityThread启动后,会调用ActivityManagerService的远程代理ActivityManagerNative.getDefault(),并attach(ApplicationThread对象)和AMS进行交互。
Instrumentation主要用来创建application对象,启动activity和管理activity生命周期回调。
H extents handle 主要处理ActivityManagerService发送过来的消息:
handleLauchActivity: 通过classLoader加载activity;
调用activity.attach()将activity和windowManager关联,管理activity的页面展示;
AMS提供了一个ArrayList mHistory来管理所有的activity,activity在AMS中的形式是ActivityRecord,task在AMS中的形式为TaskRecord,进程在AMS中的管理形式为ProcessRecord。如下图所示
-
所有的ActivityRecord会被存储在mHistory管理;
-
每个ActivityRecord会对应到一个TaskRecord,并且有着相同TaskRecord的ActivityRecord在mHistory中会处在连续的位置;
-
同一个TaskRecord的Activity可能分别处于不同的进程中,每个Activity所处的进程跟task没有关系;
- onAttach():Fragment和Activity相关联时调用。可以通过该方法获取Activity引用,还可以通过getArguments()获取参数。
- onCreate():Fragment被创建时调用。
- onCreateView():创建Fragment的布局。
- onActivityCreated():当Activity完成onCreate()时调用。
- onStart():当Fragment可见时调用。
- onResume():当Fragment可见且可交互时调用。
- onPause():当Fragment不可交互但可见时调用。
- onStop():当Fragment不可见时调用。
- onDestroyView():当Fragment的UI从视图结构中移除时调用。
- onDestroy():销毁Fragment时调用。
- onDetach():当Fragment和Activity解除关联时调用。
1、Fragment的onAttach()->onCreate()->onCreateView()->onActivityCreated()->onStart()都是在Activity的onStart()中调用的。
2、Fragment的onResume()在Activity的onResume()之后调用。
3、当点击F1的按钮,调用replace()
替换为F2,且不加addToBackStack()
时,F1最后调用了onDestroy()
和onDetach()
。
4、当点击F1的按钮,调用replace()
替换为F2,且加addToBackStack()
时,F1被替换时,最后只调到了onDestroyView()
,并没有调用onDestroy()
和onDetach()
。当用户点返回按钮回退事务时,F1会调onCreateView()->onStart()->onResume()。
FragmentTransaction有一些基本方法,下面给出调用这些方法时,Fragment生命周期的变化:
- add(): onAttach()->…->onResume()。
- remove(): onPause()->…->onDetach()。
- replace(): 相当于旧Fragment调用remove(),新Fragment调用add()。
- show(): 不调用任何生命周期方法,调用该方法的前提是要显示的 Fragment已经被添加到容器,只是纯粹把Fragment UI的setVisibility为true。
- hide(): 不调用任何生命周期方法,调用该方法的前提是要显示的Fragment已经被添加到容器,只是纯粹把Fragment UI的setVisibility为false。
- detach(): onPause()->onStop()->onDestroyView()。UI从布局中移除,但是仍然被FragmentManager管理。
- attach(): onCreateView()->onStart()->onResume()。
- mCurrentScrap:ArrayList类型,用于存储离屏的 View
- mScrapViews
- ArrayList[] 类型
- 数组中每个元素都是 ArrayList类型,效果同 mCurrentScrap
- mScrapViews[0] 就是 mCurrentScrap
- 其数组长度应为 ViewTypeCount。因为针对不同的 ViewType,ListView 都要有一个专门的 ArrayList链表来缓存它对应的 View
- mActiveView:ArrayList类型,被 layoutChildren() 用于缓存屏幕上的 View。
- 假设在某一时刻ListView中显示了10个子View,position依次为从0到9。然后我们手指向上滑动,且向上滑动了一个子View的高度,ListView需要绘制下一帧。这时候ListView在layoutChildren方法中把这10个子View都放入到了RecycleBin的mActiveViews数组中了,然后清空了children数组,然后调用fillDown方法,向ListView中依次添加position1到10的子View,在添加position为1的子View的时候,由于在上一帧中position为1的子View已经被放到mActiveViews数组中了,这次直接可以将其从mActiveViews数组中取出来,这样就是直接复用子View,所以说RecycleBin的mActiveViews数组主要是用于直接复用的。
RecyclerView 滑动场景下的回收复用涉及到的结构体两个:mCachedViews 和 RecyclerViewPool,mCachedViews 优先级高于 RecyclerViewPool。
回收时,最新的 ViewHolder 都是往 mCachedViews 里放,如果它满了,那就移出一个扔到 ViewPool 里好空出位置来缓存最新的 ViewHolder。
复用时,也是先到 mCachedViews 里找 ViewHolder,但需要各种匹配条件,概括一下就是只有原来位置的卡位可以复用存在 mCachedViews 里的 ViewHolder,如果 mCachedViews 里没有,那么才去 ViewPool 里找。
在 ViewPool 里的 ViewHolder 都是跟全新的 ViewHolder 一样,只要 type 一样,有找到,就可以拿出来复用,重新绑定下数据即可。
一定要全部替代ListView?
NO!!!列表页展示界面,需要支持动画,或者频繁更新,局部刷新,建议使用RecyclerView,更加强大完善,易扩展;其它情况(如微信卡包列表页)两者都OK,但ListView在使用上会更加方便,快捷。
和ListView的缓存机制对比:
RecyclerView比ListView多两级缓存,支持多个离ItemView缓存,支持开发者自定义缓存处理逻辑,支持所有RecyclerView共用同一个RecyclerViewPool(缓存池)。
RecyclerView 中的一缓 mAttachedScrap 与 ListView 中的一缓 mActiveViews 功能是基本相似的,为了屏幕内 item 快速复用而存在
RecyclerView 中的二缓 mCachedViews 加上四缓 RecyclerViewPool 合在一起与 ListView 的二缓 mScrapedViews意义相同,为了即将给即将入屏的 item 复用而存在。
RecyclerView的优势在于
a.mCacheViews的使用,可以做到屏幕外的列表项ItemView进入屏幕内时也无须bindView快速重用;
b.mRecyclerPool可以供多个RecyclerView共同使用,在特定场景下,如viewpaper+多个列表页下有优势.客观来说,RecyclerView在特定场景下对ListView的缓存机制做了补强和完善。
广播
Android中的广播使用了观察者模式,基于消息的发布/订阅事件模型。因此,从实现的角度来看,Android中的广播将广播的发送者和接受者极大程度上解耦,使得系统能够方便集成,更易扩展。
1.广播接收者BroadcastReceiver通过Binder机制向AMS(Activity Manager Service)进行注册;
2.广播发送者通过binder机制向AMS发送广播;
3.AMS查找符合相应条件(IntentFilter/Permission等)的BroadcastReceiver,将广播发送到BroadcastReceiver(一般情况下是Activity)相应的消息循环队列中;
4.消息循环执行拿到此广播,回调BroadcastReceiver中的onReceive()方法。
同一app内部的同一组件内的消息通信(单个或多个线程之间),实际应用中肯定是不会用到广播机制的(虽然可以用),无论是使用扩展变量作用域、基于接口的回调还是Handler-post/Handler-Message等方式,都可以直接处理此类问题
同一app内部的不同组件之间的消息通信(单个进程),对于此类需求,在有些教复杂的情况下单纯的依靠基于接口的回调等方式不好处理,此时可以直接使用EventBus等,相对而言,EventBus由于是针对统一进程,用于处理此类需求非常适合,且轻松解耦。
EventBus
EventBus.getDefault().register(this);意思是让EventBus扫描当前类,把所有onEvent开头的方法使用Map,Key为方法的参数类型,Value中包含我们的方法记录下来。这样在register执行完成以后,我们的onEventMainThread就已经以键值对的方式被存储到EventBus中了。 EventBus会根据post中实参的类型,去Map中查找对应的方法,于是找到了我们的onEventMainThread,最终调用反射去执行我们的方法。
单例的写法:
private EventBus instance;
public static EventBus shareInstance() {
if (instance == null) {
synchronized (EventBus.class) {
if (instance == null) {
instance = new EventBus();
}
}
}
return instance;
}
反射
Java 开发中定义一个类,往往是要通过许多修饰符来配合使用的。它们大致分为 4 类。
- 用来限制作用域,如 public、protected、priviate。
- 用来提示子类复写,abstract。
- 用来标记为静态类 static。
- 注解。
Class
获取Class:
getClass() 通过对象的该方法,获取相应的 Class
.class 类的属性获取Class
Class.forName() 传入一个类的全限定名称
获取ClassName:
getName()返回类的全限定名称
getSimpleName()返回嵌套类内的类名
获取修饰符:
Modifier.toString(xx.class.getModifiers())
Field
获取属性:
Class.getDeclaredFields()//获取所有的属性,但不包括从父类继承下来的属性,访问了 private 修饰的成员,需要添加. field.setAccessible(true);
Class.getFields()//获取自身的所有的 public 属性,包括从父类继承下来的属性。
获取属性类型:
field.getType()//属性类型
Type type = field.getGenericType()//包含泛型在内的属性类型
if (type instanceof ParameterizedType) {//被参数化的类型
ParameterizedType pType = (ParameterizedType)type
Type rType = pType.getRawType()//获取原始类型
Type[] tArgs = pType.getActualTypeArguments()//获取泛型类型
}
获取属性修饰符:类似于获取类的修饰符
获取属性的值:
field.get(obj)
设置属性的值:
field.set(obj,value)
Method
获取方法:
Class.getDeclaredMethod()//获取所有的方法,但不包括从父类继承下来的方法
Class.getMethod()//获取自身的所有的 public 方法,包括从父类继承下来的方法。
获取方法名:
method.getName()
获取方法修饰符:类似于获取类的修饰符
获取参数:
method.getParameters()//返回Parameter 数组
获取参数名:
Parameter.getName()
获取参数类型:
Parameter.getType()
Parameter.getGenericType()//包含泛型在内的参数类型
获取参数修饰符:
Parameter.getModifiers()
获取返回值类型:
method.getReturnType()
method.getGenericReturnType()//包含泛型在内的返回值类型
获取异常类型:
method.getExceptionTypes()
method.getGenericExceptionType()//包含泛型在内的异常类型
执行某个方法:
method.invoke(obj,obj...args)
Constructor
获取构造方法:
Class.getDeclaredConstructor()//获取当前类的所有构造方法
Class.getConstructor()//获取当前类自身的所有的 public 构造方法
访问构造方法:
Constructor.newInstance()
Array
获取数组元素类型:
array.getComponentType()//Car[] 返回com.array.test.Car
动态创建数组:
Array.newInstance(Class<?> componentType, int... dimensions)
数组的读取和赋值:
arr.set(obj,value)
arr.get(obj)
Enum
Class.isEnum()// 用来判定当前 Class 对象是不是枚举类型
Class.getEnumConstants()//获取当前类的所有的枚举常量
Field.isEnumConstant()//获取某属性是否为枚举常量
Looper
Looper中几个关键对象:Thread,Looper,MessageQueue,Handler,Message
可以从一个线程创建关联到另一个线程 Looper 的 Handler,只要能拿到对应线程的 Looper 实例。
Handler---发送和处理与某线程的 MessageQueue 相关联的 Message/Runnable 对象。每个 Handler 实例只能与一个线程和它的消息队列相关联。它将 Message 和 Runnable 传递给绑定的消息队列,并在它们从队列里被取出时执行对应逻辑。
Runnable 被封装成 Message 之后添加到 MessageQueue。Runnable 对象是被封装成 Message 对象后加入到消息队列的,Message.callback 被设置为 Runnable 本身
创建 Handler 实例时要么提供一个 Looper 实例,要么当前线程有关联的 Looper。
handler操作的MessageQueue是线程安全的,MessageQueue的message入队方法,使用了synchronized关键字
public class Handle {
final Looper mLooper
final MessageQueue mQueue;
final Callback mCallback;
public Handle(Looper looper,Callback callback,bool aysnc) {
if (looper == null) {throw 一个异常}
mLooper = looper;
mQueue = looper.mQueue;
mCallback = callback;
}
public boolean enqueueMessage(MessageQueue mQueue,Message message, long updateTime) {
message.target = this;
}
private static void handleCallback(Message message) {
message.callback.run();
}
public void dispatchMessage(Message message) {
if (message.callback != null) handleCallback(message);
else if (mCallback != null) {
if (mCallback.handleMessage()) return;
handleMessage();
}
}
}
MessageQueue---是作为Looper的一个成员变量而存在,当Looper实例化的时候,它也被初始化,并且当前的Thread对象也当做成员变量存起来。
Looper---Looper.prepare():创建一个Looper,并且将这个Looper存储到一个静态ThreadLocal变量中,而Looper中关联着Thread对象。注意如果当前线程已有Looper它会抛异常。
Looper.loop():就是进入一个死循环,不断的从MessageQueue中取出Message,然后拿到Message.target,也就是Handler,执行它的dispatchMessage方法。
另注: ThreadLocal的set和get方法可视为获取到了looper.mThread用来和looper一一对应
public final Class Looper {
final MessageQueue mQueue;
Thread mThread;
public static void prepare() {
if (sThreadLocal.get() != null) {throw一个异常}
sThreadLocal.set(new Looper())
}
private Looper() {
mQueue = new MessageQueue()
mThread = Thread.currentThread()
}
public static Looper myLooper() {
return sThreadLocal.get()
}
public static void loop() {
while(true) {
Message message = mQueue.next()
message.target.dispatchMessage(message)
}
}
}
消息发送过程:
1、启动一个子线程,并在子线程初始化一个Looper。
2、在HandlerThread中实例化Handler,Handler自动绑定上当前线程的Looper。
3、重写Handler里面的消息处理方法。
4、执行Looper.loop()启动消息循环,子线程进入等待消息状态。
Service
一些关于其定义和使用的东西:https://blog.csdn.net/guolin_blog/article/details/11952435Bitmap.recycle()
回收。
内存缓存
、
硬盘缓存
等
BitMapFactory.Options
对图片进行压缩。
ARGB_8888
,显示质量最高,占用内存最大。若要求不高时可采用
RGB_565
等模式。
图片大小:图片长度*宽度*单位像素所占据字节数
ARGB_4444:每个像素占用2byte内存
ARGB_8888:每个像素占用4byte内存 (默认)
RGB_565:每个像素占用2byte内存
一:强引用
只要引用存在,垃圾回收器永远不会回收,当内存空间不足,Java 虚拟机宁愿抛出 OutOfMemoryError 错误,使程序异常终止,也不会靠随意回收具有强引用的对象来解决内存不足问题。
Object obj = new Object();
后面有若干个方法用到obj 如自定义方法:hanlde(obj );
只有当hanle方法执行完之后,obj这个引用被释放,对象才会被释放掉,这也是我们经常所用到的编码形式。
二:软引用
非必须引用,内存溢出之前进行回收,可以通过以下代码实现
Object obj = new Object();
SoftReference<Object> sf = new SoftReference<Object>(obj);
obj = null;
sf.get();//当内存不足时可能null
这时候sf是对obj的一个软引用,通过sf.get()方法可以取到这个对象,当然,当这个对象被标记为需要回收的对象时,则返回null;
如果一个对象只具有软引用,那么如果内存空间足够,垃圾回收器就不会回收它,如果内存空间不足了,就
会回收这些对象的内存。只要垃圾回收器没有回收它,该对象就可以被程序使用。软引用可用来实现内存敏感的
高速缓存。
三:弱引用
弱引用与软引用的区别在于:只具有弱引用的对象拥有更短暂的生命周期。在垃圾回收器线程扫描它所管辖的内
存区域的过程中,一旦发现了只具有弱引用的对象,不管当前内存空间足够与否,都会回收它的内存。
四:虚引用
"虚引用"顾名思义,就是形同虚设,与其他几种引用都不同,虚引用并不会决定对象的生命周期。如果一个对象仅持有虚引用,那么它就和没有任何引用一样,在任何时候都可能被垃圾回收。虚引用主要用来跟踪对象被
垃圾回收的活动。
HashMap
数组形式储存,链表辅助。put()的时候通过map的键对象的hashCode寻找下标,如果改下标有元素,则下标往后移。如果元素达到了hashmap容量的75%,则进行扩容为原来的两倍。get()的时候也是通过对比键对象的hashCode和equals()取出对应的map。
APK签名机制
1、程序遍历apk包中的所有文件(entry),对非文件夹非签名文件的文件,逐个生成SHA1的数字签名(类似摘要MD5)信息,再用Base64进行编码。生成MANIFEST.MF文件
2、对前一步生成的Manifest,使用SHA1-RSA算法,用私钥进行签名。生成CERT.SF文件
3、CERT.RSA文件中保存了公钥、所采用的加密算法等信息
数据库
首先要有一个SQLiteOpenHelper的抽象类类,有两个抽象方法:onCreate() 创建数据库---只会创建一次,和 onUpgrade() 升级数据库。使用getWritabelDatabase()创建且打开一个数据库,返回一个SQLiteDatabase的可操作数据库对象db。SQLiteOpenHelper的初始化中传入不同的版本号就可以实现数据库的升级。
如果要添加数据,创建一个ContentValue对象,使用put方法设置column和对应的值,使用db.insert("tablename", null, contentvalue) 即添加成功。
如果要变更数据,创建一个ContentValue对象,使用put方法设置column和对应的值,使用db.update("tablename", contentvalue, conditions) 即更新成功。
如果要删除数据,使用db.delete("tablename", conditions) 即删除成功。
如果要查询数据,使用db.rowquery("tablename",null,null,null,null,null,null) 返回一个Cursor对象,用来操作数据库的游标,使用cursor的movetofirst()和movetonext()等可移动游标,cursor.getColumnIndex("columnname")获取对应column的下标index,使用cusor的g getString(index)/其他类型可获取该游标对应的值。
一些常用的第三方数据库:基于ORM
LitePal: https://blog.csdn.net/guolin_blog/article/list/2?t=1&orderby=UpdateTime
GreenDao: http://www.10tiao.com/html/227/201811/2650244473/1.html
阿里开源框架vlayout:
分三大块:
DelegateAdapter: 有八大主流布局,分离recycleview和数据部分,处理onCreateViewHandle()和onBindViewHandle,动态获取布局文件。
BaseViewHolder: 根据id返回view,并放入到itemviews中。提供设置图片和文字等基础功能
VirtualLayoutManager: recycleview的管理类,负责measure子view,layout子view,处理recycleview的滑动和触摸事件,根据滑动距离和方向设置可见子view的位置,并管理好缓冲池的问题。