Android四大组件之Activity

来源:互联网 发布:北京微信软件制作 编辑:程序博客网 时间:2024/06/14 07:35

一、什么是Activity

Activity 是用户接口程序,原则上它会提供给用户一个交互式的接口功能。它是 android 应用程序的基本功能单元。Activity 本身是没有界面的。所以activity类创建了一个窗口,开发人员可以通过setContentView(View)接口把UI放到activity创建的窗口上,当activity指向全屏窗口时,也可以用其他方式实现:作为漂浮窗口(通过windowIsFloating的主题集合),或者嵌入到其他的activity(使用ActivityGroup)。

二、Activity的声明周期

这里写图片描述

1. 启动Activity:
系统会先调用onCreate方法,然后调用onStart方法,最后调用onResume,Activity进入运行状态。

2. 当前Activity被其他Activity覆盖其上或被锁屏:
系统会调用onPause方法,暂停当前Activity的执行。

3. 当前Activity由被覆盖状态回到前台或解锁屏:
系统会调用onResume方法,再次进入运行状态。

4. 当前Activity转到新的Activity界面或按Home键回到主屏,自身退居后台:
系统会先调用onPause方法,然后调用onStop方法,进入停滞状态。

5. 用户后退回到此Activity:
系统会先调用onRestart方法,然后调用onStart方法,最后调用onResume方法,再次进入运行状态。

6. 当前Activity处于被覆盖状态或者后台不可见状态,即第2步和第4步,系统内存不足,杀死当前Activity,而后用户退回当前Activity:
再次调用onCreate方法、onStart方法、onResume方法,进入运行状态。

7.用户退出当前Activity:
系统先调用onPause方法,然后调用onStop方法,最后调用onDestory方法,结束当前Activity。

Activity有三个关键的循环

  1. 整个的生命周期:
    从onCreate(Bundle)开始到onDestroy()结束。Activity在onCreate()设置所有的“全局”状态,在onDestory()释放所有的资源。例如:某个Activity有一个在后台运行的线程,用于从网络下载数据,则该Activity可以在onCreate()中创建线程,在onDestory()中停止线程。
  2. 可见的生命周期:
    从onStart()开始到onStop()结束。在这段时间,可以看到Activity在屏幕上,尽管有可能不在前台,不能和用户交互。在这两个接口之间,需要保持显示给用户的UI数据和资源等,例如:可以在onStart中注册一个IntentReceiver来监听数据变化导致UI的变动,当不再需要显示时候,可以在onStop()中注销它。onStart(),onStop()都可以被多次调用,因为Activity随时可以在可见和隐藏之间转换。
  3. 前台的生命周期:
    从onResume()开始到onPause()结束。在这段时间里,该Activity处于所有 Activity的最前面,和用户进行交互。Activity可以经常性地在resumed和paused状态之间切换,例如:当设备准备休眠时,当一个 Activity处理结果被分发时,当一个新的Intent被分发时。所以在这些接口方法中的代码应该属于非常轻量级的。

如果Activity被系统回收了,如何保存临时数据和状态?

onSaveInstanceState()
这个方法保证一定在活动被回收之前调用,所以我们可以试用这个方法来解决活动被回收时数据得不到保存的问题; onSaveInstanceState()方法会携带一个 Bundle 类型的参数,Bundle 提供了一系列的方法用于保存数据,比如可以使用 putString()方法保存字符串,使用 putInt()方法保存整型数据,以此类推。每个保存方法需要传入两个参数,第一个参数是键,用于后面从 Bundle 中取值,第二个参数是真正要保存的内容。

保存数据:

@Overrideprotected void onSaveInstanceState(Bundle outState) {    super.onSaveInstanceState(outState);    String tempData = "Something you just typed";    outState.putString("data_key", tempData);}

恢复保存数据:
在onCreate()方法有一个 Bundle类型的参数。这个参数在一般情况下都是null,但是当活动被系统回收之前有通过 onSaveInstanceState()方法来保存数据的话,这个参数就会带有之前所保存的全部数据,我们只需要再通过相应的取值方法将数据取出即可。

@Overrideprotected void onCreate(Bundle savedInstanceState) {    super.onCreate(savedInstanceState);    Log.d(TAG, "onCreate");    requestWindowFeature(Window.FEATURE_NO_TITLE);    setContentView(R.layout.activity_main);    if (savedInstanceState != null) {        String tempData = savedInstanceState.getString("data_key");    Log.d(TAG, tempData);}……}

三、Activity的启动模式

Activity启动模式一共有四种,分别是 standard、singleTop、singleTask 和 singleInstance,可以在 AndroidManifest.xml 中通过给activity标签指定android:launchMode属性来选择启动模式。

  • standard:

    活动默认的启动模式, Android 是使用返回栈来管理活动的,在 standard 模式(即默认情况)下,每当启动一个新的活动,它就会在返回栈中入栈,并处于栈顶的位置。对于使用standard 模式的活动,系统不会在乎这个活动是否已经在返回栈中存在,每次启动都会创建该活动的一个新的实例。

  • singleTop:
    当活动的启动模式指定为 singleTop,在启动活动时如果发现返回栈的栈顶已经是该活动,则认为可以直接使用它,不会再创建新的活动实例。使用 singleTop 模式可以很好地解决重复创建栈顶活动的问题。

  • singleTask:
    当活动的启动模式指定为 singleTask,每次启动该活动时系统首先会在返回栈中检查是否存在该活动的实例,如果发现已经存在则直接使用该实例,并把在这个活动之上的所有活动统统出栈,如果没有发现就会创建一个新的活动实例。

  • singleInstance:
    当活动的启动模式指定为 singleInstance 模式,活动会启用一个新的返回栈来管理这个活动。假设我们的程序中有一个活动是允许其他程序调用的,如果我们想实现其他程序和我们的程序可以共享这个活动的实例,应该如何实现呢?使用前面三种启动模式肯定是做不到的,因为每个应用程序都会有自己的返回栈,同一个活动在不同的返回栈中入栈时必然是创建了新的实例。而使用singleInstance 模式就可以解决这个问题,在这种模式下会有一个单独的返回栈来管理这个活动,不管是哪个应用程序来访问这个活动,都共用的同一个返回栈,也就解决了共享活动实例的问题。

四、Activity的实践

1. 如何根据程序当前的界面判断出这是那一个Activity?

首先需要创建一个BaseActivity继承自Activity,然后在BaseActivity中重写onCreate()方法,如下:

public class BaseActivity extends Activity {@Overrideprotected void onCreate(Bundle savedInstanceState) {    super.onCreate(savedInstanceState);    Log.d("BaseActivity", getClass().getSimpleName());}}

接下来我们需要让 BaseActivity 成为 ActivityTest 项目中所有活动的父类。修改 FirstActivity、SecondActivity和 ThirdActivity的继承结构,让它们不再继承自 Activity,而是继承自 BaseActivity。虽然项目中的活动不再直接继承自 Activity 了,但是它们仍然完全继承了Activity中的所有特性。现在每当进入到一个活动的界面,该活动的类名就会被打印出来。

2. 随时随地退出程序

新建一个 ActivityCollector 类作为活动管理器,代码如下所示:

public class ActivityCollector {    public static List<Activity> activities = new ArrayList<Activity>();    public static void addActivity(Activity activity) {        activities.add(activity);    }    public static void removeActivity(Activity activity) {        activities.remove(activity);    }    public static void finishAll() {        for (Activity activity : activities) {            if (!activity.isFinishing()) {                activity.finish();            }        }    }}

在活动管理器中,我们通过一个 List来暂存活动,然后提供了一个 addActivity()方法用于向 List 中添加一个活动,提供了一个 removeActivity()方法用于从 List 中移除活动,最后提供了一个 finishAll()方法用于将 List中存储的活动全部都销毁掉。

接下来修改 BaseActivity中的代码,如下所示:

public class BaseActivity extends Activity {    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        Log.d("BaseActivity", getClass().getSimpleName());        ActivityCollector.addActivity(this);    }    @Override    protected void onDestroy() {        super.onDestroy();        ActivityCollector.removeActivity(this);    }}

在 BaseActivity 的 onCreate()方法中调用了 ActivityCollector 的 addActivity()方法,表明将当前正在创建的活动添加到活动管理器里。然后在 BaseActivity中重写 onDestroy()方法,并调用了 ActivityCollector 的 removeActivity()方法,表明将一个马上要销毁的活动从活动管理器里移除。

从此以后,不管你想在什么地方退出程序,只需要调用 ActivityCollector.finishAll()方法
就可以了。例如在 ThirdActivity 界面想通过点击按钮直接退出程序,只需将代码改成如下
所示:

public class ThirdActivity extends BaseActivity {    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        Log.d("ThirdActivity", "Task id is " + getTaskId());        requestWindowFeature(Window.FEATURE_NO_TITLE);        setContentView(R.layout.third_layout);        Button button3 = (Button) findViewById(R.id.button_3);        button3.setOnClickListener(new OnClickListener() {            @Override            public void onClick(View v) {                ActivityCollector.finishAll();            }        });    }}

当然你还可以在销毁所有活动的代码后面再加上杀掉当前进程的代码,以保证程序完全退出。

3. 启动活动的最佳写法

真正的项目开发中经常会有对接的问题出现。比如 SecondActivity并不是由你开发的,但现在你负责的部分需要有启动SecondActivity 这个功能,而你却不清楚启动这个活动需要传递哪些数据。
代码如下:

public class SecondActivity extends BaseActivity {    public static void actionStart(Context context, String data1, String data2) {        Intent intent = new Intent(context, SecondActivity.class);        intent.putExtra("param1", data1);        intent.putExtra("param2", data2);        context.startActivity(intent);    }……}

我们在 SecondActivity中添加了一个 actionStart()方法,在这个方法中完成了 Intent的构建,另外所有 SecondActivity中需要的数据都是通过 actionStart()方法的参数传递过来的,然后把它们存储到 Intent 中,最后调用 startActivity()方法启动 SecondActivity。这样,我们对参数就能一目了然啦。

现在我们在其他的Activity中启动SecondActivity只需要如下代码即可启动:

button1.setOnClickListener(new OnClickListener() {    @Override    public void onClick(View v) {        SecondActivity.actionStart(FirstActivity.this, "data1", "data2");    }});

参考学习:第一行代码

0 0
原创粉丝点击