- 四大组件
-
ContentProvider,进程间进行数据交互及共享,底层采用Binder机制
-
android 7.0以上应用间文件共享1 2
禁止对外部应用公开file://格式uri(否则报FileUriExposedException),必须采用content://格式uri,并需要提供临时访问权限
采用ContentProvider子类FileProvider将uri格式进行转换,并提供临时访问权限 指定打开某个拓展名文件的应用程序
-
-
-
activity启动模式launchMode(manifest中声明)
activity栈后进先出,默认情况下多次启动同一个activity会创建多个实例(任务栈相同,hasCode不同)
standard
-
singleTop栈顶复用:已经处于栈顶时,再次创建会调用onNewIntent(任务栈相同,hasCode相同),不创建新实例;不处于栈顶则重新创建新实例
推送内容对应的页面
-
singleTask栈内复用:当前栈内已存在activity时即复用,并移除同一任务栈内其上的所有其他activity
应用启动页面(或跳转时setFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK))
淘宝付款完成后回到购物界面
-
singleInstance全局唯一:该activity单独占用一个任务栈,永远位于栈顶,保证在整个系统中都只有一个实例,从不同进程中跳转均只调用该实例的onNewIntent。实质相当于多个进程共享一个应用进程
闹钟、联系人等节目
-
LruCache与DiskLruCache
- Least recently used
- LruCache:保存于内存,将近期使用对象通过强引用保存在LinkedHashMap中,在缓存值达到预设值前将最少使用的对象移除
- 由于android2.3以来垃圾回收机制更倾向于回收弱引用与软应用,使用软引用弱引用缓存很容易被回收,不再可靠。因此采用了LruCache代替这种方法
- DiskLruCache:保存于外部存储(硬盘),文件url经过md5加密为文件名key,生成journal文件记录操作日志:
- dirty:edit()准备写入
- clean:commit()完成写入
- remove:abort()写入失败
- read:get()读取数据
-
通信
-
activity间
parcelable
activity与fragment
activity与service
不同线程间
不同进程间
-
EventBus:消息总线,观察者模式实现
简化组件间的通信,发送者与接收者间耦合度低,避免了可能导致的依赖性问题与生命周期错误。可用于activity、fragment、不同线程间。文件小、高效,已被广泛运用。
事件从发布者post到eventbus,然后eventbus匹配 (handler method for the event type)参数为对应类的已注册方法,将事件发送给匹配的订阅者。
可以通过EventBus.getDefault()获取默认单例,也可以通过EventBus.Builder进行自定义
-
使用:
1.创建event实体类,对事件进行定义
2.注册订阅者subscriber
3.声明订阅方法,方法名可以自行定义,EventBus通过事件类(handler method for the event type)来进行匹配。要求必须用@Subscribe注解,返回值为void,并且只有一个参数event
4.发送事件
* 四种ThreadMode1.POSTING:默认模式,订阅者与发送者在同一线程中,避免了线程切换,性能开销最少
2.MAIN:订阅者位于主线程中,因此要求订阅方法不能耗时过长
3.BACKGROUND:订阅者位于后台线程,若发送者不在主线程,则需要再开辟一下新线程调用订阅方法;若在则不开辟,直接在当前线程调用。采用这种模式的订阅者需要尽快完成操作,以免阻塞后台线程
4.ASYNC:订阅者与发送者一定不在一个线程,也不在主线程,必须开辟新线程调用订阅方法。如果订阅者的操作比较耗时则应当使用这种模式(如网络连接)。内部采用了线程池(默认newCachedThreadPool)以重用空闲线程,因此要避免同时允许大量耗时的订阅方法以限制并发线程数量
* 粘性事件(Sticky Events):事件post出去后仍在内存保留一段时间,使得后注册的订阅者在注册完成后能接收到此前的事件(如service定位完成后发送sticky event给网页端)
-
-
生命周期 onSaveInstanceState
-
activity:(7个)
- 当前activity被覆盖一部分:onPause()
- 转到新的activity或home键、锁屏:先onPause()再onStop()<->再回到activity:先onRestart()再onStart()最后onResume()
- onPause():被另一个透明或者 Dialog 样式的 Activity 覆盖时的状态.此时它依然与窗口管理器保持连接,系统继续维护其内部状态,所以它仍然可见,但它已经失去了焦点故不可与用户交互.
- onStop()状态下更高优先级的app需要内存且当前内存不足时被杀死
- onRestart():onStop()不可见到onStart()可见时调用
- onSaveInstance():意外退出时才调用,键值对形式临时保存activity状态。一定在onStop()之前,可能在onPause前或之后
- 按home键
- 按电源键关闭屏幕
- 切换横竖屏
-
fragment:(11个)
-
创建阶段:
onAttach():与activity建立关联,获取activity传递的值
onCreate()
onCreateView():fragment创建视图,加载UI布局
onActivityCreated():activity的onCreate()完成后调用
* 显示阶段onStart()
onResume()
* 被遮挡onPause()
* 不可见阶段onStop()
* 销毁阶段onDestoryView():移除fragment的布局
onDestory()
onDetach():与activity解除关联
* 一个activity内加载多个fragment时,首先在activity.onCreate()阶段内顺序连续执行fragment.onAttach()->onActivityCreated()方法,fragment切换时再交替执行fragment.onStart->fragment.onStop()方法。销毁时fragment顺序连续执行fragment.onDestoryView()->onDetach()
* 两activity A、B跳转:
* A->B:A.onPause
B.onCreate -> B.onResume
A.onStop
* B->A:B.onPause
A.onRestart,A.onStart,A.onResume
B.onStop,B.onDestory
* add发生添加fragment:由于add采用叠加的发送,之前的fragment仍是可见的,前一个fragment仍保持再onResume不动,被add进来的fragment在其上完成自己的生命周期
* replace替换fragment:被替换f移除视图:onPause-> onStop-> onDestoryView—> 替换的f自己的生命周期。替换的f被返回时移出栈顶,使被替换的f再次初始化页面:onCreateView-> onActivityCreated-> onStart-> onResume
* 由于fragment依赖于所属activity,故创建时各阶段activity生命周期方法均早于fragment生命周期方法,而销毁时各阶段fragment生命周期方法均早于activity生命周期方法
* Service:
* onBind方式关联activity:
* onCreate
* onBind
* onUnbind
* onDestory
* startService方式启动
* onCreate
* onStart
* onDestory
* IntentService:
* onCreate
* onHandleIntent
* onDestory
-
-
-
ListView原理与优化:
- ListView的MCV:数据(M)、adapter(C)、ListView(V)
- 原理:首先调用getCount(),得到listView长度,并由此针对每个item调用getView()来绘制每一项item。
- 更新listView数据:adapter.notifyDataSetChanged()让listView重新绘制
- 需要设置两个监听器:onScrollListener、onItemClickListener
- 优化:
- 使用convertView,convertView不为空时通过setTag绑定ViewHolder对象,重复利用已经创建的view,避免findviewbid的开销
- weakReference来引用item中的图片
-
自定义view
三种实现方式- 组合控件:
- 在viewgroup子类控件中添加其他组件
- 写一个对应的java类加载布局及其中子组件,并添加组件监听事件
- 将此自定义的viewgroup组件添加到页面xml中
- 自绘控件
- 创建一个继承View类或子类的控件java类,根据要求重写onMeasure(量测尺寸)、onDraw(绘制view)方法、onLayout(绘制子控件位置)方法参考
- 在页面xml文件中引入该自定义布局
- 继承控件
- 创建自定义View的java类,继承父类View并实现其他接口
- 在页面xml中引入该自定义布局
- 组合控件:
-
View的绘制
- ViewRoot的performTraversals()开始,通过onMeasure()、onLayout()、onDraw()最终绘制出来
- view视图通过Window呈现,由WindowManager来管理。
- 父类视图负责测量、定位与绘制,
- findviewbyid查找时需要遍历整个控件树,代价高,需要尽量避免重复操作
- view的刷新由父view进行,子view需要刷新时通知父view
JNI
第三方平台
看过的源码
-
JSON、XML解析算法
- jackson
- SAX:流式处理,不能回退。解析速度快,占用内存少
- DOM:XML的对象模型,直接访问XML文档,生成树状结构。耗内存,方便插入查找节点
- PULL:内置于系统中,是官方解析布局文件所用的方式。提供了开始元素、结束元素等事件。使用方便,效率高
- XMLPullParser工具,读入xml的字节流ByteArrayInputStream(xml.getBytes(),“utf-8”)
- 对xmlPullParser.getEventType遍历读取event数据类型,判断是xml的何种标签,若为开始标签则开始获取需要的字段数据
-
Manifest原理、APP启动流程、APK打包原理
-
manifest:android应用的入口文件,描述package中暴露的组件、各自实现类、启动位置、能被处理的数据等。作用包括:
包名、应用命名、图标、设计主题等
描述各组件、组件命名与intentfilter等属性
声明权限
- 安装apk前会对其进行解析,其中就需要解析manifest.xml文件。经过PackageManagerService的解析,其结点信息保存在package对象中,持久存放到setting对象中。
- android系统启动后,都解析固定目录下apk文件,然后重新安装
-
app启动流程
- 每个app都运行在独立的进程空间中,由多个组件构成,可以通过组件启动其他app组件,因此没有类似程序入口的main方法。应用在需要的时候才启动,并创建进程
- 冷启动:应用启动时后台没有其进程。需要系统(zygote进程)创建一个新的进程分配使用
- 点击图标,调用startActivity,通过Binder机制调用ActivityManagerService来创建新进程实例化目标activity
- 创建进程:通过zygote进程得到新的进程
- 创建与初始化application:将新的进程与application绑定起来
- 创建与初始化launch activity:从已存在的进程启动activity
- 热启动:启动时后台存在对应的进程,只需要从已有进程中启动
-
apk打包:apk内包括资源文件与classes.dex,打包发送包括集成开发工具与命令行方式
- 打包资源文件,将res文件夹文件、布局xml文件、manifest文件生成R.java(assets文件不处理)
- 处理aidl文件生成相应.java文件,若没有则跳过
- 编译工程源代码、R.java、aidl.java文件生成相应class文件
- 转换所用class文件,包括源代码文件、R生成的class文件、aidl生成的class文件,得到classes.dex文件(android虚拟机可执行文件)
- 使用apkBuilder脚本工具,将dex文件、编译过的资源文件、libs文件、未编译的资源等打包生成apk
- 对apk签名
- 对apk进行对齐处理:所有资源文件距离文件起始位置偏移4字节整数倍的位置,使得内存映射访问速度更快,减少运行时对内存的使用
-
-
文件下载、断点续传:
- RandomAccessFile支持在文件任意位置读取、写入及修改数据
-
事件分发
- 点击事件封装为MotionEvent对象,包括MotionEvent.Action_DOWN、UP、MOVE、CANCLE(非人为因素结束)四个事件类型,组合成实际动作的一系列事件(如DOWN--MOVE--UP)。对点击产生的事件需要由系统传递给一个具体被点击的view处理,即为事件分发。
- UI界面<-Activity<-ViewGroup<-View,事件发生后,需要通过activity->ViewGroup->View进行传递
- activity事件分发:点击发生后首先被传递至activity的dispatchTouchEvent()进行分发,并判断是否需要调用onTouchEvent()处理点击事件或分给vG.dispatchTouchEvent()、结束分发,以及当前view是否还能接收该事件列的其他事件
- ViewGroup事件分发:先调用VG.dispatchTouchEvent(),再调用onInterceptTouchEvent()判断是非需要拦截事件,否则便利VG中所有子View,并调用view.dispatchTouchEvent()进行传递;是则自己对事件进行处理,调用vg.onTouch()
-
View事件分发:先调用v.dispatchTouchEvent(),再调用view.onTouchEvent()进行处理(调用clickListener的onClick()等)
- 子view内事件优先级:setOnTouchListener.onTouch >onTouchEvent >onClick
android Binder机制
消息机制
-
优化
- 内存
- 布局
- ListView
操作系统管理内存