Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> Android開發 >> 開發入門 >> Android記事本練習【教程: 練習 3】

Android記事本練習【教程: 練習 3】

編輯:開發入門

在這章練習中, 你將用生命周期事件回調去存儲和獲得應用程序的狀態代碼. 這個練習描述了: 生命周期函數及你的程序如何調用它 維護程序狀態的技術 步驟 1 將 Notepadv3 導入Eclipse. 如果你看到一個關於 androidManifest.XML, 的錯誤,或者一些與android.zip文件有關的問題, 右擊工程然後從彈出的按鈕中選擇Android Tools(android工具) > 修正工程屬性 . 此練習的起點正是Nodepadv2的結束處。 當前應用程序存在問題 — 點擊返回按鈕當編輯工作會失敗,,還有其他的一些在編輯過程中產生的問題也會導致編輯內容丟失. 要修正這個問題, 我們需要將創建和編輯記事本的大多數功能(函數)放進 NoteEdit類, 並且為編輯記事本制定完整的生命周期。
  1. 刪除 NoteEdit 裡的那些從附加束裡分析標題和主題的代碼.
相反(相對於上面的方法), 我們將用 DBHelper 這個類 直接從數據庫訪問記事本. 我們所需傳進 NoteEdit Activity 的是一個 mRowId (但僅僅是我們編輯的時候,如果我們執行的是創建 操作,我們什麼也不用傳進去).刪除這些行: String title = extras.getString(NotesDbAdapter.KEY_TITLE); String body = extras.getString(NotesDbAdapter.KEY_BODY);
  1. 被傳進extras Bundle的那些屬性我們也不需要了, 這些屬性只是被我們用來 在UI上編輯body文本的. 所以刪除:
  2. if (title != null) {
  3.     mTitleText.setText(title);
  4. }
  5. if (body != null) {
  6.     mBodyText.setText(body);
} 步驟 2 在NoteEdit類的頂部為NotesDbAdapter 創建一個類對象:     private NotesDbAdapter mDbHelper; 也在函數onCreate()中為 NotesDbAdapter添加一個實例 (緊接著在super.onCreate() 調用後):     mDbHelper = new NotesDbAdapter(this);

    mDbHelper.open(); 步驟 3 在 NoteEdit, 我們需要為mRowId檢查savedInstanceState , 以防編輯含有束中的已保存的狀態, 而這些是我們需要覆蓋掉的狀態 (這會發生在activity 失去焦點並被重啟的時候).
  1. 替換當前初始化 mRowId的代碼:
  2.         mRowId = null;
  3.         Bundle extras = getIntent().getExtras();
  4.         if (extras != null) {
  5.             mRowId = extras.getLong(NotesDbAdapter.KEY_ROWID);
  6.         }
        用以下代碼替換:         mRowId = savedInstanceState != null ? savedInstanceState.getLong(NotesDbAdapter.KEY_ROWID)                                             : null;         if (mRowId == null) {             Bundle extras = getIntent().getExtras();                        mRowId = extras != null ? extras.getLong(NotesDbAdapter.KEY_ROWID)                                     : null;         }        
  1. 為 savedInstanceState標注空值檢查, 並且仍需從extras Bundle 加載mRowId:如果savedInstanceState沒有為它提供.這是一個可用來快速安全使用 值的三元操作符,當然如果沒有提供,它會是空。
步驟 4 接下來, 如果我們有mRowId,我們需要在它之上產生相關的域(fIElds): populateFIElds(); 這個動作需要在confirmButton.setOnClickListener()前做, 這個方法將在呆會定義。 步驟 5 無需onClick()處理函數裡創建bundle和設置bundle值, Activity 也不再用返回任何附加信息給調用者。 因為我們無需返回值,我們可以用setResult()的簡化版: public void onClick(View vIEw) {     setResult(RESULT_OK);     finish(); } 使用生命周期函數時,要謹記將更新和方法說明存儲到數據庫。 整個 onCreate() 函數應該如此: super.onCreate(savedInstanceState);   mDbHelper = new NotesDbAdapter(this); mDbHelper.open();   setContentVIEw(R.layout.note_edit);   mTitleText = (EditText) findVIEwById(R.id.title); mBodyText = (EditText) findVIEwById(R.id.body);   Button confirmButton = (Button) findVIEwById(R.id.confirm);   mRowId = savedInstanceState != null ? savedInstanceState.getLong(NotesDbAdapter.KEY_ROWID)                                     : null; if (mRowId == null) {     Bundle extras = getIntent().getExtras();     mRowId = extras != null ? extras.getLong(NotesDbAdapter.KEY_ROWID)                             : null; }   populateFIElds();   confirmButton.setOnClickListener(new VIEw.OnClickListener() {       public void onClick(View vIEw) {         setResult(RESULT_OK);         finish();     }      }); 步驟 6 定義populateFIElds() 方法. private void populateFIElds() {     if (mRowId != null) {         Cursor note = mDbHelper.fetchNote(mRowId);         startManagingCursor(note);         mTitleText.setText(note.getString(                    note.getColumnIndexOrThrow(NotesDbAdapter.KEY_TITLE)));         mBodyText.setText(note.getString(                 note.getColumnIndexOrThrow(NotesDbAdapter.KEY_BODY)));     } } 該方法用了 NotesDbAdapter.fetchNote() 方法去找到要編輯的說明(標注) , 然後它調用Activity 類的startManagingCursor() 方法 , 這是android提供的一個跟蹤光標生命周期的方法. 然後將按照Activity生命周期所描述的一樣:釋放和創建資源, 而無需我們擔心 . 在那之後, 我們只需從光標處獲得標題和主體,並且產生它們的視圖元素。 步驟 7 為什麼處理生命周期時間非常重要 如果你習慣了總是控制著你的應用程序, 你可能會不能明白為何必需要 這些整個生命周期都存在的東西。其實原因是:在android,是操作系統,而不是你在控制著程序的運 作! 正如我們所看到的,android模型是基於ActivitIEs的相互調用的. 當 一個Activity調用另外一個時,至少當前的Activity被暫時停止掉,在操作系統運行資源不足時, 也有可能兩個都被停掉。如果這種情況真的發生,那麼該Activity必須保存足夠的狀態信息,以期恢復。 最好就是保存它被停掉時的狀態. android有一個 明確的生命周期. 即使你沒有顯式地將控制權交個一個Activity,它生命周期時間也有可能會發生. 比如說,當有電話打 進你的手機,而當時你手機上某個Activity正在運行,那麼當前運行的Activity將被交換(系統資源控制權轉換) 而電話Activity將運行(占有資源控制權). 還是在 NoteEdit 類, 現在覆蓋這些方法: onSaveInstanceState(), onPause() 及 onResume(). 這些都是已有的onCreate()函數附帶的方法。 當某Activity將被停止掉有可能在重啟之前被殺掉, android將會調用 onSaveInstanceState() 這將意味著任何有用的狀態信息將被保存,以使該Activity 重啟時能被重新初始化. 這是和 onCreate() 方法對應的, 實際上 被傳進 onCreate()的savedInstanceState 的Bundle 正是你在onSaveInstanceState() 中作為outState(暫失效狀態)創建的bundle. onPause() 與 onResume() 也是自動調用的方法. onPause() 總是在一個 Activity結束時被調用,即使我們特意調用了finish()。我們將用這個去將當前的標注保存到數據 庫。為了減少被占用的資源,良好做法是在onPause()期間盡量釋放任何能被釋放的資源. 因此我們關掉DbHelper類, 並將它的域設為空,使得它能被適時回收。 另一方面,onResume() 能重建 mDbHelper 實例以使我們能夠使用它。 然後從數據庫中將標注重新讀出,並且產生新的域。 因此,在 populateFIElds() 方法後留空以添加以下的一些生命周期的方法:
  1. onSaveInstanceState():
  2.     @重寫
  3.     protected void onSaveInstanceState(Bundle outState) {
  4.         super.onSaveInstanceState(outState);
  5.         outState.putLong(NotesDbAdapter.KEY_ROWID, mRowId);
    }
  1. onPause():
  2.     @重寫
  3.     protected void onPause() {
  4.         super.onPause();
  5.         saveState();
    } We'll define saveState() next.
  1. onResume():
  2.     @重寫
  3.     protected void onResume() {
  4.         super.onResume();
  5.         populateFIElds();
    } Step 8 定義 saveState() 方法以把數據讀出到數據庫.      private void saveState() {         String title = mTitleText.getText().toString();         String body = mBodyText.getText().toString();           if (mRowId == null) {             long id = mDbHelper.createNote(title, body);             if (id > 0) {                 mRowId = id;             }         } else {             mDbHelper.updateNote(mRowId, title, body);         }     } 注意到我們接受了 createNote() 的返回值,如果該值有效,我們將它保存到 mRowId 字段, 這樣我們就能在將來更新之,而不用再重建一個。 (重建也可能會發生在生命周期事件被觸發時). 步驟 9 現在拿出先前的在Notepadv3類 onActivityResult() 方法中定義的處理代碼 所有的標注檢索和更新都發生在NoteEdit 生命周期內, 因此所有的 onActivityResult() 方法需要做的就是更新數據視圖,不需要其他的工作了。 該方法如下: @重寫 protected void onActivityResult(int requestCode, int resultCode,                                 Intent intent) {     super.onActivityResult(requestCode, resultCode, intent);     fillData(); } 因為另外一個類正在做這個工作,這個函數所需的做的就是更新數據. 步驟 10 將onListItemClick() 方法裡設置標題和主體的代碼移除 (一樣,它們都是無需的, 除了mRowId ):     Cursor c = mNotesCursor;     c.moveToPosition(position);
也移除:     i.putExtra(NotesDbAdapter.KEY_TITLE, c.getString(                     c.getColumnIndex(NotesDbAdapter.KEY_TITLE)));     i.putExtra(NotesDbAdapter.KEY_BODY, c.getString(                     c.getColumnIndex(NotesDbAdapter.KEY_BODY)));
因此剩下的代碼應是:     super.onListItemClick(l, v, position, id);     Intent i = new Intent(this, NoteEdit.class);     i.putExtra(NotesDbAdapter.KEY_ROWID, id);     startActivityForResult(i, ACTIVITY_EDIT); 現在也可以將mNotesCursor從類中移除, 而在fillData() 方法中用一個局部變量將它 設回:     Cursor notesCursor = mDbHelper.fetchAllNotes(); 注意到 m 在 mNotesCursor 代表著成員域(成員變量), 因此當 使 notesCursor 成為一個局部變量, 要去掉 m. 記得在fillData() 方法中重命名所有的mNotesCursor。 運行之! (在Project上單擊右鍵 -> Run As -> android Application )
  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved