以前一直都是为了面试将四大组件的内容背了下来,其实到项目开发中除了activity,其他的都很少用到它们,即使用到了也只是问度娘copy一下!现在突然意识到自己还不是很理解,感觉以后不能再这样似懂非懂的了,所以今天开始就记录一下自己对四大组件深入学习之路,整理了好多大神的知识讲解!!!后续还会补充,还在持续深入学习中…
Activity需要在AndroidManifest.xml文件下的application标签中配置:
<activity android:name=".Activity "> </activity>默认启用activity:
<intent-filter> <action android:name="android.intent.action.MAIN"/> <category android:name="android.intent.category.LAUNCHER"/> </intent-filter>Activity的生命周期:
onCrete(Bundle savedInstanceState) : 当Activity被首次加载时执行,在不被销毁的情况下只执行一次。其中方法体中的参数就是我们调用onSaveInstanceState(Bundle outState)时存储的临时数据。onStart() : activity变为在屏幕上对用户可见时调用。onResume(): activity开始与用户交互时调用(无论是启动还是重新启动一个活动,该方法总是被调用的)。onPause() : activity被暂停或收回cpu和其他资源时调用,该方法用于保存活动状态。onStop() : activity被停止并转为不可见阶段及后续的生命周期事件时调用。onRestart() : 重新启动activity时调用。该活动仍在栈中,而不是启动新的活动。onDestroy() : activity被完全从系统内存中移除时调用,销毁Activity,释放资源。**A(Activity)、B(Activity)**onPause(A)代表A的onPause()方法
当刚进入activity界面时:onCreate()–>onStart()–>onResume()退出activity界面时:onPause()–>onStop()–>onDestroy()当activity界面由横竖屏切换时:onPause()–>onSaveInstanceState()–>onStop()–>onDestroy()–>onCreate()–>onStart()–>onRestoreInstanceState()–>onResume()当从A界面进入B界面时:onPause(A)–>onCreate(B)–>onStart(B)–>onResume(B)–>onSaveInstanceState(A)–>onStop(A)当从B界面返回A界面时:onPause(B)–>onRestart(A)–>onStart(A)–>onResume(A)–>onStop(B)–>onDestroy(B)**小提示:**onSaveInstanceState()每次都会执行,这里只可以保存临时数据,如果是持久化数据则可以使用缓存方式。而onRestoreInstanceState()只有当界面被系统强制杀死(比如内存不足时被后台杀死时、横竖屏切换时等等)才会执行,可以在这里获取onSaveInstanceState()方法储存的临时数据。
Activity的Intent请求意图的方式:
Intent显示:明确指出了目标组件名称,即你要跳转的目标activity。
Intent intent=new Intent( this , A.class ); startActivity(intent);Intent隐示:在使用Intent进行跳转时,没有明确指定跳转的Activity或者Service.通过Intent-Filter(Intent过滤器)进行匹配过滤,会跳转到符合匹配条件的Activity或者Service。如果有多个同时匹配,会弹出对话框,供用户来选择激活哪个组件,如调用手机浏览器。
清单文件AndroidManifest.xml的Activity声明中添加Intent-filter:
<intent-filter> <action android:name="...."/> <category android:name="...."/> <category android:name="android.intent.category.DEFAULT"/> <data android:scheme="..." android:host="..." android:path="/..." android:type="..."/> </intent-filter>activity中intent跳转代码:
Intent intent = new Intent(); intent.setAction("...."); intent.addCategory("...."); intent.setData(Uri.parse("....")); //设置data的scheme、host、path、type条件 intent.setDataAndType(Uri.parse(""),String type); startActivity(intent);注意:如果在Intent-filter中的data中多了一个Android:mimeType=”text/*”,此时在跳转的地方不能使用intent.setData,而要使用intent.setDataAndType();
各个属性详解请参考大神: (http://blog.csdn.net/weihan1314/article/details/7973511)
action 动作
一条元素至少应该包含一个,否则任何Intent请求都不能和该匹配。 如果Intent请求的Action和中个某一条匹配,那么该Intent就通过了这条的动作测试。 如果Intent请求或中没有说明具体的Action类型,那么会出现下面两种情况。 (1) 如果中没有包含任何Action类型,那么无论什么Intent请求都无法和这条匹配; (2) 反之,如果Intent请求中没有设定Action类型,那么只要中包含有Action类型,这个Intent请求就将顺利地通过的行为测试。
category 类别
只有当Intent请求中所有的Category与组件中某一个Intent-filter的完全匹配时,才会让该Intent请求通过测试,Intent-filter中多余的声明并不会导致匹配失败。即只要intent-filter中德category包含intent请求时设置的category即可。 ———————————–android.intent.category.DEFAULT的作用—————————- 每一个通过 startActivity()方法发出的隐式 Intent 都至少有一个 category,就是 “android.intent.category.DEFAULT”,所以只要是想接收一个隐式Intent 的 Activity 都应该包括 “android.intent.category.DEFAULT” category,不然将导致 Intent匹配失败。
Data
Data通常是URI格式定义的操作数据。例如:tel:// 。通过setData()方法设置。
Extras
Extras属性主要用于传递目标组件所需要的额外的数据。通过putExtras()方法设置。
Activity的加载方式:
Activity栈(Task是一个后进先出LIFO,包含所有正在运行Activity的队列)
Android中与Task相关的属性有如下几种:
taskAffinitylaunchModeallowTaskReparentingalwaysRetainTaskStateclearTaskOnLaunchfinishOnTaskLaunchnoHistory加载模式在AndroidManifest.xml中注册的< activity>标签中设置: android:launchMode=”“
<activity android:name=".Activity" android:launchMode="standard"> </activity> 加载模式作用standard标准模式,一调用startActivity()方法就会产生一个新的实例。系统默认使用这种加载模式。singleTop如果已经有一个实例位于Activity栈的顶部时,就不产生新的实例,而只是调用Activity中的newInstance()方法。如果不位于栈顶,会产生一个新的实例。singleTask会在一个新的task中产生这个实例,以后每次调用都会使用这个,不会去产生新的实例了。singleInstance这个跟singleTask基本上是一样,只有一个区别:在这个模式下的Activity实例所处的task中,只能有这个activity实例,不能有其他的实例。**代码中影响加载模式的设置:**intent.setFlags();
Intent intent=new Intent(this,A.class); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); startActivity(intent);参考了大神的,你们看一下大神的博客:http://blog.csdn.net/javazejian/article/details/52709857
Service 是一段长生命周期的,没有用户界面的程序,可以用来开发如监控类程序。
Service需要在AndroidManifest.xml清单文件下的application标签中配置:详细请参考大神:http://blog.csdn.net/think_soft/article/details/7584895
<service android:enabled=["true" | "false"] //这个属性用于指示该服务是否能够被实例化。如果设置为true,则能够被实例化,否则不能被实例化。默认值是true。如果有一个元素的enabled属性被设置为false,该服务就会被禁用,而不能被实例化。 android:exported=["true" | "false"] //这个属性用于指示该服务是否能够被其他应用程序组件调用或跟它交互。如果设置为true,则能够被调用或交互,否则不能。设置为false时,只有同一个应用程序的组件或带有相同用户ID的应用程序才能启动或绑定该服务。 android:icon="drawable resource" //这个属性定义了一个代表服务的图标,它必须要引用一个包含图片定义的可绘制资源。如果这个属性没有设置,则会使用<application>元素的icon属性所设定的图标来代替。 android:isolatedProcess=["true" | "false"] //如果设置为true,这个服务将运行在专门的进程中,这个进程从系统的剩余部分独立出来,它自身没有权限。同它唯一的通信方式就是通过这个Service API(binding或starting)。 android:label="string resource" //这个属性用于设定一个要显示给用户的服务的名称。如果没有设置这个属性,则会使用<application>元素的label属性值来代替。 android:name="string" //这个属性用于指定实现该服务的Service子类的类名。一旦发布了应用程序,就不应该改变这个名称(除非android:exported=”false”)。这个属性没有默认值,名称必须要指定。 android:permission="string" //这个属性定义了要启动或绑定服务的实体必须要有的权限。如果这个属性没被设置,那么通过<appliction>元素的permission属性所设定的权限就会适用于该服务。如果<application>元素也没有设置权限,则该服务不受权限保护。 android:process="string" > //这个属性用于设定服务所运行的进程名称。通常,应用程序的所有组件都运行在给应用程序创建的进程中,进程名与应用程序的包名相同。 . . . </service>按照启动方式分类:
开启服务 startService():Service会一直在后台运行,在Service可以调用Context.startService()启动,调用Context.stopService()结束。在内部可以调用Service.stopSelf() 或 Service.stopSelfResult()来自己停止。无论调用了多少次startService(),都只需调用一次stopService()来停止。
绑定服务 bindService():调用Context.bindService()方法建立连接,并启动,以调用 Context.unbindService()关闭连接。多个客户端可以绑定至同一个服务。当服务所有绑定都解除时,服务会被销毁。
按服务性质分类:
本地服务: Local Service 用于应用程序内部,服务和启动服务的activity在同一个进程中。在Service可以调用Context.startService()启动,调用Context.stopService()结束,服务结束时会调用onDestroy()方法。在内部可以调用Service.stopSelf() 或Service.stopSelfResult()来自己停止。无论调用了多少次startService(),都只需调用一次stopService()来停止。
远程服务: Remote Service 用于android系统内部的应用程序之间,服务和启动服务的activity不在同一个进程中。可以定义接口并把接口暴露出来,以便其他应用进行操作。客户端建立到服务对象的连接,并通过那个连接来调用服务。调用Context.bindService()方法建立连接,并启动,以调用 Context.unbindService()关闭连接。多个客户端可以绑定至同一个服务。如果服务此时还没有加载,bindService()会先加载它。
Service的生命周期:
startService() –> onCreate()–> onStartCommand()–Service running–调用stopService() –> onDestroy()bindService()–>onCreate()–> onBind()–Service running–调用onUnbind() –> onDestroy()注意: - 如果service是被开启的(startService()),那么它的活动生命周期和整个应用生命周期一同结束。除非你主动关闭它。 - 如果service是被绑定的(bindService()),它们它的活动生命周期是在onUnbind()方法返回后结束。 - 尽管一个被开启的service是通过调用 stopSelf() 或 stopService()来停止的,没有一个对应的回调函数与之对应,即没有onStop()回调方法。所以,当调用了停止的方法,除非这个service和客户组件绑定,否则系统将会直接销毁它,onDestory()方法会被调用,并且是这个时候唯一会被调用的回调方法。
小点:
API level 2.0之后,onStart()方法被onStartCommand()取代了
@Override public int onStartCommand(Intent intent, int flags, int startId){ return super.onStartCommand(intent, flags, startId); }参数:
intent:startService(Intent)中的intent;flags(启动服务的方式):Additional data about this start request. Currently either 0, START_FLAG_REDELIVERY, or START_FLAG_RETRY; START_FLAG_REDELIVERY:如果你实现onStartCommand()来安排异步工作或者在另一个线程中工作, 那么你可能需要使用它来让系统重新发送一个intent。这样如果你的服务在处理它的时候被Kill掉, Intent不会丢失。 START_FLAG_RETRY:表示服务之前被设为START_STICKY,则会被传入这个标记。startId:是对这个service请求的activity或者其他实体的编号,与stopSelfResult (int startId)配合使用,stopSelfResult 可以更安全地根据ID停止服务。该方法的四个返回值:
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后一定能重启。**提醒:**Android 5.0以后,服务在主程序退出时的自启动无效了,fork()组杀,当你的程序主进程被杀掉时,整个组都会被杀掉。我因为要写一个提醒程序APP,测试了一些双服务互相唤醒,广播唤醒服务的方法使服务一直挂在后台,但都失败了,都不能让实现APP退出后,服务一直运行在后台这种功能需要。查询了一些大神的,但我根本没到那么高的程度,完全看不懂! 如果你的service被开启并且接受绑定,那么当系统调用你的 onUnbind()方法时,如果你想要在下次客户端绑定的时候接受一个onRebind()的调用(而不是调用 onBind()),你可以选择在onUnbind()中返回true。
@Override public boolean onUnbind(Intent intent) { return super.onUnbind(intent); }这种service(被开启,还允许绑定)的生命周期如图所示:
开启服务与关闭服务(注意不要忘记在清单文件配置Service):
import android.app.Service; import android.content.Intent; import android.support.annotation.Nullable; import android.util.Log; public class ServiceTest extends Service{ /** * 如果服务已在运行,则不会调用此方法。该方法只被调用一次 */ @Override public void onCreate() { super.onCreate(); Log.i("ServiceText","onCreate()"); } /** * 每次通过startService()方法启动Service时都会被回调。 * @param intent * @param flags * @param startId * @return */ @Override public int onStartCommand(Intent intent, int flags, int startId) { Log.i("ServiceText","onStartCommand()"); return START_NOT_STICKY; } /** * 绑定服务时才会调用。多次绑定中也只有第一次时才调用onBind() * 必须要实现的方法 * @param intent * @return */ @Nullable @Override public IBinder onBind(Intent intent) { Log.i("ServiceText","onBind()"); return null; } /** * 服务销毁时的回调 */ @Override public void onDestroy() { super.onDestroy(); Log.i("ServiceText","onDestroy()"); } } Intent intent=new Intent(this, ServiceTest.class); //开启服务 startService(intent); //关闭服务 stopService(intent);绑定服务与解绑服务:
import android.app.Service; import android.content.Intent; import android.os.Binder; import android.os.IBinder; import android.support.annotation.Nullable; import android.util.Log; public class ServiceTest extends Service{ //通过binder实现调用者client与Service之间的通信 private MyIBinder binder=new MyIBinder(); public class MyIBinder extends Binder{ public ServiceTest getService(){ return ServiceTest.this; } } /** * 如果服务已在运行,则不会调用此方法。该方法只被调用一次 */ @Override public void onCreate() { super.onCreate(); Log.i("ServiceText","onCreate()"); } /** * 绑定服务时才会调用。多次绑定中也只有第一次时才调用onBind() * 必须要实现的方法 * @param intent * @return */ @Nullable @Override public IBinder onBind(Intent intent) { Log.i("ServiceText","onBind()"); return binder; } /** * 解除绑定 * @param intent * @return true,下次重新绑定的时候执行onRebind; false,下次重新绑定的时候执行onBind. */ @Override public boolean onUnbind(Intent intent) { Log.i("ServiceText","onUnbind()"); return false; } /** * 重新绑定 * @param intent */ @Override public void onRebind(Intent intent) { Log.i("ServiceText","onRebind()"); super.onRebind(intent); } /** * 服务销毁时的回调 */ @Override public void onDestroy() { super.onDestroy(); Log.i("ServiceText","onDestroy()"); } } /** * ServiceConnection代表与服务的连接,它只有两个方法, * onServiceConnected和onServiceDisconnected, * 前者是在操作者在连接一个服务成功时被调用,而后者是在服务崩溃或被杀死导致的连接中断时被调用 */ private ServiceConnection conn; private ServiceTest mService; Intent intent=new Intent(this, ServiceTest.class); conn = new ServiceConnection() { /** * 与服务器端交互的接口方法 绑定服务的时候被回调,在这个方法获取绑定Service传递过来的IBinder对象, * 通过这个IBinder对象,实现宿主和Service的交互。 */ @Override public void onServiceConnected(ComponentName name, IBinder service) { Log.d("ServiceTest", "绑定成功调用:onServiceConnected"); // 获取Binder ServiceTest.MyIBinder binder = (ServiceTest.MyIBinder) service; mService = binder.getService(); } /** * 当取消绑定的时候被回调。但正常情况下是不被调用的,它的调用时机是当Service服务被意外销毁时, * 例如内存的资源不足时这个方法才被自动调用。当客户端取消绑定时,系统“绝对不会”调用该方法。 */ @Override public void onServiceDisconnected(ComponentName name) { mService=null; } }; /** * 绑定服务 * @param intent 是一个明确指定了要绑定的service的Intent. * @param ServiceConnection ServiceConnection对象. * @param flags 是一个标志,它表明绑定中的操作.它一般应是BIND_AUTO_CREATE,这样就会在service不存在时自动创建一个。 * 其它可选的值是BIND_DEBUG_UNBIND和BIND_NOT_FOREGROUND,不想指定时设为0即可(不自动创建)。 */ bindService(intent, conn, Service.BIND_AUTO_CREATE); //解除绑定 if(mService!=null) { mService = null; unbindService(conn); }小点: IBinder接口的实现类,该类用以提供客户端用来与服务进行交互的编程接口,该接口可以通过三种方法定义接口:扩展 Binder 类、Messenger、AIDL(大神博客地址:http://blog.csdn.net/javazejian/article/details/52709857)
对外部事件进行过滤,只对感兴趣的外部事件(如当电话呼入时,或者数据网络可用时)进行接收并做出响应。广播接收器没有用户界面。然而,它们可以启动一个activity或serice来响应它们收到的信息,或者用NotificationManager来通知用户。
静态注册: 在AndroidManifest.xml文件中进行注册
<receiver android:enabled=["true" | "false"] //这个属性用于指示该服务是否能够被实例化。如果设置为true,则能够被实例化,否则不能被实例化。默认值是true。如果有一个元素的enabled属性被设置为false,该广播就会被禁用,而不能被实例化。 android:exported=["true" | "false"] //此broadcastReceiver能否接收其他App的发出的广播,这个属性默认值有点意思,其默认值是由receiver中有无intent-filter决定的,如果有intent-filter,默认值为true,否则为false。(同样的,activity/service中的此属性默认值一样遵循此规则) android:icon="drawable resource" //这个属性定义了一个代表广播的图标,它必须要引用一个包含图片定义的可绘制资源。如果这个属性没有设置,则会使用<application>元素的icon属性所设定的图标来代替。 android:label="string resource" //这个属性用于设定一个要显示给用户的广播的名称。如果没有设置这个属性,则会使用<application>元素的label属性值来代替。 android:name="string" //此broadcastReceiver类名 android:permission="string" //如果设置,具有相应权限的广播发送方发送的广播才能被此broadcastReceiver所接收 android:process="string" > //broadcastReceiver运行所处的进程。默认为app的进程。可以指定独立的进程 . . . </receiver>注册事例:
<receiver android:name=".MyBroadcastReceiver" > <intent-filter> <action android:name="android.net.conn.CONNECTIVITY_CHANGE" /> //网络状态改变所发出的广播 </intent-filter> <intent-filter> <action android:name="android.intent.action.BOOT_COMPLETED" /> //开始启动时系统自身所发出的广播 </intent-filter> </receiver>动态注册: 动态注册时,无须在AndroidManifest中注册组件。直接在代码中通过调用Context的registerReceiver函数,可以在程序中动态注册BroadcastReceiver。
Context.registerReceiver(BroadcastReceiver receiver, IntentFilter filter); Context.registerReceiver(BroadcastReceiver receiver, IntentFilter filter, String broadcastPermission, Handler scheduler);
调用事例:
private MyBroadcastReceiver mBroadcastReceiver; mBroadcastReceiver = new MyBroadcastReceiver(); IntentFilter intentFilter = new IntentFilter(); intentFilter.addAction(ACTION); //动态注册广播 registerReceiver(mBroadcastReceiver, intentFilter); //onDestroy时关闭广播 unregisterReceiver(mBroadcastReceiver);参考来自:http://www.jianshu.com/p/ca3d87a4cdf3
Normal Broadcast:普通广播 开发者自身定义intent的广播
Intent intent = new Intent(); //ACTION 为清单文件中过滤器intentFilter的action值 intent.setAction(ACTION); //发送普通广播 sendBroadcast(intent); //AndroidManifest中注册<receiver/>组件 //此广播接收者类是MyBroadcastReceiver <receiver android:name=".MyBroadcastReceiver" > <intent-filter> <action android:name="ACTION" /> </intent-filter> </receiver>System Broadcast: 系统广播
系统操作Action监听网络变化android.net.conn.CONNECTIVITY_CHANGE关闭或打开飞行模式Intent.ACTION_AIRPLANE_MODE_CHANGED充电时或电量发生变化Intent.ACTION_BATTERY_CHANGED电池电量低Intent.ACTION_BATTERY_LOW电池电量充足(即从电量低变化到饱满时会发出广播Intent.ACTION_BATTERY_OKAY系统启动完成后(仅广播一次)Intent.ACTION_BOOT_COMPLETED按下照相时的拍照按键(硬件按键)时Intent.ACTION_CAMERA_BUTTON屏幕锁屏Intent.ACTION_CLOSE_SYSTEM_DIALOGS设备当前设置被改变时(界面语言、设备方向等)Intent.ACTION_CONFIGURATION_CHANGED插入耳机时Intent.ACTION_HEADSET_PLUG未正确移除SD卡但已取出来时(正确移除方法:设置–SD卡和设备内存–卸载SD卡)Intent.ACTION_MEDIA_BAD_REMOVAL插入外部储存装置(如SD卡)Intent.ACTION_MEDIA_CHECKING成功安装APKIntent.ACTION_PACKAGE_ADDED成功删除APKIntent.ACTION_PACKAGE_REMOVED重启设备Intent.ACTION_REBOOT屏幕被关闭Intent.ACTION_SCREEN_OFF屏幕被打开Intent.ACTION_SCREEN_ON关闭系统时Intent.ACTION_SHUTDOWNOrdered broadcast:有序广播 发送出去的广播被广播接收者按照先后顺序接收
广播接受者接收广播的顺序规则(同时面向静态和动态注册的广播接收者)
按照Priority属性值从大-小排序;Priority属性相同者,动态注册的广播优先;特点:
接收广播按顺序接收先接收的广播接收者可以对广播进行截断,即后接收的广播接收者不再接收到此广播;先接收的广播接收者可以对广播进行修改,那么后接收的广播接收者将接收到被修改后的广播使用方式:
Intent intent = new Intent(); intent.setAction(ACTION); //发送有序广播 sendOrderedBroadcast(intent);Sticky Broadcast:粘性广播(在android 5.0/api 21中deprecated,不再推荐使用,相应的还有粘性有序广播,同样已经deprecated)
Local Broadcast:App应用内广播
App应用内广播可理解为一种局部广播,广播的发送者和接收者都同属于一个App。相比于全局广播(普通广播),App应用内广播优势体现在:安全性高、效率高。实现方式1:只能动态注册,不能静态注册
//注册应用内广播接收器 //步骤1:实例化BroadcastReceiver子类 & IntentFilter MyBroadcastReceiver mBroadcastReceiver= new MyBroadcastReceiver(); IntentFilter intentFilter = new IntentFilter(); //步骤2:实例化LocalBroadcastManager的实例 localBroadcastManager = LocalBroadcastManager.getInstance(this); //步骤3:设置接收广播的类型 intentFilter.addAction(ACTION); //步骤4:调用LocalBroadcastManager单一实例的registerReceiver()方法进行动态注册 localBroadcastManager.registerReceiver(mBroadcastReceiver, intentFilter); //取消注册应用内广播接收器 localBroadcastManager.unregisterReceiver(mBroadcastReceiver); //发送应用内广播 Intent intent = new Intent(); intent.setAction(ACTION); localBroadcastManager.sendBroadcast(intent);实现方式2:
注册广播时将exported属性设置为false,使得非本App内部发出的此广播不被接收;在广播发送和接收时,增设相应权限permission,用于权限验证;发送广播时指定该广播接收器所在的包名,此广播将只会发送到此包中的App内与之相匹配的有效广播接收器中。通过intent.setPackage(packageName)指定报名。自定义广播代码:
import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.util.Log; /** * 自定义广播 */ public class MyBroadcastReceiver extends BroadcastReceiver{ public static final String TAG="MyBroadcastReceiver"; /** * 接收广播的回调 * @param context * @param intent */ @Override public void onReceive(Context context, Intent intent) { Log.i(TAG,"onReceive"); } }