码迷,mamicode.com
首页 > 移动开发 > 详细

android四大组件详解

时间:2016-04-26 21:25:20      阅读:251      评论:0      收藏:0      [点我收藏+]

标签:

android四大组件分别是activity,service,content provider,broadcast receiver。



一,activity详解

1,概述

(1)一个Activity通常就是一个单独的屏幕(窗口)。

(2)Activity之间通过Intent进行通信。

(3)android应用中每一个Activity都必须要在AndroidManifest.xml配置文件中声明,否则系统将不识别也不执行该Activity

2,生命周期

ONcreate----》创建
onstart-----》界面可见
onResume----》界面可以获取焦点并且可以和用户交互
onpause-----》界面暂停,界面失去焦点
onstop -----》界面停止,不可见
ondestory---》销毁
onrestart---》重新启动

方法

描述

完成后可杀掉?

下一个

onCreate()

当activity被创建时调用。这是做一般的静态初始化的地方,比如创建界面,把数据绑定到列表,等等之类。这个方法会被传入一个Bundle对像,它包含了activity的上一次(关闭时)的状态(如果这个状态可以得到)。此方法后面永远跟着onStart()。

onStart()

onRestart()

在停止后被调用,但不是停止后马上调用,而是在再次开始前调用,也就是在再次调用onStart()之前立即调用。

onStart()

onStart()

当activity变成可见后立即调用它。如果activity成为最上层,则调用onResume(),如果完全被摭盖,就调用onStop()。

onResume()或onStop()

onResume()

当activity处于最上层时,立即调用此方法。此时activity获得输入焦点。后面跟着onPause()。

onPause()

onPause()

当另一个activity要进入Pause状态时调用此方法。这个方法一般是用来提交那些发生改变的永久化的数据们,停止动画和其它消耗CPU的玩意们。这些工作必须以最快的速度完成,因为在这个方法返回之前,另一个activity就不能进入resume状态。当它又回到最上层时,后面跟着onResume(),当它被完全摭盖时,后面跟着onStop()。

onResume()

or

onStop()

onStop()

当activity被完全摭盖时被调用。当activity要销毁时或被其它activity完全摭盖时都会发生。如果这个activity又回到最上层,则后面跟着onRestart(),如果它逝去了,则跟着onDestroy()。

onRestart()

or

onDestroy()

onDestroy()

在activity销毁之前被调用。这是activity能收到的最后一个调用。调用的原因可能是别人在这个activity上调用了finish(),也可能是系统为了更多的内存空间而把它所在的进程处死了。在这个方法中,可以调用isFinishing()来判断自己属于哪一种死法。

nothing


两个最重要的方法是:

    onCreate()--这个是必须实现的函数,在其中做初始化工作。记住:你必须在此函数中调用setContentView()函数的设置Activity的界面。

    onPause()--这个虽然很重要,但不是要必须实现的。此函数在用户离开Activity时被调用(这一般并不表示Activity要被销毁了)。在这个函数中,你一般需要提交那些需保存状态的数据(因为用户可能不再返回到这个Activity)。

其它回调方法视情况实现。

一个activity的启动顺序:

onCreate()---->onStart()----->onResume()

当另一个Activity启动时:

第一个Activity onPause()-----第二个Activity onCreate()----->onStart()----->onResume()------->第一个Activity onStop()

当返回到第一个Activity时:

第二个Activity onPause()---->第一个Activity onRestart()----->onstart()----->onResume()------>第二个Activity onstop()-----.ondestroy()


每一个活动(Activity)都处于某一个状态,对于开发者来说,是无法控制其应用程序处于某一状态的,這写均由系统来完成。

但是当一个活动的状态发生改变的时候,开发者可以通过调用onXX()的方法获取相关的通知信息。在实现Activity类的时候,通过重写这些方法即可在你需要处理的时候来调用。

onCreate:当活动第一次启动的时候,触发该方法,可以在此时完成活动的初始化工作。onCreate方法有一个参数,该参数可以为空,也可以是之前调用onSaveInstanceState()方法保存的状态信息。


onStart:该方法的触发表示所属活动将被展现给用户。



onResume:当一个活动和用户发生交互的时候,触发该方法。



onPause:当一个正在前台运行的活动因为其他的活动需要前台运行而转入后台运行的时候触发该方法。这时候需要将活动的状态持久化,比如正在编辑的数据库记录等。



onStop :当一个活动活动不再需要展示给用户的时候,触发该方法,如果内存紧张,系统会直接结束這个活动,而不会触发onStop方法。所以保存状态信息在onPause时做,而不是onStop时做。活动如果没有在前台运行,都将被停止或者linux管理进程为了给新的活动预留足够的存储空间而随时结束這些活动。因此对于开发者来说,在设计应用程序的时候,必须时刻牢记這一原则。在一些情况下,onPause方法或许是活动触发的最后方法,因此开发者需要在這个时候保存需要保存的信息。



onRestart:当处于停止状态的活动需要再次展现给用户的时候,触发该方法。



onDestroy:当活动销毁的时候,触发该方法。和onStop方法一样,如果内存紧张,系统会直接结束這个活动而不会触发该方法。



3,activity的四种加载模式

       在android的多activity开发中,activity之间的跳转可能需要多种方式,有时是普通的生成一个新实例,有时西希望跳转到原来某个activity实例,而不是生成大量的重复activity。载模式便是决定以哪种方式启动一个跳转到原来某个Activity实例。


(1)standard:标准模式,一调用startActivity方法就会产生一个新的实例。

(2)singleTop:如果已经有一个实例位于activity栈的顶部时,就不产生新的实例,而只是调用Activity中的newInstance()方法。如果不位于栈顶,会产生一个新的实例。

(3)singleTask:会在一个新的task中产生這个实例,以后每次调用都会使用這个,不会去产生新的实例了。

(4)singleInstance:這个跟singleTask基本上是一样,只有一个区别:在這个模式下的Activity实例所处的task中,只能有這个activity实例,不能有其他的实例。

這些启动模式可以在功能清单文件AndroidManifest.xml中进行设置launchMode属性



二,service详解

1,概述

(1)service用于在后台完成用户指定的操作。service分为两种:

       (a)started(启动):当应用程序组件(如activity)调用startService()方法启动服务时,服务处于started状态。

       (b)bound(绑定):当应用程序组件调用bindService()方法绑定到服务时,服务处于bound状态。

(2)startService()与bindService()的区别:

        (a)started service(启动服务)是由其他组件调用startService()方法启动的,這导致服务的onStartCommand()方法被调用。当服务是started状态时,其生命周期与启动它的组件无关,并且可以后台无限期运行,即使启动服务的组件已经被销毁。因此,服务需要在完成任务后调用stopSelf()方法停止,或者有其他组件调用stopService()方法停止。

        (b)使用bindService()方法启用服务,调用者与服务绑定在了一起,调用者一但退出,服务也就终止,大有”不求同时生,必须同时死“的特点。

(3)开发人员需要在应用程序配置文件中声明全部的service,使用<service></service>标签。

(4)Service通常位于后台运行,他一般不需要与用户交互,因此service组件没有图形用户界面。service组建需要继承service基类。service组件通常用于为其他组件提供后台服务或监控其他组件的运行状态。


  

2.Service的生命周期

onCreate  onStart  onDestroy  onBind

1). 被启动的服务的生命周期:如果一个Service被某个Activity 调用 Context.startService 方法启动,那么不管是否有Activity使用bindService绑定或unbindService解除绑定到该Service,该Service都在后台运行。如果一个Service被startService 方法多次启动,那么onCreate方法只会调用一次,onStart将会被调用多次(对应调用startService的次数),并且系统只会创建Service的一个实例(因此你应该知道只需要一次stopService调用)。该Service将会一直在后台运行,而不管对应程序的Activity是否在运行,直到被调用stopService,或自身的stopSelf方法。当然如果系统资源不足,android系统也可能结束服务。

2). 被绑定的服务的生命周期:如果一个Service被某个Activity 调用 Context.bindService 方法绑定启动,不管调用 bindService 调用几次,onCreate方法都只会调用一次,同时onStart方法始终不会被调用。当连接建立之后,Service将会一直运行,除非调用Context.unbindService 断开连接或者之前调用bindService 的 Context 不存在了(如Activity被finish的时候),系统将会自动停止Service,对应onDestroy将被调用。

3). 被启动又被绑定的服务的生命周期:如果一个Service又被启动又被绑定,则该Service将会一直在后台运行。并且不管如何调用,onCreate始终只会调用一次,对应startService调用多少次,Service的onStart便会调用多少次。调用unbindService将不会停止Service,而必须调用 stopService 或 Service的 stopSelf 来停止服务。

4). 当服务被停止时清除服务:当一个Service被终止(1、调用stopService;2、调用stopSelf;3、不再有绑定的连接(没有被启动))时,onDestroy方法将会被调用,在这里你应当做一些清除工作,如停止在Service中创建并运行的线程。

特别注意:

1、你应当知道在调用 bindService 绑定到Service的时候,你就应当保证在某处调用 unbindService 解除绑定(尽管 Activity 被 finish 的时候绑定会自      动解除,并且Service会自动停止);

2、你应当注意 使用 startService 启动服务之后,一定要使用 stopService停止服务,不管你是否使用bindService;

3、同时使用 startService 与 bindService 要注意到,Service 的终止,需要unbindService与stopService同时调用,才能终止 Service,不管 startService 与 bindService 的调用顺序,如果先调用 unbindService 此时服务不会自动终止,再调用 stopService 之后服务才会停止,如果先调用 stopService 此时服务也不会终止,而再调用 unbindService 或者 之前调用 bindService 的 Context 不存在了(如Activity 被 finish 的时候)之后服务才会自动停止;

4、当在旋转手机屏幕的时候,当手机屏幕在“横”“竖”变换时,此时如果你的 Activity 如果会自动旋转的话,旋转其实是 Activity 的重新创建,因此旋转之前的使用 bindService 建立的连接便会断开(Context 不存在了),对应服务的生命周期与上述相同。

5、在 sdk 2.0 及其以后的版本中,对应的 onStart 已经被否决变为了 onStartCommand,不过之前的 onStart 任然有效。这意味着,如果你开发的应用程序用的 sdk 为 2.0 及其以后的版本,那么你应当使用 onStartCommand 而不是 onStart。



三、Broadcast Receiver详解


  BroadcastReceiver 用于异步接收广播Intent。主要有两大类,用于接收广播的:

  ·正常广播 Normal broadcasts(用 Context.sendBroadcast()发送)是完全异步的。它们都运行在一个未定义的顺序,通常是在同一时间。这样会更有效,但意味着receiver不能包含所要使用的结果或中止的API。

  ·有序广播 Ordered broadcasts(用 Context.sendOrderedBroadcast()发送)每次被发送到一个receiver。所谓有序,就是每个receiver执行后可以传播到下一个receiver,也可以完全中止传播--不传播给其他receiver。 而receiver运行的顺序可以通过matched intent-filter 里面的android:priority来控制,当priority优先级相同的时候,Receiver以任意的顺序运行。

  要注意的是,即使是Normal broadcasts,系统在某些情况下可能会恢复到一次传播给一个receiver。 特别是receiver可能需要创建一个进程,为了避免系统超载,只能一次运行一个receiver。

  Broadcast Receiver 并没有提供可视化的界面来显示广播信息。可以使用Notification和Notification Manager来实现可视化的信息的界面,显示广播信息的内容,图标及震动信息。

  生命周期

  一个BroadcastReceiver 对象只有在被调用onReceive(Context, Intent)的才有效的,当从该函数返回后,该对象就无效的了,结束生命周期。

  因此从这个特征可以看出,在所调用的onReceive(Context, Intent)函数里,不能有过于耗时的操作,不能使用线程来执行。对于耗时的操作,请start service来完成。因为当得到其他异步操作所返回的结果时,BroadcastReceiver 可能已经无效了。

  发送广播

  事件的广播比较简单,构建Intent对象,可调用sendBroadcast(Intent)方法将广播发出。另外还有sendOrderedBroadcast(),sendStickyBroadcast()等方法,请查阅API Doc。

  1.new Intent with action name

  Intent intent = new Intent(String action);

  或者 只是new Intent, 然后

  intent.setAction(String action);

  2.set data等准备好了后,in activity,

  sendBroadcast(Intent); // 发送广播

  接收广播

  通过定义一个继承BroadcastReceiver类来实现,继承该类后覆盖其onReceiver方法,并在该方法中响应事件。


注册Receiver

  注册有两种方式:

  1. 静态方式,在AndroidManifest.xml的application里面定义receiver并设置要接收的action。

  1.   <receiver android:name=".SMSReceiver">

  2.   <intent-filter>

  3.   <action android:name="android.provider.Telephony.SMS_RECEIVED" />

  4.   </intent-filter>

  5.   </receiver>
复制代码
2. 动态方式, 在activity里面调用函数来注册,和静态的内容差不多。一个形参是receiver,另一个是IntentFilter,其中里面是要接收的action。
  1. public class HelloDemo extends Activity {    
  2.         private BroadcastReceiver receiver;    

  3.         @Override 
  4.         protected void onStart() { 
  5.                 super.onStart(); 

  6.                 receiver = new CallReceiver(); 
  7.                 registerReceiver(receiver, new IntentFilter("android.intent.action.PHONE_STATE")); 
  8.         } 

  9.         @Override 
  10.         protected void onStop() { 
  11.                 unregisterReceiver(receiver); 
  12.                 super.onStop(); 
  13.         } 
  14. }

复制代码
  一个receiver可以接收多个action的,即可以有多个intent-filter,需要在onReceive里面对intent.getAction(action name)进行判断。

  个人推荐使用静态注册方式,由系统来管理receiver,而且程序里的所有receiver,可以在xml里面一目了然。而动态注册方式,隐藏在代码中,比较难发现。

  而且动态注册,需要特别注意的是,在退出程序前要记得调用Context.unregisterReceiver()方法。一般在activity的onStart()里面进行注册, onStop()里面进行注销。官方提醒,如果在Activity.onResume()里面注册了,就必须在Activity.onPause()注销。

  Permission权限

  要接收某些action,需要在AndroidManifest.xml里面添加相应的permission。例如接收SMS:

  1. <uses-permission android:name="android.permission.RECEIVE_SMS" />
复制代码
  下面给出动态注册的接收来电的广播处理的CallReceiver的代码:

  一种方式是直接读取intent.getStringExtra("incoming_number")来获取来电号码:

  1. public class CallReceiver extends BroadcastReceiver { 

  2.         @Override 
  3.         public void onReceive(Context context, Intent intent) { 
  4.                 TelephonyManager teleManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE); 
  5.                  
  6.                 switch(teleManager.getCallState()){ 
  7.                 case TelephonyManager.CALL_STATE_RINGING: //响铃 
  8.                         Toast.makeText(context, "Ringing: " + intent.getStringExtra("incoming_number"), Toast.LENGTH_LONG).show(); 
  9.                         break; 
  10.                 case TelephonyManager.CALL_STATE_OFFHOOK: //接听 
  11.                         Toast.makeText(context, "OffHook: " + intent.getStringExtra("incoming_number"), Toast.LENGTH_LONG).show(); 
  12.                         break; 
  13.                 case TelephonyManager.CALL_STATE_IDLE: //挂断 
  14.                         Toast.makeText(m_context, "Idle: " + incomingNumber, Toast.LENGTH_LONG).show(); 
  15.                         break; 
  16.                 } 
  17.         } 
  18. }

复制代码
  在运行时,发现除了响铃时可以获取来电号码,接听和挂断都不能成功获取的,显示为null。

  另一种方式是通过PhoneStateListener的onCallStateChanged来监听状态的变化:

  1. public class CallReceiver extends BroadcastReceiver { 

  2.         private Context m_context; 
  3.         @Override 
  4.         public void onReceive(Context context, Intent intent) { 
  5.                 m_context = context; 
  6.                 TelephonyManager teleManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE); 
  7.                 teleManager.listen(new PhoneStateListener(){ 

  8.                         @Override 
  9.                         public void onCallStateChanged(int state, String incomingNumber) { 
  10.                                 switch(state){ 
  11.                                 case TelephonyManager.CALL_STATE_RINGING: //响铃 
  12.                                         Toast.makeText(m_context, "Ringing: " + incomingNumber, Toast.LENGTH_LONG) 
  13.                                                                 .show(); 
  14.                                         break; 
  15.                                 case TelephonyManager.CALL_STATE_OFFHOOK: //接听 
  16.                                         Toast.makeText(m_context, "OffHook: " + incomingNumber, Toast.LENGTH_LONG) 
  17.                                         .show(); 
  18.                                         break; 
  19.                                 case TelephonyManager.CALL_STATE_IDLE: //挂断 
  20.                                         Toast.makeText(m_context, "Idle: " + incomingNumber, Toast.LENGTH_LONG) 
  21.                                         .show(); 
  22.                                         break; 
  23.                                 } 
  24.                         }}, PhoneStateListener.LISTEN_CALL_STATE);  
  25.         } 
  26. }

复制代码
  运行时也发现incomingNumber在接听和挂断时获取为blank。

  因为这里监听的是通话的状态变化,所以这个receiver会被调用3次。

  监听通话状态需要加上权限:

  1. <uses-permission android:name="android.permission.READ_PHONE_STATE"/>
复制代码
  ===========

  小结:

  1. 对于sendBroadCast的intent对象,需要设置其action name;

  2. 推荐使用显式指明receiver,在配置文件AndroidManifest.xml指明;

  3. 一个receiver可以接收多个action;

  4. 每次接收广播都会重新生成一个接收广播的对象,再次调用onReceive;

  5. 在BroadCast 中尽量不要处理太多逻辑问题,建议复杂的逻辑交给Activity 或者 Service 去处理。




--------------------------------------------
四、Content Provider详解

  ContentProvider(内容提供者)是Android中的四大组件之一。主要用于对外共享数据,也就是通过ContentProvider把应用中的数据共享给其他应用访问,其他应用可以通过ContentProvider对指定应用中的数据进行操作。ContentProvider分为系统的和自定义的,系统的也就是例如联系人,图片等数据。

  android中对数据操作包含有:

  file, sqlite3, Preferences, ContectResolver与ContentProvider前三种数据操作方式都只是针对本应用内数据,程序不能通过这三种方法去操作别的应用内的数据。

  android中提供ContectResolver与ContentProvider来操作别的应用程序的数据。

  使用方式:

  一个应用实现ContentProvider来提供内容给别的应用来操作,

  一个应用通过ContentResolver来操作别的应用数据,当然在自己的应用中也可以。

  以下这段是Google Doc中对ContentProvider的大致概述:

  内容提供者将一些特定的应用程序数据供给其它应用程序使用。内容提供者继承于ContentProvider 基类,为其它应用程序取用和存储它管理的数据实现了一套标准方法。然而,应用程序并不直接调用这些方法,而是使用一个 ContentResolver 对象,调用它的方法作为替代。ContentResolver可以与任意内容提供者进行会话,与其合作来对所有相关交互通讯进行管理。

  1.ContentProvider

  Android提供了一些主要数据类型的ContentProvider,比如音频、视频、图片和私人通讯录等。可在android.provider包下面找到一些Android提供的ContentProvider。通过获得这些ContentProvider可以查询它们包含的数据,当然前提是已获得适当的读取权限。

  主要方法:

  public boolean onCreate() 在创建ContentProvider时调用

  public Cursor query(Uri, String[], String, String[], String) 用于查询指定Uri的ContentProvider,返回一个Cursor

  public Uri insert(Uri, ContentValues) 用于添加数据到指定Uri的ContentProvider中

  public int update(Uri, ContentValues, String, String[]) 用于更新指定Uri的ContentProvider中的数据

  public int delete(Uri, String, String[]) 用于从指定Uri的ContentProvider中删除数据

  public String getType(Uri) 用于返回指定的Uri中的数据的MIME类型

  *如果操作的数据属于集合类型,那么MIME类型字符串应该以vnd.android.cursor.dir/开头。

  例如:要得到所有person记录的Uri为content://contacts/person,那么返回的MIME类型字符串为"vnd.android.cursor.dir/person"。

  *如果要操作的数据属于非集合类型数据,那么MIME类型字符串应该以vnd.android.cursor.item/开头。

  例如:要得到id为10的person记录的Uri为content://contacts/person/10,那么返回的MIME类型字符串应为"vnd.android.cursor.item/person"。

  2.ContentResolver

  当外部应用需要对ContentProvider中的数据进行添加、删除、修改和查询操作时,可以使用ContentResolver类来完成,要获取ContentResolver对象,可以使用Context提供的getContentResolver()方法。

  ContentResolver cr = getContentResolver();

  ContentResolver提供的方法和ContentProvider提供的方法对应的有以下几个方法。

  public Uri insert(Uri uri, ContentValues values) 用于添加数据到指定Uri的ContentProvider中。

  public int delete(Uri uri, String selection, String[] selectionArgs) 用于从指定Uri的ContentProvider中删除数据。

  public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) 用于更新指定Uri的ContentProvider中的数据。

  public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) 用于查询指定Uri的ContentProvider。



  3.Uri

  Uri指定了将要操作的ContentProvider,其实可以把一个Uri看作是一个网址,我们把Uri分为三部分。

  第一部分是"content://"。可以看作是网址中的"http://"。

  第二部分是主机名或authority,用于唯一标识这个ContentProvider,外部应用需要根据这个标识来找到它。可以看作是网址中的主机名,比如"blog.csdn.net"。

  第三部分是路径名,用来表示将要操作的数据。可以看作网址中细分的内容路径。






android四大组件详解

标签:

原文地址:http://blog.csdn.net/z95501331/article/details/51232171

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!