Android基础(四)——Activity的两种启动方式、Intent初探

时间:2021-05-27 15:33:42

一、启动Activity

一个activity跳转到另外一个activity中的最简单的方式就是使用下面的Activity方法:

public void startActivity(Intent intent);

可能会有人认为startActivity(...)方法是一个类方法,启动activity就是针对Activity子类调用该方法。实际并非如此,activity调用startActivity(...)方法时,调用请求实际发给了操作系统。

准确地说,该方法调用请求是发送给操作系统的ActivityManagerActivityManager负责创建Activity实例并调用其onCreate(...)方法。那么,ActivityManager是如何知道该启动哪一个Activity呢?答案就在于传入startActivity(...)方法的Intent参数。

1、显式intent

如下模板代码:


public class MainActivity extends Activity {
    private static final String TAG = "MainActivity";
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Log.i(TAG, "onCreate called.");
        setContentView(R.layout.activity_main);
        Button btn = (Button) findViewById(R.id.btn);
        btn.setOnClickListener(new View.OnClickListener(){

            @Override
            public void onClick(View v) {
                Intent intent = new Intent(getApplicationContext(),SecondActivity.class);
                startActivity(intent);
            }
        });
    }
}

点击之后可以从MainActivity中跳转至SecondActivity。其中getApplicationContext()方法是用于获取当前上下文,在这里也可以用MainActivity.this替换。在启动activity以前,ActivityManager会检查确认指定的Class是否已在配置文件中声明。如果已经声明,则启动activity,应用正常运行。反之,则抛出ActivityNotFoundException异常。这就是我们必须在manifest配置文件中声明应用全部activity的原因所在。

通过制定ContextClass对象,然后调用intent的构造方法来创建Intent,这创建的属于显式Intent。同一应用中,我们使用显式Intent来启动activity

一个应用的activity如需启动另一个应用中的activity,就可以通过隐式Intent来处理。

2、隐式Intent

在介绍隐式Intent之前,得先知晓Intent的两个属性:

IntentActionCategory两个属性的值都是一个普通的字符串,其中Action代表该Intent所要完成的一个抽象“动作”,而Category则用于为Action增加额外的附加类别信息。通常Action属性会与Category属性结合使用。

Action要完成的只是一个抽象动作,这个动作具体由哪个组件(或许是Activity或许是BroadcastReceiver)来完成,Actioin这个字符串本身并不管。比如Android提供的标准Action:Intent.ACTION_VIEW,它只表示一个抽象的查看操作,但具体查看什么、启动哪个Activity来查看,Intent.ACTION_VIEW并不知道——这取决于Activity<intent-filter.../>配置,只要某个Activity<intent-filter.../>配置中包含了该ACTION_VIEW,该Activity就有可能被启动。

下面有一个简单示例,在MainActivity中设置一个按钮,点击按钮后会跳到SecondActivityUI布局太过简单这里就不说了。

MainActivity的代码如下:

public class MainActivity extends Activity {
    private final static String TAG = "MainActivity";
    public final static String TEXT="com.intent.action.ONLYATEST";
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Button btn = (Button) findViewById(R.id.btn);
        btn.setOnClickListener(new View.OnClickListener() {

            @Override
            public void onClick(View v) {
                Intent intent = new Intent();//创建Intent对象
                intent.setAction(MainActivity.TEXT);//为Intent设置Action属性(属性值就是一个普通字符串)
                startActivity(intent);
            }
        });
    }
}

    在上述程序代码中,


      Intent intent = new Intent();//创建Intent对象
      intent.setAction(MainActivity.TEXT);//为Intent设置Action属性(属性值就是一个普通字符串)
      startActivity(intent);

指定了根据Intent来自动Activity——至于启动哪个Activity,这取决于Activity配置中<intent-filter.../>元素的配置。

<intent-filter.../>元素是AndroidManifest.xml文件中<activity.../>元素的子元素,前面已经介绍过,<activity.../>元素用于为应用程序配置Activity,<activity.../><intent-filter.../>子元素则用于配置该Activity所能“响应”的Intent

<intent-filter.../>元素里通常可包含如下子元素。

0~N<action.../>子元素。

0~N<category.../>子元素。

0~1<data.../>子元素。

<intent-filter.../>元素也可以是<service.../><receiver.../>两个元素的子元素,用于表明它们可以响应的Intent

<action.../><category.../>子元素的配置非常简单,它们都可指定android:name属性,该属性的值就是一个普通字符串。

<activity.../>元素的<intent-filter.../>子元素里包含多个<action.../>子元素(相当于指定了多个字符串)时,就表明该Activity能响应Action属性值为其中任意一个字符串的Intent

由于上面的程序制定启动Action属性为TEXT常量(常量值为com.intent.action.ONLYATEST)的Activity,也就要求被启动的Activity对应的配置元素的<intent-filter.../>元素里至少包括一个如下的<action.../>子元素:

<action android:name="com.intent.action.ONLYATEST"/>

需要注意的是,一个Intent对象最多只能包括一个Action属性,程序可调用IntentsetAction(String str)方法来设置Action属性值;但一个Intent对象可以包括多个Category属性,程序可调用IntentaddCategory(String str)方法来为Intent添加Category属性。当程序创建Intent时,该Intent默认启动Category属性值为android.intent.category.DEFAULT常量的组件。

因此,虽然上面程序中的粗体字代码并未指定目标IntentCategory属性,但该Intent已有一个值为android.intent.category.DEFAULTCategory属性值,因此被启动Activity对应的配置元素的<intent-filter.../>元素里至少还包括一个如下的<category.../>子元素:

<category android:name="android.intent.category.DEFAULT"/>

下面是完整的AndroidManifest.xml文件代码:

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

    <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"
            android:label="@string/app_name"
            android:theme="@style/AppTheme"
            >
            <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>
                <!-- 指定该Activity能响应Action属性值为指定字符串的Intent -->
                <action android:name="com.intent.action.ONLYATEST"/>
                <category android:name="android.intent.category.DEFAULT"/>
            </intent-filter>
        </activity>
    </application>

</manifest>