目录
一、Activity与Fragment
二、Service
1. Service 启动方法与生命周期
2. Service与Activity之间通信的几种方式
3.IntentService
4.service保活
5.service onStartCommand返回值
6.JobService, JobScheduler 使用
7.AIDL
三、ContentProvider
四、BroadcastReceiver
五、一些View
六、Context问题
七、Handler
Handler实现原理
一、Activity与Fragment
- Activity各种情况下的生命周期:onCreate,onStart,onResume,onRestart, onPause,onStop,onDestory.
- Activity与Fragment之间生命周期比较
- Activity的四种启动模式对比
singleTask:适合:App 主入口(MainActivity)、首页型页面(你希望回到首页并把中间页清掉)。SingleInstance 典型特征:中断当前流程、独立完成任务、结束后回到原处。比如来电接听界面。模式
允许同一类多个实例?
是否会复用旧实例?
复用时是否清掉上面兄弟?
是否可能独占/分Task
standard
✅ 允许多个
❌
—
❌
singleTop
✅(但top不叠)
✅(仅当 top)
❌
❌
singleTask
❌(同affinity-task唯一)
✅
✅ clear top
可能(受 affinity 影响)
singleInstance
❌(全局唯一)
✅
✅(其实没兄弟可清)
✅ 独占一个 Task
- Activity状态保存与恢复:复写onSaveInstanceState和onRestoreInstanceState
onSaveInstanceState(Bundle outState)会在以下情况被调用(进入后台,可能被销毁(不是确定会被销毁)):
1、当用户按下HOME键时,屏幕被关闭时。
2、从当前activity启动一个新的activity时。
3、屏幕方向切换时。
Fragment状态保存startActivityForResult是哪个类的方法,在什么情况下使用?总结起来就是:从哪里发起调用,最终就会走到哪里。
1.用getActivity方法发起调用,只有父Activity的onActivityResult会调用,Fragment中的onActivityResult不会被调用; 2.直接发起startActivityForResult调用,当前的Fragment的onActivityResult,和父Activity的onActivityResult都会调用; 3.用getParentFragment发起调用,则只有父Activity和父Fragment的onActivityResult会被调用,当前的Fragment的onActivityResult不会被调用。 这里2和3的前提是如果父activity中重写了onActivityResult,父Activity的onActivityResult中必须添加super.onActivityResult()。- 如何实现Fragment的滑动:ViewPager
- fragment之间传递数据的方式?
- 通过所在Activity中的set, get 方法;
- 利用bundle 和setArguments进行参数传递;
- EventBus; EventBus原理 发布订阅模式。
二、Service
1. Service 启动方法与生命周期
1. startService启动类型的服务: onCreate()- >onStartCommand()->Service running--调用context.stopService() ->onDestroy() 。
2. bindService 绑定类型的服务: onCreate()->onBind()->Service running--调用>onUnbind() -> onDestroy()
2. Service与Activity之间通信的几种方式
- 在startService 时,把数据通过Intent传递过去;
- bindservice时,实现ServiceConnection;
- 注册Callback的方式;
3.IntentService
一个继承自Service的抽象类,里面封装了Handler和HandlerThread,子线程运行。所有任务结束后能自动销毁。
4.service保活
- onStartCommand 中返回START_STICKY;
- 在onDestory中启动该服务;
- 同时开启两个进程和服务;
5.service onStartCommand返回值
START_STICKY:service被杀后重新创建,但不处理之前的intent。(默认值)START_STICKY_COMPATIBILITY 是其兼容版,2.0一下使用。
START_NOT_STICKY:服务被杀后不会重新启动。
START_REDELIVER_INTENT:服务被杀重启后会再分发intent.
6.JobService, JobScheduler 使用
执行时间不精准,但利于省电。
Android JobScheduler 的使用-CSDN博客
7.AIDL
- 使用方法;
- 客户端与服务端挂了怎么办?DeadObjectException,
客户端deadObject异常处理 :注册死亡代理DeathRecipient,当binder死亡后,系统会回调binderDied方法 。
服务端如何知道客户端挂了:客户端在注册时把客户端的binder传给服务端,并调用binder.linkToDeath注册死亡代理(在服务端处理),当客户端挂了时,服务端就知道了。
当binder断开连接后,系统会回调onServiceDisconnected,然后我们可以重连服务。
inout,oneway等参数。常见组合示例:
// 1. in + oneway:异步传递输入参数(调用方发指令,不等待结果)
oneway void startDownload(in String url);// 2. out + 同步:同步获取服务端输出结果(调用方等待服务端填充数据)
void getDownloadProgress(out Progress progress);// 3. inout + 同步:同步双向交互(调用方传初始配置,服务端更新后返回)
void syncSettings(inout AppSettings settings);
三、ContentProvider
- ContentProvider的原理:ContentProvider原理分析_blueberry_mu的博客-CSDN博客_contentprovider原理 ,难点主要在获取ContentResolver的获取流程。
- ContentProvider、ContentResolver、ContentObserver 之间的关系:使用ContentResolver来获取ContentProvider提供的数据,同时注册ContentObserver监听Uri数据的变化
- ContentProvider 是如何实现数据共享的?
- getContentResolver:返回的ContentResolver是在ContextImpl 中创建,一个ApplicationContentResolver对象;
- 调用增删改查方法时,是调用acquireProvider(返回一个IContentProvider 对象)的增删改查方法;
- 调用ActivityManagerService.getContentProvider方法---startProcessLocked---ActivityThread.installProvider---ContentProvider.onCreate;
- ContentProvider的权限管理(解答:读写分离,权限控制-精确到表级,URL控制)
四、BroadcastReceiver
- 请描述一下广播BroadcastReceiver的理解,广播使用的方式和场景。
BroadcastReceiver.onReceive() 中不可以开启新的线程来进行耗时的操作。在BroadcastReceiver.onReceive()方法收到广播,开启一个线程,接着它返回也就是执行完毕后,系统会认为BroadcastReceiver不在处于活动状态。因此不在需要起托管进程(除非其他应用程序组件处于活动状态,如Activity,Service)。因此系统可能随时终止进程来回收内存,并且这样会终止进程中运行的线程。- BroadcastReceiver,LocalBroadcastReceiver 区别:LocalBroadcastReceiver用于内部传递消息,更高效安全,只能动态注册。依托LocalBroadcastManager使用。原理:借助一个静态单例类LocalBroadcastManager。静态保证了他一旦创建就基本上与application一样的生命周期。他持有 所有register到他里面的broadcast的引用。因此需要利用他发广播时,就可以立即拿到这个broadcast引用 调用 这个broadcast对象的onReceive方法。
- BroadcastReceiver与EventBus比较:广播资源消耗高、需要Context,能用于跨进程。EventBus调用灵活,不依赖Context;使用简单,Subscriber 即可。但逻辑性不是很好,适合统一进程。
五、一些View
Android view 学习总结
六、Context问题
ApplicationContext和ActivityContext的区别:ApplicationContext 不应该用于界面相关的地方,ActivityContext 可能使得对象不能及时被释放,从而引发内存泄漏。
进程和 Application 的生命周期:
在大多数情况下,每个Android应用程序都在自己的Linux进程中运行。当需要运行某些代码时,将为应用程序创建此过程,并且该过程将一直运行,直到不再需要它为止,并且 系统需要回收其内存以供其他应用程序使用。
七、Handler
Handler实现原理
Handler持有MessageQueue和Looper, 底层利用Linux epoll 机制,没有消息时会通过epoll_wait进入睡眠状态。
Handler机制和底层实现:handler通过sendMessage把消息发送到MessageQueue里面,enqueueMessage函数解析 参考如下:
boolean enqueueMessage(Message msg, long when) { //这里处理的普通消息必须是包含Handler的,下面会提及一个同步屏障消息,它其中不包含Handler if (msg.target == null) { throw new IllegalArgumentException("Message must have a target."); } //存在已经消费过的标记,不在继续添加 if (msg.isInUse()) { throw new IllegalStateException(msg + " This message is already in use."); } synchronized (this) { if (mQuitting) { //如果Queue已经退出,则将消息recycler msg.recycle(); return false; } //标记使用状态 msg.markInUse(); //设置延迟时间 msg.when = when; //mMessage是一个全局变量,代表MessageQueue的头节点 Message p = mMessages; //头节点为空 或者 等待时间小于头节点 那么都放在队列的前端 if (p == null || when == 0 || when < p.when) { //给msg的上一个节点赋值,这里将头节点设置为下一个,当前msg为头节点 msg.next = p; //给头节点赋值 mMessages = msg; } else { Message prev; for (;;) { //比较时间,将消息按照时间进行排列 prev = p; p = p.next; if (p == null || when < p.when) { break; } } //将消息插入合适的位置 msg.next = p; //这里也就是一个排队的逻辑 prev.next = msg; } } return true; } 原文链接:https://blog.csdn.net/wcy0312808/article/details/90295965Looper中有个for循环不断调用queue.next读取消息(nativePollOnce),底层采用的是pipe/epoll机制,无消息时会释放CPU从而不会导致阻塞。 最终调用Message.target.dispatchMessage ,里面具体实现如下:
public void dispatchMessage(Message msg) { if (msg.callback != null) { handleCallback(msg); } else { if (mCallback != null) { if (mCallback.handleMessage(msg)) { return; } } handleMessage(msg); } }handler.post(...) //第一优先级:执行post所传递的Runnable参数.run()。会被封装为message处理
new Handler(callback) //第二优先级:执行构造方法传来的callback匿名内部类。
handleMessage(msg)//第三优先级:调用Handler的handleMessage()方法
public final boolean post(@NonNull Runnable r) { return sendMessageDelayed(getPostMessage(r), 0); }- Handler、Thread和HandlerThread的差别:HandlerThread 自带消息循环的线程,用于处理一系列串行的后台任务。
- handler发消息给子线程,looper怎么启动? 调用Loop.prepare() 与Loop.loop()。
- 关于Handler,在任何地方new Handler 都是什么线程下? - 不传参数时,在什么线程下new,就和什么线程绑定。在子线程new时,要调用Loop.prepare();Loop.loop()
- Handler 内存泄漏原因及解决方案