1. 程式人生 > >Android 學習之《Android程式設計權威指南》第二版 程式碼+筆記整理(四)

Android 學習之《Android程式設計權威指南》第二版 程式碼+筆記整理(四)

(程式碼)GeoQuiz最終開發

GeoQuiz應用初步開發

GeoQuiz應用升級開發

解決GeoQuiz應用旋轉恢復第一題的BUG

不展示編譯器自動完成的程式碼,僅提供手動修改或者編寫的程式碼。
省略了先前一些程式碼,可參照上方連結。
升級內容: 增加作弊按鈕,給使用者提供檢視答案的作弊頁面。

一、組成:

三個java類(一個實體類+兩個Activity)、三個layout佈局檔案(一個主介面,一個作弊介面以及一個手機水平放置時的主介面)和各種資原始檔(圖片和字串等)

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

GeoQuiz應用最終版拼接效果圖 1
GeoQuiz應用最終版拼接效果圖 2

三、開發

1. Android專案:

應用名稱為:GeoQuiz
活動及對應佈局名稱為:
A. QuizActivity – activity_quiz(一垂直,一水平 兩個xml)
B. CheatActivity – activity_cheat
模型類:Question

2. 使用者介面設計(僅展示activity_cheat.xml 其餘頁面參照先前部落格)

設計圖:
GeoQuiz最終版_作弊介面_效果圖
程式碼:(activity_cheat.xml)

<?xml version="1.0" encoding="utf-8"?>
<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"/> <!--tools & tools:text屬性的名稱空間比較特別,該名稱空間可以覆蓋元件的任何屬性--> <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">GeoQuiz</string>
    <string name="true_button">TRUE</string>
    <string name="false_button">FALSE</string>
    <string name="next_button">NEXT</string>
    <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)

<?xml version="1.0" encoding="utf-8"?>
<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)

<?xml version="1.0" encoding="utf-8"?>
<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_TR