Android四大组件之1 - Activity

本文详细介绍了Android中的核心组件Activity,包括Activity的概念、Activity/ActionBarActivity/AppCompatActivity的区别、创建流程、生命周期、四种加载模式、启动方式及数据传递。重点解析了Activity的生命周期各个状态,以及不同启动模式下的行为差异,帮助开发者更好地理解和运用Activity。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

目录

 

1. 什么是Activity

2. Activity / ActionBarActivity / AppCompatActivity 的区别

3. Activity 的创建流程

4. Activity生命周期

5.  Activity 的4种加载模式

6. Activity 的启动方式

7. Activity 数据传递


1. 什么是Activity

Activity 是一个应用组件,用户可与其提供的屏幕进行交互,以执行拨打电话、拍摄照片、发送电子邮件或查看地图等操作

Activity 用于显示用户界面,用户通过 Activity 交互完成相关操作

每个 Activity 都会获得一个用于绘制其用户界面的窗口

 

2. Activity / ActionBarActivity / AppCompatActivity 的区别

  1. ActionBarActivity 和 AppCompatActivity 都是为了低版本兼容而提出的提出来的,他们都在 v7 包下

  2. ActionBarActivity 已被废弃,在 5.0+ 版本弃用了,可以使用 ToolBar 代替

  3. Android Studio 创建一个 Activity 默认继承的是:AppCompatActivity

3. Activity 的创建流程

  1. 自定义 Activity 类名,继承 Activity 类或者其它子类,比如 AppCompatActivity

    class MainActivity extends AppCompatActivity
    
  2. 重写 onCreate() 方法,然后在该方法中调用 setContentView() 设置要显示的视图

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main); // 设置显示的试图
    }
    
  3. 在 AndroidManifest.xml 中对 Activity 进行注册和配置

    <activity
        android:icon="图标"
        android:name="类名"
        android:label="Activity 要显示的标题"
        android:theme="要应用的主题" >
    </activity>
    
  4. 调用 startActivity(Intent) 启动 Activity

    Intent it = new Intent(MainActivity.this, MsActivity.class);
    startActivity(it);
    
  5. 调用 finish() 直接关闭当前 Activity

    finish();
    

    其实我们可以把它写到启动第二个 Activity 的方法中,当启动了第二个 Activity 时就会关闭第一个 Activity

4. Activity生命周期

 

4.1 Activity的四种基本状态:

Active/Running: Activity处于活动状态,此时Activity处于栈顶,是可见状态,可与用户进行交互

Paused: 当Activity失去焦点时,或被一个新的非全屏的Activity,或被一个透明的Activity放置在栈顶时,Activity就转化为Paused状态。但我们需要明白,此时Activity只是失去了与用户交互的能力,其所有的状态信息及其成员变量都还存在,只有在系统内存紧张的情况下,才有可能被系统回收掉。

Stopped: 当一个Activity被另一个Activity完全覆盖时,被覆盖的Activity就会进入Stopped状态,此时它不再可见,但是跟Paused状态一样保持着其所有状态信息及其成员变量。

Killed: 当Activity被系统回收掉时,Activity就处于Killed状态。 Activity会在以上四种形态中相互切换,至于如何切换,这因用户的操作不同而异。

 

对于activity生命周期中各个方法,需要记住他们是成对出现的

图片13.jpg

 

onCreate只在activity被创建时调用一次,表示正在被创建,一些初始化工作在这里(加载布局资源,初始化所需要的数据等),如果有耗时任务需开异步线程去完成。
onStartActivity正在被启动,在这个状态下Activity还在加载其他资源,正在向我们展示,用户还无法看到,不能交互
onResumeActivity创建完成,用户可看见界面,可交互
onPauseActivity正在暂停,正常情况下接着会执行onStop()。这时可以做数据的存储、动画停止的操作,但是不能太耗时,要不然影响新Activity的创建
onStopActivity即将停止,这时可以做一些回收工作,一样不能太耗时
onDestoryActivity即将被销毁,可以做一些工作和资源的回收(Service、BroadCastReceiver、Map、Bitmap回收等)
onRestartActivity正在重新启动,一般时当前Activity从不可见到可见状态时会执行这个方法,例如:用户按下Home键(锁屏)或者打开新Activity再返回这个Activity

4.2 activity生命周期中各个相邻状态之间的区别:

1. onCreate和onStart之间有什么区别?

(1)可见与不可见的区别。前者不可见,后者可见。
(2)执行次数的区别。onCreate方法只在Activity创建时执行一次,而onStart方法在Activity的切换以及按Home键返回桌面再切回应用的过程中被多次调用。因此Bundle数据的恢复在onStart中进行比onCreate中执行更合适。
(3)onCreate能做的事onStart其实都能做,但是onstart能做的事onCreate却未必适合做。如:setContentView和资源初始化在两者都能做,然而想动画的初始化在onStart中做比较好。

2.onStart方法 和 onResume 方法有什么区别?

(1)是否在前台。onStart方法中Activity可见但不在前台,不可交互,而在onResume中在前台。
(2)职责不同,onStart方法中主要还是进行初始化工作,而onResume方法,根据官方的建议,可以做开启动画和独占设备的操作。

这里所谓的前台并不是我们日常所说的前台任务的那个前台, 这里的前台指: 能否与用户产生交互

3.onPause方法和onStop方法有什么区别?

(1)是否可见。onPause时Activity可见,onStop时Activity不可见,但 Activity对象还在内存中。
(2)在系统内存不足的时候可能不会执行onStop方法,因此程序状态的保存、独占设备和动画的关闭、以及一些数据的保存最好在onPause中进行,但要注意不能太耗时。

4.onStop方法和onDestroy方法有什么区别?

onStop阶段Activity还没有被销毁,对象还在内存中,此时可以通过切换Activity再次回到该Activity,而onDestroy阶段Acivity被销毁

 

4.3 按键对生命周期的影响:

1. BACK键:

这个应用程序将结束,这时候我们将先后调用 onPause()->onStop()->onDestory() 三个方法。

再次启动App时,会执行 onCreate()->onStart()->onResume()

2. HOME键:

当我们打开应用程序时,比如浏览器,我正在浏览NBA新闻,看到一半时,我突然想听歌,这时候我们会选择按HOME键,然后去打开音乐应用程序

当我们按HOME的时候,Activity先后执行了 onPause()->onStop() 这两个方法,这时候应用程序并没有销毁。

当我们从桌面再次启动应用程序时,则先后分别执行了 onRestart()->onStart()->onResume() 三个方法。

Activity切换的生命周期:

1.从启动ActivityA 进入到ActivityB的生命周期走向:

 

ActivityA 的生命周期onPause()---------------------------------->onStop(),

ActivityB的生命周期onCreate() -> onStart()->onResume()。

当ActivityA启动ActivityB时,执行到onPause()时,并没有立即执行onStop();

而是先执行ActivityB 的相应方法,直到ActivityB 的onResume()执行完毕,也就是ActivityB启动成功后,才调用自身的onStop()

 

2.从ActivityB 返回到ActivityA时的生命周期走向

ActivityB的生命周期  onPause()->onStop()->onDestory()

ActivityA的生命周期了从onStop()开始,onRestart()->onStart()->onResume()

ActivityA执行完 onResume(),  ActivityB才开始执行 onStop()->onDestory()

 

5.  Activity 的4种加载模式

 

Activity的启动模式:(面试注意)

Activity有四种启动模式:standard、singleTop、singleTask、singleInstance。可以在AndroidManifest.xml中activity标签的属性android:launchMode中设置该activity的加载模式。

  • standard模式:默认的模式,以这种模式加载时,每当启动一个新的活动,必定会构造一个新的Activity实例放到返回栈(目标task)的栈顶,不管这个Activity是否已经存在于返回栈中;
  • singleTop模式:如果一个以singleTop模式启动的activity的实例已经存在于返回桟的桟顶,那么再启动这个Activity时,不会创建新的实例,而是重用位于栈顶的那个实例,并且会调用该实例的onNewIntent()方法将Intent对象传递到这个实例中;

注:如果以singleTop模式启动的activity的一个实例已经存在于返回桟中,但是不在桟顶,那么它的行为和standard模式相同,也会创建多个实例;

  • singleTask模式:这种模式下,每次启动一个activity时,系统首先会在返回栈中检查是否存在该活动的实例,如果存在,则直接使用该实例,并把这个活动之上的所有活动统统清除;如果没有发现就会创建一个新的活动实例;
  • singleInstance模式:总是在新的任务中开启,并且这个新的任务中有且只有这一个实例,也就是说被该实例启动的其他activity会自动运行于另一个任务中。当再次启动该activity的实例时,会重新调用已存在的任务和实例。并且会调用这个实例的onNewIntent()方法,将Intent实例传递到该实例中。和singleTask相同,同一时刻在系统中只会存在一个这样的Activity实例。(singleInstance即单实例)

注:前面三种模式中,每个应用程序都有自己的返回栈,同一个活动在不同的返回栈中入栈时,必然是创建了新的实例。而使用singleInstance模式可以解决这个问题,在这种模式下会有一个单独的返回栈来管理这个活动,不管是哪一个应用程序来访问这个活动,都公用同一个返回栈,也就解决了共享活动实例的问题。(此时可以实现任务之间的切换,而不是单独某个栈中的实例切换)

 

Activity有四种启动模式:standard、singleTop、singleTask、singleInstance。可以在AndroidManifest.xml中activity标签的属性android:launchMode中设置该activity的加载模式。

我们也可以不在清单文件中设置,只在代码中通过flag来设置也是可以的,如下:

1         Intent intent = new Intent(MainActivity.this,SecondActivity.class);
2         //相当于singleTask
3         intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
4         startActivity(intent);

 

设置加载模式:

<activity
            android:name=".SingleTaskActivity"
            android:label="singleTask launchMode"
            android:launchMode="singleTask">

任务栈:

 

每个应用都有一个任务栈,是用来存放Activity的,功能类似于函数调用的栈,先后顺序代表了Activity的出现顺序;

左侧任务栈为:Activity1-->Activity2-->Activity3

 

standard (默认): 每次激活Activity时(startActivity),都创建Activity实例,并放入任务栈;

singleTop:如果某个Activity自己激活自己,即任务栈栈顶就是该Activity,则不需要创建,其余情况都要创建Activity实例

singleTask:如果要激活的那个Activity在任务栈中存在该实例,则不需要创建,只需要把此Activity放入栈顶,并把该Activity以上的Activity实例都pop;

singleInstance:如果应用1的任务栈中创建了MainActivity实例,如果应用2也要激活MainActivity,则不需要创建,两应用共享该Activity实例;

Activity四种启动模式的应用场景

image.png

6. Activity 的启动方式

6.1 显式启动:

通过包名来启动,这是最常见的

startActivity(new Intent(当前 Activity.this,要启动的 Activity.class));

通过 Intent 的 ComponentName

ComponentName cn = new ComponentName("当前 Activity 的全限定类名","启动 Activity 的全限定类名") ;
Intent intent = new Intent() ;
intent.setComponent(cn) ;
startActivity(intent) ;

初始化 Intent 时指定包名

Intent intent = new Intent("android.intent.action.MAIN");
intent.setClassName("当前 Activity 的全限定类名","启动 Activity 的全限定类名");
startActivity(intent);

6.2 隐式启动:

通过 Intent-filter 的 Action,Category 或 data 来实现

AndroidManifest.xml 配置

<activity android:name=".SecondActivity"
    android:label="第二个 Activity" >
    <intent-filter>
        <action android:name="ms_action" />
        <category android:name="ms_category" />
        <category android:name="android.intent.catetory.DEFAULT" />
    </intent-filter>

Java 代码

Intent it = new Intent();
it.setAction("ms_action");
it.addCategory("ms_category");
startActivity(it);

直接通过包名启动 apk 的

Intent intent = getPackageManager().getLaunchIntentForPackage
("apk 第一个启动的 Activity 的全限定类名") ;
if(intent != null)
    startActivity(intent) ;

7. Activity 数据传递

一个 App 一般都由多个 Activity 构成的,这就涉及到了多个 Activity 间数据传递的问题了

Activity 间的数据传递流程一般如下

  1. 一个传一个

    存数据

    Intent it1 = new Intent(A.this, B.class);
    it1.putExtra("key",value);
    startActivity(it1);
    

    取数据

    Intent it2 = getIntent();
    
    getXxxExtra("key");  // Xxx 是数据类型
    
  2. 一次传多个

    存数据

    Intent it1 = new Intent(A.this, B.class);
    Bundle bd  = new Bundle();
    
    bd.putInt("num",1);
    bd.putString("detail","www.twle.cn");
    
    it1.putExtra(bd);
    startActivity(it1);
    

    取数据

    Intent it2 = getIntent();
    Bundle bd  = it2.getExtra();
    
    int n = bd.getInt("num");
    String d = bd.getString("detail");

多个 Activity 间的交互 (后一个传回给前一个):

  1. 使用下面的方法启动一个 Activity

    startActivityForResult(Intent intent, int requestCode)
    
  2. 在要启动的 Activity 中重写方法

    onActivityResult(int requestCode, int resultCode, Intent data);
    
    参数说明
    requestCode

    用于区分该 Activity 中不同的启动方式,可以自定义

    比如有两个不同的按钮,启动的是同一个 Activity, 传递的数据可能不同,就可以使用 requestCode 来区分

    resultCode子 Activity 通过 setResult() 放回的码
  3. 在子 Activity 中重写

startActivityForResult的一个例子:

第一个Activity打开第二个Activity时,第二个Activity关闭并想返回数据给第一个Activity时,我们就要重写

onActivityResult(int requestCode, int resultCode, Intent data)这个方法.首先我们要在第一个Activity调用startActivityForResult这个方法,代码如下:

   public void onClick(View v) {
                //得到新打开Activity关闭后返回的数据
                //第二个参数为请求码,可以根据业务需求自己编号
                startActivityForResult(new Intent(MainActivity.this, OtherActivity.class), 1);
            }
        });

第二个Activity中使用setResult设置要返回的值:

putExtra() : 将数据返回 给 Intent

setResult // 设置返回的数据

public void onClick(View v) {
                //数据是使用Intent返回
                Intent intent = new Intent();
                //把返回数据存入Intent
                intent.putExtra("result", "My name is luis");
                //设置返回数据
                OtherActivity.this.setResult(RESULT_OK, intent);//RESULT_OK为自定义常量
                //关闭Activity
                OtherActivity.this.finish();
            }
        });

当第二个Activity关闭时,返回第一个Activity,在第一个Activity中重写onActivityResult方法,数据可以从data中取出:

String result = data.getExtras().getString("result");//得到新Activity 关闭后返回的数据

a.请求码的作用  requestCode :

使用startActivityForResult(Intent intent, int requestCode)方法打开新的Activity,我们需要为startActivityForResult()方法传入一个请求码(第二个参数)。请求码的值是根据业务需要由自已设定,用于标识请求来源。

例如:一个Activity有两个按钮,点击这两个按钮都会打开同一个Activity,不管是那个按钮打开新Activity,当这个新Activity关闭后,系统都会调用前面Activity的onActivityResult(int requestCode, int resultCode, Intent data)方法。在onActivityResult()方法如果需要知道新Activity是由那个按钮打开的,并且要做出相应的业务处理,这时可以这样做:

@Override  public void onCreate(Bundle savedInstanceState) {
        ....
        button1.setOnClickListener(new View.OnClickListener(){
            public void onClick(View v) {
                startActivityForResult (new Intent(MainActivity.this, NewActivity.class), 1);

           }

        });
        button2.setOnClickListener(new View.OnClickListener(){
            public void onClick(View v) {
                 startActivityForResult (new Intent(MainActivity.this, NewActivity.class), 2);

            }

        });

                          
       @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) {
               switch(requestCode){
                   case 1:
                   //来自按钮1的请求,作相应业务处理
                        String result = data.getExtras().getString("result");//得到新Activity 关闭后返回的数据
                   case 2:
                   //来自按钮2的请求,作相应业务处理
                }
          }
}

b.结果码的作用 resultCode:

在一个Activity中,可能会使用main 主活动页面中,startActivityForResult()方法打开多个不同的Activity处理不同的业务,

当这些新Activity关闭后,系统都会调用前面Activity的onActivityResult(int requestCode, int resultCode, Intent data)方法。为了知道返回的数据来自于哪个新Activity,在onActivityResult()方法中可以这样做(ResultActivity和NewActivity为要打开的新Activity):

public class ResultActivity extends Activity {
       .....
       ResultActivity.this.setResult(1, intent);
       ResultActivity.this.finish();
}
public class NewActivity extends Activity {
       ......
        NewActivity.this.setResult(2, intent);
        NewActivity.this.finish();
}
public class MainActivity extends Activity { // 在该Activity会打开ResultActivity和NewActivity
       @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) {
               switch(resultCode){
                   case 1:
                   // ResultActivity的返回数据
                   case 2:
                    // NewActivity的返回数据
                }
          }
} 

 

判断当前是哪个 Activity:

如果要判断当前是那个 Activity ,只需要让所有的 Activity 继承一个自定义的 BaseActivity

然后在 onCreate() 方法中添加以下语句

Log.d("BaseActivity",getClass().getSimpleName());
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值