1. 程式人生 > >Android程式設計權威指南第五章學習

Android程式設計權威指南第五章學習

第五章—第二個activity 5.1.1 建立新的 activity 建立新的activity至少涉及三個檔案: Java類、 XML佈局和應用的manifest檔案。這三個文 件關聯密切,搞錯了就是災難。因此,強烈建議使用Android Studio的新建activity嚮導功能。 在專案工具視窗中,右鍵單擊com.bignerdranch.android.geoquiz包,選擇New → Activity → Empty Activity選單項啟動新建activity嚮導,如圖5-3所示 在這裡插入圖片描述

5.1.3 在 manifest 配置檔案中宣告 activity manifest配置檔案是一個包含元資料的XML檔案,用來向Android作業系統描述應用。該檔案 總是以AndroidManifest.xml命名,可在專案的app/manifests目錄中找到它。 應用的所有activity都必須在manifest配置檔案中宣告

,這樣作業系統才能夠找到它們。 建立QuizActivity時,因使用了新建應用嚮導,嚮導已自動完成宣告工作。同樣,新建activity 嚮導也自動聲明瞭CheatActivity, 如程式碼清單5-3灰底部分所示 在這裡插入圖片描述

5.2 啟動 activity 一個activity啟動另一個activity最簡單的方式是使用startActivity方法: public void startActivity(Intent intent) 你也許會想當然地認為, startActivity(Intent)方法是一個靜態方法,啟動activity就是 呼叫Activity子類的該方法。實際並非如此。 activity呼叫startActivity(Intent)方法時,調 用請求實際發給了作業系統。 準確地說,呼叫請求傳送給了作業系統的ActivityManager。 ActivityManager負責建立 Activity例項並呼叫其onCreate(Bundle)方法

,如圖5-7所示。 在這裡插入圖片描述 ActivityManager該啟動哪個activity呢?答案就在於傳入startActivity(Intent)方法的 Intent引數。

基於 intent 的通訊 在GeoQuiz應用中, intent用來告訴ActivityManager該啟動哪個activity,因此可使用以下構 造方法: public Intent(Context packageContext, Class<?> cls) 在這裡插入圖片描述

如果通過指定Context與Class物件,然後呼叫intent的構造方法來建立Intent,則建立的是 顯式intent在同一應用中,我們使用顯式intent來啟動activity。

5.3 activity 間的資料傳遞 在這裡插入圖片描述

5.3.1 使用 intent extra 要將extra資料資訊新增給intent,需要呼叫Intent.putExtra(…)方法。確切地說,是呼叫 如下方法: public Intent putExtra(String name, boolean value) Intent.putExtra(…)方法形式多變。不變的是,它總是有兩個引數。一個引數是固定為 String型別的鍵,另一個引數是鍵值,可以是多種資料型別。該方法返回intent自身,因此,需 要時可進行鏈式呼叫。 在這裡插入圖片描述 activity可能啟動自不同的地方,所以,應該在獲取和使用extra資訊的activity那裡,為它定義 鍵。如程式碼清單5-8所示,記得使用包名修飾extra資料資訊,這樣,可避免來自不同應用的extra 間發生命名衝突。 現在,可以返回到QuizActivity,將extra附加到intent上。不過我們有個更好的實現方法。 對於CheatActivity處理extra資訊的實現細節, QuizActivity和應用的其他程式碼無需知道。因 此,我們可轉而在newIntent(…)方法中封裝這些邏輯。 在CheatActivity中,建立newIntent(…)方法,如程式碼清單5-9所示。 在這裡插入圖片描述 在QuizActivity的按鈕監聽器中,應用newIntent(…)方法,如程式碼清單5-10所示 在這裡插入圖片描述 這裡只需一個extra,但如果有需要,也可以附加多個extra到同一個Intent上。如果附加多 個extra,也要給newIntent(…)方法相應新增多個引數。 要從extra獲取資料,會用到如下方法: public boolean getBooleanExtra(String name, boolean defaultValue) 第一個引數是extra的名字。 getBooleanExtra(…)方法的第二個引數是指定預設值(預設 答案),它在無法獲得有效鍵值時使用。 在這裡插入圖片描述

然後再根據mAnswerIsTrue來設定對應的Toast資訊: 在這裡插入圖片描述

5.3.2 從子 activity 獲取返回結果 需要從子activity獲取返回資訊時(即子activity是否偷看答案),可呼叫以下Activity方法: public void startActivityForResult(Intent intent, int requestCode) 該方法的第一個引數同前述的intent。**第二個引數是請求程式碼。 請求程式碼是先發送給子 activity,然後再返回給父activity的整數值,由使用者定義。在一個activity啟動多個不同型別的子 activity,且需要判斷訊息回饋方時,就會用到該請求程式碼。**雖然QuizActivity只啟動一種型別 的子activity,但為應對未來的需求變化,現在就應設定請求程式碼常量。 在QuizActivity中,修改mCheatButton的監聽器,呼叫startActivityForResult(Intent, int)方法,如程式碼清單5-13所示。 在這裡插入圖片描述 1. 設定返回結果 實現子activity傳送返回資訊給父activity,有以下兩種方法可用: public final void setResult(int resultCode) public final void setResult(int resultCode, Intent data) 一般來說,引數resultCode可以是以下任意一個預定義常量。  Activity.RESULT_OK  Activity.RESULT_CANCELED (如需自己定義結果程式碼,還可使用另一個常量: RESULT_FIRST_USER。) 在父activity需要依據子activity的完成結果採取不同操作時,設定結果程式碼就非常有用。 例如,假設子activity有一個OK按鈕和一個Cancel按鈕,並且每個按鈕的單擊動作分別設定 有不同的結果程式碼。那麼,根據不同的結果程式碼,父activity就能採取不同的操作。 子activity可以不呼叫setResult(…)方法。如果不需要區分附加在intent上的結果或其他信 息,可讓作業系統傳送預設的結果程式碼。如果子activity是以呼叫startActivityForResult(…) 方法啟動的,結果程式碼則總是會返回給父activity。在沒有呼叫setResult(…)方法的情況下, 如果使用者按了後退按鈕,父activity則會收到Activity.RESULT_CANCELED的結果程式碼。 2. 返還intent GeoQuiz應用中,資料資訊需要回傳給QuizActivity。因此,我們需要建立一個Intent,附 加上extra資訊後,呼叫Activity.setResult(int, Intent)方法將資訊回傳給QuizActivity。 在CheatActivity程式碼中,為extra的鍵增加常量,再建立一個私有方法,用來建立intent、 附加extra並設定結果值。然後在SHOW ANSWER按鈕的監聽器程式碼中呼叫該方法。設定結果值 的方法如程式碼清單5-14所示 在這裡插入圖片描述 使用者單擊SHOW ANSWER按鈕時, CheatActivity呼叫setResult(int, Intent)方法將 結果程式碼以及intent打包。 然後,在使用者按後退鍵回到QuizActivity時, ActivityManager呼叫父activity的以下方法: protected void onActivityResult(int requestCode, int resultCode, Intent data) 該方法的引數來自QuizActivity的原始請求程式碼以及傳入setResult(int, Intent)方法 的結果程式碼和intent。 在這裡插入圖片描述 在這裡插入圖片描述

3. 處理返回結果 重寫onActivityResult函式

在這裡插入圖片描述

在這裡插入圖片描述

1.跟第三章的方法一樣,重寫CheatActivity裡的onSaveInstanceState(Bundle saveInstanceState)方法,把mAnswerIsTrue的值保留,旋轉後在onCreate(Bundle savedInstanceState)方法裡取出來,並判斷然後顯示。

    @Override
    protected void onSaveInstanceState(Bundle outState) {   //重寫onSaveInstanceState方法
        super.onSaveInstanceState(outState);
        outState.putBoolean(KEY_ANSWER,mAnswerIsTrue);
    }
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_cheat);



        mAnswerIsTrue = getIntent().getBooleanExtra(EXTRA_ANSWER_IS_TRUE,false);
        mAnswerTextView=(TextView)findViewById(R.id.answer_text_view);
        mShowAnswerButtton=(Button)findViewById(R.id.show_answer_button);

        if(savedInstanceState!=null){    
            mAnswerIsTrue=savedInstanceState.getBoolean(KEY_ANSWER,true);  //將答案取出
            if(mAnswerIsTrue){
                mAnswerTextView.setText(R.string.true_button);
            }else{
                mAnswerTextView.setText(R.string.false_button);
            }

        }

        mShowAnswerButtton.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);
                }
                setAnswerShownResult(true);

            }
        });
    }
    

2.跟第一題類似,在MainActivity的onSaveInstanceState(Bundle saveInstanceState)裡把IsCheater的值保留,旋轉後自動呼叫onCreate函式,再取出來。

3.建立一個mIsCheater[]陣列,把得到的每題是否作弊的記錄儲存在裡面。 private boolean mIsCheater[]=new boolean[]{false,false,false,false,false,false}; 這行要去掉: 在這裡插入圖片描述

**小bug:**測試過程中發現旋轉後,回答已經回答了的問題又可以重複回答了,所以旋轉之前也應該把每道題是否回答的變數儲存下來,查閱了資料Bundle不能之間傳物件陣列,可以傳遞物件。但是這個我傳遞的是一個Boolean型的陣列,即把每個問題的AnswerOrNot變數組成一個數組。程式碼如下:

 boolean AnswerOrNot_Array[]=new boolean[mQuestionBank.length];   //將每道題是否回答的陣列傳入Bundle
        for(int i=0;i<mQuestionBank.length;i++){
            AnswerOrNot_Array[i]=mQuestionBank[i].isAnswerOrNot();
        }
        saveInstanceState.putBooleanArray(KEY_ANSWERORNOTARRAY,AnswerOrNot_Array);

    if(savedInstanceState!=null){
        mCurrentIndex=savedInstanceState.getInt(KEY_INDEX,0);
        mIsCheater[mCurrentIndex]=savedInstanceState.getBoolean(KEY_ISCHEATER,false);
        boolean AnswerOrNot_Array[]=savedInstanceState.getBooleanArray(KEY_ANSWERORNOTARRAY);
        for (int i=0;i<mQuestionBank.length;i++){
            mQuestionBank[i].setAnswerOrNot(AnswerOrNot_Array[i]);
        }
    }