Activity
先附上图(来自官方文档)
生命周期方法介绍:
onCreate
作为Activity的第一个生命周期方法,表示正在被创建,此方法一般用来加载布局文件和初始化一些控件(findviewbyId),在Activity的生命周期中它只会执行一次onStart
Activity正在启动,在此期间,用户可以在屏幕上看到Activity,但是它不在前台,无法与用户进行交互;该方法时Activity重新回到前台第一个要回调的方法,与它相应的方法时onStoponResume
Activity已经进入运行状态,用户可以与它进行交互,和它相应的是onPause,当Activity切换到后台时,一般都要在onPause中去释放资源,然后重新回到前台时需要在onResume中重新恢复已经释放调的资源,例如Camera的开启与关闭onPause
Activity可见但不在前台,因为无法与用户进行交互
该方法需要持久化用户数据、暂停动画、暂停正在播放的视频等不太耗时的操作onStop
Activity即将停止,不可见耗时的清理工作要放在onStop方法中;如果在系统内存不够时,系统接下来很快会销毁掉该Activity,在极端情况下,直接 kill Activity 且不执行onDestroy()函数。所以务必在onStop()函数中就清理掉可能引起内存泄露的资源,当然更极端的时系统内存已严重不足,导致系统无法保留该进程的情况下,onStop() 可能都不会被执行onDestory
Activity即将被销毁
很多情况下 Activity 是不需要定义这个函数,因为在onPause()和onStop()中,大多数的清理工作都已经完成了。但是,如果在onCreate()中定义了后台线程,或者可能引起内存泄露的代码,那就需要在onDestroy()中清理,如,静态对象持有其他Activity的引用,广播注销等操作;-
onRestart
Activity正在被重新启动
在原Activity没有销毁时重新要回到该Activity时会回调该方法,紧接着会回调onStart方法,一般在该方法中恢复用户数据;
Activity生命周期变化
-
启动Activity
onCreate() > onStart() > onResume()
-
调用finish方法/按back键
onPause() > onStop() > onDestory()
-
按Home键/启动另一个Activity
onPause() > onStop()
-
从ActivityA进入ActivityB,再按back键返回A,A中的生命周期变化
onRestart() > onStart() > onResume()
Intent传递数据
使用Intent
进行Activity跳转时,可以携带参数,将需要的数据传递给目标Activity,Intent
的putExtra(...)
方法可
以传递基本数据和基本数据的数组,putExtras(...)
方法可以传递对象,前提是对象需要实现序列化,即实现Serializable
或Parcelable
。例如:
-
向目标Activity传递基本数据,如下传递
int
类型的数据intent.putExtra("type",1);
-
向目标Activity传递对象
实现序列化 class A implements Serializable{ ... ... } 使用Bundle进行传递 Bundle bundle = new Bundle(); bundle.putSerializable("obj",new A()); intent.putExtras(bundle);
Activity的启动模式
首先涉及到一个任务栈的概念,在Android中每启动一个Activity,该Activity就会被放入任务栈的栈顶,当在代码中调用finish
方法或者按back
键时,栈顶的Activity就会出栈,因此任务栈所遵循的原则就是先进后出,而每次启动一个Activity,无论之前是否已经启动过此Activity,系统都会实例化一个Activity,并把它放到栈顶,这样就造成了在任务栈中有多个相同的Activity实例,这样就比较浪费内存,为了解决这个问题,谷歌引入了启动模式这个概念,目前有四种启动模式(在清淡文件中指定launchMode属性):
standard、singleTop、singleTask、singleInstance
- standard(标准模式)
系统的默认启动模式,每次启动一个Activity都会重新创建一个新的实例,不管这个实例是否已经存在。在这种模式下,谁启动了这个Activity,那么这个Activity就会运行在启动它的那个Activity所在的栈中。
- singleTop(栈顶复用模式)
这种模式下,如果新的Activity已经位于任务栈的栈顶,那么此Activity将不会重新创建,而它的onNewIntent
方法会被回调,通过此方法的参数我们可以取出当前请求的信息。另外需要注意的是:该Activity的onCreate
、onStart
并不会被系统调用,因为它并没有发生改变。如果新的Activity不是位于栈顶,那么新的Activity仍会被重新创建。
- SingleTask(栈内复用模式)
这是一种单实例模式,在这种模式下,只要Activity在一个栈中存在,那么多次启动此Activity都不会重新创建实例,和singleTop一样,系统也会回调onNewIntent
。当一个具有singleTask模式的Activity请求启动后,比如ActivityA,系统首先会寻找是否存在A想要的任务栈,如果不存在,就重新创建一个任务栈,然后创建A的实例后把A放到栈中。如果存在A所需的任务栈,这时要看A是否在栈中有实例存在,如果有实例存在,那么系统就会把A调到栈顶并调用它的onNewIntent
方法,如果实例不存在,就创建A的实例并把A压入栈中。
- singleInstance(单实例模式)
这是一种加强后的singleTask模式,它除了具有singleTask模式的所有特性外,还加强了一点,那就是具有此种模式的Activity只能单独地位于一个任务栈中,换句话说,比如ActivityA是singleInstance模式,当A启动后,系统会为它创建一个新的任务栈,然后A独自在这个新的任务栈中,由于栈内复用的特性,后续的请求均不会创建新的Activity,除非这个独特的任务栈被系统销毁了。
Intent的Flags
-
FLAG_ACTIVITY_NEW_TASK
这个标记位的作用是为Activity指定singleTask启动模式,其效果和在XML中指定该启动模式相同
-
FLAG_ACTIVITY_SINGLE_TOP
这个标记位的作用是为Activity指定singleTop启动模式,其效果和在XML中指定该启动模式相同
-
FLAG_ACTIVITY_CLEAR_TOP
具有此标记位的Activity,当它启动时,在同一个任务栈中所有位于它上面的Activity都要出栈。这个标记位一般会和singleTask启动模式一起出现,在这种情况下,被启动Activity的实例如果已经存在,那么系统就会调用它的onNewIntent。如果被启动的Activity采用standard模式启动,那么它连同它之上的Activity都要出栈,系统会创建新的Activity实例并放入栈顶。而singleTask启动模式默认就具有此标记位的效果。
-
FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
具有这个标记的Activity不会出现在历史Activity的列表中,当某些情况下我们不希望用户通过历史列表回到我们的Activity的时候这个标记比较有用。它等同于在XML中指定Activity的属性
android:excludeFromRecents="true"
。
Activity数据的保存与恢复
OnSaveInstanceState
当Activity被系统异常杀死后,会调用onSaveInstanceState(Bundle outState)
方法,此方法中有一个参数Bundle
,开发者可以使用它来保存当前的临时数据,那么到底是什么情况下此方法会被调用呢?
此方法被调用会遵循一个原则,就是系统未经你同意时销毁你的Activity
,一般会有如下几种情况:
- 按下Home键
- 长按Home键,选择打开其它程序
- 按下电源键
- 从一个Activity中启动另一个Activity
- 切换屏幕方向(如果不指定configchange属性),在屏幕切换前,系统会销毁该Activity,切换完成后又会重新创建这个Activity,因此onSaveInstanceState一定会执行
OnRestaoreInstanceState
首先此方法和onSaveInstanceState
方法不一定是成对出现的,
OnRestoreInstanceState
被调用的前提是: Activity确实被销毁了,而仅仅是有这种可能的情况下,该方法并不会被调用。
例如,当正在显示activity A的时候,用户按下HOME键回到主界面,然后用户紧接着又返回到activity A,这种情况下activity A一般不会因为内存的原因被系统销毁,故activity A的onRestoreInstanceState方法不会被执行
另外,onRestoreInstanceState的bundle参数也会传递到onCreate方法中,你也可以选择在onCreate方法中做数据还原。 还有onRestoreInstanceState在onstart之后执行。
应用被强杀,如何处理?
-
如何判断应用被强杀
在Application中定义一个static常量,赋值为-1,在欢迎界面改为0,如果被强杀,application重新初始化,在父类Activity判断该常量的值
-
应用被强杀如何解决
如果在每一个Activity的onCreate里判断是否被强杀,冗余了,封装到Activity的父类中,如果被强杀,跳转回主界面,如果没有被强杀,执行Activity的初始化操作,给主界面传递intent参数,主界面会调用onNewIntent方法,在onNewIntent跳转到欢迎页面,重新来一遍流程。
IntentFilter匹配规则
IntentFilter的过滤信息有action、category、data
为了匹配过滤列表,需要同时匹配过滤表中的 action、category、data 信息,否则匹配失败。一个过滤列表中的 action、category、data 可以有多个,只有一个Intent同时匹配action类别、category类别、data类别才算完全匹配,只有完全匹配才能成功启动目标Activity。另外一点,一个Activity中可以有多个intent-filter,一个Intent只要能匹配任何一组intent-filter即可成功启动对应的Activity。详细的匹配规则可在此链接查看:
https://www.jianshu.com/p/d2446661cd4c
Fragment
先附上图
Activity&Fragment 关系图如下
各生命周期方法介绍
onAttach
当该Fragment被添加到Activity时回调,
该方法只会被调用一次。onCreate
创建Fragment时被回调。该方法只会被调用一次。onCreateView
创建Fragmetn的View组件时回调,并显示该方法返回的View组件。onActivityCreate
当Fragment所依附的Activity被启动完成后回调该方法onStart
启动Fragment时被回调onResume
Fragment进入运行状态或者说恢复Fragment时被回调,在onStart方法后一定会回调此方法onPause
暂停Fragment时被回调onStop
停止Fragment时被回调onDestroyView
销毁该Fragment中的View组件时调用onDestroy
销毁Fragment时被回调,该方法只会被调用一次onDetach
将该Fragment从Activity中删除、替换完成时回调该方法,在onDestroy方法后一定会回调onDetach方法,该方法只会被调用一次
将Fragment添加到Activity中有如下两种方式
在布局文件中使用
<fragment.../>
元素添加Fragment,<fragment.../>
元素的android:name
属性指定Fragment的实现类在Java代码中通过FragmentTransaction对象的
add()
或replace()
方法来添加Fragment
Fragment与Activity交互方式
Fragment获取它所在的Activity
调用Fragment的getActivity()
方法即可返回它所在的ActivityActivity获取它包含的Fragment
调用Activity关联的FragmentManager的findFragmentById(int id)
或findFragmentByTag(String tag)
方法即可获取指定的Fragment
Fragment与Activity数据传递
Activity向Fragment传递数据
创建Bundle
数据包,调用Fragment的setArguments(Bundle bundle)
方法Fragment向Activity传递数据或Activity需要在Fragment运行中进行实时通信
在Fragment中定义一个内部回调接口,再让包含该Fragment的Activity实现该回调接口,通过该回调接口将数据传给Activity
Fragment管理与Fragment事务
- 使用
findFragmentById()
或findFragmentByTag()
方法来获取指定Fragment - 调用
popBackStack()
方法将Fragment从后台栈中弹出(模拟用户按下Back键) - 调用
addOnBackStackChangedListener()
注册一个监听器,用于监听后台栈的变化 - 如果需要添加、删除、替换Fragment,则需要借助于FragmentTransaction对象
ContentProvider
自定义ContentProvider
需要实现以下几个方法
public boolean onCreate()
该方法在ContentProvider创建后会被调用,其它应用程序第一次访问ContentProvider时,该ContentProvider会被创建出来,并立即回调该onCreate()方法public Uri insert(Uri uri,ConentValues values)
根据该Uri插入values对应的数据public int delete(Uri uri,String selection,String[] selectionArgs)
根据Uri删除selection条件所匹配的全部记录public int update(Uri uri,ContentValues values,String selection,String[] selectionArgs)
根据Uri修改selection条件所匹配的全部记录public Cursor query(Uri uri,String[] projection,String selection,String[] selectionArgs,String sortOrder)
根据Uri查询出selection条件所匹配的全部记录,其中progection就是一个列名列表,表明只选择出指定的数据列
UriMatcher 关联Uri和Code
使用它的addUri方法将Uri和Code关联到一起,外界通过Uri获取对应的Code,然后根据Code去访问对应的表
BroadCastReceiver
注册广播的两种方式
-
静态注册
在AndroidManifest.xml文件中使用<receiver.../>
元素完成注册 -
动态注册
在Java代码中通过Context.registerReceiver()
方法注册BroadcastReceiver
有序广播
普通广播
是完全异步的,可以在同一时刻(逻辑上)被所有接收者接收到,效率比较高。缺点是不可以将处理结果传递给下一个接收者,并且无法终止Broadcast Intent的传播有序广播
Ordered Broadcast的接收者将按预先声明的优先级依次接收Broadcast。优先级声明在<intent-filter.../>
元素的android:priority
属性中,数值越大优先级别越高,在java代码中使用IntentFilter对象的setPriority()
设置优先级别。Ordered Broadcast接收者可以终止Broadcast Intent的传播,Broadcast Intent的传播一旦终止,后面的接收者就无法接收到Broadcast。在onReceiver(...)
方法中通过abortBroadcast()
方法来取消Broadcast的继续传播。
发送广播的两种方法
sendBroadcast()
发送 Normal BroadcastsendOrderedBroadcast()
发送 Ordered Broadcast
通过代码Bundle bundle = getResultExtras(true)
可以获取上一个接收者存入的数据。
-
提示
系统收到短信,发出的Broadcast属于Ordered Broadcast。如果想阻止用户收到短信,可以通过设置优先级,让自定义的BroadcastReceiver先获取到Broadcast,然后终止Broadcast。
Service
生命周期
- 以
startService
方式启动服务,client的生命周期与service没有任何关联,在client中通过stopService()
或在service内部通过stopSelf()
方式来停止此服务,生命周期图如下所示:
- 以
bindService
方式启动服务,使用此方式将client和service建立绑定关系,当client销毁后,service也将被销毁,通过在client中调用unbindService()
方式来解除client与service之间的绑定关系,而Client与Service之间的通信主要通过Binder对象来实现,在Service内部的onBind()
方法中返回此Binder对象,生命周期图如下所示:
注意
有一种特殊的情况,就是当同时以startService()
、bindService()
两种方式开启服务时,在销毁此服务的时候需要同时调用stopService()
和unbindService()
方法来停止服务。
onStartCommand返回值
-
START_STICKY
如果service进程被kill掉,保留service的状态为开始状态,但不保留递送的intent对象。随后系统会尝试重新创建service,由 于服务状态为开始状态,所以创建服务后一定会调用onStartCommand(Intent,int,int)方法。如果在此期间没有任何启动命令被传 递到service,那么参数Intent将为null; -
START_NOT_STICKY
“非粘性的”。使用这个返回值时,如果在执行完onStartCommand后,服务被异常kill掉,系统不会自动重启该服务; -
START_REDELIVER_INTENT
重传Intent。使用这个返回值时,如果在执行完onStartCommand后,服务被异常kill掉,系统会自动重启该服务,并将Intent的值传入; -
START_STICKY_COMPATIBILITY
START_STICKY的兼容版本,但不保证服务被kill后一定能重启。
如何保证Service不被杀死
Service 设置成 START_STICKY
service被杀死后会重启(等待5秒钟左右),重传intent,保证与重启前一样
提升Service优先级
- 在AndroidManifest.xml文件中对于intent-filter可以通过android:priority = "1000"这个属性设置最高优先级,1000是最高值,如果数字越小则优先级越低,同时适用于广播。(目前好像这个属性只对broadcast有效,对于service可能无效)
提升Service进程优先级
- Android中的进程是托管的,当系统进程空间紧张的时候,会依照优先级自动进行进程的回收
- 当service运行在低内存的环境时,将会kill掉一些存在的进程。因此进程的优先级将会很重要,可以在startForeground()使用startForeground()将service放到前台状态。这样在低内存时被kill的几率会低一些。
- 【注意】在极低内存的压力下,service还是会被kill掉的,并且不一定会重启
onDestory方法里重启service
- service +broadcast 方式,就是当service走onDestory()的时候,发送一个自定义的广播,当收到广播的时候,重新启动service
- 也可以直接在onDestroy()里startService
- 当使用类似口口管家等第三方应用或是在setting里-应用-强制停止时,APP进程可能就直接被干掉了,onDestroy方法都进不来,所以还是无法保证