Android 学习之《Android编程权威指南》第二版 代码+笔记整理(四)

(代码)GeoQuiz最终开发

GeoQuiz应用初步开发

GeoQuiz应用升级开发

解决GeoQuiz应用旋转恢复第一题的BUG

不展示编译器自动完成的代码,仅提供手动修改或者编写的代码。
省略了先前一些代码,可参照上方链接。
升级内容: 增加作弊按钮,给用户提供查看答案的作弊页面。

一、组成:

三个java类(一个实体类+两个Activity)、三个layout布局文件(一个主界面,一个作弊界面以及一个手机水平放置时的主界面)和各种资源文件(图片和字符串等)

二、界面(展示大部分效果)

Android 学习之《Android编程权威指南》第二版 代码+笔记整理(四)_第1张图片
Android 学习之《Android编程权威指南》第二版 代码+笔记整理(四)_第2张图片

三、开发

1. Android项目:

应用名称为:GeoQuiz
活动及对应布局名称为:
A. QuizActivity – activity_quiz(一垂直,一水平 两个xml)
B. CheatActivity – activity_cheat
模型类:Question

2. 用户界面设计(仅展示activity_cheat.xml 其余页面参照先前博客)

设计图:
Android 学习之《Android编程权威指南》第二版 代码+笔记整理(四)_第3张图片
代码:(activity_cheat.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:gravity="center"
    android:orientation="vertical"
    tools:context="com.example.thinkpad.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>

3. 更新字符串资源(strings.xml):

<resources>
    <string name="app_name">GeoQuizstring>
    <string name="true_button">TRUEstring>
    <string name="false_button">FALSEstring>
    <string name="next_button">NEXTstring>
    <string name="correct_toast">Correct!string>
    <string name="incorrect_toast">Incorrect!string>
    <string name="question_oceans">
        The Pacific Ocean is larger than the Atlantic Ocean.
    string>
    <string name="question_mideast">
        The Suez Canal connects the Red Sea and the Indian Ocean.
    string>
    <string name="question_africa">
        The source of the Nile River is in Egypt.
    string>
    <string name="question_americas">
        The Amazon River is the longest river in the Americas.
    string>
    <string name="question_asia">
        Lake Baikal is the world\'s oldest and deepest freshwater lake.
    string>

    <string name="warning_text">
        Are you sure you want to do this?
    string>
    <string name="show_answer_button">
        SHOW ANSWER
    string>
    <string name="cheat_button">
        CHEAT!
    string>
    <string name="judgment_toast">
        Cheating is wrong.
    string>
resources>

4. 默认主界面布局(activity_quiz.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:gravity="center"
    android:orientation="vertical"
    tools:context="com.example.thinkpad.geoquiz.QuizActivity">

    <TextView
        android:id="@+id/question_text_view"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:padding="24dp" />

    <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="horizontal">

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

    LinearLayout>

    <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/next_button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/next_button"
        android:drawableRight="@drawable/arrow_right"
        android:drawablePadding="4dp"/>
LinearLayout>

5. 水平主界面布局(activity_quiz.xml)


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

    <TextView
        android:id="@+id/question_text_view"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:padding="24dp" />

    <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_vertical|center_horizontal"
        android:orientation="horizontal">

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

    LinearLayout>

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

    <Button
        android:id="@+id/next_button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="bottom|right"
        android:text="@string/next_button"
        android:drawableRight="@drawable/arrow_right"
        android:drawablePadding="4dp"/>

FrameLayout>

6. activity活动编写(QuizActivity.java )

import android.app.Activity;
import android.content.Intent;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;

public class QuizActivity extends AppCompatActivity {

    private Button mTrueButton; //true选项按钮
    private Button mFalseButton; //false选项按钮
    private Button mNextButton; //next选项按钮
    private Button mCheatButton; //Cheat选项按钮
    private TextView mQuestionTextView; //textView文本显示
    private Question[] mQuestionBank = new Question[]{ //Question对象数组
            new Question(R.string.question_oceans,true),
            new Question(R.string.question_mideast,false),
            new Question(R.string.question_africa,false),
            new Question(R.string.question_americas,true),
            new Question(R.string.question_asia,true),
    };
    //KEY_INDEX常量作为将要存储在Bundle中的数组索引变量的键值对的键
    private static final String KEY_INDEX = "index";
    private int mCurrentIndex = 0; //数组索引变量

    private static final int REQUEST_CODE_CHEAT = 0;//设置请求代码常量,用于区分多个不同类型的子activity
    private boolean mIsCheater;//判断是否作弊的变量

    private void updateQuestion(){ //更新问题文本内容函数
        int question = mQuestionBank[mCurrentIndex].getTextResId(); //获取资源ID
        mQuestionTextView.setText(question); //设置文本内容
    }

    private void checkAnswer(boolean userPressedTrue){ //检查问题答案函数
        boolean answerIsTrue = mQuestionBank[mCurrentIndex].isAnswerTrue(); //获取对应问题的答案

        int messageResId = 0;

        if(mIsCheater){
            messageResId = R.string.judgment_toast;
        }else{
            //根据答案正确与否分配资源ID
            if(userPressedTrue == answerIsTrue){
                messageResId = R.string.correct_toast;
            }else{
                messageResId = R.string.incorrect_toast;
            }
        }
        Toast.makeText(this,messageResId,Toast.LENGTH_SHORT).show();
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_quiz); //加载布局

        mQuestionTextView = (TextView) findViewById(R.id.question_text_view); //获取TextView对象

        mTrueButton = (Button) findViewById(R.id.true_button); //获取trueButton按钮对象
        mTrueButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                checkAnswer(true);
            }
        });

        mFalseButton = (Button) findViewById(R.id.false_button); //获取falseButton按钮对象
        mFalseButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                checkAnswer(false);
            }
        });

        mNextButton = (Button) findViewById(R.id.next_button); //获取NextButton按钮对象
        mNextButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                mCurrentIndex = (mCurrentIndex+1) % mQuestionBank.length; //索引值增加1
                mIsCheater = false; //是否作弊的flag回归默认值
                updateQuestion();
            }
        });

        mCheatButton = (Button) findViewById(R.id.cheat_button); //获取CheatButton对象
        mCheatButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                boolean answerIsTrue = mQuestionBank[mCurrentIndex].isAnswerTrue();//获取问题答案
                Intent intent = CheatActivity.newIntent(QuizActivity.this,answerIsTrue);
                startActivityForResult(intent,REQUEST_CODE_CHEAT);
            }
        });

        if(savedInstanceState != null){
            mCurrentIndex = savedInstanceState.getInt(KEY_INDEX,0);
        }
        updateQuestion(); //更新问题
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        if(resultCode!= Activity.RESULT_OK){
            return ;
        }
        if(requestCode == REQUEST_CODE_CHEAT){
            if(data == null){
                return ;
            }
            mIsCheater = CheatActivity.wasAnswerShown(data);
        }
    }

    @Override
    protected void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        outState.putInt(KEY_INDEX,mCurrentIndex);
    }
}

7. activity活动编写(CheatActivity.java )

import android.content.Context;
import android.content.Intent;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;

public class CheatActivity extends AppCompatActivity {

    //储存在extra中的问题答案的键,使用包名修饰extra数据信息,可以避免来自不同应用的extra间发生命名冲突
    private static final String EXTRA_ANSWER_IS_TRUE =
            "com.example.thinkpad.geoquiz.answer_is_true";
    //储存在extra中的是否显示过答案的键
    private static final String EXTRA_ANSWER_SHOWN =
            "com.example.thinkpad.geoquiz.answer_shown";

    private boolean mAnswerIsTrue;//问题答案

    private TextView mAnswerTextView; //问题答案文本
    private Button mShowAnswer; //显示答案按钮

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_cheat);
        //getBooleanExtra(...)第一个参数为extra的键名,第二个参数为默认值,即获取不到该键的值时的默认值
        mAnswerIsTrue = getIntent().getBooleanExtra(EXTRA_ANSWER_IS_TRUE,false);

        mAnswerTextView = (TextView) findViewById(R.id.answer_text_view);//获取AnswerTextView实例

        mShowAnswer = (Button) findViewById(R.id.show_answer_button); //获取显示答案按钮实例
        mShowAnswer.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                //根据问题的答案显示不同的文字
                if(mAnswerIsTrue){
                    //TextView.setText(...)方法用来设置TextView要显示的文字
                    mAnswerTextView.setText(R.string.true_button);
                }else{
                    mAnswerTextView.setText(R.string.false_button);
                }
                setAnswerShownResult(true);
            }
        });
    }

    //创建Intent的CheatActivity实例,并且将问题答案传入其中
    public static Intent newIntent(Context packageContext,boolean answerIsTrue){
        //Intent的这个构造函数第一个参数为上下文,第二个参数为所要启动的Activity
        Intent intent = new Intent(packageContext,CheatActivity.class);
        intent.putExtra(EXTRA_ANSWER_IS_TRUE,answerIsTrue);
        return intent;
    }

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

    //解析结果Intent
    public static boolean wasAnswerShown(Intent result){
        return result.getBooleanExtra(EXTRA_ANSWER_SHOWN,false);
    }
}

(笔记)第5章 创建第二个activity

  1. 创建新的 activity 至少涉及三个文件:Java类、XML布局以及应用的manifest文件。所以建议使用 Android Studio 的新建 activity 向导功能
  2. 启动activity的方法:
    A. public void startActivity(Intent intent)
    B. public void startActivityForResult(Intent intent,int requestCode)(可从子activity获取返回结果)
    调用方法的请求发送给了操作系统的ActivityManager,由它负责创建Activity实例并调用onCreate(…)方法。
  3. 基于Intent通信
    A. Intent有多种构造方法,其中之一为:
    public Intent (Context packageContext,Class cls)
    该方法的第一个参数为启动活动的上下文,告诉ActivityManager在哪里可以找到它,第二个参数则告诉ActivityManager应该启动哪个activity
    B. 同一个应用中,我们使用显式的intent来启动activity。在不同的应用中,则可通过创建隐式的intent来处理。
    C. 使用intent的extra来实现数据传递。
    extra为一种键值结构,Xxx为某种类型
    添加信息时调用intent.putExtra(String name,Xxx xx) 第一个参数固定为String类型的键,第二个参数则为多种数据类型的值。
    获取信息时调用intent.getXxxExtra(name,xx) 第一个参数为键,第二个参数为默认值(即该键没有找到对应值时使用的值)。
  4. 从子activity获取返回结果:
    A. 设置返回结果:
    有以下两个方法可调用:
    1.)public final void setResult(int resultCode)
    2.)public final void setResult(int resultCode,Intent data)
    resultCode取值:
    Activity.RESULT_OK 或者 Activity.RESULT_CANCELED
    (如需自己定义结果代码,还可使用RESULT_FIRST_USER
    B. 返还intent 调用setResult(int resultCode,Intent data)
    C. 处理返回结果,重写onActivityResult(…)方法
  5. ActivityManager维护着一个非特定应用独享的回退栈。

来自一名刚刚开始学习Android的小菜鸟~

你可能感兴趣的:(Android,《Android编程权威指南》)