购买
下载掌阅APP,畅读海量书库
立即打开
畅读海量书库
扫码下载掌阅APP

5.1 Activity基础

Activity是Android项目中最直观并且也是使用最多的一个组件,基本上所有的项目都是由多个Activity组成的。作为Android的四大组件之一,在使用它的时候还需要对其在清单文件AndroidManifest.xml中进行配置。本小节将讲解Activity在Android中的正常使用,以及如何开启一个新的Activity、如何在Activity开启的过程中传值、如何在清单文件AndroidManifest.xml中配置Activity等内容。

5.1.1 Activity简介

在一个新建的Android项目中,将会自动生成一个Activity,默认情况下,这个Activity作为当前应用的主页面,在应用被启动的时候初始化。

从自动生成的Activity中可以看出,使用Activity非常的简单,只需要继承即可。Activity位于android.app.Activity包下,间接继承了Context,而作为一个承载显示界面的系统组件,它有具有多个子类,用于实现一些特殊的显示界面。

下图显示了Activity的继承结构:

如上图所示,Ac tivity类间接或直接继承了Context、ContextWrapper、ContextThemeWrapper,因此可以直接使用它们中定义的方法,Activity还具有很多已实现的子类,无非就是对Activity进行了扩展,在Activity的基础上封装了一些额外的功能,例如ListActivity就在Activity中封装了一个ListView,ListActivity的例子在讲解ListView已经给出,这里不再赘述。

既然Activity是用来承载一个操作界面的,那么必须在Activity初始化的时候,完成操作界面的绘制,这个必须在onCreate()方法中实现,这是一个Activity的生命周期方法,在启动Activity的时候会被回调,在onCreate()方法中调用Activity.setContentView()方法加载一个需要显示的View,setContentView()具有多个重载方法,无非就是数据源不同而已,下面是这些setContentView()方法的重载方法的完整签名:

· void setContentView(int layoutResID):指定一个XML布局资源。

· void setContentView(View view):指定一个View对象。

· void setContentView(View view,ViewGroup.LayoutParams params):指定一个View对象,并设置其位置。

当加载了界面显示的View之后,可以使用Activity.findViewById(int)方法找到界面显示的View中的UI组件。

下面在默认项目中添加一个初始的Activity。

代码清单:\codes\05\01\ActivityBaseDemo\src\com\bookdemo\activitybasedemo\NewActivity.java

public class NewActivity extends Activity {
    private Button btnFinish;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_new);

        btnFinish = (Button) findViewById(R.id.btnFinish);
    }
} 

新定义的Activity还无法使用,还需要对其进行配置,下面来讲解如何配置一个Activity。

5.1.2 配置Activity

Android四大组件,在使用的时候均需要在清单文件AndroidManifest.xml中显示的进行配置。所以只定义一个Activity还无法使用它,需要在AndroidManifest.xml文件的<application…/>元素中添加<activity…/>子元素即可完成Activity的配置。在<activity…/>元素中,必须配置android:name属性,用来设定配置的Activity的实现类,它还具有一些其它的属性,用来配置其它的内容。

代码清单:\codes\05\01\ActivityBaseDemo\AndroidManifest.xml

    <activity
    android:icon="@drawable/icon"
    android:name="com.bookdemo.activitybasedemo.NewActivity"
    android:label="NewActivity" >
    </activity>

上面为之前定义的Activity进行了配置,其中的<activity…/>元素内有三个比较常用的属性,它们分别代表了:

· android:name:指定Activity的实现类。

· android:label:指定Activity的标签。

· android:icon:指定Activity的图标。

对于android:name属性而言,有时候会看到不写全类名,而只是用一个点代替,这是因为在当前<manifest…/>的包下的Activity,是可以使用省略包名,使用一个点代替,如:

android:name=".MainActivity"

在<activity…/>元素中,还有一个子元素<intent-filter…/>,这是一个意图过滤器,用来指定开启的Activity,在后面会有单独章节对其进行详细介绍。

5.1.3 启动和关闭一个Activity

Android项目中会包含多个Activity,但是只有一个Activity作为程序的入口Activity,该Activity通过清单文件AndroidManifest.xml进行配置,通常其它Activity会从一个当前显示的Activity进行启动。

从一个Activity启动另外一个Activity,需要用到一个Activity.startActivity()方法,这方法会传递一个Intent对象,它封装了一个意图信息,用于指定启动的Android组件,这里指定的是一个Activity。这个方法的完整签名如下:

void startActivity(Intent intent)

启动了一个Activity就伴随着需要关闭一个Activity。关闭Activity除了使用设备上的回退键之外,还可以使用Activity.finish()方法,这个方法会关闭当前的Activity,使当前Activity从回退栈退栈,并显示退栈后栈顶的Activity。

示例:开启一个新的Activity,并在其中关闭自己,注意新声明的Activity也需要在清单文件中进行配置。

代码清单:\codes\05\01\ActivityBaseDemo\src\com\bookdemo\activitybasedemo\MainActivity.java

public class MainActivity extends Activity {
    private Button btnOpenNewActivity;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        btnOpenNewActivity=(Button) findViewById(R.id.btnOpenNewActivity);
        btnOpenNewActivity.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                // 开启一个Activity,指定当前上下文和目标Activity
                Intent intent=new Intent(MainActivity.this, NewActivity.class);
                startActivity(intent);
            }
        });        
    }    
}

代码清单:\codes\05\01\ActivityBaseDemo\src\com\bookdemo\activitybasedemo\NewActivity.java

public class NewActivity extends Activity {
    private Button btnFinish;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_new);

        btnFinish = (Button) findViewById(R.id.btnFinish);
        btnFinish.setOnClickListener(new View.OnClickListener() {

            @Override
            public void onClick(View v) {
                Toast.makeText(NewActivity.this, "您关闭了新开启的Activity",
                        Toast.LENGTH_SHORT).show();
                finish();
            }
        });
    }
}

5.1.4 从新启动的Activity中返回数据

启动与关闭一个Activity,两个Activity并没有任何数据的交互。但是在实际项目中,通常情况下开启一个新的Activity是为了处理一些任务,并在任务处理结束后,获得处理结果。

如果需要从新开启的Activity中返回数据,需要用到Activity的另外一个启动方法Activity.startActivityForResult(),它会传递一个Intent对象,还需要传递一个整形的请求码,用于标识唯一的请求,这个标识可以是任意数。startActivityForResult()方法的完整签名如下:

void startActivityForResult(Intent intent,int requestCode)

在新的Activity中,处理完成任务之后,需要把处理结果进行返回。对于一些简单的逻辑,只需要在返回成功或者失败的情况下,可以使用setResult()方法,指定一个响应码,使用这个响应码来确定任务是否成功完成,最后调用finish()方法关闭这个Activity,它的完整签名如下:

void setResult(int resultCode)

在确定了requestCode和resultCode之后,还需要再重写原Activity的onActivityResult()方法,用于接受新开启的Activity的返回码开启时的请求码,onActivityResult()方法的完整签名如下:

void onActivityResult(int requestCode, int resultCode, Intent data)

onActivityResult()方法的参数很简单,requestCode是开启Activity的时候传递的请求码,resultCode是新开启的Activity返回的响应码,date是新开启的Activity传递的数据内容,之后会详细讲解。

从新Activity中返回数据的整个流程如下:

1. 在原Activity中使用startActivityForResult()方法启动一个目标Activity,并指定请求码。

2. 在目标Activity中执行任务,在执行完成之后使用setResult()方法返回响应码,并使用finish()关闭Activity。

3. 重写原Activity的onActivityResult()方法,用于处理目标Activity返回的数据。

示例:开启一个新的Activity,获得其用户选择的性别。

代码清单:\codes\05\01\ActivityBaseReturnCodeDemo\src\com\bookdemo\activitybasereturncodedemo\MainActivity.java

public class MainActivity extends Activity {
    private Button btnOpenNewActivity;
    private final static int REQUEST_CODE = 101;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        btnOpenNewActivity = (Button) findViewById(R.id.btnOpenNewActivity);
        btnOpenNewActivity.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                // 实例化一意图,指定当前上下文和目标Activity
                Intent intent = new Intent(MainActivity.this, NewActivity.class);
                // 启动一个指定请求码的Activity
                startActivityForResult(intent, REQUEST_CODE);
            }
        });
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        // 通过请求码和响应码判断逻辑
        if (requestCode == REQUEST_CODE) {
            if (resultCode == 1) {
                Toast.makeText(MainActivity.this, "您选择了:male!", Toast.LENGTH_SHORT)
                        .show();
            } else if (resultCode == 0) {
                Toast.makeText(MainActivity.this, "您选择了:female!", Toast.LENGTH_SHORT)
                        .show();
            }
        }
        super.onActivityResult(requestCode, resultCode, data);
    }
}

代码清单:\codes\05\01\ActivityBaseReturnCodeDemo\res\layout\activity_new.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="请选择性别" />

    <RadioGroup
        android:id="@+id/rgGender"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" >

        <RadioButton
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="male" />

        <RadioButton
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="female" />
</RadioGroup>

    <Button
        android:id="@+id/btnReturn"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="关闭" />

</LinearLayout><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="请选择性别" />

    <RadioGroup
        android:id="@+id/rgGender"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" >

        <RadioButton
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="male" />

        <RadioButton
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="female" />
</RadioGroup>

    <Button
        android:id="@+id/btnReturn"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="关闭" />

</LinearLayout>

代码清单:\codes\05\01\ActivityBaseReturnCodeDemo\src\com\bookdemo\activitybasereturncodedemo\NewActivity.java

public class NewActivity extends Activity {
    private Button btnReturn;
    private RadioGroup rgGender;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_new);

        rgGender = (RadioGroup) findViewById(R.id.rgGender);
        btnReturn = (Button) findViewById(R.id.btnReturn);
        btnReturn.setOnClickListener(new View.OnClickListener() {

            @Override
            public void onClick(View v) {
                int flag = -1;
                for (int i = 0; i < rgGender.getChildCount(); i++) {
                    // 判断用户选择的性别
                    RadioButton radioButton = (RadioButton) rgGender
                            .getChildAt(i);
                    if (radioButton.isChecked()) {
                        if (radioButton.getText().toString().equals("male")) {
                            flag = 1;
                        } else if (radioButton.getText().toString()
                                .equals("female")) {
                            flag = 0;
                        }
                    }
                }
                if (flag == -1) {
                    Toast.makeText(NewActivity.this, "请选择性别!",
                            Toast.LENGTH_SHORT).show();
                }else{
                    // 设置响应码,并结束Activity
                    setResult(flag);
                    finish();
                }                
            }
        });
    }
}

在模拟器上运行效果如图:

在原Activity重写的onActivityResult()方法中,通过请求码和响应码判断响应逻辑是非常明智的设计,因为同一个Activity可以被多个Activity启动,而一个Activity也可以启动多个Activity。使用请求码和响应码就可以在onActivityResult()方法中唯一确定一个返回的处理逻辑,这样避免了处理逻辑的混乱。

5.1.5 在Activity间使用Bundle传递数据

无论是开启一个Activity还是从开启的Activity中返回数据,仅仅使用请求码和响应码,是远远达不到我们的需求的。那么如何在Activity启动和关闭的过程中,传递一个复杂的数据呢?

先让我们回忆一下前面讲解的启动与关闭Activity时获取数据的几个关键的方法:

· void startActivity(Intent intent):开启一个Intent指定的Activity。

· void startActivityForResult(Intent intent,int requestCode):开启一个待返回数据的Intent指定的Activity,并设置请求码。

· void setResult(int resultCode,Intent date):设置返回码,并指定一个Intent对象。

· void onActivityResult(int requestCode, int resultCode, Intent data):以startActivityForResult()方法开启的Activity,结束时设置了返回码的情况下被回调。

上面的方法,都涉及到一个Intent对象,之前讲解如何启动Activity的时候,提到Intent是一个意图,可以指定待启动的Android组件,其实它还可以在各个Android组件之间传递数据。

Intent本身并不维护数据,它维护一个Bundle对象,这个Bundle对象内部又维护了一个Key-Value键值对的HashMap<String, Object>集合,在这个Map集合中即可完成数据的存储,并伴随着Intent在各个Android组件之间进行传递。

Bundle既然是一个HashMap<String, Object>的集合,它也提供了一系列的putXxx()方法,用于设置Key-Value键值对的数据,还为putXxx()方法提供了一系列对应的getXxx()方法,用于通过key值获取数据。Bundle除了可以操作基本数据类型和基本数据类型的数组,它还可以传递一个实现了Serializable接口的对象,Serializable指定该对象可被序列化,也就是说,Bundle不但可以传递基本数据类型,还可以传递任何对象数据。而Bundle本身也是实现了Serializable接口,可以被序列化的,所以它才可以在不同组件之间完成数据的传递。

定义好Bundle对象中的数据之后,可以把数据关联到Intent中,在Intent中设置与获取其中的Bundle对象,可以使用如下两个方法:

· Intent putExtras(Bundle extras):为Intent设置Bundle对象。

· Bundle getExtras():获取Intent中的Bundle对象。

Intent内部维护了Bundle对象,为了简化操作,它还提供了putExtra()方法,这个方法具有一系列的重载,用于支持Bundle类支持的多种类型,其实内部还是在Bundle对象中保存数据。Intent并没有提供对应的getExtra方法,只能通过getExtras()获取Intent中的对象,再从Bundle对象获取所需的数据。 C1MN+TIvFItWgs5QVBoFH0/XbNtLmSmOlDwhf0aP9DYguQgHvY7kTMaj8H+pxJbV

点击中间区域
呼出菜单
上一章
目录
下一章
×