直接为之前的GeoQuiz应用添加第二个activity

第一个activity控制一屏信息,新activity将带来第二个用户界面,方便用户偷看当前问题的答案。

一.创建第二个 activity

   创建新的activity至少涉及三个文件:Java类、XML布局和应用的manifest文件。使用Android stdio的新建activity向导功能。

   activity_cheat.xml创建布局XML文件,代码如下:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:gravity="center"
    tools:context="com.bignerdranch.android.geoquiz.CheatActivity"
>

    <TextView   android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:padding="24dp"
        android:text="@string/warning_text"
/>

    <TextView   android:id="@+id/answer_text_view"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:padding="24dp"
        tools:text="Answer"
/>

    <Button   android:id="@+id/show_answer_button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/show_answer_button"
/>
</LinearLayout>

manifest配置文件中声明 activity manifest配置文件是一个包含元数据的XML文件,用来向Android操作系统描述应用。

这里记下一个小技巧:使用Android Studio的快速打开文件功能---使用Command+Shift+O(或Ctrl+Shift+N)快捷键,呼出快速打开对话框,利用提示功 能或直接输入目标文件名,按回车键打开。

应用的所有activity都必须在manifest配置文件中声明,这样操作系统才能够找到它们。

现在在manifest文件中已经可以看到新建activity的声明:

<activity android:name=".CheatActivity"></activity>

这样之后直接在layout/activity_quiz.xml和layout-land/activity_quiz.xml布局文件中定义CHEAT新按钮就可以了。

<Button   android:id="@+id/cheat_button"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="@string/cheat_button"
/>

 

<Button   android:id="@+id/cheat_button"
           android:layout_width="wrap_content"
          android:layout_height="wrap_content"
          android:layout_gravity="bottom|center_horizontal "
          android:text="@string/cheat_button"
/>

最后为CHEAT按钮添 加View.onClickListener监听器代码:

mCheatButton = (Button)findViewById(R.id.cheat_button);
mCheatButton.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        // Start CheatActivity   }   });

二.启动activity

   public void startActivity(Intent intent)

activity调用startActivity(Intent)方法时,调用请求实际发给了操作系统。 准确地说,调用请求发送给了操作系统的ActivityManager。ActivityManager负责创建 Activity实例并调用其onCreate(Bundle)方法。

Android开发之第二个activity 

intent对象是component用来与操作系统通信的一种媒介工具。

public Intent(Context packageContext, Class<?> cls) 传入该方法的Class类型参数告诉ActivityManager应该启动哪个activity;Context参数告 诉ActivityManager在哪里可以找到它。如图:

Android开发之第二个activity 

在启动activity前,ActivityManager会确认指定的Class是否已在manifest配置文件中声明。 如果已完成声明,则启动activity,应用正常运行。反之,则抛出ActivityNotFoundException 异常,应用崩溃。这就是必须在manifest配置文件中声明应用的全部activity的原因。

显式intent与隐式intent

如果通过指定Context与Class对象,然后调用intent的构造方法来创建Intent,则创建的是显式intent。在同一应用中,我们使用显式intent来启动activity。

同一应用里的两个activity,却要借助于应用外部的ActivityManager通信,这似乎有点怪。不过,这种模式会让不同应用间的activity交互变得容易很多。

一个应用的activity如需启动另一个应用的activity,可通过创建隐式intent来处理。

三.activity间的数据传递 

  例如本例中

   Android开发之第二个activity

CheatActivity启动后,QuizActivity会通知它当前问题的答案。 用户知道答案后,点击后退键回到QuizActivity,CheatActivity随即被销毁。在销毁前 的瞬间,它会将用户是否作弊的数据传递给QuizActivity。

1. QuizActivity到CheatActivity的数据传递

为通知CheatActivity当前问题的答案,需将以下语句的返回值传递给它: mQuestionBank[mCurrentIndex].isAnswerTrue()

该值将作为extra信息,附加在传入startActivity(Intent)方法的Intent上发送出去。  

extra信息可以是任意数据,它包含在Intent中,由启动方activity发送出去。可以把extra信息想象成构造函数参数。接受方activity接收到操作系统转发的intent后,访问并获取其中的 extra数据信息。

如图:

Android开发之第二个activity 

extra是一种键值结构。要将extra数据信息添加给intent,调用:

public Intent putExtra(String name, boolean value)

这其中一个参数是固定为 String类型的键,另一个参数是键值,可以是多种数据类型。该方法返回intent自身。

现在,可以返回到QuizActivity,将extra附加到intent上。不过有个更好的实现方法。 对于CheatActivity处理extra信息的实现细节,QuizActivity和应用的其他代码无需知道。因此,我们可转而在newIntent(...)方法中封装这些逻辑。

CheatActivity.java中:  

public static Intent newIntent(Context packageContext, boolean answerIsTrue) {
    Intent intent = new Intent(packageContext, CheatActivity.class);
    intent.putExtra(EXTRA_ANSWER_IS_TRUE, answerIsTrue);
    return intent;
    QuizActivity.java中:

  boolean answerIsTrue = mQuestionBank[mCurrentIndex].isAnswerTrue();
Intent intent = CheatActivity.newIntent(QuizActivity.this, answerIsTrue);

 

获取extra信息:

mAnswerIsTrue = getIntent().getBooleanExtra(EXTRA_ANSWER_IS_TRUE, false);

最后在CheatActivity.java中提供作弊机会:

mAnswerIsTrue = getIntent().getBooleanExtra(EXTRA_ANSWER_IS_TRUE, false);
mAnswerTextView = (TextView) findViewById(R.id.answer_text_view);
mShowAnswerButton= (Button) findViewById(R.id.show_answer_button);
mShowAnswerButton.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        if (mAnswerIsTrue) {
            mAnswerTextView.setText(R.string.true_button);
        } else {
            mAnswerTextView.setText(R.string.false_button);
        }
    }
});

下面接着来实现从QuizActivity中可以获知是否已经查看答案,也就是要实现从子activity中获取返回结果。

需要调用函数:

public void startActivityForResult(Intent intent, int requestCode)

该方法的第一个参数同前述的intent。第二个参数是请求代码。请求代码是先发送给子 activity,然后再返回给父activity的整数值,由用户定义。

1. 设置返回结果

实现子activity发送返回信息给父activity,有以下两种方法可用: public final void setResult(int resultCode)

public final void setResult(int resultCode, Intent data)

在父activity需要依据子activity的完成结果采取不同操作时,设置结果代码就非常有用。

2. 返还intent

GeoQuiz应用中,数据信息需要回传给QuizActivity。因此,我们需要创建一个Intent,附加上extra信息后,调用Activity.setResult(int, Intent)方法将信息回传给QuizActivity。

CheatActivity代码中,为extra的键增加常量,再创建一个私有方法,用来创建intent、 附加extra并设置结果值。然后在SHOW ANSWER按钮的监听器代码中调用该方法。

private void setAnswerShownResult(boolean isAnswerShown) {
    Intent data = new Intent();
    data.putExtra(EXTRA_ANSWER_SHOWN, isAnswerShown);
    setResult(RESULT_OK, data);
}

现如今应用内部的交互时序如图:

 Android开发之第二个activity 

3. 处理返回结果

QuizActivity.java中,新增一个成员变量保存CheatActivity回传的值。然后覆盖 onActivityResult(...)方法获取它。

最后,修改QuizActivity中的checkAnswer(boolean)方法,确认用户是否偷看答案并作出相应的反应。

 

activity的使用与管理。

来看看在各activity间往返的时候,操作系统层面到底发生了什么。首先,在桌面启动器中点击GeoQuiz应用时,操作系统并没有启动应用,而只是启动了应用中的一个activity。确切地说,它启动了应用的launcher activity。在GeoQuiz应用中,QuizActivity就是它的launcher activity。

 

 


相关文章: