分享

Android基础之四大组件

 纪平aa8woyo5no 2017-11-04


1.什么是Activity?

  Activity是用户接口程序,它是Android应用程序的基本功能单元,它的主要功能是提供界面。Activity是Android的核心类,该类的全名是android.app.Activity。Activity相当于C/S程序中的窗体(From)或Web程序的页面。每一个Activity提供一个可视化的区域。在这个区域可以放置各种Android组件,例如按钮、图像、文本框等。
  在Activity类中有一个oncreate事件方法,一般在该方法中对Acticity进行初始化。通过setContentView方法可以设置在Activity上显示视图组件。
  一个带界面的Android应用程序可以由一个或者多个Activity组成。至于这些Activity如何工作,它们之间的依赖关系,则完全取决于应用程序间的业务逻辑。

2.Activity生命周期

  在Activity建立到摧毁的过程中需要在不同的阶段调用7个生命周期方法。这七个生命周期的定义如下:

    protected void onCreate(Bundle savedInstanceState) {} //在这里创建界面,做一些数据的初始化工作;
    protected void onStart() {} //到这一步变成“用户可见不可交互”的状态;
    protected void onResume() {} //变成和用户可交互的,(在Activity栈系统通过栈的方式管理这些Activity,即当前Activity在栈的最上端,运行完弹出栈,则回到上一个Activity);
    protected void onPause() {} //到这一步是可见但不可交互的,系统会停止动画等消耗CPU的事情。从上文的描述已经知道,应该在这里保存你的一些数据,因为这个时候你的程序的优先级降低,有可能被系统收回。在这里保存的数据,应该在onResume里读出来。
    protected void onStop() {} //变得不可见 ,被下一个activity覆盖了
    protected void onRestart() {}
    protected void onDestroy() {} //activity被消灭
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

  上面7个生命周期分别在4个阶段按一定顺序进行调用,

  • 开始Activity:onCreate、onStart和onResume方法
  • Activity失去焦点:onPause和onStop方法
  • Activity重新获得焦点:onRestart、onStart和onResume方法
  • 关闭Activity:当Activity被关闭时系统会依次执行3个生命周期方法—onPause、onStop和onDestory方法

    Activity的生命周期如下图所示

    这里写图片描述

      从图中可以看出Activity包含两层循环,第一层是onPause->onResume->onPause,第二层循环是onStop->onRestart->onStart->onResume->onPause->onStop。我们可以讲两层循环看成是整个Activity生命周期中的子生命周期。第一层成为焦点生命周期,第二层为可视生命周期。也就是说,第一层循环在Acitvity焦点的获取与失去的过程中循环,这一过程中Activity是可见的。第二层循环实在Activity可见与不可见的过程中循环。
      因此,Activity有如下三种生命周期:

  • 整体生命周期:onCreate->……->onDestroy.

  • 可视生命周期:onStart->……->onStop.
  • 焦点生命周期:onResume->onPause.

3.生命周期演示

示例代码如下:

package com.hlh.activitydemo;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;

public class MainActivity extends AppCompatActivity {

    private static String TAG = "MainActivity";

    @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 onRestart() {
        super.onRestart();
        Log.d(TAG, "onRestart: ");
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        Log.d(TAG, "onDestroy: ");
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53

按如下步骤来操作应用程序:
(1)启动应用程序
(2)按手机上的主页按钮进入主界面,然后重新进入应用程序界面
(3)关闭应用程序
按照上面步骤执行后,DDMS的Logcat打印的信息如下:
这里写图片描述
从这个例子我们可以清晰看出Activity的整个生命周期的过程。

4.Activity之间的通信

  在 Android 中,不同的 Activity 实例可能运行在一个进程中,也可能运行在不同的进程中。因此我们需要一种特别的机制帮助我们在 Activity 之间传递消息。Android 中通过 Intent 对象来表示一条消息,一个 Intent 对象不仅包含有这个消息的目的地,还可以包含消息的内容,这好比一封 Email,其中不仅应该包含收件地址,还可以包含具体的内容。对于一个 Intent 对象,消息“目的地”是必须的,而内容则是可选项。
  Intent负责对操作的动作、动作涉及数据、附加数据进行描述,Android则根据此Intent的描述,负责找到对应的组件,将 Intent传递给调用的组件,并完成组件的调用。因此,Intent在这里起着一个媒体中介的作用,专门提供组件互相调用的相关信息,实现调用者与被调用者之间的解耦。
  通过下面实例我们可以很好的了解Activity之间的通信,在主界面中点击按钮跳转到另外一个activity,同时将数据传递给OtherActivity,绑定在TextView中。
  MainActivity.java

public class MainActivity extends AppCompatActivity {
    private static String TAG = "MainActivity";
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Button bt = (Button) findViewById(R.id.toOther);
        bt.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent(MainActivity.this, OtherActivity.class);
                intent.putExtra("msg", "hello Activity");
                startActivity(intent);
            }
        });
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

OtherActivity.java

public class OtherActivity extends Activity{
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_other);
        TextView tv = (TextView) findViewById(R.id.tv);
        Intent intent = getIntent();
        //设置文本
        tv.setText(intent.getStringExtra("msg"));
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

note:新建立了一个Actvity后,必须在AndroidManifest.xml清单文件中的标签中注册该actvity。

<activity android:name=".OtherActivity"/>
  • 1

应用程序截图:这里写图片描述这里写图片描述

5.Activity之加载模式

  Activity有四种加载模式(launchMode)。launchMode在多个Activity跳转的过程中扮演着重要的角色,它可以决定是否生成新的Activity实例,是否重用已经存在的实例,是否和其他Activity共用一个task。简单介绍一个task,task是一个具有栈结构的对象,一个task可以管理多个Activity,启动一个应用,也就创建一个与之对应的task。
  Activity的四种加载模式如下:
  1.standard
  2.singleTop
  3.singleTask
  4.singleInstance
  我们可以在AndroidManifest.xml配置的Android:launchMode属性为以上四种之一即可。
  下面我们结合实例一一介绍这四种lanchMode:
  1.standard
  standard模式是默认的启动方式,不用为配置android:launchMode属性即可,当然也可以指定值为standard。我们创建一个Activity,命名为FirstActivity,来演示一下标准的启动模式。FirstActivity代码如下:

public class FirstActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_first);
        TextView textView = (TextView) findViewById(R.id.tv);
        textView.setText(this.toString());
        Button button = (Button) findViewById(R.id.start);
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent(FirstActivity.this, FirstActivity.class);
                startActivity(intent);
            }
        });
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

  FirstActivity界面中的TextView用来显示当前Activity实例的序列号,Button跳转到下一个界面
连续点击几个Button按钮,将会出现下面现象:
这里写图片描述
这里写图片描述
这里写图片描述
  我们发现都是FirstActivity实例但是序列号不一样,并且我们需要按两次后退键才能返回到第一个  FirstActivity。每次跳转系统都会在task中生成一个新的FirstActivity实例,并且将其放在栈顶,当我们按下back键时,才能看到原来的FirstActivity实例。
  因此总结出standard启动模式,不管有没有已经存在的实例,都会生成一个新的实例。 
  2.singleTop
  我们在上面的基础上为指定属性android:launchMode=”singleTop”,系统就会按照singleTop启动模式处理跳转行为。我们重复上面几个动作,将会出现下面的现象:
这里写图片描述
这里写图片描述
这里写图片描述
我们看到这个跟standard的结果不同,三个序列号都一样,也就是说使用的是同一个FirstActivity实例。如果按back键,程序会立即退出。跳转时系统会先在栈结构中寻找是否有一个FirstActivity实例正位于栈顶,如果有则不再生成新的,而是直接使用。也许有人会有疑问,我只看到栈内只有一个Activity,如果是多个Activity怎么办,如果不是在栈顶会如何?我们接下来再通过一个示例来证实一下大家的疑问。
再新建一个Activity命名为SecondActivity,代码如下:

public class SecondActivity extends Activity{
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_second);
        TextView tv = (TextView) findViewById(R.id.tv);
        tv.setText(this.toString());
        Button button = (Button) findViewById(R.id.start);
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent(SecondActivity.this, FirstActivity.class);
                startActivity(intent);
            }
        });
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

然后将之前的FirstActivity跳转代码改为:

Intent intent = new Intent(FirstActivity.this, SecondActivity.class);  
startActivity(intent);  
  • 1
  • 2

演示结果如下:
这里写图片描述
这里写图片描述
这里写图片描述
我们看到,两个FirstActivity的序列号是不同的,证明从SecondActivity跳转到FirstActivity时生成了新的FirstActivity实例。
我们看到,当从SecondActivity跳转到FirstActivity时,系统发现存在有FirstActivity实例,但不是位于栈顶,于是重新生成一个实例。
这就是singleTop启动模式,如果发现有对应的Activity实例正位于栈顶,则重复利用,不再生成新的实例。
  3.singleTask
  在上面的基础上我们修改FirstActivity的属性android:launchMode=”singleTask”。演示的结果如下:
这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述
我们注意到,在上面的过程中,FirstActivity的序列号是不变的,SecondActivity的序列号却不是唯一的,说明从SecondActivity跳转到FirstActivity时,没有生成新的实例,但是从FirstActivity跳转到SecondActivity时生成了新的实例。
  在这个跳转过程中系统发现有存在的FirstActivity实例,于是不再生成新的实例,而是根据栈先进后出的原则将FirstActivity之上的Activity实例统统出栈(如SecondActivity),将FirstActivity变为栈顶对象,显示到幕前。如果将SecondActivity也设置为singleTask模式,那么SecondActivity实例是不是可以唯一呢?在我们这个示例中是不可能的,因为每次从SecondActivity跳转到FirstActivity时,SecondActivity实例都被迫出栈,下次等FirstActivity跳转到SecondActivity时,找不到存在的SecondActivity实例,于是必须生成新的实例。但是如果我们有ThirdActivity,让SecondActivity和ThirdActivity互相跳转,那么SecondActivity实例就可以保证唯一。
  这就是singleTask模式,如果发现有对应的Activity实例,则使此Activity实例之上的其他Activity实例统统出栈,使此Activity实例成为栈顶对象,显示到幕前。
  4.singleInstance
  这种启动模式比较特殊,因为它会启用一个新的栈结构,将Acitvity放置于这个新的栈结构中,并保证不再有其他Activity实例进入。
我们修改FirstActivity的launchMode=”standard”,SecondActivity的launchMode=”singleInstance”,由于涉及到了多个栈结构,我们需要在每个Activity中显示当前栈结构的id,所以我们为每个Activity添加如下代码:

TextView textView = (TextView) findViewById(R.id.tv);
textView.setText("current task id: " + this.getTaskId());
  • 1
  • 2

然后再演示一下这个流程:
这里写图片描述
这里写图片描述
我们发现这两个Activity实例分别被放置在不同的栈结构中.可以发现从FirstActivity跳转到SecondActivity时,重新启用了一个新的栈结构,来放置SecondActivity实例,然后按下后退键,再次回到原始栈结构。

6.Activity的栈式管理

  Android针对Activity的管理使用的是栈。你有可能不清楚什么是栈,现在来解释一下,栈是指数据项按序排列的数据结构,只能在一端(称为栈顶(top))对数据项进行插入和删除,一种先进后出的数据结构。而Android中是用task来存放Activity的。在第五小节简单介绍了一下task。这里详细介绍一下
  google官网对task的定义:

A task is a collection of activities that users interact with when 
performing a certain job. The activities are arranged in a stack 
(the back stack), in the order in which each activity is opened.
  • 1
  • 2
  • 3

  简单来说task就是一组特定的activities集合,这些activities按照每一个被打开的顺序放到一个stack(栈)中。Activity栈可以由一个或者多个Task组成。
  启动一个应用时,系统会为之创建一个task来放置Activity,默认情况下,一个Activity启动另外一个Activity时,两个Activity放入同一个task中,后者被压入前者所在的task栈中。当用户按back键,后者从栈中弹出,前者又显示在屏幕上。重点强调的是,启动其他应用的Activity时,两个Activity对用户来说好像属于同一个应用,其实这两个Activity都创建了自己的task栈。系统中task和task之间是相互独立的,当我们运行应用A时,按Home键回到主屏,启动另外一个应用B,这时应用A的task被转移到后台,刚启动的应用B的task被转移到前台,其栈顶Activity会显示在屏幕上;再次按Home键回到开始启动的应用A时,A应用的task任务栈又被转移到前台,这时系统仍然保留task的所有Activity实例。
  
  

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多