一、启动Activity
一个activity跳转到另外一个activity中的最简单的方式就是使用下面的Activity方法:
public void startActivity(Intent intent);
可能会有人认为startActivity(...)方法是一个类方法,启动activity就是针对Activity子类调用该方法。实际并非如此,activity调用startActivity(...)方法时,调用请求实际发给了操作系统。
准确地说,该方法调用请求是发送给操作系统的ActivityManager。ActivityManager负责创建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的原因所在。
通过制定Context与Class对象,然后调用intent的构造方法来创建Intent,这创建的属于显式Intent。同一应用中,我们使用显式Intent来启动activity。
一个应用的activity如需启动另一个应用中的activity,就可以通过隐式Intent来处理。
2、隐式Intent
在介绍隐式Intent之前,得先知晓Intent的两个属性:
Intent的Action、Category两个属性的值都是一个普通的字符串,其中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中设置一个按钮,点击按钮后会跳到SecondActivity,UI布局太过简单这里就不说了。
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属性,程序可调用Intent的setAction(String str)方法来设置Action属性值;但一个Intent对象可以包括多个Category属性,程序可调用Intent的addCategory(String str)方法来为Intent添加Category属性。当程序创建Intent时,该Intent默认启动Category属性值为android.intent.category.DEFAULT常量的组件。
因此,虽然上面程序中的粗体字代码并未指定目标Intent的Category属性,但该Intent已有一个值为android.intent.category.DEFAULT的Category属性值,因此被启动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>