Android API Guides学习3——Activities

来源:互联网 发布:asp会员积分系统源码 编辑:程序博客网 时间:2024/05/17 23:25

http://developer.android.com/guide/components/activities.html

  activity是显示在屏幕上让用户可以做一些事的app组件,如打电话,照相,显示地图,每个activity都给出一个窗口并画上用户交互界面,这个窗口一般是填充整个屏幕的,有时候也会小于屏幕并且浮动在其他窗口上。
  一个app包含许多的activity,它们之间被松散的绑定。一般在一个app有一个”main”activity所谓用户的启动app的入口。每一个activity可以执行其他activity来执行各种行为。当一个新的activity被启动时,旧的activity会被暂停,然后系统会将其压入回退栈,然后新的activity取走用户焦点。回退栈遵循”后进先出”的栈机制,所以当用户按下后退按钮结束当前activity时,从回退栈中取出先前的activity恢复。
 当一个activity因为另一个activity启动而被被暂停时,activity的生命周期回调方法会得到状态改变的通知。为了改变activity状态——无论是创建、停止、恢复、销毁掉,每个activity会接收到一些回调方法,每一个回调提供你执行一些特别操作(对于状态改变的适当操作)的机会。如当暂停一个activity,你应该释放所有的大对象,如网络和数据库连接。当activity恢复时,你可以再次获取必须的资源,恢复被打断的行动。这些状态改变都是activity生命周期的一部分。
 接下来展示怎么去新建一个activity,包括对activity生命周期的完整讨论,正确的管理activity状态的改变。


创建一个activity

  继承Activity父类来创建一个activity。你需要实现当activity在多种生命周期状态转变时系统调用的回调方法。如activity 创建、停止、恢复、销毁。其中两个最重要的方法为:

  • onCreate()
    你必须实现这个方法,系统会在activity创建时调用这个方法,在方法实现中,你应该必要的组件。最重要的是,你必须调用setContentView()来确定activity的用户界面。
  • onPause()
    系统会在你离开当前activity时第一个调用(并不代表activity被销毁)。你应该在这个方法里提交所有的改变并保存(持久化)在用户当前会话中(因为用户可能不会再回到这个界面来)。

       你还应该使用其他的一些生命周期回调方法来使activity间的交互的用户体验流水般顺滑(…)并处理一些意外的中断。这些在之后介绍


实现一个用户交互界面

  activity的用户界面由一些层级结构的view(视图)对象组成(由View类派生来的)。每个view控制着窗口中的特定矩形空间并且可以相应用户交互。如一个可以在你单击它的时候启动一个动作的按钮。
  Android提供很多现成的view来设计组织自己的布局(layout)。”Widgets”(窗口小部件)是为屏幕提供视觉(交互)元素的view,如按钮、文本、复选框、图片等。”Layout”是从ViewGroup派生出来为其子view提供独一无二的布局模型的view,如线性布局、表格布局、相对布局等。你也可以自己继承View或ViewGroup类来创建自己的widgets和layout,并在activity的布局中应用它们。
  定义一个布局最常见的方式是使用XML布局文件并将它们保存在app资源中。这样就可以将用户界面设计与 定义activity行为的代码分离开来。你可以通过向setContentView()传入布局的资源ID来设置activity的布局。你也可以直接在源代码中创建视图层级通过在viewGroup中插入view然后将根viewGroup传给setContentView()。


在清单文件中声明

  你必须在清单文件中声明activity保证它对于系统是可进入的。在 < application >元素下声明< activity >元素来声明一个activity。如:

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

  activity还有一些其他属性来定义activity标签、activity的UI风格等。android:name为必须的属性指定activity的类名。一旦发布了app你就不应该改变它的名字,因为如果这么做了会损坏一些功能如app快捷方式。 
  使用intent filters来声明其他应用组件怎么启动它。当你使用Android SDK来创建一个新的应用,会自动在第一个activity声明中包含一个intent filter,用来宣布activity响应”main”行为,种类属性为”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>

  < action >元素指定这是”main”程序入口点。< category >元素指定这个activity会被列入系统应用程序启动器中(允许用户启动这个activity)。
  如果你不想其他app启动你的activity,不要声明任何intent filiter。只需要有一个activity应该有”main” action 和”launcher” category。
  如果你想你的activity响应其他app的隐式intent你必须为你的activity定义额外的intent filter。指定那种类型的intent你的activity可以响应。


启动一个activity

  你可以通过给startActivity()传入intent来启动另一个activity。intent描述你要启动的activity。intent指定确定的activity或描述要执行action的类型。同时你也可以携带一些较小的数据到下一个activity。
  通常在自己的应用中,要简单的启动一个一直的activity,创建一个显示意图来启动activity。

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

  有时,你需要执行一些你自己activity不能执行的行为,如发送email,状态更新,并用到了这个activity的数据,所以你要使用这台设备的其他app的activity,创建一个隐式intent描述你要处理的行为,来打开可以处理这个行为的activity。如想要发送一条email,可以创建如下intent:

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


启动一个有返回结果的activity

  有些情况,你需要获得你所打开的activity传回的数据,使用startActivityForResult()然后从之后activity接受结果,实现onActivityResult()回调方法。当之后的activity结束了,会给onActivityResult() 方法放回一个Intent对象。如你要选择一个联系人,返回并进行处理:

private void pickContact() {    // 创建ACTION_PICK,通过内容提供者的URI来创建intent    Intent intent = new Intent(Intent.ACTION_PICK, Contacts.CONTENT_URI);    startActivityForResult(intent, PICK_CONTACT_REQUEST);}@Overrideprotected void onActivityResult(int requestCode, int resultCode, Intent data) {    // 如果返回为OK并且请求码为PICK_CONTACT_REQUEST    if (resultCode == Activity.RESULT_OK && requestCode == PICK_CONTACT_REQUEST) {        // 通过联系人name来查询联系人内容提供者        Cursor cursor = getContentResolver().query(data.getData(),        new String[] {Contacts.DISPLAY_NAME}, null, null, null);        if (cursor.moveToFirst()) { // cursor不为空则为True            int columnIndex = cursor.getColumnIndex(Contacts.DISPLAY_NAME);            String name = cursor.getString(columnIndex);            // Do something with the selected contact's name...        }    }}

  以上为使用onActivityResult() 处理结果的基础逻辑。首先检测请求是否成功,再检测resultCode是否为RESULT_OK(常数)。

关闭一个activity

  通过调用finish()方法可以关闭一个activity,你也可以通过finishActivity()关闭一个之前启动的单独的activity。
  Note:大多数情况下,你不应显式的用这些方法结束一个活动,像下面部分关于活动的生命周期的讨论 ,Android系统为你管理活动的生命周期,所以不需要自己关闭活动的生命周期,调用这些方法可能对用户体验有不利的影响,并且应该只用于,当你确定不想让用户返回到那个活动的实例时的情况。

管理activity的生命周期

  通过实现回调方法来管理activity的生命周期十分重要。一个activity的生命周期直接的影响与它相关的activity和其任务及任务栈。
 一个活动在本质上存在三种状态:

  • Resumed(恢复)
    activity在前台并且获得用户的焦点。
  • Paused(暂停)
    其他activity在前台并且有用户焦点,但是这个activity还是可见的。也就是说另外一个activity显示在这一个activity的上面,可以是半透明的或没有覆盖整个屏幕。这个activity还是完全活着的(这个activity对象还存在内存里,保持所有的状态和用户信息,仍然隶属于窗口管理器)。但是它可以被系统销毁当内存极度低的时候。
  • Stopped(停止)
    这个activity完全的被其他activity覆盖(activity在后台),一个停止的activity也还时活着的(这个activity对象还存在内存里,保持所有的状态和用户信息,但不隶属于窗口管理器)。但是但用户长时间没有访问且需要内存的时候会被销毁。

       如果一个activity被暂停或停止,系统可以不提示的把它给结束掉(使用finish()方法),或简单的销毁它的进程。当这个activity重新启动(已经被结束或销毁了)必须重新创建它。

实现生命周期回调

  当activity转入/出不同的状态,会通知各种生命周期回调方法。你可以覆写所有的回调方法来做一些适当的事当activity的状态改变时。下面这个框架包含基本的activity生命周期方法:

public class ExampleActivity extends Activity {    @Override    public void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        // 当activity被创建    }    @Override    protected void onStart() {        super.onStart();        // 当activity开始变得可以访问    }    @Override    protected void onResume() {        super.onResume();        // 当activity可访问    }    @Override    protected void onPause() {        super.onPause();        // 其他activity得到用户焦点    }    @Override    protected void onStop() {        super.onStop();        // activity变得不可见    }    @Override    protected void onDestroy() {        super.onDestroy();        // activity被销毁    }}

Note:实现这些方法必须总先调用父类的方法。

  总的来说,这些方法声明一个完整的activity声明周期。通过实现这些方法,你可以在activity生命周期中监控三个嵌套循环

  • 整个activity的生存期发生在调用onCreate()和onDestroy()间。你的activity应该在onCreate()中设置全局状态(定义布局),在onDestroy()释放所有剩余的资源。如你的activity有个线程用于后台下载,在onCreate()中创建,在onDestroy()中停止。
  • 可访问的生存期发生在调用onStart()和onStop()间。在这段时间中你可以在屏幕上看到它和被他所影响。举个例子,onStop()被调用当一个新的activity启动,这个activity将不再可见,在这两个方法间,你可以维持需要展示在activity上的资源。再举个例子,你的onStart()方法中注册一个广播来监听影响UI的改变,在onStop()方法释放它当用户将不在看到这个界面时。系统可能会在activity整个生存期调用onStart()和onStop()方法许多次,当activity在可见和不可见间变化。
  • 前台生存期发生在调用onResume() 和onPause()方法间。在这些时间中,这个activity展示在屏幕上在其他activity之前,并且获得用户焦点,一个activity可以在前台、后台之间转变。如onPause()被调用当设备锁屏或出现一个对话框。因为需要经常转变,为了让用户等待,所以这两个方法里的代码必须非常轻量级的。

生命周期图如下:
activity_lifecycle


保存activity状态

  但activity暂停或停止的时候,所有的信息都还保存在内存中,所以所以用户对activity所做的改变还被保存着,但activity回到前台的时候,这些改变都还在。
  然而,当系统需要内存时,将这些activity的对象销毁, 所以系统不能简单的完整恢复它,而是重新创建一个activity对象当回到被销毁的activity上时。但是用户不知道系统销毁了它并重新创建它。因此,我们期望activity还是保存着原来的状态。这种情况下,你可以通过实现一个允许你保存activity状态信息的回调方法onSaveInstanceState()来保存activity的重要信息。
  系统会在activity易被销毁前调用onSaveInstanceState(),系统个这个方法传入一个Bundle(通过键值对保存),使用putString(),putInt()等方法保存数据,当系统销毁掉了app进程时,用户又回到这个界面上时,系统会通过传入的Bundle的onCreate()和onRestoreInstanceState()方法重新创建activity,用这两个方法之一你可以取出保存的信息恢复你的activity状态。如果没有信息,bundle为null。
  restore_instance

Note:在activity销毁前并不会总是调用onSaveInstanceState(),如用户显式的使用finish()掉一个activity回到上一个activity。如果系统调用了onSaveInstanceState(),会在onStop()前调用,有可能在onPause前调用。


  然而,当用户没有实现onSaveInstanceState()时,默认的onSaveInstanceState()方法中会保存布局文件中部分view的状态,这些view必须有被声明android:id属性,如果没有不会被保存。
  虽然有onSaveInstanceState()的默认实现,但在有些情况下还是需要手动的重写来保存数据。
  你可以通过旋转屏幕来简单测试数据保存的状况,因为横竖屏切换会重新创建activity。

Note:你不应该使用onSaveInstanceState()来保存持久数据,应该在onPause中保存activity的持久化数据。

处理配置改变

  一些设备配置在运行中可能发生改变(如横竖屏切换,键盘),当这些改变发生时,Android重新创建activity(onDestroy()然后onCreate())。这样的设计可以通过可替代资源自动地重新加载应用帮助app适应不同的配置(如分别使用横竖屏的layout文件)。
  如果你正确的设计activity来处理横竖屏切换,app会对一些意外事件更具弹性。
  最好的方式来处理重启恢复状态的是onSaveInstanceState()和onRestoreInstanceState() (或onCreate()),如之前所说

协调activity

  当一个activity启动另一个,他们都经历了自己的生命周期,第一个暂停或停止,第二个被创建。假设这些activity贡献数据保存在光盘或其他地方,重要的是在第二个activity关闭后,第一个activity并没有完全停止。第二个开启的进程重叠在第一个停止的进程上。生命周期回调方法的顺序已经被很好的定义了。特别的是当两个activity在同一个进程里,并且一个启动另一个。下面是一个activity启动另一个的顺序。
  1. activity A 执行onPause()。
  2. activity B 顺序执行onCreate(), onStart(), 和 onResume()。
  3. 如果activity A不再可见,执行onStop()。
  这些可预知的顺序允许我们管理一个activity转变为另一个时的信息。如你在第二个activity可以读到第一个activity停止时写入数据库的信息,你应该在onPause()方法中执行写数据库操作而不是onStop()。

0 0