Android - Intent

Intent

Intent 是 Android 中的各个组件之间交互的一种重要方式,它可以用来启动 Activity、Service 和 BroadcastReceiver,还可以在不同组件之间传递数据。

Intent Filter

  1. Intent Filter 就是用来注册 Activity 、 Service 和 Broadcast Receiver 具有能在某种数据上执行一个动作的能力。使用 Intent Filter,应用程序组件告诉 Android,它们能为其它程序的组件的动作请求提供服务,包括同一个程序的组件、本地的或第三方的应用程序。—— Android开发--Intent-filter属性详解
  2. Intent Filter 负责过滤掉组件本身无法响应和处理的 Intent,只将自己关心的 Intent 接收进来进行处理。—— IntentFilter

Intent 的七大属性

  1. ComponentName: 指定了 ComponentName 属性的 Intent已经明确了它将要启动哪个组件,这种 Intent 被称为显式 Intent;没有指定 ComponentName 属性的 Intent 被称为隐式 Intent。隐式Intent没有明确要启动哪个组件,应用会根据 Intent 指定的规则去启动符合条件的组件。
  2. Action: Action 属性用于指定要执行的动作,一个 Intent 只能设置一个 Action。
  3. Category: Category 属性为 Action 增加额外的附加类别信息。CATEGORY_LAUNCHER 意味着在加载程序的时候 Acticity 出现在最上面,而 CATEGORY_HOME 表示页面跳转到 HOME 界面。一个 Intent 可以添加多个 Category。
  4. Data: Data 属性通常用于向 Action 属性提供操作的数据。Data 属性的值是个 Uri 对象。
    Uri 的格式如下:scheme://host:port/path
    - scheme:用于指定数据的协议部分,如 http
    - host:用于指定数据的主机名部分,如 www.google.com
    - port:用于指定数据的端口部分,跟在主机后面,可以省略
    - path:用于指定主机名和端口之后的部分,通常是资源的路径,可以省略
  5. Type: Type 属性用于指定 Data 所指定的 Uri 对应的 MIME 类型。MIME 只要符合 “abc/xyz” 这样的字符串格式即可。
  6. Extras: Extras 属性用于保存需要传递的额外数据。
  7. Flag: Intent 可调用 addFlags() 方法来为 Intent 添加控制标记。

AndroidManifest.xml 中的 <intent-filter> 标签

<intent-filter> 标签可以包含以下三个元素:

  1. <action>: 一个 <intent-filter> 可以有一个或多个 <action> 用于过滤,到达的 Intent 只需要匹配其中一个 <action> 即可。
  2. <category>: 一个 <intent-filter> 中可以有多个 <category>,只有 Intent 中的所有 Category 都能匹配到 <intent-filter> 中的 <category> 时,Intent 才能通过检查。
  3. <data>: <data> 元素包含的内容为 Uri 和数据类型,<data> 元素中一般不会指定过多的内容。
    - Uri 格式见上面。
    - mimeType:用于指定可以处理的数据类型,可以省略。
  4. 更多内容,请看这篇文章 IntentFilter

Intent 的用法 - 启动组件


Intent 启动组件的方法可以分为两种,分别是显式 Intent 和 隐式 Intent。显式 Intent 必须明确指出要启动的是哪个组件;隐式 Intent 只须指出想要启动的组件的特征,系统就会自动启动符合该特征的组件。

启动组件 - 使用显式 Intent

这里我们以从一个 Activity 跳转到 另一个 Activity 为例。

1. XML 布局文件:

  1. activity_first.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center_horizontal"
    android:orientation="vertical"
    android:paddingBottom="16dp"
    android:paddingLeft="16dp"
    android:paddingRight="16dp"
    android:paddingTop="16dp"
    tools:context=".FirstActivity">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="这是第一个Activity" />

    <Button
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:onClick="startSecondActivity"
        android:text="启动第二个Activity" />

</LinearLayout>
  1. activity_second.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center_horizontal"
    android:orientation="vertical"
    android:paddingBottom="16dp"
    android:paddingLeft="16dp"
    android:paddingRight="16dp"
    android:paddingTop="16dp">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="这是第二个Activity" />

</LinearLayout>

2. Java 代码:

  1. FirstActivity.java
public class FirstActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_first);
    }

    public void startSecondActivity(View view) {
        // 第一个参数为当前上下文,第二个参数为要启动的组件
        Intent intent = new Intent(FirstActivity.this, SecondActivity.class);
        startActivity(intent);
    }

}
  1. SecondActivity.java
public class SecondActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_second);
    }

}
  1. 不要忘了在清单文件 AndroidManifest.xml 中注册第二个 Activity:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="net.monkeychan.intenttest">

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme">
        <activity
            android:name=".FirstActivity"
            android:label="@string/app_name">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <activity android:name=".SecondActivity"></activity>
    </application>

</manifest>
  1. 效果演示:

点击按钮,启动第二个 Activity

启动组件 - 使用隐式 Intent

下面我们使用隐式 Intent 来实现上面的跳转效果。

1. 首先修改 AndroidManifest.xml 成如下:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="net.monkeychan.intenttest">

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme">
        <activity
            android:name=".FirstActivity"
            android:label="@string/app_name">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

        <activity android:name=".SecondActivity">
            <intent-filter>
                <action android:name="net.monkeychan.intenttest.action.START" />
                <category android:name="android.intent.category.DEFAULT" />
            </intent-filter>
        </activity>
    </application>

</manifest>

可以看到,我们给 SecondActivity 配置了 intent-filter,并在 intent-filter 下增加了 action 属性和 category 属性。

2. Java 代码,这里只须修改 FirstActivity.java:

public class FirstActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_first);
    }

    public void startSecondActivity(View view) {
        Intent intent = new Intent("net.monkeychan.intenttest.action.START");
        startActivity(intent);
    }

}
  1. 效果演示:

效果与上面使用显式 Intent 方式启动一样,只不过这里是使用隐式 Intent 方式实现罢了。

使用隐式 Intent 启动系统组件

使用隐式隐式 Intent 除了可以启动同一个应用程序的组件,还可以启动系统或第三方应用程序的组件。下面使用隐式 Intent 来启动系统的组件。

1. 启动拨号界面

  1. XML 布局文件,activity_main.xml:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:paddingBottom="16dp"
    android:paddingLeft="16dp"
    android:paddingRight="16dp"
    android:paddingTop="16dp"
    tools:context=".MainActivity">

    <Button
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="启动拨号界面"
        android:onClick="startDial"/>
</LinearLayout>
  1. Java 代码,MainActivity.java:
public class MainActivity extends AppCompatActivity {

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

   public void startDial(View view) {

       // 1. 创建一个 Intent 对象
       Intent intent = new Intent();

       // 2. 设置 Intent 对象的 Action
       // ACTION_DIAL 是 Intent 中定义的一个常量,查源码可知:
       // public static final String ACTION_DIAL = "android.intent.action.DIAL";
       // 这是 Android 中已经定义好的,事实上 Intent 中还有许多这样的常量
       intent.setAction(Intent.ACTION_DIAL);
       
       // 3. 跳转到对应的组件
       startActivity(intent);
   }

}
  1. AndroidManifest.xml 文件,记得声明权限,这里的权限是使用电话:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="net.monkeychan.intenttest">

    <!-- 声明该应用需要使用电话 -->
    <uses-permission android:name="android.permission.CALL_PHONE">

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

    </uses-permission>

</manifest>

上面的代码实现的功能是这样的:当我们点击按钮时,将会跳转到拨号界面。

  1. 效果演示:

点击按钮,将会跳转到拨号界面:

接下来我们对上面的程序进行修改,当点击按钮时,将会把我们要拨打的号码自动写好,我们只须按下拨号键就可以拨打了。

  1. XML 布局文件以及 AndroidManifest.xml 文件无须修改, Java 代码部分修改成如下:
public class MainActivity extends AppCompatActivity {

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

    public void startDial(View view) {

        // 1. 创建一个 Intent 对象
        Intent intent = new Intent();

        // 2. 设置 Intent 对象的 Action
        // ACTION_DIAL 是 Intent 中定义的一个常量,查源码可知:
        // public static final String ACTION_DIAL = "android.intent.action.DIAL";
        // 这是 Android 中已经定义好的,事实上 Intent 中还有许多这样的常量
        intent.setAction(Intent.ACTION_DIAL);

        // tel 是 Android 中已经定义好的,用于拨打电话,这里设置要拨打的号码为 10010
        Uri uri = Uri.parse("tel://10010");

        // 3. 调用 Intent 对象的 setData() 方法,该方法需要传入一个 Uri 类型的参数
        intent.setData(uri);

        // 4. 跳转到对应的组件
        startActivity(intent);
    }

}
  1. 效果演示:


点击按钮之后,号码将自动写好:

2. 发送短信

  1. XML 布局文件,activity_main.xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:paddingBottom="16dp"
    android:paddingLeft="16dp"
    android:paddingRight="16dp"
    android:paddingTop="16dp"
    tools:context=".MainActivity">

    <Button
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="发送短信"
        android:onClick="sendSMS"/>
    
</LinearLayout>
  1. Java 代码,MainActivity.java:
public class MainActivity extends AppCompatActivity {

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

    public void sendSMS(View view) {

        // 1. 创建一个 Intent 对象
        Intent intent = new Intent();

        // 2. 设置 Intent 对象的 Action
        intent.setAction(Intent.ACTION_VIEW);

        // smsto 是 Android 中已经定义好的,用于发送,这里设置要发送的号码为 10010
        Uri uri = Uri.parse("smsto://10010");

        // 3. 设置 Intent 对象的 setData() 方法,该方法需要传入一个 Uri 类型的参数
        intent.setData(uri);

        // 4. 设置短信的内容,调用 Intent 对象的 putExtra() 方法,该方法需要传入一个键值对(key-value)
        // 其中 key 为 sms_body,是 Android 系统已经定义好的,系统的短信发送程序只能识别 sms_body
        intent.putExtra("sms_body", "CXYE");

        // 5. 跳转到对应的组件
        startActivity(intent);
    }

}
  1. 声明权限,这里的权限是发送短信,AndroidManifest.xml:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="net.monkeychan.intenttest">

    <uses-permission android:name="android.permission.SEND_SMS"/>

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <activity android:name=".SecondActivity"></activity>
    </application>

</manifest>
  1. 效果演示:

点击按钮,启动发送短信程序,并将我们要发送的号码及内容传递给系统短信程序

点击发送按钮:

注意,这里使用的是虚拟机,实际上并没有给10010发送短信。

总结:使用 Intent 启动 Activity 的步骤

  1. 创建一个 Intent 对象;
    若是显式启动直接向构造方法里传入源 Activity 和 目的 Activity,然后进行第 3 步:
Intent intent = new Intent(OriActivity.this, DesActivity.class);

若是隐式启动直接调用无参的构造方法:

Intent intent = new Intent();
  1. 根据具体对 Intent 对象进行设置,如设置 Action、添加 Category 、设置 Data 等
    等;
intent.setAction("MyAction");
intent.addCategory("MyCategory");
intent.setData(Uri.parse("scheme://host"));
  1. 跳转到相应的 Activity。
startActivity(intent);

Intent 的用法 - 传递数据


Intent 除了可以用来启动各种组件之外,还可以用来在组件之间传递数据。

使用 Intent 在 Activity 之间传递数据

1. 传递简单数据

我们来做一个实现注册功能的程序:用户在注册界面填写用户名和密码,之后点击注册按钮,跳转到注册成功界面,该界面提示用户注册成功,并显示用户的注册信息。

1. XML 布局文件

  1. 注册界面,activity_signup.xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
   android:layout_width="match_parent"
   android:layout_height="match_parent"
   android:orientation="vertical"
   android:padding="16dp">

   <TableRow
       android:layout_width="match_parent"
       android:layout_height="wrap_content">

       <TextView
           android:id="@+id/tv_userName"
           android:layout_width="wrap_content"
           android:layout_height="wrap_content"
           android:text="用户名:" />

       <EditText
           android:id="@+id/et_userName"
           android:layout_width="match_parent"
           android:layout_height="wrap_content"
           android:hint="请输入用户名" />
   </TableRow>

   <TableRow
       android:layout_width="match_parent"
       android:layout_height="wrap_content">

       <TextView
           android:id="@+id/tv_userPassword"
           android:layout_width="wrap_content"
           android:layout_height="wrap_content"
           android:text="密码:" />

       <EditText
           android:id="@+id/et_userPassword"
           android:layout_width="match_parent"
           android:layout_height="wrap_content"
           android:hint="请输入密码" />
   </TableRow>

   <Button
       android:id="@+id/btn_signUp"
       android:layout_width="match_parent"
       android:layout_height="wrap_content"
       android:text="注册"
       android:onClick="signUp"/>

</LinearLayout>
  1. 注册成功界面,activity_signup_success.xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:padding="16dp">

    <TextView
        android:id="@+id/tv_userName"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

    <TextView
        android:id="@+id/tv_userPassword"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

</LinearLayout>

2. Java 代码

  1. 注册界面,SignUpActivity.java:
public class SignUpActivity extends AppCompatActivity {

    private EditText et_userName;
    private EditText et_userPassword;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_signup);

        // 设置 title
        setTitle("注册界面");

        initView();

    }

    // 该方法用于实例化布局中的控件
    private void initView() {
        et_userName = (EditText) findViewById(R.id.et_userName);
        et_userPassword = (EditText) findViewById(R.id.et_userPassword);
    }


    public void signUp(View view) {

        // 获取 EditText 里的数据
        String userName = et_userName.getText().toString();
        String userPassword = et_userPassword.getText().toString();

        // 1. 创建一个 Intent 对象,并传入将要启动的 Activity
        Intent intent = new Intent(SignUpActivity.this, SignUpSuccessActivity.class);

        // 2. 往 Intent 的对象里放入需要传递的数据
        intent.putExtra("userName", userName);
        intent.putExtra("userPassword", userPassword);

        // 3. 启动相应的组件,并将数据传递过去
        startActivity(intent);
    }

}
  1. 注册成功界面,SignUpSuccessActivity.java:
public class SignUpSuccessActivity extends AppCompatActivity {

    private TextView tv_userName;
    private TextView tv_userPassword;
    private Intent intent;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_signup_success);

        // 设置 title
        setTitle("注册成功");

        initView();
        display();

    }

    // 该方法用来显示用户的注册信息
    private void display() {

        //1. 获取启动本 Activity 的 Intent
        intent = getIntent();

        // 2. 从 Intent 中取出数据,根据键取出相应的值
        // 注意,此键要与传递过来的键一致,否则会出现 NullPointerException 异常
        String userName = intent.getStringExtra("userName");
        String userPassword = intent.getStringExtra("userPassword");

        // 3. 显示用户的注册信息
        tv_userName.setText("您的用户名为:" + userName);
        tv_userPassword.setText("您的注册密码为:" + userPassword);

    }

    // 该方法用来实例化布局中的控件
    private void initView() {
        tv_userName = (TextView) findViewById(R.id.tv_userName);
        tv_userPassword = (TextView) findViewById(R.id.tv_userPassword);
    }

}

3. 最后,在 AndroidManifest.xml 中注册:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="net.monkeychan.intenttest">

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".SignUpActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <activity android:name=".SignUpSuccessActivity"></activity>
    </application>

</manifest>

4) 效果演示:

输入用户名和密码:

点击注册按钮:

返回数据给上一个 Activity

除了向下一个 Activity 传递数据,下一个 Activity 也可以向上一个 Activity 传递数据,具体步骤如下:

  1. 上一个 Activity 在跳转到相应的 Activity 时调用 startActivityForResult(Intent intent, int requestCode) 方法;
  2. 在下一个 Activity 调用 setResult(int resultCode, Intent data) 方法;
  3. 重写上一个 Activity 中的 onActivityResult(int requestCode, int resultCode, Intent data) 方法,在此方法中根据 resultCode 和 resultCode 对对应的返回数据进行处理。
    注意:requestCode 必须是唯一的,resultCode 也必须是唯一的,但两者可以相同。

修改上面的程序中 Java 部分的代码如下:

  1. SignUpActivity.java:
public class SignUpActivity extends AppCompatActivity {

    private EditText et_userName;
    private EditText et_userPassword;
    private Button btn_signUp;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_signup);

        // 设置 title
        setTitle("注册界面");

        initView();

    }

    // 该方法用于实例化布局中的控件
    private void initView() {
        et_userName = (EditText) findViewById(R.id.et_userName);
        et_userPassword = (EditText) findViewById(R.id.et_userPassword);
        btn_signUp = (Button) findViewById(R.id.btn_signUp);
    }


    public void signUp(View view) {

        // 获取 EditText 里的数据
        String userName = et_userName.getText().toString();
        String userPassword = et_userPassword.getText().toString();

        // 1. 创建一个 Intent 对象,并传入将要启动的目的 Activity
        Intent intent = new Intent(SignUpActivity.this, SignUpSuccessActivity.class);

        // 2. 往 Intent 的对象里放入需要传递的数据
        intent.putExtra("userName", userName);
        intent.putExtra("userPassword", userPassword);

        // 3. 启动相应的组件,将数据传递过去,并设置 requestCode
        startActivityForResult(intent, 0);
    }

    // 在此方法中根据 requestCode 和 resultCode 对对应的返回数据进行处理
    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        if (requestCode == 0 && resultCode == 0) {
            // 将 Button 上的文字设置为返回的数据
            btn_signUp.setText(data.getStringExtra("signUpSuccess"));
            btn_signUp.setTextColor(Color.RED);
        }
    }

}
  1. SignUpSuccessActivity.java:
public class SignUpSuccessActivity extends AppCompatActivity {

    private TextView tv_userName;
    private TextView tv_userPassword;
    private Intent intent;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_signup_success);

        // 设置 title
        setTitle("注册成功");

        initView();
        display();

    }

    // 该方法用来显示用户的注册信息
    private void display() {

        //1. 获取启动本 Activity 的 Intent
        intent = getIntent();

        // 2. 从 Intent 中取出数据,根据键取出相应的值
        // 注意,此键要与传递过来的键一致,否则会出现 NullPointerException 异常
        String userName = intent.getStringExtra("userName");
        String userPassword = intent.getStringExtra("userPassword");

        // 3. 显示用户的注册信息
        tv_userName.setText("您的用户名为:" + userName);
        tv_userPassword.setText("您的注册密码为:" + userPassword);

        // 设置返回的数据
        intent.putExtra("signUpSuccess", "注册成功");

        // 设置 resultCode 和返回的 Intent
        setResult(0, intent);

    }

    // 该方法用来实例化布局中的控件
    private void initView() {
        tv_userName = (TextView) findViewById(R.id.tv_userName);
        tv_userPassword = (TextView) findViewById(R.id.tv_userPassword);
    }

}
  1. 效果演示:

填写信息并点击提交注册按钮:

点击返回键:

可以看到,按钮上的文字即为返回的数据。

使用 Bundle 传递数据

除了 Intent,Bundle 也可以用来传递数据,其用法跟 Intent 差不多。将上面的程序修改成如下 (只须修改 SignUpActivity.java 和 SignUpSuccessActivity.java):

  1. SignUpActivity.java:
public class SignUpActivity extends AppCompatActivity {

    private EditText et_userName;
    private EditText et_userPassword;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_signup);

        // 设置 title
        setTitle("注册界面");

        initView();

    }

    // 该方法用于实例化布局中的控件
    private void initView() {
        et_userName = (EditText) findViewById(R.id.et_userName);
        et_userPassword = (EditText) findViewById(R.id.et_userPassword);
    }


    public void signUp(View view) {

        // 获取 EditText 里的数据
        String userName = et_userName.getText().toString();
        String userPassword = et_userPassword.getText().toString();

        // 1. 创建一个 Intent 对象,并传入将要启动的 Activity
        Intent intent = new Intent(SignUpActivity.this, SignUpSuccessActivity.class);

        // 2. 创建一个 Bundle 对象
        Bundle bundle = new Bundle();

        // 3. 往 Bundle 的对象里放入需要传递的数据
        bundle.putString("userName", userName);
        bundle.putString("userPassword", userPassword);

        // 4. 将 Bundle 对象放进 Intent 里
        intent.putExtras(bundle);

        // 5. 启动相应的组件,并将数据传递过去
        startActivity(intent);
    }

}
  1. SignUpSuccessActivity.java:
public class SignUpSuccessActivity extends AppCompatActivity {

    private TextView tv_userName;
    private TextView tv_userPassword;
    private Bundle bundle;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_signup_success);

        // 设置 title
        setTitle("注册成功");

        initView();
        display();

    }

    // 该方法用来显示用户的注册信息
    private void display() {

        //1. 获取启动本 Activity 的 Intent 里的 Bundle
        bundle = getIntent().getExtras();

        // 2. 从 Bundle 中取出数据,根据键取出相应的值
        // 注意,此键要与传递过来的键一致,否则会出现 NullPointerException 异常
        String userName = bundle.getString("userName");
        String userPassword = bundle.getString("userPassword");

        // 3. 显示用户的注册信息
        tv_userName.setText("您的用户名为:" + userName);
        tv_userPassword.setText("您的注册密码为:" + userPassword);

    }

    // 该方法用来实例化布局中的控件
    private void initView() {
        tv_userName = (TextView) findViewById(R.id.tv_userName);
        tv_userPassword = (TextView) findViewById(R.id.tv_userPassword);
    }

}

从上面的代码可以看出,使用 Bundle 来传递数据跟使用 Intent 来传递数据差不多。实际上还是用的 Intent 来传递数据,只不过 Intent 并不直接将数据传递过去,而是传递一个 Bundle 对象,我们将要传递的数据封装在一个 Bundle 对象里,再使用 Intent 将 Bundle 对象传递过去。

  1. 效果演示:

效果跟上面的程序完全一样。

2. 传递对象

当要传递的数据较多时,我们可以把数据封装成一个对象,再把这个对象传递过去,条件是该对象必须实现 Serializable 接口或 Parcelable 接口。

  1. 对象实现 Serializable 接口

在使用内存方面,Serializable 效率比 Parcelable 低,但它能把数据存储在磁盘上。

a. XML 布局文件

信息提交页面,activity_info.xml:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:padding="16dp">

    <TableRow
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

        <TextView
            android:id="@+id/tv_name"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="姓名:" />

        <EditText
            android:id="@+id/et_name"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:hint="请输入姓名" />
    </TableRow>

    <TableRow
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

        <TextView
            android:id="@+id/tv_age"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="年龄:" />

        <EditText
            android:id="@+id/et_age"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:hint="请输入年龄" />
    </TableRow>

    <Button
        android:id="@+id/btn_summit"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="提交"
        android:onClick="summit"/>

</LinearLayout>

信息显示页面,activity_info_display.xml:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:padding="16dp">

    <TextView
        android:id="@+id/tv_name"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

    <TextView
        android:id="@+id/tv_age"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

</LinearLayout>

b. Java 代码

信息提交页面,InfoSummitActivity.java:

public class InfoSummitActivity extends AppCompatActivity {

    private EditText et_name;
    private EditText et_age;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_info);

        // 设置 title
        setTitle("提交信息");

        initView();
    }

    // 该方法用于实例化布局中的控件
    private void initView() {
        et_name = (EditText) findViewById(R.id.et_name);
        et_age = (EditText) findViewById(R.id.et_age);
    }

    // 该方法用于提交用户信息,并跳转用户信息页面
    public void summit(View view) {

        // 获取 EditText 里的信息
        String name = et_name.getText().toString();
        int age = Integer.parseInt(et_age.getText().toString());

        // 1. 创建一个 Teacher 对象,并设置其属性
        Teacher teacher = new Teacher();
        teacher.setName(name);
        teacher.setAge(age);

        // 2. 创建一个 Intent 对象,指定要跳转的目的组件
        Intent intent = new Intent(InfoSummitActivity.this, InfoDisplayActivity.class);

        // 3. 将要传递的对象放入 Intent 中
        intent.putExtra("teacher", teacher);

        // 4. 跳转到对应的组件
        startActivity(intent);
    }
    
}

信息显示页面,InfoDisplayActivity.java:

public class InfoDisplayActivity extends AppCompatActivity {

    private TextView tv_name;
    private TextView tv_age;
    private Intent intent;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_info_display);

        // 设置 title
        setTitle("用户信息");

        initView();
        display();
    }

    // 该方法用于显示用户的信息
    private void display() {

        // 1. 获取启动本 Activity 的 Intent
        intent = getIntent();

        // 2. 创建一个 Teacher 对象,用来接收从 Intent 里取出的数据
        Teacher teacher = (Teacher) intent.getSerializableExtra("teacher");

        // 3. 设置数据到对应的控件上
        tv_name.setText("您的姓名是:" + teacher.getName());
        tv_age.setText("您的年龄为:" + teacher.getAge());
        // 注意,由于 setText 只能接受 CharSequence 类型的参数,
        // 而在这里我们的年龄是 int 类型的,如果写成:
        // tv_age.setText(teacher.getAge());
        // 点击按钮时会出现 Resources$NotFoundException,即资源未找到异常
        // 解决办法是加个空字符:tv_age.setText(teacher.getAge() + "");

    }

    // 该方法用于实例化布局中的控件
    private void initView() {
        tv_name = (TextView) findViewById(R.id.tv_name);
        tv_age = (TextView) findViewById(R.id.tv_age);
    }

}

c. 效果演示:

输入信息,并点击提交按钮:

  1. 对象实现 Parcelable 接口
  1. 在使用内存方面,Parcelable 效率比 Serializable 高,但它不能将数据存储在磁盘上。
  2. 实现 Parcelable 接口必须重写 writeToParcel() 方法和 describeContents() 方法,并实例化静态内部对象 CREATOR 实现 Creator 接口。详情请看这篇文章 Android中Parcelable接口用法

a. XML 布局文件

信息提交页面,activity_info.xml:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:padding="16dp">

    <TableRow
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

        <TextView
            android:id="@+id/tv_name"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="姓名:" />

        <EditText
            android:id="@+id/et_name"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:hint="请输入姓名" />
    </TableRow>

    <TableRow
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

        <TextView
            android:id="@+id/tv_id"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="学号:" />

        <EditText
            android:id="@+id/et_id"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:hint="请输入学号" />
    </TableRow>

    <Button
        android:id="@+id/btn_summit"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="提交"
        android:onClick="summit"/>

</LinearLayout>

信息显示页面,activity_info_display.xml:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:padding="16dp">

    <TextView
        android:id="@+id/tv_name"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

    <TextView
        android:id="@+id/tv_id"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

</LinearLayout>

b. Java 代码

新建一个 Student 类,该类实现了 Parcelable 接口:

public class Student implements Parcelable {

    private String name;
    private int id;

    public Student() {

    }

    public Student(Parcel source) {
        name = source.readString();
        id = source.readInt();
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    // 此方法为内容描述,默认即可
    @Override
    public int describeContents() {
        return 0;
    }

    // 此方法用来写入数据
    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeString(this.name);
        dest.writeInt(this.id);
    }

    // 实例化 CREATOR 对象,实现 Creator 接口
    public static final Creator<Student> CREATOR = new Creator<Student>() {

        // 此方法用来读取传递过来的数据,注意读取的顺序要与写入的顺序一致
        @Override
        public Student createFromParcel(Parcel source) {
            return new Student(source);
        }

        // 此方法用来供外部类反序列化本类数组使用
        @Override
        public Student[] newArray(int size) {
            return new Student[size];
        }
    };

}

信息提交页面,InfoSummitActivity.java:

public class InfoSummitActivity extends AppCompatActivity {

    private EditText et_name;
    private EditText et_id;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_info);

        // 设置 title
        setTitle("提交信息");

        initView();
    }

    // 该方法用于实例化布局中的控件
    private void initView() {
        et_name = (EditText) findViewById(R.id.et_name);
        et_id = (EditText) findViewById(R.id.et_id);
    }

    // 该方法用于提交用户信息,并跳转用户信息页面
    public void summit(View view) {

        // 获取 EditText 里的信息
        String name = et_name.getText().toString();
        int id = Integer.parseInt(et_id.getText().toString());

        // 1. 创建一个 Student 对象,并设置其属性
        Student student = new Student();
        student.setName(name);
        student.setId(id);

        // 2. 创建一个 Intent 对象,指定要跳转的目的组件
        Intent intent = new Intent(InfoSummitActivity.this, InfoDisplayActivity.class);

        // 3. 将要传递的对象放入 Intent 中
        intent.putExtra("student", student);

        // 4. 跳转到对应的组件
        startActivity(intent);
    }

}

信息显示页面,InfoDisplayActivity.java:

public class InfoDisplayActivity extends AppCompatActivity {

    private TextView tv_name;
    private TextView tv_id;
    private Intent intent;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_info_display);

        // 设置 title
        setTitle("用户信息");

        initView();
        display();
    }

    // 该方法用于显示用户的信息
    private void display() {

        // 1. 获取启动本 Activity 的 Intent
        intent = getIntent();

        // 2. 创建一个 Student 对象,用来接收从 Intent 里取出的数据
        Student student = intent.getParcelableExtra("student");

        // 3. 设置数据到对应的控件上
        tv_name.setText("您的姓名是:" + student.getName());
        tv_id.setText("您的学号是:" + student.getId());
        // 注意,由于 setText 只能接受 CharSequence 类型的参数,
        // 而在这里我们的年龄是 int 类型的,如果写成:
        // tv_id.setText(student.getId());
        // 点击按钮时会出现 Resources$NotFoundException,即资源未找到异常
        // 解决办法是加个空字符:tv_id.setText(student.getId() + "");

    }

    // 该方法用于实例化布局中的控件
    private void initView() {
        tv_name = (TextView) findViewById(R.id.tv_name);
        tv_id = (TextView) findViewById(R.id.tv_id);
    }

}

c. 效果演示:

填写信息,并点击提交按钮:

总结:使用 Intent 在 Activity 之间传递数据

  1. 在传递数据的地方创建一个 Intent 对象;
Intent intent = new Intent();
  1. 对 Intent 对象进行设置,可以传入简单的数据、对象 (包括 Bundle 对象),注意传入的参数键值对形式;
 - intent.putExtra("key", value);
 - Person person = new Person(); intent.putExtra("person", person);
 - Bundle bundle = new Bundle(); bundle.putXxx("key", value); intent.putExtra("bundle", bundle); // Xxx 为具体数据类型
  1. 在接收数据的地方创建一个 Intent 对象;
Intent intent = new Intent();
  1. 获取启动本 Activity 的 Intent;
intent = getIntent();
  1. 从 Intent 中取出数据,根据键取出相应的值,注意,此键要与传递过来的键一致,否则会出现 NullPointerException 异常;根据传递过来的值的类型,用对应的数据类型去接收。
 - String string = intent.getStringExtra("string");
 - Teacher teacher = (Teacher) intent.getSerializableExtra("teacher");
 - Student student = intent.getParcelableExtra("student");

参考资料:

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,013评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,205评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,370评论 0 342
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,168评论 1 278
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,153评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,954评论 1 283
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,271评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,916评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,382评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,877评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,989评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,624评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,209评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,199评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,418评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,401评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,700评论 2 345

推荐阅读更多精彩内容

  • 显示Intent和隐式Intent Android中的Intent是一个非常重要且常用的类,可以用来在一个组件中启...
    狮_子歌歌阅读 1,158评论 0 2
  • 一、显式Intent和隐式Intent 参考Android理解:显式和隐式IntentAndroid中Intent...
    合肥黑阅读 764评论 0 1
  • Intent 是 Android 非常常用的一个用于组件间互相通信的信息对象,常用于启动组件和传递数据,大部分的程...
    seven_Android阅读 34,408评论 1 38
  • Intent用于启动Activity, Service, 以及BroadcastReceiver三种组件, 同时还...
    枫羽望空阅读 1,026评论 0 7
  • 不能念就给我滚出去,课文都背不好,你有什么脸在这呆着?滚!说着,那位老师把这位少年的书包从教室扔了出去,滚落在寂静...
    欲_除名阅读 177评论 0 0