一、activity生命周期
什么是activity?
Android中的四大组件,用来于用户交互的组件,利用setContentView可以来显示组件
activity的四种状态
running (activity处于栈顶)/paused(失去焦点)/stopped/killed
activity生命周期
onCreate 正在创建,常做初始化工作
onStart 正在启动,这时activity可见但不在前台,无法和用户交互
onResume 获得焦点,此时activity可见且在前台并开始活动
onPause activity正在停止,可做数据存储、停止动画操作
onStop 即将停止,可做稍微重量级回收工作,如取消网络连接、注销广播接收器等
onDestory activity即将销毁,常做回收工作、资源释放
当activity由后台切换到前台,由不可见到可见时会调用onRestart,activity重新启动
onStart() 和onResume 与onPause()和onStop()得区别?
onStart()和onStop()是从Activity是否可见角度调用的
onResume()和onPause()是从Activity是否在前台这个角度回调的,实际中没其它明显区别
Activity A启动B回调的方法有?
A onPause -> B onCreate -> B onStart -> B onResume -> A onStop
如果B是完全透明或者对话框,则不会调用A onStop
onSaveInstanceState()方法,何时调用?
非人为终止Activity时,比如系统配置发生改变导致Activity被杀死并重新创建、资源内存不足导致低优先级的Activity被杀死,会调用onSaveInstanceState()来保存状态,该方法调用在onStop之前
恢复数据时,一般在onRestoreInstanceState()方法,一般在onStart之后调用
onSaveInstanceState()和onPause的区别?
onSaveInstanceState()适用于对临时性状态的保存,而onPause()适用于对数据的持久化保存
activity任务栈
Task,栈结构,后进先出,用于存放Activity组件,例如默认模式下,A启动B,那么A的栈定是Activity B
activity启动模式
standard 标准模式,每次启动一个Activity就会创建一个新实例
singleTop 栈顶复用模式,新Activity在任务栈栈顶,就不会创建,并回调onNewIntent()方法,如果不在则新建
singleTask 栈内复用模式,任务栈内有该Activity实例,就会移除该activity栈顶activity,并回调onNewIntent()方法,不存在则会新建该实例
singleInstance 单实例模式,此模式的Activity只能单独位于一个任务栈中,且只有唯一一个实例
singleTop可重复创建实例,不会引起任务栈的变更,防止多次快速点击启动activity,可以将activity设置为singleTop,singleTask可以利用taskAffinity指定任务栈,一般用于登录页
Activity的启动过程
Activity的startActivity到Instrumenation的execStartActivity,再利用Binder进程通信,调用AMS的startActivity,中间经过一些流程最终会到ActivityThread内部类ApplicationThread的scheduleLaunchActivity,然后将启动Activity的消息发送交给ActivityThread的Handler类H处理,handleLaunchActivity()再调用performLaunchActivity()
scheme跳转协议
页面内跳转协议,方便APP页面内的跳转
服务端下发跳转路径,H5点击描点,根据描点具体跳转路径APP的具体页面
在清单文件的intent-filter中进行data配置,host:代表scheme作用于哪个地址域,port代表该路径的端口号,path代表scheme指定的页面,还可以携带参数
二、Fragment 第五大组件
Fragment的生命周期(起初是为了给大屏幕展现UI设计的,Android 3.0)
onAttach -> onCreate -> onCreateView -> onViewCreated -> Activity : onCreate -> onActivityCreated -> Activity : onStart -> onStart -> Activity : onResume -> onResume -> onPause -> Activity : onPause -> onStop -> Activity : onStop -> onDestroyView -> onDestroy -> onDetach -> Activity : onDestroy
加载方式
添加到布局
动态在activity中添加
FragmentPagerAdapter和FragmentStatePagerAdapter的区别?
从源码角度看,FragmentPagerAdaper在destroyItem中仅仅是detach fragment,解绑视图,而FragmentStatePagerAdapter是remove Fragment,所以前者适合界面少的应用,后者适合界面多的应用
Fragment通信
与Activity通信,推荐谷歌官方做法,接口回调方法
可以使用EventBus或者findFragmentById做法
Activity和Fragment的区别
两者都包含布局
但是Fragment依附在Activity上的,多了和宿主Activity相关的生命周期方法,例如onAttach、onDetach等,并且Fragment的生命周期方法是由宿主Activity调用的,而不是系统,从生命周期修饰符可以印证,Activity的都是protected,而Fragment的是public
我们可以在Activity中动态替换、移除Fragment
Activity的FragmentManager负责用来调用队列中Fragment的生命周期方法,和Activity同步状态
单一场景,切换时更适合用Fragment,或者模块化中,一个Fragment对应一个模块。
三、Service
Service是什么?
一种长生命周期,无可视化界面,运行于后台的一种服务程序
Service与Thread的区别
service运行在主线程中,不能执行耗时操作,主线程难以控制Thread,当Activity销毁后,是没有办法获取之前的Thread的,如果Thread内的run方法没有执行完毕,它会一直执行
两种启动方式的生命周期
onCreate -> onStartCommand -> onDestroy
onCreate -> onBind -> onUnbind -> onDestroy
Service的启动方式
startService onCreate -> onStartCommand 后一直保持运行,如果服务已经开了,仅仅是会调用onStartCommand方法,无论startService调用了多少次,只需要调用一次stopService就会停止
bindService onCreate -> onBind,只要服务没断开就可以一直通信
两种启动方式的工作流程
startService 会调用ContextImpl的startServiceCommon,然后通过Binder机制与AMS通信,调用AMS的startService方法,最后调用ApplicationThread的scheduleCreateService,然后在发送消息交由ActivityThread的Handle类H处理,调用handleCreateService、handleServiceArgs,这两个方法内分别调用了service的onCreate和onStartCommand方法
bindService 会调用bindServiceCommon方法,然后与AMS通信,调用bindService方法,同样最后会调用ApplicationThread的scheduleCreateService方法,然后发送消息交由H处理,调用handCreateService方法,然后会调用ApplicationThread的scheduleBindService方法,发送消息交给H处理,调用handBindService,然后会调用AMS的publishService方法,最后会调用ServiceConnection的onServiceConnected方法
如何保证Service不杀死
增加Service优先级,例如设置为一个前台服务
如果是startService的话,直接在onStartCommand的返回值改为START_STICKY,每次被杀死后都会再次启动
当然还可以再onDestroy发送广播,然后onReceive中启动Service
一些系统常见的Service
WINDOW_SERVICE 管理打开窗口程序 WindowManager
ACTIVITY_SERVICE 管理应用程序 ActivityManager 对应的ActivityManagerService,负责四大组件的启动、切换、调度和进程管理等作用
ALARM_SERVICE 闹钟服务 AlarmManager 例如它的定时服务,定层也是通过handler实现的
四、BroadcastReceiver
广播的定义
类似一个全局的监听器,属于Android四大组件,优点观察者模式的味道
不同APP或者同一APP间多个进程的不同组件通信
静态注册完成后将一直运行,进程杀死还在运行
广播的种类
普通广播
有序广播,可以称为系统广播
本地广播,只在APP内传播,利用LocalBroadcastManager类
有序广播的工作流程
注册的话,直接通过AMS,调用其registerReceiver
调用ContextImpl的sendBroadcast,将消息放到BroadcastQueue中,然后再发送消息交由BroadcastHandler处理,最后会调用ApplicationThread的scheduleRegisteredReceiver,最后会调用LoadedApk内部类ReceiverDispatcher的performReceive,进而调用receiver.onReceive方法
五、ContentProvider
什么是ContentProvider?
ContentProvider是不同应用程序之间进行交换数据的标准API,主要负责存储和共享数据
Android内置的许多数据都是使用ContentProvider形式,供开发者调用的,如音频、图片、通讯录
ContentProvider工作流程
使用ContentResolver的query来说,调用query方法,它会调用ApplicationContentResolver的acquireUnstableProvider方法,继而调用ActivityThread的acquireProvider方法,然后与AMS通信,调用其getContentProvider方法,接下来会调用Process.start方法开启一个进程,运行ActivityThread的main方法,再调用AMS的attachApplication方法,最后会经由ActivityThread的H处理,调用handleBindApplication,再调用installContentProviders方法。
与SharePreferencs的区别?
SP是一种轻量级的数据存储方式,一般用来存储简单的配置信息,基于xml文件的KEY-VALUE数据
保存的数据仅能被本应用使用,而CP则能被不同应用使用
SP的读写有一定的缓存策略,在内存中有一份该文件的缓存,在多进程模式下,读写会很不可靠,可能会丢失数据
与SQLite的区别?
轻量级关系型数据库,占用资源少,存储大量数据时可以使用
批量操作可以利用SQLiteStatement操作,开启事务和结束事务
SQLite使用完得注意及时关闭Cursor,读取数据库属于耗时操作
使用索引加快检索进度
创建好的表,不允许修改和删除表字段,除非赋值新表保留想要的字段
六、WebView
Android API16之前的版本存在远程代码执行安全漏洞,该漏洞源于程序没有正确限制使用WebView.addJavascriptInterface接口,远程攻击者可以通过使用Java Reflection API利用该漏洞执行任意JAVA对象的方法
WebView内存泄露
记得及时remove WebView,再将webview onDestroy
WebView方法一个独立进程,减轻负担
动态创建WebView的时候,对传入WebView的Content使用弱引用。Activity创建时add,onDestroy时remove
WebViewClient.onPageFinished调用多次,采用WebChromeClient.onProgressChanged方法替换
后台耗电问题
直接System.exit(0)将虚拟机退出,暴力解决或其他好的方法
七、Binder
为什么要多进行多进程间通信,也就是IPC
不同进程的四大组件的运行,依赖于IPC机制,它们之间需要通过内存共享数据,每个进程相当于一个独立的虚拟机,不同的虚拟机在内存分配上地址空间不同,不同虚拟机访问同一个类对象会出现很多副本的
多进程可使SharedPreference不可靠性增加,数据丢失率有一定的增加,Application创建多个,静态变量和单例模式失效
序列化
Serializable 简单、效率低、开销大。适合将对象序列化到存储设备,或者将对象序列化后通过网络传输
Parcelable 高效、使用相对复杂。主要用在内存序列化上。使用IBinder作为载体,直接在内存上读写
为什么用Binder来所谓主要的IPC通信方式?
Android使用的Linux内核拥有着非常多的跨进程通信
传输效率高,可操作性强。前者是指内存拷贝次数,一般的通信,都是先从发送方的缓存区拷贝到内核开辟的缓存区,再从内核缓存区拷贝到接受方的缓存区。有两次拷贝。而Binder,只需要将数据从发送方的缓存区拷贝到内核的缓存区,接收方的缓存区与内核的缓存区是映射到同一块物理地址的。
实现C/S架构方便。Binder基于C/S架构,Server端和Client端相对独立,稳定性好。
安全性高。例如Socket通信,IP地址可以人为修改,而Binder机制为每个进程分配了UIP/PID,在通信时会进行校验
Binder进行数据传输的具体过程
服务端返回Binder对象,客户端通过AIDL接口asInterface()得到Binder对象(不同进程是代理Binder),通过得到的Binder类发起RPC请求,客户端挂起当前线程,将参数写入到data,然后调用transact方法,RPC请求通过底层封装后交由服务端的onTransact方法处理,将结果写入到reply,最后返回结果并唤醒客户端线程。
Binder驱动
例如A通过通讯录给B打电话,号码通过通讯录获取,两者通信必须依靠电话基站,这个相当于Binder驱动,通讯录相当于ServiceManager
两个运行在用户空间的进程要完成通信,必须依靠于内核的帮助,而这个运行在内核的程序就是Binder驱动
Service在ServiceManager中注册,Client通过名字去ServiceManager中查找,返回查找的Binder对象,然后拿到Binder后调用Service方法
如何优化多模块使用AIDL的情况
如果为每个模块创建特定的AIDL文件,那么相对应的Service就会很多,会出现资源耗损严重等情况,这时候就应该使用Binder连接池解决。Server端提供一个queryBinder接口,不同业务模块拿到不同的Binder对象就可以使用了,Binder连接池的作用主要是将每个业务模块的Binder请求统一转发到远程Service执行。
八、Handler
什么是handler
主线程更新UI,子线程不能更新UI,利用Handler可以灵活更新UI
handler post(runnable)方法,sendMessage(message)方法,最后调用的都是sendMessageAtTime方法
Handler内部机制
sendMessage把消息和Handler通过MeesageQueeu的enqueueMessage方法传给MessageQueue,也就是所谓的把消息放入到消息队列中,然后通过Looper的next方法处理信息,调用handler的dispatchMessage方法,最后回调handMessage方法
Handler引起的内存泄露以及解决办法
静态内部类持有外部类的匿名引用,导致外部Activity无法释放
解决办法:handler内部持有外部activity的弱引用,并把Handler改为静态类,或者在activity的onDestroy中调用removeCallback
九、AsyncTask
什么是AsyncTask
它本质上是一个封装了线程池和handler的异步框架
需要注意事项上篇有提及,主要就是新建AsyncTask需要在主线程中执行
AsyncTask机制原理
上篇也有提,这里做个小结。
AsyncTask的本质是一个静态的线程池,AsyncTask派生出的子类可以实现不同的异步任务,这些任务默认都是排队提交到静态的线程池中执行的
线程池的工作线程会执行doInBackground(mParams)方法执行异步任务
当任务状态改变后,工作线程会向UI线程发送消息,AsyncTask内部的InternalHandler响应这些消息并调用相关的回调函数
内存泄露问题
和handler类似,改成静态类
最好在onDestroy时cancel
十、HandlerThread
HandlerThread是什么?
开启Thread子线程进行耗时操作,多次创建和销毁是很耗系统资源的
本质是handler + thread + looper,thread 内部有looper
HanderlThread继承了Thread,有自己内部的Looper对象,可以进行Looper循环
通过HandlerThread的looper对象传递Handler,在handleMessage方法中执行异步任务
优点是不会有堵塞,减少了对性能的消耗,缺点是不能同时进行多任务处理,属于串行
HandlerThread机制
在run方法里,通过Looper.prepare和Looper.loop开启了消息循环,然后将Handler传递给Looper,在Looper.loop内会调用handler的dispatchMessage方法,然后会调用传递的callback或者是handlerMessage方法处理消息
十一、IntentService
IntentService是什么?
IntentService是继承并处理异步请求的一个类,在IntentService内有一个工作线程来处理耗时操作,启动方式和传统的一样,当任务执行完毕后,内部会调用stopSelf(id)类自动停止,可以启动IntentService多次,而每一个耗时操作会以工作队列的方式在IntentService的onHandleIntent回调方法中执行,并且,每次指挥执行一个工作线程,执行完后再执行第二个
本质是通过HandlerThread和Handler实现异步操作
是一种特殊的Service,继承自Service
IntentService原理机制
在它的onCreate中会初始化一个HandlerThrad和ServiceHandler,然后在onStart方法内会将intent封装成Message,利用ServiceHandler发送出去,经由自己的handleMessage处理,最后会调用onHandleIntent方法