【Android四大组件】必知必会知识点

Activity


Activity 页面单元 负责页面的显示与交互


生命周期1
生命周期2

1.生命周期

onCreate()
Activity初始化操作:设置布局,初始化视图,绑定事件等。方法中有一个bundle参数用于恢复activity意外销毁时保存的数据,bundle不为空,取数据。
onStart()
这个方法在活动由不可见变为可见的时候调用。
onResume()
Activity变为可见 执行完onResume()之后, Activity就会请求AMS渲染它所管理的视图。此时的Activity位于返回栈的栈顶,并且处于运行状态。这个方法在活动获得焦点,准备好和用户进行交互的时候调用。
onPause()
在另一个活动来到前台时调用,部分可见。在这个函数中将一些消耗cpu的资源释放掉,保存一些关键数据。
返回上一个活动经历:onPause()-->onResume()
onStop()
Activity完全不可见时调用。
返回上一个活动经历:onStop()-->onRestart()-->onStart()
onDestory()
销毁时得到调用,释放内存。
onRestart()
在停止状态(onstop)返回上一个活动,变成运行状态(onstart)之前调用。
在 onCreate()方法和 onDestroy() 方法之间所经历的,就是完整生存期。
活动在 onStart() 方法和 onStop() 方法之间所经历的,就是可见生存期。在可见生存期内, 活动对于用户总是可见的, 即便有可能无法和用户进行交互。 我们可以通过这两个方法,合理地管理那些对用户可见的资源。比如在 onStart() 方法中对资源进行加载,而在 onStop() 方法中对资源进行释放, 从而保证处于停止状态的活动不会占用过多内存。
在 onResume() 方法和 onPause() 方法之间所经历的,就是前台生存期。在前台生存期内, 活动总是处于运行状态的, 此时的活动是可以和用户进行相互的, 我们平时看到和接触最多的也这个状态下的活动。

典型生命周期总结

当经历onPause和onStop时,如果遇到更高优先级的程序需要内存,将需要杀掉进程,重新返回到onCreate()。
点击back键经历的生命周期:onPause()-->onStop()-->onDestory ()
点击back键再返回应用经历的生命周期:(因为活动已经销毁,需要重新创建)onCreate -->onStart-->....
点击home键经历的生命周期:onPause()-->onStop()
点击home键后再返回应用的生命周期:onRestart()-->onStart()....
关于使用dialog的生命周期
把Activity的Theme设置成Dialog【android:theme="@android:style/Theme.Dialog"】,这样Activity显示成Dialog,本质还是Activity。拥有Activity的生命周期函数和特性 。但调转词activity的效果是和dialog一样的,此时在Activity A中启动这样的Dialog B,这时Activity A会运行onPause,退出Dialog B时,Activity A会运行onResume。
一个对话框来到前台:onPause()
但是还有一种,是使用Dialog,而不是具有Dialog属性的Activity,这时,在Activity A中启动Dialog B,如在onCreate中启动,肯定是会接着运行onStart,onResume等的,但是是不会运行onPause的。退出Dialog B,Activity A不会运行周期函数,也就是不会走onResume()。
A页面-B页面跳转 若B覆盖A: onPause(A)-onCreate(B)-onStart(B)-onResume(B)-onStop(A)
此时B页面按back键返回 :onPause(B)-onRestart(A)-onStart(A)-onResume(A)-onStop(B)-onDestory(B)
A页面-B页面跳转 若B透明,没有覆盖A:onPause(A)-onCreate(B)-onStart(B)-onResume(B)
横竖屏切换:不设置Activity的android:configChanges时,切屏会重新调用各个生命周期,切横屏时会执行一次,切竖屏时会执行两次。
Activity退出生命周期:
结束一个活动:Activity---finish –>onpause onstop ondestory
结束进程:android.os.Process.killProcess(android.os.Process.myPid());System.exit(int code) 这两个方法,会使activity非正常退出,不会去执行onpause onstop ondestory

2.InstanceState

InstanceState用来保存和恢复数据功能,主要时onSaveInstanceState() 和 onRestoreInstanceState() 。关于这两个方法,在应用程序在不知道的情况下退出后,可以实现其数据保存的功能。Activity的 onSaveInstanceState() 和 onRestoreInstanceState()并不是生命周期方法,它们不同于 onCreate()、onPause()等生命周期方法,它们并不一定会被触发。
当应用遇到意外情况(如:内存不足、用户直接按Home键、横竖屏切换 即当某个activity变得"容易"被系统销毁时)由系统销毁一个Activity时,onSaveInstanceState() 会被调用。但是当用户主动去销毁一个Activity时,例如在应用中按返回键,手动调用finish() 等,onSaveInstanceState()就不会被调用。因为在这种情况下,用户的行为决定了不需要保存Activity的状态。通常onSaveInstanceState()只适合用于保存一些临时性的状态,而onPause()适合用于数据的持久化保存。

划重点:onSavedInstanceState中保存的是瞬时数据。onpause中保存的时持久化数据。

onSaveInstanceState() 的调用更多时是在onPause()方法之前,有时也在onStop()方法之前。这个方法在一个activity被杀死前调用(onSaveInstanceState将需要保存的状态封装在Bundle中:调用View的onSaveInstanceState (),返回Parcelable对象,接着用Bundle的putParcelable方法保存在Bundle savedInstanceState中。)当该activity在将来某个时刻回来时可以在onCreate(Bundle)或者onRestoreInstanceState(Bundle)恢复其先前状态。 (当系统调用Activity的的onRestoreInstanceState(Bundle savedInstanceState)时, 同过Bundle的getParcelable方法得到Parcelable对象,然后把该Parcelable对象传给View的onRestoreInstanceState (Parcelable state)。在的View的onRestoreInstanceState中从Parcelable读取保存的数据以便View使用。)
onRestoreInstanceState()在onStart() 和 onPostCreate(Bundle)之间调用。他和onSaveInstanceState()不一定是成对使用的,例如,当正在显示activity A的时候,用户按下HOME键回到主界面,然后用户紧接着又返回到activity A,这种情况下activity A一般不会因为内存的原因被系统销毁,故activity A的onRestoreInstanceState方法不会被执行 。

3.Activity的构成

需要了解在Activity和xml之间隔着 Window和 DecorView ,一张图示了解他们的层级关系。


层级关系

4.Activity的启动模式

developer--model
在AndroidManifest.xml中在注册activity时设置它的启动模式 android:launchMode="standard"
android内部使用通过回退栈来管理activity实例。栈是一种后进先出的集合。activity的四种启动模式为:standard,singleTop,singleTask,singleInstance.

1.standard:标准启动模式,是activity默认的启动模式,这个模式下的activity可以被多次实例化。

2.singleTop:单一栈顶模式,如果以singleTop模式启动的Activity 的实例已经存在于任务栈的栈顶,那么再启动这个Activity时,将使用栈顶实例,不会重新创建。但若在任务栈中,却不在栈顶,那么还是会重新创建新的实例。

3.singleTask:单一任务栈模式,(即在一个任务栈中只能有一个该activity 的实例),没有会重新创建,如果已经存在activity,系统则会销毁处在该activity上的所有activity,最终让activity处于栈顶,同时回调该activity的onNewIntent()函数。

即在同一个进程中,若启动一个singletask模式的activity,看当前进程的任务栈中是否存在该activity 如果不存在,创建activtiy 如果存在,将该activity上面的其他activtiy销毁,并回调该activity的onnewintent。

4.singleInstance:单一实例模式,(即保证activity系统只有一个实例),设置该模式的实例,会在一个独立的任务栈中开启,并且这个新的任务栈中有且只有这一个实例,不会要其他的activtiy和它共存在同一个任务栈中,如果这个实例想再去启动activityc,activityc就会到其他或创建新的任务栈中去。

singleTask和singleInstance:

相同点:

两者相同的是,它们只能启动任务。 它们始终位于 Activity 堆栈的根位置。一个任务栈中只能有一个该activity的实例。

不同点:

“singleTask”Activity 允许其他 Activity 成为其任务的组成部分。 它始终位于其任务的根位置,但其他 Activity(必然是“standard”和“singleTop”Activity)可以启动到该任务中。 相反,“singleInstance”Activity 则不允许其他 Activity 成为其任务的组成部分。它是任务中唯一的 Activity。 如果它启动另一个 Activity,系统会将该 Activity 分配给其他任务 — 就好像 Intent 中包含 FLAG_ACTIVITY_NEW_TASK 一样。
FLAG_ACTIVITY_NEW_TASK
当Intent对象包含这个标记时,系统会寻找或创建一个新的task来放置目标Activity,寻找时依据目标Activity的taskAffinity属性进行匹配,如果找到一个task的taskAffinity与之相同,就将目标Activity压入此task中,如果查找无果,则创建一个新的task,并将该task的taskAffinity设置为目标Activity的taskActivity,将目标Activity放置于此task。注意,如果同一个应用中Activity的taskAffinity都使用默认值或都设置相同值时,应用内的Activity之间的跳转使用这个标记是没有意义的,因为当前应用task就是目标Activity最好的宿主。

启动模式和生命周期

Service


Service 负责与UI无关的工作 【后台】执行的操作
Android的后台就是指,它的运行是完全不依赖UI的。即使Activity被销毁,或者程序被关闭,只要进程还在,Service就可以继续运行。

1.开启 Service

方式一:startService()
注意生命周期:当通过startService() 启动一个Service的时候,会调用该Service中的onCreate()和onStartCommand()方法。当再次调用startService(),这次只有onStartCommand()方法执行了,onCreate()方法并没有执行。因为onCreate()只会在创建时执行一次。不管创建多少次,调用一次stopService()或stopSelf() 将会停止服务。
方式二:bindService()
bindService()相比startService()多了与Activity之间的关系,绑定了Activity。调用这个方法会使Service中的onCreate()方法得到执行,但onStartCommand()方法不会执行。此时如果想解除Activity和Service之间的关联,调用一下unbindService()方法就可以了。

如果我们既调用了startService()又调用了bindService(),此时单独执行stopService()或unbindService()都不能使服务停止,必要将两个方法都执行,Service才会被销毁。也就是说,调用stopService()只会让Service停止,调用unbindService()只会让Service和Activity解除关联,【一个Service必须要在既没有和任何Activity关联又处理停止状态的时候才会被销毁。】

2.生命周期

对于startService() 方式启动Service:创建服务onCreate() 开始服务onStartCommand() 销毁服务onDestory() 【一个服务会被创建一次,销毁一次,但是会开始多次。】
对于bindService()方式启动Service:onCreate() onBind() onUnbind() onDestory()【采用bind方式 和activity绑定,一但销毁activity,与之绑定的service也就相应结束。“不求同时生,必须同时死”】

只使用startService启动服务的生命周期:


image.png

只使用BindService绑定服务的生命周期:


image.png

同时使用startService()启动服务、BindService()绑定服务的生命周期:
image.png

3.切记混淆服务与线程,要注意的是服务执行在UI 线程中,所以不要在Service中执行【耗时操作】,除非在Service中创建了子线程来完成耗时操作。这些耗时逻辑,需要在service中创建子线程。既然在Service里也要创建一个子线程,那为什么不直接在Activity里创建呢?这是因为Activity很难对Thread进行控制,当Activity被销毁之后,就没有任何其它的办法可以再重新获取到之前创建的子线程的实例。而且在一个Activity中创建的子线程,另一个Activity无法对其进行操作。但是Service就不同了,所有的Activity都可以与Service进行关联,然后可以很方便地操作其中的方法,即使Activity被销毁了,之后只要重新与Service建立关联,就又能够获取到原有的Service中Binder的实例。因此,使用Service来处理后台任务,Activity就可以放心地finish,完全不需要担心无法对后台任务进行控制的情况。

4.IntentService : 将用户的请求执行在一个子线程中,用户只需要复写onHandleIntent函数,并且在函数中完成自己的耗时操作即可。需要注意的是,在任务执行完毕之后IntentService会调用stopSelf自我销毁。所以它适用于完成一些短期的耗时任务。

5.Service默认是运行在后台,但在后台优先级比较低,当系统内存不足时,很有可能被回收。如果希望Service可以一直保持运行状态,可以将 Service运行在前台。前台Service和普通Service最大的区别就在于,它会一直有一个正在运行的图标在系统的状态栏显示,下拉状态栏后可以看到更加详细的信息,非常类似于通知的效果。

6.AIDL

如果当前Activity要与另一个进程的服务建立连接,这就要使用AIDL来进行跨进程通信(IPC)了。
AIDL接口描述语言,通常用于进程间通信。它可以用于让某个Service与多个应用程序组件之间进行跨进程通信,从而可以实现多个应用程序共享同一个Service的功能。查阅资料了解AIDL的使用和原理。推荐文章1&&推荐文章2

Broadcast


Broadcast 组件间、应用间通信
android中的广播就像我们平时说的电台广播,一个广播可以有多个接受者,广播机制是一个典型的发布-订阅模式(观察者模式)。广播机制最大的特点就是发送方并不关心接受方是否接受或是如何处理数据的,这样接收双方完全解耦合。

广播机制主要包含三个要素,发送广播的BroadCast 、接收广播的BroadCastReceiver、用于传递信息的Intent。

1.注册方式:

静态注册 AndroidManifast.xml中,只要app在运行就一直能接收到广播。
动态注册 在activity或service中注册,它们若被销毁,广播也就接受不到了。

2.生命周期:onReceive()

生命周期只有十秒左右,如果在 onReceive() 内做超过十秒内的事情,就会报ANR 程序无响应的错误信息。
如果需要完成一项比较耗时的工作 , 应该通过发送 Intent 给 Service, 由Service 来完成。
不要在广播接受者中创建子线程,因为它的生命周期非常短,子线程可能还没有结束BroadcastReceiver 就先结束了,子线程相应也就结束了。

3.类型:Android广播主要分为普通广播、有序广播、本地广播、 Sticky广播。

普通广播:

sendBroadcast(Intent intent)发送广播
优点:效率高
缺点:一个接受者不能将处理结果传递给下一个接受者,并且无法终止广播的传播。完全异步,接收器的执行顺序不确定。

有序广播:

sendOrderedBroadcast(intent, receiverPermission)
缺点:效率低
优点:按优先级别由高到低依次传播,高级别的或同级别先接收到广播的可以通过abortBroadcast()方法截断广播使其他的接收者无法收到该广播。也可以通过setResultExtras(bundle)方法将处理结果存入bundle中,下一个接受可以通过getResultExtra(true) 方法获取上一个接受者传来的bundle数据。

本地广播:

LocalBroadcastManager 普通广播和有序广播都是全局广播,所有应用程序都可以接收到,这样就会带来安全隐患。但是有的时候我们并不需要把自己的应用内的信息广播给所有应用,而只是在进程内使用。所以使用本地广播就能实现限于应用内的广播。本地广播和普通广播只是操作的类不一样,其他接口都类似,只需把从前的registerReceiver()变成LocalBroadcastManager.getInstance(context).registerReceiver()。替换成本比较低,为了程序的安全性,建议在不需要其他进程接收广播的情况下使用本地广播。

Sticky广播:

sendStickyBroadcast 用此函数发送的广播会一直滞留,当有匹配此广播的广播接收器被注册后,该广播接收器就会收到此条广播。(记得在AndroidManifest 里注册BROADCAST_STICKY权限)。sendStickyBroadcast只保留最后一条广播,并且一直保留下去,这样即使已经有广播接收器处理了该广播,当再有匹配的广播接收器被注册时,次广播仍然会被接收。如果你只想处理一遍该广播,可以通过removeStickyBroadcast()函数实现。

ContentProvider


ContentProvider 应用间数据共享 使用其对外共享数据的好处是统一了数据的访问方式,实际上是对SQliteOpenHelper 的进一步封装,通过Uri地址映射来判断选择需要操作数据库中的哪个表,并且进行增删改查处理。

Content Provider 内容提供者,用于对外提供数据
Content Resolver 内容解析者,用户获取提供者提供的数据(外部应用通过resolver来访问provider)
Content Observer 内容监听器,可以监听数据的改变状态
使用Content Provider对外共享数据的步骤:
定义一个类继承Content Provider,然后重写query、insert、delete、update方法等
参考文章

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,425评论 4 361
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,058评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,186评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,848评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,249评论 3 286
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,554评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,830评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,536评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,239评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,505评论 2 244
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,004评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,346评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,999评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,060评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,821评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,574评论 2 271
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,480评论 2 267