Android学习笔记---四大组件之Activity活动详解

Activity是所有程序的根本,所有程序的流程都运行在Activity 之中,Activity是由Android系统进行维护的,它的一个产生、运行、销毁即为一个生命周期,这里分别从以下4个方面记录学习下Activity的以下用法:
1.Activity中的方法以及生命周期
2.状态的保存onSaveInstanceState()和恢复onRestoreInstanceState()
3.Activity的启动模式
4.Activity切换过程中Intent传值

1.Activity中的方法以及生命周期

和很多解释Activity的文档一样,这里也先引用一张很经典讲解Activity生命周期的图:

可以看到,Activity 类中定义了七个回调方法,而我们的重点也是需要理清楚这七个方法的使用场景,我们通过打印出两个Activity间切换各个方法的调用情况为切入点来一个个梳理这些方法。
启动MainActivity的截图:
Android学习笔记---四大组件之Activity活动详解_第1张图片
启动SecondActivity的截图:
Android学习笔记---四大组件之Activity活动详解_第2张图片

Activity1即MainActivity.java的代码如下:

package com.example.androidstudyactivity;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
public class MainActivity extends Activity {
    private Button button1;
    String TAG = "data";
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Log.d(TAG, "onCreate1");
        setContentView(R.layout.activity_main);
        button1 = (Button) findViewById(R.id.bt1); 
        button1.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent(MainActivity.this, SecondActivity.class);
                startActivity(intent);
            }
        });
    }
    @Override
    protected void onStart() {
        super.onStart();
        Log.d(TAG, "onStart1");
    }
    @Override
    protected void onResume() {
        super.onResume();
        Log.d(TAG, "onResume1");
    }
    @Override
    protected void onPause() {
        super.onPause();
        Log.d(TAG, "onPause1");
    }
    @Override
    protected void onStop() {
        super.onStop();
        Log.d(TAG, "onStop1");
    }
    @Override
    protected void onDestroy() {
        super.onDestroy();
        Log.d(TAG, "onDestroy1");
    }
    @Override
    protected void onRestart() {
        super.onRestart();
        Log.d(TAG, "onRestart1");
    }
}

Activity2即SecondActivity.java的代码如下:

package com.example.androidstudyactivity;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
public class SecondActivity extends Activity {
    private Button button2;
    String TAG = "data";
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Log.d(TAG, "onCreate2");
        setContentView(R.layout.activity_main2);
        button2 = (Button) findViewById(R.id.bt2); 
        button2.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent(SecondActivity.this, MainActivity.class);
                startActivity(intent);
            }
        });
    }

    @Override
    protected void onStart() {
        super.onStart();
        Log.d(TAG, "onStart2");
    }
    @Override
    protected void onResume() {
        super.onResume();
        Log.d(TAG, "onResume2");
    }
    @Override
    protected void onPause() {
        super.onPause();
        Log.d(TAG, "onPause2");
    }
    @Override
    protected void onStop() {
        super.onStop();
        Log.d(TAG, "onStop2");
    }
    @Override
    protected void onDestroy() {
        super.onDestroy();
        Log.d(TAG, "onDestroy2");
    }
    @Override
    protected void onRestart() {
        super.onRestart();
        Log.d(TAG, "onRestart2");
    }
}

现在我们一起来看下从Activity1启动到切换到Activity2再切回Activity1,以及按下BACK键以及HOME键再重新进入Activity过程中回调方法的调用情况。

启动Activity
Activity1依次调用onCreate()->onStart()->onResume()方法
这里写图片描述
Activity1跳转到Activity2
Activity1调用onPause()方法,然后Activity2依次调用onCreate()->onStart()->onResume()方法,最后Activity1调用onStop()方法,这里可能比较疑惑的是为什么要Activity1会先调用onPause()方法,这里我抓取了一个切换过程中的截图就知道了,在Activity2覆盖Activity1的过程中,Activity1有一个可见到不完全可见到完全不可见的过程,而onPause()方法证书不完全可见即不能与用户交互过程中调用的,当Activity2完全覆盖住Activity1后Activity1就会调用onStop()方法。 onPause()方法另外一个比较常见的是在对话框组件不完全覆盖当前Activity的时候会调用。

这里写图片描述
Activity2返回到Activity1
和上面的相反,Activity2调用onPause()方法,然后Activity1依次调用onCreate()->onStart()->onResume()方法,最后Activity2调用onStop()方法。
这里写图片描述
以上基础按BACK键第1次返回到Activity2
BACK键相当于结束程序,所以最终当前的Activity是会调用onDestory()方法,Activity1调用onPause()方法,然后Activity2调用onRestart()->onStart()->onResume(), 最后Activity1调用onStop()->onDestory()方法。
这里写图片描述
以上基础按BACK键第2次返回到Activity1
看下面的图就明白了,这里不再分析:
这里写图片描述
以上基础按BACK键第3次(完全退出)
看下面的图就明白了,这里不再分析:
这里写图片描述

新启动后HOME键
同样,当前Activity也是有不完全可见到完全不可见的过程,所以依次调用onPause()->onStop()这两个方法,这时候应用程序并没有销毁:

再次进入程序
Activity分别执行了onRestart()->onStart()->onResume()三个方法:
这里写图片描述

通过以上的例子,我们可以总结各个方法在Activity中的调用的情况:
1. onCreate()
这个方法在活动开始创建的时候就默认创建了,每个Activity都是需要重写这个方法的,一般在这个方法中完成控件的初始化以及一些控件的监听事件。
2. onStart()
这个方法在活动变成和用户可见不可交互的时候调用
3. onResume()
这个方法在活动变成和用户可见可交互的时候调用
4. onPause()
这个方法在活动变成和用户可见不可交互的时候调用,系统会停止动画等消耗CPU 的事情,应该在这里保存你的一些数据,因为这个时候你的程序的优先级降低,有可能被系统收回。在这里保存的数据,应该在onResume里读出来,注意:这个方法里做的事情时间要短,因为下一个activity不会等到这个方法完成才启动。
5. onStop()
变得不可见 ,被下一个activity覆盖了
6. onDestroy()
这个方法在活动被销毁之前调用(一般是按了BACK键)之后活动的状态将变为销毁状态,一般用在于完成释放内存的操作。
7. onRestart()
这个方法在活动由停止状态onStop或者onDestory状态变为运行状态onStart之前调用,也就是活动被重新启动了。

另外,也有一些规律比如onCreate()->onStart()->onResume()是会紧接着先后完成的,然后onRestart()->onStart()->onResume()也是会紧接着先后完成的。按BACK键一定会onDestroy()当前Activity且是最后调用的。

但问题是为什么要细分出这么多方法呢,我们之前的所有写的Activity中都只是重写了onCreate()方法就都实现了,为什么不设计出这一个方法就可以了呢,其余的方法一般具体是怎样使用的呢,这是我学习Activity中会去思考的问题,这里我结合网上的一些资料给出一些疑问的解答。
1.onPause()方法一般用在什么地方
上面讲的Activity1跳转到Activity2,为什么是Activity1调用onPause()方法,然后Activity2依次调用onCreate()->onStart()->onResume()方法,最后Activity1调用onStop()方法的顺序,考虑一下如下场景:
如果Activity1打开了相机,我们点击某按钮要跳转到Activity2中,Activity2也想打开相机;假设Activity1的onPause()在 Activity2启动后再被调用,那Activity2根本就无法再正常启动相机,所以我们也可以看到对于类似这种类型的操作,我们的onPause()方法就有用场了,比如关闭独占设备,关闭动画,或其它耗费cpu的操作,以防止Activity2也需要使用这些资源,关闭耗CPU的操作,也有利于Activity2运行的流畅。
2.onDestroy()方法一般用在什么地方
经过上面的分析,onDestory()中完成的也是一些资源的释放,关闭独占设备,关闭动画,或其它耗费cpu的操作,如果Activity有一个线程在后台运行从网络下载数据,它会在onCreate()创建线程,当我们将Activity销毁的时候,有的场景就需要结束这个线程,这个时候我们就要用到onDestory()方法。
3.onStart()方法一般用在什么地方
当用户不再看见我们显示的内容时,我们可以在onStart()中注册一个BroadcastReceiver来监控会影响UI的变化,而在onStop()中来注消。

更多的一些具体的用法我们在以后的学习中再通过具体的例子来展示。

2.状态的保存onSaveInstanceState()和恢复onRestoreInstanceState()

Activity中除了提供以上七个方法之外,还有两个比较重要的方法onSaveInstanceState()状态的保存和onRestoreInstanceState()状态的恢复,但它们并不是生命周期方法,它们不同于onCreate(),onPause()等生命周期方法,它们并不一定会被触发,onSaveInstanceState()的调用遵循一个重要原则,即当系统存在出现意外“未经你许可”时销毁了我们的activity的可能时,则onSaveInstanceState()会被系统调用,这是系统的责任,因为它必须要提供一个机会让你保存你的数据(当然你不保存那就随便你了),当用户主动去销毁一个Activity时,例如在应用中按返回键,onSaveInstanceState()就不会被调用。因为在这种情况下,用户的行为决定了不需要保存Activity的状态。

意外情况比如如内存不足: 应用中有一个活动A,用户在活动A的基础上启动了活动B,活动A就进入了停止状态,这个时候由于系统内存不足,将活动A回收掉了,然后用户按下BACK键返回活动A, 这是活动A的一些临时数据就会丢失了我们可以通过这个方法来解决活动被回收时临时数据得不到保存的问题。
当用户按下HOME键时也是很有可能调用onSaveInstanceState()方法的,这是显而易见的,系统不知道你按下HOME后要运行多少其他的程序,自然也不知道activity是否会被销毁,因此系统会调用onSaveInstanceState(),让用户有机会保存某些非永久性的数据。以下几种情况的分析都遵循该原则:
长按HOME键,选择运行其他的程序时。
按下电源按键(关闭屏幕显示)时。
从activity A中启动一个新的activity时。
屏幕方向切换时,例如从竖屏切换到横屏时。

而我们可以在onRestoreInstanceState()或者干脆直接在onCreate()方法中来获取这些被onSaveInstanceState()方法保存下来的数据。获取这些数据的原则是activity“确实“被系统意外销毁了,如果仅仅是停留在有这种可能性的情况下,则该方法不会被调用,例如,当正在显示activity的时候,用户按下HOME键回到主界面,然后用户紧接着又返回到activity,这种情况下activity一般不会因为内存的原因被系统销毁,故activity的onRestoreInstanceState方法不会被执行此。

更详细的区别可以参考onSaveInstanceState和onRestoreInstanceState

下面我们提供以一个具体的例子来看下这两个方法的使用情况:在Activity1中有一个文本输入框且里面有输入内容的情况下跳转到Activity2中,然后再Activity2返回到Activity1输入框里面的内容需要完整显示出来。

具体的代码布局文件的代码这里就不给了,直接给出两个Activity中的效果图如下:
Android学习笔记---四大组件之Activity活动详解_第3张图片
Android学习笔记---四大组件之Activity活动详解_第4张图片

因为我是在Android虚拟机里面模拟的,每当我在Activity1中输入一段字符然后提交到Activity2后再返回Edittext中的文字都是丢失了的,因为系统都回收了他们。

我们会发现之前所有的创建的Activity中继承的onCreate()方法都默认传递了一个Buddle类型的参数,然后都调用了父类中的一个方法super.onCreate(savedInstanceState);所以我们在onCreate()方法中就可以完成状态的恢复功能了。

protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
}

所以用这两个方法之前我先解释下Android中的Bundle类的概念,其实很简单,Bundle类是一个key-value对,我们可以建一个Bundle类,在Bundle类中加入数据(key -value的形式),然后需要取数据的时候,用相应的key找出对应的value就可以了,一般用法如下:

Bundle mBundle = new Bundle(); 
//存放数据的一些例子
mBundle.putBoolean("MyBoolean", true);
mBundle.putDouble("myDouble", 1.9);
mBundle.putInt("MyInt", 1);
mBundle.putString("MyString", "Welcome back to Android");
//从mBundle中取数据
boolean myBoolean = mBundle.getBoolean("MyBoolean");
double myDouble = mBundle.getDouble("myDouble");
int myInt = mBundle.getInt("MyInt");
String myString = mBundle.getString("MyString");

我这里给出Activity1中用到onSaveInstanceState()和onRestoreInstanceState()方法的代码:

package com.example.androidstudyactivity;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;

public class MainActivity extends Activity {
    private Button button;
    private EditText edittext;
    String savetext;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        button = (Button) findViewById(R.id.bt1);
        edittext = (EditText) findViewById(R.id.et);

        //直接在onCreate方法中恢复
        if(savedInstanceState != null){
            savetext = savedInstanceState.getString("data_key");
            Log.d("savedata", "onCreate中savetext执行");
            edittext.setText(savetext);
        }

        button.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent(MainActivity.this, SecondActivity.class);
                startActivity(intent);
            }
        });
    }

    @Override
    protected void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        Log.d("savedata", "onSaveInstanceState方法执行");
        savetext = edittext.getText().toString();
        Log.d("savedata", savetext);
        outState.putString("data_key", savetext);
    }

    //通过onRestoreInstanceState()方法恢复
    @Override
    protected void onRestoreInstanceState(Bundle savedInstanceState) {
        super.onRestoreInstanceState(savedInstanceState);
        Log.d("savedata", "onRestoreInstanceState方法执行");
        if(savedInstanceState != null){
            savetext = savedInstanceState.getString("data_key");
            edittext.setText(savetext);
        }
    }
}

3.Activity的启动模式

在上面介绍Android的生命周期的时候,我们从启动Activity1->然后Activity1跳转到Activity2->Activity2返回到Activity1, 这个时候我们发现按BACK键其实是需要按3次才能够完全退出程序的,这样如果对于Activity切换频繁(加入切换了N次)的程序来说,我想用BACK键来退出程序,就需要按N次BACK键才可以,这样显然是对用户不友好的,所以我们必须要学习下活动的启动模式。

首先解释下Android的启动模式的作用,它主要是在多个Activity跳转的过程中扮演着重要的角色,它可以决定是否生成新的Activity实例,是否重用已存在的Activity实例,是否和其他Activity实例共用一个任务(Task)里,这里我还是介绍一下Android中的Task的概念,以便理解Android的四种启动模式。
Android是用Task来管理Activity的,一个Task就是一组存放在栈里的Activity的集合,在默认情况下, 每当我们启动了一个新的Activity,它会在栈中入栈, 并处于栈顶的位置,而每当我们按下BACK键或调用 finish()方法去销毁一个Activity时,处于栈顶的Activity会出栈, 这时前一个入栈的Activity就会重新处于栈顶的位置,系统总是会显示处于栈顶的Activity给用户。

Activity一共有以下四种启动模式:
1.standard
2.singleTop
3.singleTask
4.singleInstance
我们直接在AndroidManifest.xml配置<activity>标签中配置android:launchMode属性为以上四种之一即可, 如下示例:

<activity 
    android:name=".SecondActivity"> 
    android:launchMode = "standard"
    //android:launchMode = "singleTop"
    //android:launchMode = "singleTask"
    //android:launchMode = "singleInstance"
</activity>

1.standard模式
standard模式是默认的启动模式,不用为<activity>配置android:launchMode属性即可,当然也可以指定值为standard。在standard模式下,每当启动一个新的Activity, 它就会在返回栈中入栈, 并处于栈顶的位置, 对于使用standard模式的Activity,系统不会在乎这个Activity是否已经在返回栈中存在, 每次启动都会创建该Activity的一个新的实例。

我们通过一个具体的实例演示下:

package com.example.androidstudyactivitylaunchmode;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.Window;
import android.widget.Button;

public class FirstActivity extends Activity {
    private Button button;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Log.d("launchMode", this.toString());
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        setContentView(R.layout.activity_main);
        button = (Button) findViewById(R.id.bt);
        button.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                //FirstActivity跳转到FirstActivity
                Intent intent = new Intent(FirstActivity.this, FirstActivity.class);
                startActivity(intent);
            }
        });

    }
}

这个是程序的界面截图:
Android学习笔记---四大组件之Activity活动详解_第5张图片
以下是点击三次按钮,Logcat打印出来的信息截图:
这里写图片描述
从打印信息中我们就可以看出,每点击一次按钮就会创建出一个新的 FirstActivity 实例。此时返回栈中也会存在三个 FirstActivity 的实例,因此你需要连按三次BACK键才能退出程序。

可以看出standard模式的原理如下图所示:
Android学习笔记---四大组件之Activity活动详解_第6张图片
每次跳转系统都会在task中生成一个新的FirstActivity实例,并且放于栈结构的顶部,当我们按下BACK键时,才能看到原来的FirstActivity实例。
这就是standard启动模式,不管有没有已存在的实例,都生成新的实例。

2.singleTop启动模式
可能在有些情况下,你会觉得 standard 模式不太合理。活动明明已经在栈顶了,为什么再次启动的时候还要创建一个新的活动实例呢? 别着急,这只是系统默认的一种启动模式而已, 你完全可以根据自己的需要进行修改,比如说使用 singleTop 模式。当活动的启动模式 指定为 singleTop,在启动活动时如果发现返回栈的栈顶已经是该活动,则认为可以直接使用它,不会再创建新的活动实例。
我在AndroidManifest.xml中将FirstActivity启动模式改成singleTop后再次运行点击按钮Logcat的截图如下,会看到已经创建了一个 FirstActivity 的实例:

但是之后不管你点击多少次按钮都不会再有新的打印信息出现,因为目前 FirstActivity 已经处于返回栈的栈顶,每当想要再启动一个 FirstActivity 时都会直接使用栈顶的活动,因 此 FirstActivity 也只会有一个实例,仅按一次 Back 键就可以退出程序。
可以看出singleTop模式的原理如下图所示:

不过当 FirstActivity 并未处于栈顶位置时, 这时再启动 FirstActivity,还是会创建新的实例,我们再新建一个Activity命名为SecondActivity并且修改下FirstActivity中的代码跳转到SecondActivity,SecondActivity代码如下:

package com.example.androidstudyactivitylaunchmode;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.Window;
import android.widget.Button;

public class SecondActivity extends Activity {
    private Button button;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Log.d("launchMode", this.toString());
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        setContentView(R.layout.activity_main2);
        button = (Button) findViewById(R.id.bt);
        button.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                //SecondActivity跳转到FirstActivity
                Intent intent = new Intent(SecondActivity.this, FirstActivity.class);
                startActivity(intent);
            }
        });

    }
}

下面是两个Activity界面截图
Android学习笔记---四大组件之Activity活动详解_第7张图片
Android学习笔记---四大组件之Activity活动详解_第8张图片
下面给出Logcat中按两次按钮后打印的信息的截图:
这里写图片描述

可以看到系统创建了两个不同的 FirstActivity 实例,这是由于在 SecondActivity 中再次启动 FirstActivity 时,栈顶活动已经变成了 SecondActivity,因此会创建一个新的 FirstActivity 实例。现在按下BACK 键会返回到 SecondActivity,再次按下 BACK 键又会回到 FirstActivity, 再按一次BACK键才会退出程序。
原理如下:
Android学习笔记---四大组件之Activity活动详解_第9张图片
这就是singleTop启动模式,如果发现有对应的Activity实例正位于栈顶,则重复利用,不再生成新的实例。

3.singleTask启动模式

使用 singleTop 模式可以很好地解决重复创建栈顶活动的问题,但是正如上面看到的,如果该活动并没有处于栈顶的位置,还是可能会创建多个活动实例的。那么有没有什么办法可以让某个活动在整个应用程序的上下文中只存在一个实例呢?这就要借助 singleTask 模式来实现了。当活动的启动模式指定为 singleTask,每次启动该活动时系统首先会在返回栈中检查是否存在该活动的实例,如果发现已经存在则直接使用该实例,并把在这个活动之上的所有活动统统出栈, 如果没有发现就会创建一个新的活动实例。

我们修改FirstActivity的属性android:launchMode=”singleTask”。演示的结果如下:
这里写图片描述
在上面的过程中,FirstActivity的序列号是不变的,SecondActivity的序列号却不是唯一的,说明从SecondActivity跳转到FirstActivity时,没有生成新的实例,但是从FirstActivity跳转到SecondActivity时生成了新的实例。

我们再在FirstActivity中onRestart()中添加如下代码:

@Override
protected void onRestart() {
    super.onRestart();
    Log.d("launchMode", "FirstActivity启动了onRestart方法");
}

在SecondActivity中onDestory()中添加如下代码:

protected void onDestroy() {
    super.onDestroy();
    Log.d("launchMode", "SecondActivity启动了onDestroy()方法");
}

运行的时候我们多点击几次按钮Logcat的截图如下:

这里我们会看到在SecondActivity返回到FirstActivity的过程中,最后的SecondActivity是会调用onDestory()方法的,现在返回栈中只剩下一个 FirstActivity 的实例了, 按一下 Back 键就可以退出程序。
而这个方法我们最开始讲Activity的生命周期的时候按下BACK键才会调用这个方法的,如果是普通的返回键最后只会调用onStop()方法。

singleTask模式的原理图如下图所示:
Android学习笔记---四大组件之Activity活动详解_第10张图片
这就是singleTask模式,如果发现有对应的Activity实例,则使此Activity实例之上的其他Activity实例统统出栈,使此Activity实例成为栈顶对象,显示到幕前。

4.singleInstance启动模式

singleInstance模式应该算是四种启动模式中最特殊也最复杂的一个了,不同于以上三种启动模式, 指定为singleInstance模式的活动会启用一个新的返回栈来管理这个活动(其实如果 singleTask 模式指定了不同的 taskAffinity,也会启动一个新的返回栈)。那么这样做有什么意义呢?想象以下场景,假设我们的程序中有一个活动是允许其他程序调用的, 如果我们想实现其他程序和我们的程序可以共享这个活动的实例,应该如何实现呢?使用前面三种启动模式肯定是做不到的,因为每个应用程序都会有自己的返回栈,同一个活动在不同的返回栈中入栈时必然是创建了新的实例。而使用 singleInstance模式就可以解决这个问题,在这种模式下会有一个单独的返回栈来管理这个活动,不管是哪个应用程序来访问这个活动, 都共用的同一个返回栈,也就解决了共享活动实例的问题。

我们在上面代码的基础上讲FirstActivity设置为standard模式,将SecondActivity设置为singleInstance模式,然后来启动过程中分别打印下它们的Task id,可以看到截图如下:

从FirstActivity跳转到SecondActivity时,重新启用了一个新的栈结构,来放置SecondActivity实例,然后按下后退键,再次回到原始栈结构, 再次BACK后退出,流程将会如图所示:
Android学习笔记---四大组件之Activity活动详解_第11张图片
我们也可以看到Logcat中的截图如下,主要看下onDestory()方法的调用的情况:
这里写图片描述

如果在SecondActivity中再次跳转到FirstActivity,这个时候系统会在原始栈结构中生成一个FirstActivity实例,然后回退两次,注意,并没有退出,而是回到了SecondActivity,为什么呢?是因为从SecondActivity跳转到FirstActivity的时候,我们的起点变成了SecondActivity实例所在的栈结构,这样一来,我们需要“回归”到这个栈结构,流程图所示:
Android学习笔记---四大组件之Activity活动详解_第12张图片
LogCat打印的信息如下,因为我们设置的FirstActivity的启动模式为stand模式,这样每次回到FirstActivity的时候会创建一个新的实例,而我们想要完全退出程序,是需要所有实例都onDestory()的。

所以如果我们将FirstActivity的启动模式改成singleTop、singleTask、singleInstance中的任意一个,流程将会如图所示:
Android学习笔记---四大组件之Activity活动详解_第13张图片
我们可以看到Logcat中打印出来的信息,因为返回到FirstActivity后是没有再次创建新的实例的。

4.Activity切换过程中Intent传值

关于Activity相互跳转过程中值的传递也是我们需要好好掌握的,我们学习了状态的保存onSaveInstanceState()和恢复onRestoreInstanceState()这两个方法是可以保存与恢复一些数据的,这里我们通过讲解Intent的用法,Intent 中提供了一系列 putExtra()方法的重载,可 以把我们想要传递的数据暂存在 Intent 中,启动了另一个活动后,只需要把这些数据再从 Intent 中取出就可以了,这有点像我们通过表单给Servlet发送一组数据,Servlet得到这些数据之后进行解析出来就可以了, Intent中存放数据也可以是key-value的形式,正是因为这样,所以可以将Bundle中的数据直接给Intent使用,关于Intent和Bundle的区别可以参考: Intent 传值和 Bundle传值的区别

Intent向下一个活动传递数据:
第一步,在Activity A中通过Intent添加需要传送的数据:

//Activity A 传递数据, 在A中添加需要传递的数据,方法一
Intent intent = new Intent(A.this, B.class); 
intent.putExtra("name", "dxy");
intent.putExtra("age", 25);
startActivity(intent);

//Activity A 传递数据, 在A中添加需要传递的数据,通过bundle的方法
Intent intent = new Intent(A.this, B.class);  
Bundle bundle = new Bundle();
bundle.putString("name", "dxy");
bundle.putInt("age", 25);
intent.putExtras(bundle); 
startActivity(intent);

第二步,在Activity B中解析出这些数据:

// 获取参数1
Intent intent = this.getIntent(); 
String name = intent.getStringExtra("name");
int age = intent.getIntExtra("age", 25); // 缺省值为22

// 获取参数2
Bundle bundle = intent.getExtras();
String name2 = bundle.getString("name");
int age2 = bundle.getInt("age", 25);

这里给出两个Activity的代码:
FirstActivity代码如下:

package com.example.androidstudyactivitylaunchmode;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.Window;
import android.widget.Button;

public class FirstActivity extends Activity {
    private Button button;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        setContentView(R.layout.activity_main);
        button = (Button) findViewById(R.id.bt);
        button.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent(FirstActivity.this, SecondActivity.class);
                intent.putExtra("name","dxy");
                intent.putExtra("age",25);
                startActivity(intent);
            }
        });
    }
}

SecondActivity代码如下:

package com.example.androidstudyactivitylaunchmode;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.view.Window;

public class SecondActivity extends Activity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        Intent intent = this.getIntent(); 
        String name = intent.getStringExtra("name");
        int age = intent.getIntExtra("age", 25);
        Log.d("Intent", "name is " + name);
        Log.d("Intent", "age is " + age);
    }
}

可以看到切换到SecondActivity后Logcat打印出的信息:
这里写图片描述

Intent返回数据给上一个活动:
既然可以传递数据给下一个活动, 那么我们也是可以返回数据给上一个活动的,不过相比第一种情况还是复杂一点。

具体的做法和之前是不一样的地方:
1.从A页面跳转到B页面时不可使用startActivity()方法,而要使用startActivityForResult()方法
2.在A页面的Activity中,需要重写onActivityResult(int requestCode, int resultCode, Intent data)方法
这里直接给出两个Activity中的代码以及一些方法的具体解释:
FirstActivity代码如下:

package com.example.androidstudyactivitylaunchmode;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.Window;
import android.widget.Button;

public class FirstActivity extends Activity {
    private Button button;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        setContentView(R.layout.activity_main);
        button = (Button) findViewById(R.id.bt);
        button.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent(FirstActivity.this, SecondActivity.class);
                //使用了 startActivityForResult()方法来启动 SecondActivity,请求码只要是一个唯一值就可以了,这里传入了1
                startActivityForResult(intent,1);
            }
        });
    }

    /*在 SecondActivity 被销毁之后会回调上一个活动的onActivityResult()方法,因此我们需要在FirstActivity中重写这个方法来得到返回的数据 onActivityResult()方法带有三个参数,第一个参数 requestCode,即我们在启动活动时传入的请求码 第二个参数 resultCode,即我们在返回数据时传入的处理结果。 第三个参数 data, 即携带着返回数据的 Intent。*/
    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        /*由于在一个活动中有可能调用 startActivityForResult()方法去启动很多不同的活动, 每一个活动返回的数据都会回调到 onActivityResult()这个方法中, 因此我们首先要做的就是通过检查 requestCode 的值来判断数据来源。 确定数据是从SecondActivity 返回的之后,我们再通过resultCode的值来判断处理结果是否成功。 最后从 data 中取值并打印出来,这样就完成了向上一个活动返回数据的工作。*/
        switch (requestCode) {
        case 1:
            if(requestCode == RESULT_OK){
                String name = data.getStringExtra("name");
                int age = data.getIntExtra("age", 25);
                Log.d("Intent", "name is " + name);
                Log.d("Intent", "age is " + age);
            }
            break;
        default:
        }
    }

}

SecondActivity代码如下:

package com.example.androidstudyactivitylaunchmode;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.Window;
import android.widget.Button;

public class SecondActivity extends Activity {
    private Button button;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        requestWindowFeature(Window.FEATURE_NO_TITLE);
        setContentView(R.layout.activity_main2);
        button = (Button) findViewById(R.id.bt);
        button.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                /*还是构建了一个 Intent,只不过这个 Intent 仅仅是用于传递数据而已, 它没有指定任何的“意图”。紧接着把要传递的数据存放在 Intent 中, 然后调用了 setResult()方法。这个方法非常重要,是专门用于向上一个活动返回数据的。 setResult()方法接收两个参数,第一个参数用于向上一个活动返回处理结果,一般只使用 RESULT_OK 或 RESULT_CANCELED 这两个值, 第二个参数则是把带有数据的 Intent 传递回去*/
                Intent intent = new Intent();
                intent.putExtra("name","dxy");
                intent.putExtra("age",25);
                setResult(RESULT_OK, intent);
                //调用finish方法结束Activity
                finish();
            }
        });

    }
    //按下BACK键回到 FirstActivity数据返回,重写onBackPressed()方法
    @Override
    public void onBackPressed() {
        Intent intent = new Intent();
        intent.putExtra("name","dxy");
        intent.putExtra("age",25);
        setResult(RESULT_OK, intent);
        finish();
    }
}

这篇关于Activity的文章写得时间比较长,整体下来篇幅也比较长,参考了很多blog以及第一行代码这本书,有很多觉得写得比较好的语句就直接复制过来了,不过代码都是自己亲自都跑了一遍,主要是希望将Activity将清楚,因为Activity应该是Android中最最需要了解的一个知识点,没有Activity就没有Android程序应用程序,当然关于Activity还有很多别的知识点,这些我们遇到的时候可以再查看相关资料获取。

不积跬步,无以至千里;不积小流,无以成江海。

你可能感兴趣的:(android)