Android四大组件之Activity

1、什么是Activity?

Activity是安卓四大组件之一,主要用来与用户进行交互。除了一些用来后台启动一些服务的程序,基本上每个程序都会包含Activity的,想一些简单的程序,比如在学习安卓的时候,可能就只有简单的一个Activity,但是,在实际的开发中,一个程序至少也会由几十个Activity组成。

2、加载布局

在Activity中加载布局的方法也很简单,只要在onCreate()方法中调用setContentView()方法,然后将要调用的布局文件传进setContentView()方法即可,当然,也可以用java代码进行布局的构建,但是并不推荐这样子,因为这样代码量过大,而且也不方便,在这里更加推荐使用xml文件进行布局的构建。

@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);//加载布局文件
    }

3、在AndroidManifest.xml中注册创建的Activity

每创建一个Activity,都需要在AndroidManifest.xml中注册,没有经过注册的Activity,不仅没法运行,更会导致程序奔溃闪退。虽然我们在使用Android Studio创建Acitivity的时候,会自动为我们注册,但是我们也是要知道这件事的。

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.android.helloworld">

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

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

</manifest>

Activity的注册,需要放在<application>标签之内,然后通过<activity>标签来对Activity进行注册。
细心的人可以发现,在注册信息中,存在着以下语句:

<intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" /> 
</intent-filter>

这两句语句通过<intent-filter>这个标签来申明,具体信息代表着这个Activity注册成为程序的主活动,也就是说,程序启动的时候,最先启动此Activity。
此外,在注册信息中,另外的几个属性代表的含义如下:
android:allowBackup这个属性代表改程序是否允许自动进行备份;
android:icon 这个属性代表该程序要以哪个图片作为程序的图标;
android:label 这个代表程序的要显示的名字;
android:roundIcon 表示程序指定了哪张图片作为应用程序的圆形桌面图标;android:supportsRtl 表示该程序是否支持从右往左显示。
android:theme表示该程序要调用那种主题风格

4、Activity的跳转
在学习Activity的跳转之前,我们得先认识Intent,那么Intent是什么呢?
Intent:作为安卓程序中各组件进行交互的重要方式,可以用于启动Activity,广播,以及服务。不仅可以指明当前组件想要执行的动作,而且可以携带数据进行交互。Intent一般可以分为显示Intent和隐式Intent。
(1)显示Intent

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

在上面的例子中,当我们点击mTurnSecondButton这个按钮的时候,程序会跳转到SecondActivity这个活动中,当中我们使用了Intent(Context packageContext, Class<?> cls)这个构造函数来创建Intent实例,在这个构造方法中,需要传入两个参数,一个是上下文对象,另一个则是指定想要跳转的Activity,最后,调用startActivity()这个方法,传入Intent参数便可以通过显示Intent的方式启动另一个Activity了。
(2)隐式Inent
隐式Intent是通过添加action,category等信息,然后交由系统自行分析启动哪个Activity的方法。如下所示,在注册Activity的时候添加所需要的action以及category。

<activity
            android:name=".SecondActivity"
            android:exported="false" >
            <intent-filter>
                <action android:name="android.intent.test.ACTION_START"/>
                <category android:name="android.intent.category.DEFAULT"/>
                <category android:name="android.intent.category.MY_INTENT"/>
            </intent-filter>
        </activity>

然后在启动的逻辑代码中进行如下操作:

mTurnSecondButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Intent intent = new Intent("android.intent.test.ACTION_START");
                intent.addCategory("android.intent.category.MY_INTENT");
                startActivity(intent);
            }
        });

当action信息和category信息都对应上的时候,系统便会去启动对应的Activity。有一种特殊的情况,当我们在注册Activity的时候,可以直接这么写:

<activity
            android:name=".SecondActivity"
            android:exported="false" >
            <intent-filter>
                <action android:name="android.intent.test.ACTION_START"/>
                <category android:name="android.intent.category.DEFAULT"/>
            </intent-filter>
        </activity>

android.intent.category.DEFAULT 这个是一个默认的category,在我们调用startActivity()这个方法的时候,会自动加载进去,因此,如果按照上面这样写得话,我们在使用隐式Intent的时候只需要这么写:

Intent intent = new Intent("android.intent.test.ACTION_START");
startActivity(intent);

另外,在使用隐式Intent去启动Activity的时候,有一个踩坑点,就是在上面使用隐式Intent的第一种方法,也就是使用我们自己定义的category的时候,一定要将android.intent.category.DEFAULT这个在注册的时候也加进去,否则会出现找不到要启动的Acitivity,从而导致程序运行奔溃。

5、携带数据到下一个Activity

在前面介绍过,Intent不仅可以指明控件的意图,还可以携带数据,在这里,我们变使用Intent的另一个功能:携带数据进行交互。
其实通过Intent携带数据进行交互也很简单,只需要调用Intent当中的putExtra()方法就可以了,这个方法通过键值对的方式进行数据的携带保存。例如:

              String data = "I Love Android!";
              Intent intent = new Intent(MainActivity.this,SecondActivity.class);
              intent.putExtra("intent_string",data);
              startActivity(intent);

putExtra()方法需要传入两个参数,一个是“键”,也就是上面代码中的intent_string,另一个是“值”,也就是上面中的data这个字符串。最后通过 startActivity(intent)将数据传送到下一个Activity当中。
既然有传递数据,那么必然就有获取数据,否则,数据的传递就没有意义了。通过Intent发送的数据,获取方法如下:
(1)通过getIntent()的方法获取启动当前Activity(SecondActivity)的Intent。
(2)通过getStringExtra()的方法获取传递的数据,例子中传递的为String类型数据,因此这里就使用getStringExtra()的方法,根据传递数据类型的不同,也可以使用getBooleanExtra()或者getIntExtra()等等方法。

Intent intent = getIntent();
String data = intent.getStringExtra("intent_string");
tv_getIntent.setText(data);

例子中,我们通过一个TextView来显示获取的数据,效果如下:


Intent.png

6、返回数据到上一个Activity
(1)使用startActivityForResult()来启动下一个Activity

mTurnSecondButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
              Intent intent = new Intent(MainActivity.this,SecondActivity.class);
              startActivityForResult(intent,1);
            }
        });

在这里我们使用startActivityForResult()来启动下一个Activity,传入了唯一的Request Code,值为1。这个数值后面在获取返回的数值的时候,还要作为判断的依据。
(2)使用setResult()方法返回数据

btn_forRusult.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Intent intent1 = new Intent();
                intent1.putExtra("data_return","Turn to the FirstActivity!!");
                setResult(RESULT_OK,intent1);
                finish();
            }
        });

在上面的例子中,先构建了一个Intent来传递数据,然后调用setResult()的方法,改方法接收两个参数,第一个参数用于向上一个Activity返回处理的结果,一般传递RESULT_OK或者RESULT_CANCELED这两个参数;第二个参数则是带着数据的Intent。
(3)在返回上一个Activity后调用onActivityResult()方法。

@Override
    protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
        switch (requestCode){
            case 1:
                if (resultCode == RESULT_OK){
                    String dataReturn = data.getStringExtra("data_return");
                    Log.d("Activity",dataReturn);
                }
        }
        super.onActivityResult(requestCode, resultCode, data);
    }

onActivityResult()方法需要传入3个参数,第一个是requestCode,是我们启动下一个Activity是传入的请求码,也就是上面例子中的1;第二个是resultCode,是我们在返回数据时传入的处理结果,也就是上面例子中的RESULT_OK;最后一个是携带着是数据的Intent。
上面的例子先去判断requestCode,因为一个Activity中,可能会存在不止一处用startActivityForResult()来启动下一个Activity,因此,通过唯一的requestCode来判断是哪个Activity返回的数据,再通过resultCode来判断处理结果,最后取出返回的数据并打印出来。

7、Activity的启动模式
Activity的启动模式有4种,分别为standard、singleTop、singleTask和singleInstance。Activity的启动模式可以在AndroidManifest.xml中给<activity>标签指定android:launchMode属性来选择需要的启动模式。
(1)standard模式
standard模式是默认的启动模式,如果没有对Activity进行特殊的声明的话,都是属于standard模式。在standard模式下,系统每次都会创建该活动的一个新的实例。
首先我们在AndroidManifest.xml中将对象Activity设置成standard的启动模式。

<activity
            android:name=".setupFirstActivity"
            android:launchMode="standard"
            android:exported="false" />

接着将按钮的事件设置为启动本Activity。然后点击3次按钮,打开信息过滤。


image.png

从上图中可以看出,FirstSetupActivity创建了3次。然后我们一直按返回键,知道退出桌面。


image.png

我们会发现,我们需要按4次返回键,才能退出到桌面,这是因为standard模式,会不管返回栈里面是什么情况,都会新创建一个Activity实例,我们启动了3次setupFitstActivity,再加上本身存在一个,我们就需要返回4次,才能将返回栈中的Activity全部退出,然后到达桌面。
(2)singleTop模式

从上面的例子中,或许我们可以看到standard模式确实存在一些不太合理的地方,我们不妨来看一下第二种启动模式--singleTop模式,在这种模式下,如果要启动的Activity已经是返回栈的栈顶了,那么这时候就不会再去创建一个Activity实例了,相当于是直接复用了栈顶的Activity。
复用上面例子中的程序,将启动模式改成singleTop模式,同样是点击3次按钮。我们会发现从程序运行到点击完3次按钮,Activity就只创建了一次。


image.png

(3)singleTask模式
在singleTop模式下,虽然在栈顶的Activity不会被重新创建,但是如果要启动的Activity是存在于返回栈的,只是不是再栈顶,那么它还是会被重新创建的。为了让整个上下文当中一个Activity不被重复创建,只有一个实例,我们可以使用第三种启动模式--singleTask模式。在这个模式之下,系统每次启动该Activity的时候,都会检查返回栈中是否存在该Activity的实例,如果存在,则不再创建,把这个Activity实例上面的所有Activity全部弹出栈,让这个Activity成为栈顶。
我们将setupFirstActivity的启动模式改成singleTask模式,然后将Button的事件改成跳转到setupSecondActivity,然后将setupSecondActivity的按钮点击事件设置成跳转到setupFirstActivity,完成代码编写之后,完成如下操作:在setupFirstActivity启动setupSecondActivity,然后再从setupScondActivity启动setupFirstActivity,我们可以从过滤信息中看到如下信息:
image.png

可以看到这时候我们启动setupFirstActivity的时候,并没有执行onCreate()的方法,而是直接执行了onRestart(),并且可以看到,setupSecondActivity直接执行了onDestroy()的方法进行了销毁。
(4)singleInstance模式
不同于以上3中启动模式,singleInstance模式是直接开辟一个新的返回栈出来的。
创建一个新的setupThirdActivity,然后将setupSecondActivity的启动模式改成singleInstance模式,然后在每个Activity的onCreate()方法里面打印当前Activity的返回栈id,通过过滤信息,可以看到如下信息:


image.png

从图片中可以看到,setupFirstActivity和setupThirdActivity的返回栈的id是一样的,都是26,但是setupSecondActivity的返回栈的id是27,这是由于我们将setupSecondActivity的启动模式改成singleInstance了,在启动这个Activity的时候,重新创建了一个返回栈,并且,这个返回栈只有这一个Activity。
接着我们按返回键,我们会发现,从setupThirdActivity会调到setupFirstActivity,然后再按一次返回键,才会到setupSecondActivity。

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容