欢迎您访问 最编程 本站为您分享编程语言代码,编程技术文章!
您现在的位置是: 首页

深入理解Android应用架构:Activity组件详细解析

最编程 2024-07-23 08:39:59
...

【正文】

注:四大组件指的是应用组件:Activity、Service、BroadcastReceiver、ContentProvider;之前的控件指的是UI组件。

博文目录:

  • 一、Activity简介
  • 二、Activity的状态和生命周期
  • 三、Activity的基本用法
  • 四、向下一个Activity传递数据
  • 五、返回数据给上一个Activity
  • 六、Activity运行时屏幕方向与显示方式
  • 七、Activity的现场保存
  • 八、Activity通过SharedPreferences保存数据

一、Activity简介:

Activity组件是四大组件之一,在应用中一个Activity可以用来表示一个界面, 中文意思也可以理解为“活动” ,即一个活动开始,代表Activity组件启动;活动结束,代表一个Activity的生命周期结束。

一个android应用必须通过Activity来运行和启动,和J2ME 的MIDlet 一样,在android中,Activity的生命周期统一交给系统管理。与MIDlet 不同的是安装在android 中的所有的Activity 都是平等的。

理解以下四个基本概念,将有助于我们更好的了解Activity:

• Application(APP)

• Activity

• Activity栈

• Task

每个Application均占有独立的内存空间。需要注意的是:Application之间虽然相互独立,但APP_1中的Activity与APP_2中的Activity之间可以进行通信(调用、访问等)。

二、Activity的状态和生命周期

1、Activity的状态:

(1)Resumed:Activity对象出于运行状态。一个新Activity 启动入栈后,它在屏幕最前端,处于栈的最顶端,此时它处于可见并可以与用户交互的激活状态。

(2)Paused:另一个Activity位于前端,但是本Activity还可见。

        Paused状态常用于:当Activity被另一个透明或者Dialog样式的Activity覆盖时的状态。此时它依然与窗口管理器保持连接,系统继续维护其内部状态,所以它仍然可见,但它已经失去了焦点故不可与用户交互。注:一个Activity出于paused状态时,系统并不会释放资源。释放资源你的操作要靠开发者来完成。

(3)Stopped:另一个Activity位于前端,完全遮挡本Activity。

(4)killed:Activity被系统杀死回收或者没有被启动时。

 绘制表格如下:

生命周期函数

调用时机

举例

onCreate

在Activity对象被第一次创建时调用

买车

onStart

当Activity变得可见时调用

打火,启动

onResume

当Activity开始准备和用户交互时调用

踩油门,驱动汽车前进

onPause

当系统即将启动另外一个Activity之前调用

松开油门

onStop

当前Activity变得不可见时调用

熄火

onDestroy

当前Activity被销毁之前调用

车辆报废

onRestart

当一个Activity再次启动之前调用

 

 

 

 

 

 

 

 

 

 

 

 

 

 

注:on开头的一般是事件的方法。(引申知识:观察者的设计模式

2、Activity的生命周期:

详情请见本人的另外一篇博客:Activity的生命周期

 

生命周期的完整代码如下:

import android.app.Activity;
import android.os.Bundle;
import android.util.Log;

public class MainActivity extends Activity {

    private static final String TAG = "smyhvae";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Log.d(TAG, "onCreate");
    }

    @Override
    protected void onStart() {
        super.onStart();
        Log.d(TAG, "onStart");
    }

    @Override
    protected void onResume() {
        super.onResume();
        Log.d(TAG, "onResume");
    }


    @Override
    protected void onPause() {
        super.onPause();
        Log.d(TAG, "onPause");
    }


    @Override
    protected void onStop() {
        super.onStop();
        Log.d(TAG, "onStop");
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        Log.d(TAG, "onDestroy");
    }

    @Override
    protected void onRestart() {
        super.onRestart();
        Log.d(TAG, "onRestart");
    }
}

 

 

三、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时,系统首先会在返回栈中检查是否存在该活动的实例,如果存在,则直接使用该实例(会调用实例的onNewIntent()方法),并把这个活动之上的所有活动统统清除;如果没有发现就会创建一个新的活动实例;

 

  • singleInstance模式:总是在新的任务中开启,并且这个新的任务中有且只有这一个实例,并让多个应用共享该栈中的该Activity实例。一旦该模式的Activity的实例存在于某个栈中,任何应用再激活该Activity时都会重用该栈中的实例。其效果相当于多个应用程序共享一个应用,不管谁激活该Activity都会进入同一个应用中。

注:也就是说被该实例启动的其他activity会自动运行于另一个任务中。当再次启动该activity的实例时,会重新调用已存在的任务和实例。并且会调用这个实例的onNewIntent()方法,将Intent实例传递到该实例中。和singleTask相同,同一时刻在系统中只会存在一个这样的Activity实例。(singleInstance即单实例)

 

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

 

1、singleInstance模式详解:

singleInstance模式从字面上看比较难理解,下面通过代码举例来分析。代码如下:

(1)新建三个Activity:FirstActivity、SecondActivity、ThirdActivity。同时,将SecondActivity的启动模式设置为singleInstance

(2)三个Activity的代码如下:

FirstActivity.java:

 1 import android.app.Activity;
 2 import android.content.Intent;
 3 import android.os.Bundle;
 4 import android.util.Log;
 5 import android.view.View;
 6 import android.widget.Button;
 7 
 8 
 9 public class FirstActivity extends Activity {
10 
11     private Button button1;
12 
13     @Override
14     protected void onCreate(Bundle savedInstanceState) {
15         super.onCreate(savedInstanceState);
16         Log.d("--->FirstActivity", "返回栈的id是" + getTaskId());  //打印当前返回栈的id
17         setContentView(R.layout.activity_main);
18         button1 = (Button) findViewById(R.id.button1);
19         button1.setOnClickListener(new View.OnClickListener() {
20             @Override
21             public void onClick(View v) {
22                 startActivity(new Intent(FirstActivity.this, SecondActivity.class));
23 
24             }
25         });
26     }
27 
28 }

上方代码中,在onCreate()方法中打印当前返回栈的id。点击按钮,跳转到SecondActivity。

 

SecondActivity.java:

 1 import android.app.Activity;
 2 import android.content.Intent;
 3 import android.os.Bundle;
 4 import android.util.Log;
 5 import android.view.View;
 6 import android.widget.Button;
 7 
 8 
 9 public class SecondActivity extends Activity {
10 
11     private Button button2;
12 
13     @Override
14     protected void onCreate(Bundle savedInstanceState) {
15         super.onCreate(savedInstanceState);
16         Log.d("--->SecondActivity", "返回栈的id是" + getTaskId());  //打印当前返回栈的id
17         setContentView(R.layout.activity_second);
18         button2 = (Button) findViewById(R.id.button2);
19         button2.setOnClickListener(new View.OnClickListener() {
20             @Override
21             public void onClick(View v) {
22                 startActivity(new Intent(SecondActivity.this, ThirdActivity.class));
23 
24             }
25         });
26     }
27 
28 }

 

上方代码中,在onCreate()方法中打印当前返回栈的id。点击按钮,跳转到ThirdActivity。

ThirdActivity.java:

 1 import android.app.Activity;
 2 import android.os.Bundle;
 3 import android.util.Log;
 4 import android.widget.Button;
 5 
 6 
 7 public class ThirdActivity extends Activity {
 8 
 9     private Button button3;
10 
11     @Override
12     protected void onCreate(Bundle savedInstanceState) {
13         super.onCreate(savedInstanceState);
14         Log.d("--->ThirdActivity", "返回栈的id是" + getTaskId());  //打印当前返回栈的id
15         setContentView(R.layout.activity_third);
16     }
17 
18 }

 

运行程序,在FirstActivity中点击按钮进入SecondActivity中,然后在SecondActivity中点击按钮进入ThirdActivity。后台打印日志如下:

上方日志可以看到:SecondActivity的Task id不同于FirstActivity和ThirdActivity,这说明SecondActivity确实是存放在一个单独的返回栈中的,而且这个返回栈中只有SecondActivity这一个活动。

然后,我们按下Back键进行返回,你会发现ThirdActivity竟然直接返回到了FirstActivity,再按下Back键又会返回到SecondActivity,再按下Back键才会退出程序。解释如下:

FirstActivity和ThirdActivity存放在同一个返回栈里,当在ThirdActivity中按下Back键,ThirdActivity出栈,那么FirstActivity就成为了栈顶活动显示在界面上;然后在FirstActivity界面再次按下Back键,这是当前的返回栈已经空了,于是就显示了另一个返回栈的栈顶活动,即SecondActivity。最后按下Back键,这时,所有的返回栈都已经空了,自然也就退出了程序。 

 

三、Activity的基本用法:

1、隐藏标题栏:

requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.activity_main);  

注:第一行代码一定要在第二行代码之前执行。

2、在活动当中使用Toast:

例如点击按钮时,弹出吐司:

1          button.setOnClickListener(new OnClickListener() {            
2              @Override
3              public void onClick(View v) {
4                  Toast.makeText(MainActivity.this, "You clicked the Button",Toast.LENGTH_SHORT).show();                
5              }                
6          });

3、启动一个Activity的方法:即在默认启动的Activity中启动另一个Activity

核心代码如下:

Intent intent = new Intent();
intent.setClass(MainActivity.this, SecondActivity.class); 

具体过程请参考本人的另一篇博客: 当前Activity跳转到另一个Activity的详细过程

 

4、隐式Intent的用法:

使用隐式Intent,我们不仅可以启动自己程序内的活动,还可以启动其他程序的活动,这使得Android多个应用程序之间的功能共享成为了可能。比如应用程序中需要展示一个网页,没有必要自己去实现一个浏览器(事实上也不太可能),而是只需要条用系统的浏览器来打开这个网页就行了。

【实例】:打开指定网页。

监听器部分的核心代码如下:

1         button.setOnClickListener(new OnClickListener() {            
2             @Override
3             public void onClick(View v) {
4                 Intent intent = new Intent(Intent.ACTION_VIEW);
5                 intent.setData(Uri.parse("http://www.baidu.com"));
6                 startActivity(intent);
7             }
8         }); 

第4行代码:指定了Intent的action是 Intent.ACTION_VIEW,这是一个Android系统内置的动作;

第5行代码:通过Uri.parse()方法,将一个网址字符串解析成一个Uri对象,再调用intent的setData()方法将这个Uri对象传递进去。

详见:《android第一行代码》P48页。

如果要打电话的话,可以使用下面的代码:

                Intent intent = new Intent(Intent.ACTION_DIAL);
                intent.setData(Uri.parse("tel:10086"));
                startActivity(intent);					

推荐阅读