Android activity概述

转载请标注原文地址: http://blog.csdn.net/uranus_wm/article/details/8773717

Android activity概述
概述
Activities 是一个程序的组件之一。它的主要功能是提供界面。
    一个程序一般由多个Activity组成,各activities之间关系很松散,它们之间没有直接的关联。必须有一个activity被指定为主activity,它是程序启动时首先显示的界面。每个activity都可以随意启动其它的activity。每当一个activity被启动,则前一个activity就被停止。一个程序中的所有启动的activity都被放在一个栈中,所以被停止的activity并没有销毁,而在存于棧中。新启动的activity先被存放于栈中,然后获得输入焦点。在当前活动的activity上点返回键,它被从棧中取出,然后销毁,然后上一个activity被恢复。
当一个activity因为新的activity启动而被停止时,它会收到状态变化的通知,这样的变化有多个,每个都会引起系统调用一个相应的回调方法以通知activity,这些回调方法被统称为“生命周期回调方法”。这些回调方法分别在Activity被创建、停止、恢复、销毁时被调用。
如何创建Activity
1 从类activity继承。
2 实现“生命周期回调方法”
两个最重要的方法是:
onCreate()--这个是必须实现的函数,在其中做初始化工作。记住:你必须在此函数中调用setContentView()函数设置Activity的布局。
onPause()—用户离开当前Activity时,系统首先调用这个方法(一般并不意味着Activity要被销毁)。通常在这个函数中,你需要提交那些需要保存的数据(因为用户可能不再返回到这个Activity)。
其它回调方法视情况实现,我们在后面讨论。
实现用户界面
此处的用户界面指的就是activity上的控件们。所有的控件都从View类派生,所以可以把它们都称为View。每个控件占据一个矩形区域,可以响应用户的交互操作。
控件又分为以下两类:Widgets是完成特定功能的控件,比如button,text field,checkbox,或仅是一张image等。Layouts是容纳Widgets控件并进行排版的控件,当然,Layout中还可以容纳Layout。Widgets从View类派生,Layouts从ViewGroup类中派生,开发者可以从View或ViewGroup派生创造自己的控件。
定义界面的最好的方法是使用XML格式的layout文件,它作为资源保存在工程中,可以在工程的res/layout下面找到这些XML文件。通过这种方式就做到了代码与UI界面分离。把layout 下的某个XML设置为某个Activity的界面,需调用Activity的setContentView(),把XML的资源ID作为参数传入即可。当然你也可以在Activity代码中创建一个view并插入ViewGroup,然后把这个ViewGroup传递给setContentView()。
在manifest名单文件中声明activity
为了能让系统操作你的Activity,你必须在工程的manifest名单文件中声明它。例如:

<manifest ... >
  <application ... >
      <activity android:name=".ExampleActivity" />
      ...
  </application ... >
  ...
</manifest >


    当然有很多属性可以设置给Activity,比如label,icon或主题等等。详情请查看<activity>元素的说明。android:name是唯一必须的属性,它指定了Activity的名称。注意看<activity android:name=".ExampleActivity"/>,看到activity name的值中,最前面有个”.”,如果你把它忘了,程序运行就会出错,而你很难找出错误的原因。其次,不论你的Activity是只内部使用还是外部使用,都要去名单文件中注册,否则依然会出现莫名其妙的错误,只是在内部使用时,不需要为acitivity增加意图过滤器。
使用intent过虑器
    可以为一个<activity>元素指定多个过虑器。使用<intent-filter>元素指定。intent过虑器的目的是告诉其它组件如何启动这个Activity。当你使用ADT创建一个新工程时,根Activity被自动创建,它已具有两个意图过虑器,一个意图过虑器声明这个Activity负责响应“main”action;另一个过虑器声明这个Activity须被置于”launcher”类别之下。一般是这个样子:

<activity android:name=".ExampleActivity" android:icon="@drawable/app_icon">
    <intent-filter>
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />
    </intent-filter>
</activity>


<intent-filter>中就是过滤器。此例中<action>说明此Acitivity是程序的主入口,<category>指出这个Acitivity需要在系统的Launcher应用中列出。
    如果你写的程序中的Activity不需被其它程序调用,那么不需为这个Activity增加任何intent意图过滤器。程序中只能有一个Activity被指定为”main” Action和”launcher” category。没有指定intent的activity不能被其他应用打开,你只能在自己应用中通过显示调用方式打开,后面说明此种方法。
    然而,如果你想让你的Activity被其它程序隐式调用,那么你需要为它增加意图过滤器。这些过意图滤器必须包括<action>,而<category>以及<data>为可选。这些元素指明了你的activity响应何种类型的intent。
启动一个Activity
    你可以用startActivity()启动一个activity,它有一个参数是intent,你需要在这个intent中指明要调用的activity。Intent中你可以明确地指定要启动的activity,或只指定activity的类型,此时系统会为你挑选一个合适的activity,这个activity可能位于其它程序中,也可能位于你自己的程序中。Intent中可以带新activity需要使用的数据参数(相当于参数传递)。
    在你的程序内部,如果需要启动一个内部的activity,你通常需在intent中明确指定新activity的类名。例如:

Intent intent = new Intent(this, SignInActivity.class);
startActivity(intent);


    SignInActivity是要启动的activity类。
    然而,你的程序可能想执行自身没有提供的功能,比如发出邮件,发送短信息等。此时,需要启动其它应用程序提供的activity。此时就体现出intent的真正价值来了:它可以很容易地启动其它程序提供的activity,你只需要在intent中指定你要执行的动作,然后调用 startActivity() ,系统就会跟据你的需要,为你选择一个合适的activity,并启动它。如果同时有多个activity可以执行这动作,那么由用户选择哪个被使用。例如,你想让用户发送一个电子邮件,你可以创建以下的Intent:

Intent intent = new Intent(Intent.ACTION_SEND);
intent.putExtra(Intent.EXTRA_EMAIL, recipientArray);
startActivity(intent);


putExtra()是设置扩充数据的,.EXTRA_EMAIL表明第二个参数recipientArray里面放的是多个email地址。当发邮件的程序被启动并接收到这个intent时,它就把邮件地址们放到它的Acitivity界面的“to”控件中。当用户发送完毕返回时,你的activity就恢复运行(resume)。
启动一个acitvity并得到结果
有时,你可能想从你启动的activity获得其执行后返回的结果。此时你可以用方法startActivityForResult()来启动新acitivity(不再是startActivity了)。然后,你的程序还需要定义回调方法onActivityResult()。当新activity运行结束时,它把一个intent返回给你的程序,这个intent是在onActivityResult()中被接收。
例如:你想让用户打开通讯录,从中选择一个联系人,然后你取得用户所选的联系人,对之进行处理。以下是示例代码:

private void pickContact() {
    // Create an intent to "pick" a contact, as defined by the content provider URI
    Intent intent = new Intent(Intent.ACTION_PICK, Contacts.CONTENT_URI);
    startActivityForResult(intent, PICK_CONTACT_REQUEST);
}

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    // If the request went well (OK) and the request was PICK_CONTACT_REQUEST
    if (resultCode == Activity.RESULT_OK && requestCode == PICK_CONTACT_REQUEST) {
        // Perform a query to the contact's content provider for the contact's name
        Cursor cursor = getContentResolver().query(data.getData(),
        new String[] {Contacts.DISPLAY_NAME}, null, null, null);
        if (cursor.moveToFirst()) { // True if the cursor is not empty
            int columnIndex = cursor.getColumnIndex(Contacts.DISPLAY_NAME);
            String name = cursor.getString(columnIndex);
            // Do something with the selected contact's name...
        }
    }
}


此例子展示了在onActivityResult()中的基本逻辑流程。首选检查所启动的Activity是否正确运行,resultCode为Activity.RESULT_OK表示正常,其次,查看requestCode是否与当时请求的一致,即是否为PICK_CONTACT_REQUEST。都通过后,开始操作返回的数据,也就是data参数。
Data是这样处理的,用ContentResolver向内容提供者发出请求,这个请求会返回一个游标,通过这个游标读取数据,这很像数据库表的操作。要理解此处,请查阅Content Providers一节。 
关闭Activity
Activity可以内部调用finish()方法关闭它自己,也可以调用finishActivity()方法关闭其它的activity。
注意:大多数情况下,你不应主动结束一个activity。系统掌管着activity的生命,所以你也不必结束自己的activity。使用上述方法会破坏用户体验。除非你觉得很必要时,否则就不要做!
管理Activity的生命周期
通过实现activity的生命周期回调方法来管理你的activity,是创造既稳定又灵活的activity的关键。Activity的生命周期直接受到其相关的activity,任务以及所在栈的影响。
一个activity可生存在三种基本的状态中:
Resumed
Activity位于屏幕的最上层,并具有用户焦点,用户可以操作它。(此状态有时也被认为是“运行”状态)。
Paused
Activity B位于最上层并其获得输入焦点,acitvity A位于其下一层,但activity A依然可见,此时activity A就处于Paused状态。Activity A可见的原因可能是activity B是半透明的,或acitvity B不覆盖整个屏幕。此状态的activity依然是“活”的,因为它还是位于内存中,并且它被窗口管理器所管理。此状态的activity在RAM剩余极少时,可能被系统杀掉。
Stoped
一个Activity如果被其它activity完全遮盖,那么它就处于Stoped状态。此时它处于“后台”。此状态的activity也是“活”的,它依然位于内存中,但是窗口管理器中把它除名。然而,它不再被用户看到并且系统可以在其它组件需要内存时把它杀掉,也就是说它比paused状态的更容易被杀掉。
如果一个activtiy处于paused或stoped状态,系统可以杀死它。杀死它的方法有比较温和的:请求activity用finish()自杀,或直接用暴力的方法:杀掉activity所在的进程。不论怎样,activity被从内存中移除。当被杀或自杀的activity重新启动时,它必须被从头创建。
实现生命周期回调

public class ExampleActivity extends Activity {
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // The activity is being created.
    }
    @Override
    protected void onStart() {
        super.onStart();
        // The activity is about to become visible.
    }
    @Override
    protected void onResume() {
        super.onResume();
        // The activity has become visible (it is now "resumed").
    }
    @Override
    protected void onPause() {
        super.onPause();
        // Another activity is taking focus (this activity is about to be "paused").
    }
    @Override
    protected void onStop() {
        super.onStop();
        // The activity is no longer visible (it is now "stopped")
    }
    @Override
    protected void onDestroy() {
        super.onDestroy();
        // The activity is about to be destroyed.
    }
}


注意:当你覆写以上函数时,必须首先调用父类的同一方法,就像上例中所示。
这六个方法涵盖了activity的整个生命周期,覆写这些方法们,可以监视activity生命周期中三种状态的嵌套循环:
实例生命周期:窗口实例存在于onCreate()和onDestory()之间。你需要在onCreate()中完成全局状态的初始工作(如定义布局),在onDestory()中完成资源的释放工作。如负责后台下载的线程。
可视生命周期:窗口在onStart()和onStop()之间,对于用户在屏幕上是可见且可操作的。在此之间你可以获取显示窗口给用户所需要的资源。例如在onStart()注册一个BroadcastReceiver监测UI的变化,在onStop()用户不可见时释放它。这两个方法在实例化生命周期内可能被多次调用,因为窗口可能在用户操作下交替可见和隐藏。
前景生命周期:窗口在onResume()和onPause()之间处于所有窗口最上层,拥有用户输入焦点,窗口可以频繁在前景和后台切换。例如onPause()在设备休眠时或对话框出现时被调用。正因为可能的频繁调用,所以这两个方法的实现需要相当的轻量级,避免过渡缓慢造成用户等待。
下图展示了这些循环以及在状态切换时activity所经过的步骤。方框表示回调方法。 
   
   
下表更详细的介绍了生命周期函数的事项。

 

"Killable after?"这一列表示在当前方法返回后,未执行任何其他代码,系统能否随意杀死这个activity。onPause(),onStop(),和onDestory()三个方法填写的是。onPause()被认为是activity被杀死前最后一个确保执行到的方法,因为紧急情况下activity被杀掉onStop()和onDestory()可能不被调用到。因此你可以将一些关键数据在此方法中保存,但是多长的延时会影响用户体验,因此需要选择哪些数据才是必须在此保存的。
注:技术上表中定义为“不可被杀”的活动仍然可能被系统杀死,但是,只有在极端情况下会发生,当没有其他资源时。这个将在可能被杀死的进程和线程文档中详细讨论。
保存activity的状态
在“acitvity的生命周期”一节中提到了当暂停和停止时,activity的状态是被保留在内存中的,当resume时,它会立即开始执行。如果activity对象被系统销毁,则不能简单的恢复窗口,必须重新创建窗口,此时用户并不知道activity被系统销毁,当用户选择返回此窗口时,总是希望恢复原有窗口的面貌状态,此时必须执行另一个方法保存activity的状态信息:onSaveInstanceState()。
系统在activtiy被销毁前会传递一个Bundle给onSaveInstanceState()方法,开发者可以以name-value键值对的方式保存activity的信息。当activity被系统杀死,用户选择返回此窗口时,系统会将Bundle传递给onCreate()和onRestoreInstanceState()两个方法。我们可以通过提取Bundle信息恢复activity状态。如果没有信息被保存,Bundle会传过来一个null。(例如窗口首次被调用打开)。
 
上图表示了activity重新获得用户焦点的两种方式:一种是窗口被销毁,重新创建并恢复原有保存的状态,另一种是窗口失去焦点,恢复到原来的状态。
注意:onRestoreInstanceState()不是在窗口被销毁时一定被调用到的,因为有时窗口状态是不需要保存的(例如用户按返回键主动退出)。如果系统调用onRestoreInstanceState(),通常是在onStop()甚至onPause()被调用前。
然而,即使你没有实现自己的onSaveInstanceState(),但activity上控件的样子可能依然能被保存并恢复。原来activity类已实现了onSaveInstanceState(),在onSaveInstanceState()的默认实现中,会调用所有控件的相关方法,把控件们的状态都保存下来,比如EditText中输入的文字,CheckBox是否被选中等等。然而不是所有的控件都能被保存,这取决于你是否在layout文件中为控件赋了唯一的名字ID(android:id)。有名的就存,没有名字的系统就无法保存
既然有现成的可用,那么我们到底还要不要自己实现onSaveInstanceState()?这得看情况了,如果你自己的派生类中有变量影响到UI,或你程序的行为,当然就要把这个变量也保存了,那么就需要自己实现,否则就不需要,但大多数情况肯定需要自己实现一下。别忘了在你的实现中调用父类的onSaveInstanceState()。
注:由于onSaveInstanceState()并不是每次销毁时都会调用,所以不要在其中保存那些需要永久化的数据,执行保存那些数据的最好地方是:onPause()中。
测试你程序的状态恢复能力的最好方法是:旋转屏幕,每当屏幕的方向改变时,当前的activity就会被系统销毁,然后重新创建。
处理系统配置变化
很多设备可以在运行时改变系统配置,比如屏幕方向,键盘布局以及语言等。当类似的变化发生时,系统会把运行的activity重启(调用onDestroy(),然后调用onCreate()),这种设计保证你的activity能跟据这些配置变化自动做出相应处理,那么你的程序将更具有弹性。
那么如何应付这些变化呢,最好的办法就是写好状态保存/恢复方法们。比如onSaveInstanceState(),onRestoreInstanceState()/onCreate()。
对于系统配置改变的详细信息以及基体应对方法,请观“Handling Runtime Changes”一节。
协调activities
当一个activity启动另一个activity时,两者都有自己的生命周期。如果这两个activity之间有共享数据,那么重点要理解当第二个activity被创建时,第一个activity还没有执行到onStop()。第二个窗口打开和第一个窗口停止是相互重叠,有交集的。
回调函数的调用顺序一般定义如下,特别是当这两种活动都在同一进程中,当activityA启动ActivityB时,会按以下顺序执行:
1.Activity A 的onPause()执行。
2.Activity B的onCreate(),onStart(),onResume()依次执行(此时actvityB具有用户焦点)。
3.Activity A的onStop()被执行(假设A被B完全遮盖)。
你应跟据这个顺序来管理两者之间的数据传递。比如,如果A要向数据库中写入数据,要保证B在初始化时能读到A写入的完整数据,那么A应在onPause()方法中写入数据,而不能在onStop()中写入。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值