Activity的生命周期
正常的流程:
onCreate():被创建的时候被回调,
onStart():Activity正在启动状态,处于可见但无法交互,但处在后台
onResume():已经在前台可见,可以和用户交互,Activity已经在运行
onPause():Activity正在停止,和onResume()成对出现
onStop():即将停止,或被新的Activity覆盖,Activity不可见,在后台运行
onDestory():Activity正在被销毁,回收和资源的释放,和onCreate()成对
onRestart():Activity正在重新启动不会执行此方法
异常的流程(1、系统发生改变 2、内存不足造成的改变):
只有在Activity异常的情况下才会调用
onSaveInstanceState()是出现异常情况下,会自动调用,来保存当前Activity的信息,(当异常启动的时候,这个方法中的bunlder可能为空,所以要进行非空判断)
onRestoreInstanceState()当Activity重新创建后,自动调用,会通过onSaveInstanceState()的Bundle来保存状态
一旦被异常启动,Bundle()方法不会为空
总结: 1、Activity正常启动:onCreate--onStart--onResume
2、点击Back回退:onPause--onStop--onDestroy
3、打开新的Activity:onPause--onStop
4、Activity异常:onSaveInstanceState来保存数据
5、Activity重新创建:调用onRestoreInstanceState
1.任务栈
四种形态:
Active:Activity处于栈顶
Paused:可见但不可交互 只是失去了和用户的交互,只有在系统内存不足时才会被回收
Stopped:不可见 被完全覆盖时,只有在系统内存不足时才会被回收
Killed:系统回收掉
(在内存不足的时候,会回收栈底部的Activity)
总结:1、Activity是与用户交互的接口 2、Android系统是通过Activity栈的形式来管理Activity 3、四种形态:Active/Paused/Stopped/Killed
2.四种启动模式
Activity启动模式(当多次启动Activity的时候,系统会创建多个实例,按照先后进出的顺序放入任务栈中,当按下Back键的时候,整个任务栈就会为空,系统就会回收)
1、standard(标准模式)(默认启动模式)
一、在不指定启动模式的前提下,系统默认使用该模式启动每个Activity
二、每次启动一个Activity都会重写创建一个新的实例(消耗资源)
三、Activity在启动的时候,onCreate(),onStart(),onResume()都会依次调用
2、singleTop(栈顶复用) ps:只有在栈顶才可以
一、当前栈中已有该Activity实例并且该实例位于栈顶时
二、当前栈中已有该Activity实例单实该实例不再栈顶时
三、当前栈中不存在该Activity的实例
SingleTop应用场景:
IM对话框
新闻客户端推送
3、singleTask(栈内复用模式),检测的是整个栈中是否存在要启动的Activity
(适合于应用中主界面模式)
一、首先根据taskAffinity去寻找当前是否存在一个对应名字(就是包名)的任务栈
(任务相关性)
二、如果不存在,就重新创建一个Task任务栈
然后创建新的Activity的实例假如栈中
三、如果存在,先得到该任务栈,查找该任务栈中是否存在该Activity实例
存在的话,就会将所有这个实例的Activity都出栈
SingleTask应用场景
应用的主界面
4、singleInstance(单一实例模式)
singleInstance模式下,所有的Activity中只有一个实例,所有Activity会独享一个任务栈
如果有别的Activity使用的话,这两个Activity会使用一个任务栈
应用场景:呼叫来电、
特性:
1、以SingleInstance模式启动的Activity具有全局唯一性
2、如果在启动这样的Activity时,已经存在了一个实例
3、以SingleInstance模式启动的Activity具有独占性
Activity和Activity之间的通信
1、Intent/Bundle
Intent:首先创建Bundle对象,通过Key,Value传递数据
例:
第一个Activity发送
Bundle bundle = new Bundle();
bundle.putString("Key","value");
bundle.putInt("Key2",1);
Intent intent = new Intent(GoActivity.this,ToActivity.class);
intent.putExtras(bundle);
startActivity(intent);
将Bundle对象和Intent建立联系
第二个Activity接收
Intent intent = getIntent();
String key = intent.getStringExtra("Key");
int value = intent.getIntExtra("Key2",1);
第二个Activity中获取第一个Activity传过来的值
2、类静态变量
3、全局变量
Activity和Service之间的通信
1、绑定服务,利用ServiceConnection类
在Activity中实现接口(ServiceConnection)
重写onServiceConnected(绑定成功执行) onServiceDisconnected(进程崩溃执行)这两个方法,这两个方法是在绑定成功和进程崩溃的时候调用
首先在onServiceConnected()中创建Binder对象,利用binder的setData()方法,向Service中传递数据
2、简单通信,利用Intent进行传值
用Intent进行传值,从Activity中传值(putExtras.("key","value"))
在Service中直接用(getIntent)获取
3、定义一个CallBack接口来监听服务中的进程的变化
在Service中定义一个接口
在Activity中,在onServiceConnected()方法中,用binder对象来实现Callback中重写的方法
如果是在子线程中,需要通过Handler来发送到主线程中,
Activity和Fragment之间的通信
Activity将数据传递给Fragment
Bundle:
当用Bundle来传递数据时,用fragment.setArguments(bundle对象名);
在Fragment的时候,用(isAdded()方法)判断是否已经依附在Activity上。
直接在Activity中定义方法:
在第一个Activity中定义构造方法
然后在需要接收数据的Fragment中用onAttach()方法中强转为Activity的类型
Fragment将数据传递给Activity
1、接口回调:
一、在fragment中定义一个内部回调接口//Acticity实现这个接口就行
二、fragment的方法onAttch()//检查fragment中是否实现了内部接口
三、调用onDetach方法,销毁,把Activity传过来的资源释放
Fragment与Service数据通信
Activity调用bindService (Intent service, ServiceConnection conn, int flags)方法,得到Service对象的一个引用,这样Activity可以直接调用到Service中的方法,如果要主动通知Activity,我们可以利用回调方法
Service向Activity发送消息,可以使用广播,当然Activity要注册相应的接收器。比如Service要向多个Activity发送同样的消息的话,用这种方法就更好
Fragment复用
为什么要复用Fragment?
Activity 在重建的时候会恢复其包含的 FragmentManager ,FragmentManager 又会恢复其管理的 Fragment ,同理 Fragment 也会恢复其包含的 FragmentManager,层层递进,直到全部恢复
复用的好处:
避免显示错乱
避免重复添加
避免多余的内存占用
优化界面启动速度
两种适配器的区别?
(1).FragmentPagerAdapter
适合于 Fragment数量不多的情况。当某个页面不可见时,该页面对应的View可能会被销毁,
但是所有的Fragment都会一直存在于内存中。
如果Fragment需要保存的状态较多时,会导致占用内存较大,
(2).FragmentStatePagerAdapter
适合于Fragment数量较多的情况。当页面不可见时, 对应的Fragment实例可能会被销毁,
但是Fragment的状态会被保存。
因此每个Fragment占用的内存会更少,但是页面切换会引起较大开销。
1、service和线程(Thread)的区别和场景
Thread:程序执行的最小单元,它是分配CPU的基本单位
Thread:生命周期
1.新建new
2.就绪runnable
3.运行running
4.死亡death
5.阻塞block
缺点:无法控制,当Activity被关闭之后,无法控制线程
场景:Thread需要连续不断地每隔一段时间就要连接服务器一次做某种操作
2、如何管理service生命周期
不管如何启动service,oncreate()和ondestory()都会运行
Service运行在后台
Service时Android的一种机制,服务是运行在主线程上的
Service生命周期:
onCreate()通过onCreate开始
onStart()
onDestroy()到onDestory结束
onBind()
onUnbind()
四种情况:
1:StartService:
2:stopService:
3:bindService:
4:unBindService:
3、Service和IntentService的区别
Service:不建议在service中执行耗时操作,否则会报ANR
IntentService:内部有一个工作线程HandlerThread来处理耗时操作
工作机制:继承与Service,
和Service不同点:在onCreate()方法中会创建并启动HandlerThread,还创建了ServiceHandler异步处理类,执行异步任务
当持有IntentService会实现onHandlerIntent方法,
如果后台只有一个任务,执行完onHandlerIntent会进行销毁
如果后台有很多任务,onHandlerIntent会依次执行,直到执行完毕之后,才会销毁(调用StopSelf()结束操作)
总结:
1、IntentService是继承并处理异步请求的一个类
2、内有一个工作线程(也就是HandlerThread)来处理耗时操作
3、IntentService内部则是通过消息的方式发送给HandlerThread的,然后由Handler中的Looper来处理消息
4、启动服务和绑定服务先后次序问题
Android中只会又一个服务
启动服务:service会无限期的运行
先绑定service后启动
绑定服务会转为启动服务状态,不会影响服务运行,之到onStop为止
先启动service后绑定
不会转为绑定的状态,当Activity解除绑定服务的时候,还会按照启动的生命周期在后台运行,之到onStop为止
总结: 1、启动服务的优先级比绑定服务高
2、服务在其托管进程的主线程中执行,主线程
ALDL:
AIDL:是一种android内部进程通信接口描述语言,用过它我们可以定义进程间的通信接口但是记住仅仅只是 android ,换个平台就不是AIDL 了。 AIDL进程间通讯的原理:
1.通过编写aidl文件夹来定义进程间通信接口
2.编译后会自动生成相应的java文件 在各未见中我们可以看到是继承啦一个Binder对象,实现刚刚定义的接口
3.服务器我们通过一个服务实现里面的Binder方法,将接口的具体实现写在stub中,用ibinder对象传递给客户端
4.客户端bindservice的时候,服务是实现serviceConnection重写里面的方法,用asinterface的形式将ibinder还原成接口,在调用其接口中的方法来实现通信
Binder机制:
Android使用Linux内核拥有这非常多的跨进程通信机制,比如Socket,管道。为什么还要binder呢?
性能:Binder相比较于传统的socket/管道通信而言,更加高效,它在IPC时,只需要数据拷贝1次,而传统的socket之类的需要2次;
出于安全上的考虑:传统的进程间通信对于通信双方的身份没有进行严格的验证,只有上层协议才会进行架构,比如说,socket通信时,IP地址是手动填写的,可以进行人为的伪造,而Binder支持通信双方进行身份校验,极大的保障了安全性;
Binder的通信模型:
我们其实可以进程通信的双方一方称为服务端进程,另一方称为客户端进程,我们知道,由于进程隔离的存在,在不进行进程间通信的方式的情况下,客户端进程是无法访问服务端进程的;
对于A和B相当于两个进程,他们要打电话就相当于要进行通信,其中电话基站就想到与Binder驱动,而通信录则相当于其中的一个ServerManager
ServerManager其实就是一个进程,它里面维护了一张表,表里面存储的是向他注册过的进程信息,在通信之初,首先需要有一个进程向驱动申请成为ServerManager,当内核驱动同意之后,这个成为ServerManager的进程就负责管理所有需要通信的进程信息,当客户端进程要访问服务端进程时,服务端进程首先会向ServerManager注册,让ServerManager保存自己的有关信息,当ServerManger保存完毕后,客户端进程就会通过Binder驱动向ServerManger查询服务端进程的信息,ServerManage就会将服务端进程的信息返回给客户端进程,客户端与服务端进程之间就可以通过这些信息,利用Binder驱动来进行通信了;
总结来说,Binder通信机制分三步:
第一步:ServerManager在其内部维护一张表;
第二步:服务端进程向ServerManager注册信息;
第三步:客户端进程向ServerManager取得信息,通过Binder驱动与服务端进程通信;
手写网络框架:理解http网络请求的过程,会存在的问题记录下来,对比okhttp, 为啥要手写?
问题?
扩展性:不能只处理Json/Xml,image,file,video
易用性:解决问题只需要调用一两个API
稳定性,封装性,模块化
和其他框架能不能集成(数据库,网络,MVC,MVVM,资源加载)
对比?
okhttp:
1.占用储存空间
okhttp占用内存空间过大。
2.功能介绍
Square 公司开源的 OkHttp 是一个专注于连接效率的 HTTP 客户端。OkHttp 提供了对 HTTP/2 和 SPDY 的支持,并提供了连接池,GZIP 压缩和 HTTP 响应缓存功能。
3.优点
支持http请求,https请求。
支持文件下载。
使用的是HttpURLConnection,不要担心android版本的变换。(至少目前是都支持的)。
支持get,post请求。
基于Http的文件上传。
加载图片。
4.缺点
比如callback回来是在线程里面, 不能刷新UI,需要我们手动处理。
封装比较麻烦。
Volley
1.占用储存空间
占用内存空间小。
2.功能介绍
Volley是Goole在2013年Google I/O大会上推出了一个新的网络通信框架,它是开源的。
Volley 的特点:特别适合数据量小,通信频繁的网络操作。
3.优点
非常适合进行数据量不大,但通信频繁的网络操作。
内部分装了异步线程。
支持get,post网络请求。
图片下载。
可直接在主线程调用服务端并处理返回结果。
可以取消请求,容易扩展,面向接口编程。
4.缺点
对大文件下载 Volley的表现非常糟糕。
只支持http请求。
为啥手写?
因为在项目中,可以使代码简介明了,做到代码职责划分明显,实现某一块功能不会有多余的代码,而使用别人的开源框架会使我们的代码混乱,代码过多,不简洁,从而导致App的内存占用太大,而且某些开源框架,不能满足我们功能上的需求,而且自己写的更方便自己理解和修改。