日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > Android >内容正文

Android

Android-入门学习笔记-使用 CursorLoader 加载数据

發布時間:2023/11/29 Android 24 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Android-入门学习笔记-使用 CursorLoader 加载数据 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

3

使用這個代碼片段開始練習

也可以參考?Codepath 教程


高級內容補充:

你是否在思考ArrayAdapter’s 的 getView() 方法和CursorAdapter 的 newView() 和 bindView() 方法?

你可以查看?CursorAdapter 類的源碼. getView() 方法依然存在, 但是它實際根據是否存在列表項能夠被循環使用,來決定調用 newView() 或 bindView(),如果 convertView 為空,那么我們需要創建新的列表項,如果 convertView 不為空,那么我們可以循環使用舊的列表項。

因此,作為一個開發者,我們不需要重載 CursorAdapter 的 getView() 方法. 我們可以僅僅重載 newView() 和 bindView() 方法, 剩下的工作交給適配器來完成!

4

空視圖是在 ListView 中無項目時展示的視圖。在沒有數據的情況下不是在應用中展示一個空白屏幕,而是通過有吸引力的圖像或描述性文字來提升用戶體驗。 文字甚至可以提示用戶添加一些數據。

在我們的 Pets 應用中,我們想要在 ListView 中沒有要顯示的寵物時,設置以下空視圖。

設置空視圖非常簡單。

第 1 步:在 ListView 旁邊創建空視圖

首先在你的布局中創建空視圖。在我們的案例中,應該有兩個 TextViews 和一個 ImageView,像這樣對齊。并給空視圖一個 id“@+id/empty_view”,以便我們之后在 Java 代碼中引用。

<red lines><!-- Empty view for the list --><RelativeLayout android:id="@+id/empty_view" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerInParent="true"> <ImageView android:id="@+id/empty_shelter_image" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerHorizontal="true" android:src="@drawable/ic_empty_shelter"/> <TextView android:id="@+id/empty_title_text" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_below="@+id/empty_shelter_image" android:layout_centerHorizontal="true" android:fontFamily="sans-serif-medium" android:paddingTop="16dp" android:text="@string/empty_view_title_text" android:textAppearance="?android:textAppearanceMedium"/> <TextView android:id="@+id/empty_subtitle_text" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_below="@+id/empty_title_text" android:layout_centerHorizontal="true" android:fontFamily="sans-serif" android:paddingTop="8dp" android:text="@string/empty_view_subtitle_text" android:textAppearance="?android:textAppearanceSmall" android:textColor="#A2AAB0"/> </RelativeLayout>

對于文本,使用 strings.xml 資源文件。

<!-- Title text for the empty view, which describes the empty dog house image [CHAR LIMIT=50] --><string name="empty_view_title_text">It\'s a bit lonely here...</string> <!-- Subtitle text for the empty view that prompts the user to add a pet [CHAR LIMIT=50] --> <string name="empty_view_subtitle_text">Get started by adding a pet</string>

第 2 步:添加空視圖

在創建 ListView 時,你可以使用 id 指定一個空視圖。使用我們之前設置的 id,用 findViewById() 方法獲取視圖,然后使用 ListView 的 setEmptyView() 方法設置空視圖。

// Find the ListView which will be populated with the pet data ListView petListView = (ListView) findViewById(R.id.list);// Find and set empty view on the ListView, so that it only shows when the list has 0 items. View emptyView = findViewById(R.id.empty_view);petListView.setEmptyView(emptyView);

第 3 步:測試

刪除數據或卸載并重裝應用,使用一個空數據庫啟動。現在,你應該會看到空視圖出現在屏幕上!

練習完成前后的差異。

6

參閱此教程?或此文檔。

提示:添加需要從接口實現的方法的鍵盤快捷鍵:Ctrl + I 提示:將 CursorAdapter 作為全局變量 提示:對于 onLoadFinished() 和 onLoaderReset() 方法,你可以使用 CursorAdapter 的?swapCursor() 方法更改數據源 Cursor。

注:插入新寵物(從虛擬菜單項或編輯器)不會自動更新寵物列表(直到下一個編碼任務前)。你需要強制關閉應用并重新打開它,才能看到寵物列表更新。

如果你在想為什么 projection 需要包含 _id,請參見CursorAdapter 類的描述。CursorAdapter 假設 Cursor 包含一個名為 _id 的列。

7

目前,我們的 CursorLoader 有一個小缺陷,那就是它不會在底層 SQLite 數據庫變化時進行自動更新。

為什么列表之前可以更新,而現在不行?我們返回去看看舊的代碼。

在之前,displayDatabaseInfo 在 onStart() 內及在菜單項被單擊時調用。這可以完全確保數據始終為最新狀態,但它也會在主線程上多次進行不必要的數據加載。

在主線程上進行加載會降低應用的速度,如我們之前所講,而且進行無用的加載更是浪費資源。

那么,它什么時候的數據加載是無用的呢?是這樣,每次當應用被旋轉或你導航到別處一會兒并返回后 onStart 就會被觸發。 如果你旋轉應用或導航到別處并返回后,你真的需要再次從數據庫獲取數據嗎?數據庫中有任何東西發生變化了嗎?答案是沒有,數據庫未發生任何變化,所以你并不需要重新加載數據。

這實際上就是 CursorLoader 主要用于解決的問題之一:我們想追蹤數據是否已加載,且如果已加載,則避免重新加載,除非有必要。

很顯然我們不需要在每次調用 onStart 時重新加載方法。那么我們何時需要重新加載數據呢?

  • 查看答案
  • 提交答案

解答

我們僅需要在 SQLite 數據庫中的某些數據發生變化時更新Cursor。

用戶關閉和重新打開應用、旋轉應用和滾動 ListView 實際上不會更改數據庫中的數據,我們這時就不需要重新加載數據。

8

這個?教程?展示了何時調用notifyChange()

Cursor?setNotificationUri()?方法

?

9

注意:在這里,編輯器尚不會顯示數據庫中特定寵物的數據。這將在之后的步驟中實現。

提示 1:通過?setOnItemClickListener()?方法將 OnItemClickListener 設置到 ListView。

提示 2:創建特定寵物內容 URI,使用?Uri.withAppendedId()?方法。

提示 3:在 AndroidManifest.xml 中,你可以刪除 EditorActivity 活動元素中的?label?屬性,因為應用欄中新寵物和現有寵物情況的活動標題被在 Java 代碼中通過編程方式覆寫了。

10

好的,現在我們的 Editor Activity 中有了寵物的 URI。在此情況下,我們還應從內容提供程序 中加載寵物數據。我們可以使用 CursorLoader 進行加載。

這與我們上次使用 CursorLoader 的區別這次我們不是獲取Cursor并將其放入 CursorAdapter,而是獲取Cursor中的所有項然后使用它們來填充 EditText 字段。

我們使用的步驟大體和之前一樣,只是當我們創建加載器時,URI 將為單個寵物的,而非全部寵物的。

然后我們從 onLoadFinished 中獲得Cursor,這時候我們不是使用 Cursor Adapter,而是更新所有輸入,即包含寵物值的 editTexts 和性別 spinner。

最后在 onLoaderReset 方法中,我們應清除輸入字段。

現在花一些時間來實際操作吧。

你的步驟:

  • 實現加載器回調接口。
  • 初始化加載器。
  • 編寫加載器回調方法 onCreateLoader 的代碼;確保它使用的是單個寵物的 URI。
  • 編寫加載器回調方法 onLoadFinished 的代碼,并使用寵物數據更新輸入。
  • 編寫加載器回調方法 onLoaderReset 的代碼,然后清除輸入字段。
  • 提示 1:當你從加載器收到Cursor結果,記得在開始從中提取列值前,將Cursor移到位置 0。

    提示 2:你可以使用?Spinner?的?setSelection()?方法來設置下拉菜單 Spinner。

    • 查看答案
    • 提交答案

    解答

    首先實現加載器回調,然后使用 Ctrl + I 熱鍵來獲取所有加載器回調方法:

    public class EditorActivity extends AppCompatActivity implements LoaderManager.LoaderCallbacks<Cursor> {

    接下來,使用此代碼初始化加載器:

    getLoaderManager().initLoader(EXISTING_PET_LOADER, null, this);

    在 onCreateLoader() 中,我將創建一個新的 CursorLoader,傳入 uri 和 projection。我需要從 onCreate() 獲取 uri,所以我需要將它放在一個名為?mCurrentPetUri?的實例變量:

    /** Content URI for the existing pet (null if it's a new pet) */ private Uri mCurrentPetUri;...@Override public Loader<Cursor> onCreateLoader(int i, Bundle bundle) { // Since the editor shows all pet attributes, define a projection that contains // all columns from the pet table String[] projection = { PetEntry._ID, PetEntry.COLUMN_PET_NAME, PetEntry.COLUMN_PET_BREED, PetEntry.COLUMN_PET_GENDER, PetEntry.COLUMN_PET_WEIGHT }; // This loader will execute the ContentProvider's query method on a background thread return new CursorLoader(this, // Parent activity context mCurrentPetUri, // Query the content URI for the current pet projection, // Columns to include in the resulting Cursor null, // No selection clause null, // No selection arguments null); // Default sort order }

    當寵物的數據加載到游標后,onLoadFinished() 將被調用。在這里,我首先要將游標移到第一個項的位置。盡快它只有一個項,并從位置 -1 開始。

    // Proceed with moving to the first row of the cursor and reading data from it// (This should be the only row in the cursor)if (cursor.moveToFirst()) {

    然后,我將獲得每個數據項的索引,然后使用所有和 get() 方法抓取實際整數和字符串,以從游標中獲得數據。

    if (cursor.moveToFirst()) {// Find the columns of pet attributes that we're interested inint nameColumnIndex = cursor.getColumnIndex(PetEntry.COLUMN_PET_NAME);int breedColumnIndex = cursor.getColumnIndex(PetEntry.COLUMN_PET_BREED);int genderColumnIndex = cursor.getColumnIndex(PetEntry.COLUMN_PET_GENDER); int weightColumnIndex = cursor.getColumnIndex(PetEntry.COLUMN_PET_WEIGHT); // Extract out the value from the Cursor for the given column index String name = cursor.getString(nameColumnIndex); String breed = cursor.getString(breedColumnIndex); int gender = cursor.getInt(genderColumnIndex); int weight = cursor.getInt(weightColumnIndex);

    對于每一個 textView,我將設置適當的文本。

    // Update the views on the screen with the values from the database mNameEditText.setText(name); mBreedEditText.setText(breed); mWeightEditText.setText(Integer.toString(weight));

    對于 Spinner,我將使用一個 switch 語句來使用 setSelection 方法設置它的狀態。

    // Gender is a dropdown spinner, so map the constant value from the database// into one of the dropdown options (0 is Unknown, 1 is Male, 2 is Female).// Then call setSelection() so that option is displayed on screen as the current selection.switch (gender) {case PetEntry.GENDER_MALE: mGenderSpinner.setSelection(1); break; case PetEntry.GENDER_FEMALE: mGenderSpinner.setSelection(2); break; default: mGenderSpinner.setSelection(0); break; }

    練習完成前后的差異

    11

    我們的“編輯寵物”(Edit Pet) 版本頁面缺失一項重大功能,那就是實際編輯寵物。

    目前,當你更改現有寵物的任何值時,并不會更新寵物,而是會保存寵物的一個副本,這并非我們想要的。

    解決方法就是使“編輯寵物”模式更新當前寵物,使“添加寵物”模式插入新寵物。

    這次我們不使用“insertPet”方法,我們將它改名或“重構”為“savePet”。在這里,就像我們之前一樣,你可以判斷 EditorActivity 是“插入”模式還是“編輯”模式。如果為編輯模式,你需要使用內容提供程序 執行一個“更新”操作。

    好的,現在來試一試吧,更新 savePet 方法。完成后,EditActivity 應該不會創建寵物的副本,而是更新現有寵物。在你按下 FAB 按鈕來插入新寵物時,它也應正確執行。在這兩種情況下,你的應用都應顯示 toast 消息。

    提示:如何判斷我們是在“插入新寵物”還是“編輯現有寵物”?你可以在設置 EditorActivity 標題時執行此檢查。

    注意:確保在 strings.xml 文件中聲明 toast 消息的字符串。

    ContentResolver update() 示例。

    • 查看答案
    • 提交答案

    練習完成前后的差異.

    無論你是第一次更新寵物還是創建寵物,你都需要使用 content values 對象。創建它的方式還是跟之前一樣。創建好后,你需要根據是要編輯現有寵物還是插入新寵物來進行不同操作。

    你可以使用設置標題時所用的方法,通過檢查 mCurrentPetUri 是否為空值來區分編輯模式和插入模式。如果為空值,那么就是新寵物,你可以運行此方法中原有的代碼。

    if (mCurrentPetUri == null) {

    如果 uri 不為空值,這意味著你在更新現有寵物。你可以使用 ContentResolver 的 update 方法來更新寵物。你更新的內容的 URI 為 mCurrentPetUri,這會簡化代碼編寫。

    } else {// Otherwise this is an EXISTING pet, so update the pet with content URI: mCurrentPetUri// and pass in the new ContentValues. Pass in null for the selection and selection args// because mCurrentPetUri will already identify the correct row in the database that// we want to modify. int rowsAffected = getContentResolver().update(mCurrentPetUri, values, null, null);

    現在,它會返回已更新的列數。要顯示更新是否成功,我們可以檢查已更新的列數。若為 0,那么更新不成功,則我們可以顯示一條錯誤 toast 消息。若為相反情況,則顯示成功 toast 消息。

    // Show a toast message depending on whether or not the update was successful.if (rowsAffected == 0) {// If no rows were affected, then there was an error with the update.Toast.makeText(this, getString(R.string.editor_update_pet_failed), Toast.LENGTH_SHORT).show(); } else { // Otherwise, the update was successful and we can display a toast. Toast.makeText(this, getString(R.string.editor_update_pet_successful), Toast.LENGTH_SHORT).show(); }

    12

    干得不錯!

    EditorActivity 在編輯模式下的主要功能已完成。

    后續操作

    我們依然需要實現 delete 和解決幾個 bug。例如,當你為插入新寵物而打開 EditorActivity 時,你在沒有輸入任何東西時不小心點了保存按鈕……這時候就會發生崩潰。

    閱讀錯誤消息,我們得知這是因為你沒有為體重輸入數字;基本上是因為它無法將空白值轉換為數字。

    通常情況下,我們應在 UI 中要求用戶在嘗試將寵物信息存入數據庫之前先輸入一些寵物信息。而所有空白值應視為用戶不小心按下保存鍵,而非作為新寵物進行保存。

    你的任務

    你的任務就是解決這個 bug。為此,首先你得檢查輸入是否為空字符串。你可以使用?TextUtils.isEmpty()) 方法來檢查一個字符串是否全由空格或空字符串構成。如果所有的輸入都為空字符串,且根據 GENDER UNKNOWN 消息性別未更新,則 savePet 方法會直接返回但不包含任何內容。

    此外,當你在保存新寵物時沒有提供體重,則寵物的給定體重將為 0,而不會導致應用崩潰。

    提示 1:調用?finish()?方法來終止 activity。

    提示 2:如果輸入字符串為空值或空字符串,TextUtils.isEmpty(String s)?返回 true。

    • 查看答案
    • 提交答案

    解答

    我們要做的所有更改都在 EditorActivity.java 文件中進行,特別是在 savePet() 方法中。

    要解決第一個問題,在我們獲得所有值后但在創建 ContentValues 對象之前,我將添加一個 if 語句來檢查它們是否為空字符串及性別是否為未知。如果是,我將不再執行剩余的方法或插入寵物,而是直接返回。

    if (mCurrentPetUri == null &&TextUtils.isEmpty(nameString) && TextUtils.isEmpty(breedString) &&TextUtils.isEmpty(weightString) && mGender == PetEntry.GENDER_UNKNOWN) {return;}

    在將體重放入 content value 對象之前,我要解決的下一個問題是:如果用戶未指定寵物體重,應將其設為 0,而不是導致崩潰。所以在代碼中,我們將體重的默認值設為 0,然后在用戶輸入體重后,我會將其更改為輸入的整數值。

    // If the weight is not provided by the user, don't try to parse the string into an// integer value. Use 0 by default.int weight = 0;if (!TextUtils.isEmpty(weightString)) { weight = Integer.parseInt(weightString); } values.put(PetEntry.COLUMN_PET_WEIGHT, weight);

    做了這些更改后,應用便不會崩潰,也不會保存完全空白的寵物信息。非常棒!

    練習完成前后的差異

    13

    警告用戶

    你可能注意到了,按下 EditorActivity 的“上一個”(UP) 或“返回”(back) 按鈕會使你離開 EditorActivity,但不會保存你的更改。你想要明確保存數據庫更改的方法,那么我們只在用戶點擊“保存”(Save) 按鈕的時候保存更改。

    那么,當用戶在添加一些編輯時不小心按下“上一個”(UP) 或“返回”(back) 按鈕時會怎樣呢?為避免用戶丟失工作,我們可以跳出一個對話框,警告用戶其在離開編輯器時有未保存的更改。

    下面是聯系人應用中的警告演示。當你輸入新的聯系人信息,然后在未保存的情況下點擊了“上一個”(UP) 按鈕時,你會看到此行為:

    期望的行為

    在我們的應用中,我們所期望的行為是跳出一個對話框,用消息“是否放棄更改并退出編輯”(Discard your changes and quit editing?) 來警告用戶。用戶可以選擇“繼續編輯”(Keep Editing)(即留在此活動)或“放棄”(Discard)(即結束活動)。

    步驟

    第 1 步:監聽是否進行了更改

    第一步是決定什么時候顯示“放棄更改”對話框。這應僅在用戶更改了表格的某一個部分時發生。你可以做的是創建一個名為 mPetHasChanged 的 boolean,如果用戶更新了 pet 表的任何部分則為 true。

    private boolean mPetHasChanged = false;

    你可以添加?OnTouchListener?來檢查是否發生了更改:

    private View.OnTouchListener mTouchListener = new View.OnTouchListener() {@Overridepublic boolean onTouch(View view, MotionEvent motionEvent) { mPetHasChanged = true; return false; } };

    在?onCreate?中:

    mNameEditText.setOnTouchListener(mTouchListener);mBreedEditText.setOnTouchListener(mTouchListener); mWeightEditText.setOnTouchListener(mTouchListener); mGenderSpinner.setOnTouchListener(mTouchListener);

    第 2 步:編寫創建“放棄更改”對話框的方法

    我們在下面編寫一個創建此對話框的方法:

    private void showUnsavedChangesDialog(DialogInterface.OnClickListener discardButtonClickListener) {// Create an AlertDialog.Builder and set the message, and click listeners// for the positive and negative buttons on the dialog.AlertDialog.Builder builder = new AlertDialog.Builder(this);builder.setMessage(R.string.unsaved_changes_dialog_msg);builder.setPositiveButton(R.string.discard, discardButtonClickListener);builder.setNegativeButton(R.string.keep_editing, new DialogInterface.OnClickListener() {public void onClick(DialogInterface dialog, int id) {// User clicked the "Keep editing" button, so dismiss the dialog// and continue editing the pet.if (dialog != null) {dialog.dismiss();}}});// Create and show the AlertDialogAlertDialog alertDialog = builder.create();alertDialog.show(); }

    此代碼使用?AlertDialogBuilder?創建了一個 AlertDialog。此方法接受放棄按鈕的 OnClickListener。我們這樣做是因為點擊“返回”(back) 或“上一個”(up) 的行為略有不同。

    并且注意,我們還使用了很多 R.string,你可以添加這些:

    Discard your changes and quit editing?DiscardKeep Editing

    第 3 步:連接“返回”(Back)按鈕

    這是“返回”按鈕的代碼。你需要覆蓋此活動的正常返回按鈕。如果寵物發生了變化,你建立會關閉當前活動的放棄點擊偵聽器。然后將此偵聽器傳入剛創建的?showUnsavedChangesDialog?方法。

    @Override public void onBackPressed() {// If the pet hasn't changed, continue with handling back button pressif (!mPetHasChanged) {super.onBackPressed();return;}// Otherwise if there are unsaved changes, setup a dialog to warn the user.// Create a click listener to handle the user confirming that changes should be discarded.DialogInterface.OnClickListener discardButtonClickListener =new DialogInterface.OnClickListener() {@Overridepublic void onClick(DialogInterface dialogInterface, int i) {// User clicked "Discard" button, close the current activity.finish();}};// Show dialog that there are unsaved changesshowUnsavedChangesDialog(discardButtonClickListener); }

    第 4 步:連接“上一個”(Up)按鈕

    這里是“上一個”按鈕的代碼。它在?onOptionsItemSelected?方法中。如果寵物發生變化,你建立一個會導航至“上一個”的放棄點擊偵聽器。然后將此偵聽器傳入剛創建的?showUnsavedChangesDialog?方法。

    case android.R.id.home:// If the pet hasn't changed, continue with navigating up to parent activity// which is the {@link CatalogActivity}.if (!mPetHasChanged) {NavUtils.navigateUpFromSameTask(EditorActivity.this);return true;}// Otherwise if there are unsaved changes, setup a dialog to warn the user.// Create a click listener to handle the user confirming that// changes should be discarded.DialogInterface.OnClickListener discardButtonClickListener =new DialogInterface.OnClickListener() {@Overridepublic void onClick(DialogInterface dialogInterface, int i) {// User clicked "Discard" button, navigate to parent activity.NavUtils.navigateUpFromSameTask(EditorActivity.this);}};// Show a dialog that notifies the user they have unsaved changesshowUnsavedChangesDialog(discardButtonClickListener);return true;

    練習完成前后的差異

    有用鏈接:

    要向“返回”(back)按鈕被點擊的情況添加行為,參閱此 StackOverflow 帖子。

    要向“上一個”(Up)按鈕被點擊的情況添加行為,參閱此文章。你還需要向 android.R.id.home 按鈕被點擊的情況添加代碼。

    如何創建 AlertDialog。

    14

    如果寵物還不存在,則無法刪除它

    我們當前的代碼還有一個“問題”,那就是當你處于 EditorActivity 的插入模式時,會在菜單中看到一個“刪除”(Delete) 選項。由于你當前在插入寵物,因此沒有寵物可供刪除,那么這個選項是多余的。

    我們來解決這個問題。我們要刪除“插入模式”中的刪除選項。

    如何選擇運行應用時的菜單

    當你第一次打開活動時,會調用?onCreateOptionsMenu?方法。它會用所有可見的菜單項填充菜單。要更改它,你需要做的是在確定它是一個新寵物后(mPetContentUri 為空值),你要使選項菜單無效。

    所以在 onCreate 中……

    if (mCurrentPetUri == null) {// This is a new pet, so change the app bar to say "Add a Pet"setTitle(getString(R.string.editor_activity_title_new_pet));// Invalidate the options menu, so the "Delete" menu option can be hidden.// (It doesn't make sense to delete a pet that hasn't been created yet.) invalidateOptionsMenu(); } else { //other stuff }

    然后,onPrepareOptionsMenu?會被調用,你可以在它是新寵物時隱藏刪除菜單選項來修改菜單對象。 此操作的代碼如下:

    @Overridepublic boolean onPrepareOptionsMenu(Menu menu) { super.onPrepareOptionsMenu(menu); // If this is a new pet, hide the "Delete" menu item. if (mCurrentPetUri == null) { MenuItem menuItem = menu.findItem(R.id.action_delete); menuItem.setVisible(false); } return true; }

    練習完成前后的差異

    有用鏈接:

    Android開發文檔:菜單選項

    Stack Overflow 提問:如何改變菜單項

    15

    我們的最后一項重大任務是實現刪除寵物的能力。此功能在應用的兩個地方:第一個是在 EditorActivity 頁面的菜單中,當你更新寵物時會用到。 第二個是在 CatalogActivity 的菜單中,在此處,刪除 (delete) 選項可用于刪除所有寵物,你在測試數據庫時可以使用。

    首先我們來看 EditorActivity 中的 delete 方法。我們已添加了使它僅在“編輯寵物”模式出現的代碼。現在我想要實現的功能是,當我們選擇刪除寵物時,出現一個對話框, 即按下刪除按鈕應出現一條 toast 消息“已刪除寵物”(Pet deleted) ,并從數據庫中刪除寵物。

    我們復制此代碼片段。它包含 tring.xml 的一些新字符串,也包含生成對話框的代碼,位于一個名為“showDeleteConfirmationDialog”的方法和一個空的“deletePet”方法中。

    此對話框有兩個 onClick 偵聽器,一個用于這里顯示的“刪除”(delete) 按鈕,另一個用于這里顯示的“取消”(cancel) 按鈕。Delete 對話框調用空的“deletePet”方法,你需要在這個方法中添加代碼來實際刪除當前寵物。

    你的任務:

    首先,找到代碼中正確的位置,以當你從下拉菜單中選擇“刪除寵物”(Delete Pet) 時,它會打開 DeleteConfirmationDialog。

    接下來,填上deletePet 方法以刪除當前寵物。你應僅在“編輯模式”中刪除寵物。你還應顯示一條 toast 消息,說明是否刪除了寵物,方法和我們之前用 toast 消息表明是否成功更新了寵物一樣。

    ContentResolver delete() 示例

    • 查看答案
    • 提交答案

    解答

    在復制代碼片段后,首先我們要通過在按下刪除按鈕時調用 showDeleteConfirmationDialog 方法來確保觸發它。方法是前往 onOptionsItemSelected 并在 action.delete 下添加對 showDeleteConfirmationDialog 的調用。

    // Respond to a click on the "Delete" menu optioncase R.id.action_delete:// Pop up confirmation dialog for deletionshowDeleteConfirmationDialog();

    showDeleteConfirmationDialog 會創建一個對話框,在刪除按鈕被按下時調用 deletePet。首先,我確保我們是對現有寵物執行刪除。因為對數據庫中尚不存在的新寵物執行刪除是沒有意義的。所以我檢查是否存在現有寵物(mCurrentPetUri 是否等于 null)。然后使用 content resolver 和當前的寵物 uri 刪除寵物。

    /*** Perform the deletion of the pet in the database.*/ private void deletePet() {// Only perform the delete if this is an existing pet.if (mCurrentPetUri != null) { // Call the ContentResolver to delete the pet at the given content URI. // Pass in null for the selection and selection args because the mCurrentPetUri // content URI already identifies the pet that we want. int rowsDeleted = getContentResolver().delete(mCurrentPetUri, null, null);

    delete 方法和 update 方法一樣,會返回被刪除的行數。我可以通過檢查被刪除的行數是否為 0 來確定刪除成功與否。若為 0,則刪除失敗,我會顯示一條 toast 消息,說明“刪除寵物時出錯”(Error with deleting pet)。 否則,操作將是成功的,且我跳出一條 toast 消息說“寵物已刪除”(Pet deleted)。

    // Show a toast message depending on whether or not the delete was successful.if (rowsDeleted == 0) {// If no rows were deleted, then there was an error with the delete.Toast.makeText(this, getString(R.string.editor_delete_pet_failed), Toast.LENGTH_SHORT).show(); } else { // Otherwise, the delete was successful and we can display a toast. Toast.makeText(this, getString(R.string.editor_delete_pet_successful), Toast.LENGTH_SHORT).show(); }

    完成操作后,調用 finish() 方法關閉此 activity。

    // Close the activityfinish();

    到此,我們就能成功從 EditorActivity 中刪除寵物了!

    練習完成前后的差異.

    16

    現在,我要你添加當用戶從 CatalogActivity 上的溢出菜單點擊“刪除所有寵物”(Delete All Pets) 選項時,用于刪除所有寵物的代碼。無需添加確認消息,但是如果你想,也可以自行實現。

    完成后,菜單看起來應該是這樣的:

    這里的變更較小,所以我就不多做講解,由你自己來完成。

    Android 中的?菜單選項。

    • 查看答案
    • 提交答案

    解答

    對于此練習,我們在 CatalogActivity.java 文件中進行。

    此菜單按鈕與 R.id.action_delete_all_entries 關聯,所以在 onOptionsMenuSelected 方法的該 case 下,我將添加對名為“deleteAllPets()”方法的調用。

    case R.id.action_delete_all_entries:deleteAllPets();return true;

    然后在該方法中,我將使用 ContentResolver 的 delete 方法,并傳入PetEntry.CONTENT_URI。為什么要用內容 URI?因為這是一個一般?__/pets uri,在我們的 內容提供程序中將刪除所有寵物。

    /*** Helper method to delete all pets in the database.*/ private void deleteAllPets() {int rowsDeleted = getContentResolver().delete(PetEntry.CONTENT_URI, null, null); Log.v("CatalogActivity", rowsDeleted + " rows deleted from pet database"); }

    此菜單按鈕與R.id.action_delete_all_entries 關聯,所以在 onOptionsMenuSelected 方法的該 case 下,我將添加對名為“deleteAllPets()”方法的調用。

    練習完成前后的差異.

    17

    對于我們的最后一項更新,你需要解決 UI 中的另一個奇怪的行為。當品種未知時,寵物列表看起來總覺得缺點什么。因為寵物名下就是一片空白。

    在未提供品種信息的情況下,比起留白,顯示一個語句“品種未知”(Unknown breed) 會提供更好的用戶體驗。

    完成此步后應用看起來應該是這個樣子的:

    注意,這只是 CatalogActivity 中的一個 UI 變化,文本“Unknown breed”不應保存在數據庫中。如果你在編輯器中打開此寵物,“品種”(breed) 字段應該是空白的:

    提示:如果輸入字符串為空值或空字符串TextUtils.isEmpty(String s)?將返回 true。

    • 查看答案
    • 提交答案

    解答

    首先,由于我們要添加字符串“Unknown breed”,我們在 strings.xml 文件中保存它。

    <!-- Label for the pet's breed if the breed is unknown [CHAR LIMIT=20] --> <string name="unknown_breed">Unknown breed</string>

    接下來,我們移至 PetCursorAdapter.java 文件。當我們在 CatalogActivity 中顯示寵物時,我們要檢查是否有使用 TextUtils.isEmpty 方法的品種。如果沒有,我們將列表項的 TextView 設為顯示“Unknown breed”。

    In PetCursorAdapter.java:

    /*** This method binds the pet data (in the current row pointed to by cursor) to the given* list item layout. For example, the name for the current pet can be set on the name TextView* in the list item layout.** @param view Existing view, returned earlier by newView() method* @param context app context* @param cursor The cursor from which to get the data. The cursor is already moved to the* correct row.*/ @Override public void bindView(View view, Context context, Cursor cursor) { // Find individual views that we want to modify in the list item layout TextView nameTextView = (TextView) view.findViewById(R.id.name); TextView summaryTextView = (TextView) view.findViewById(R.id.summary); // Find the columns of pet attributes that we're interested in int nameColumnIndex = cursor.getColumnIndex(PetEntry.COLUMN_PET_NAME); int breedColumnIndex = cursor.getColumnIndex(PetEntry.COLUMN_PET_BREED); // Read the pet attributes from the Cursor for the current pet String petName = cursor.getString(nameColumnIndex); String petBreed = cursor.getString(breedColumnIndex); // If the pet breed is empty string or null, then use some default text // that says "Unknown breed", so the TextView isn't blank. if (TextUtils.isEmpty(petBreed)) { petBreed = context.getString(R.string.unknown_breed); } // Update the TextViews with the attributes for the current pet nameTextView.setText(petName); summaryTextView.setText(petBreed); }

    練習完成前后的差異.

    ?

    ?

    ?

    ?

    ?

    ?

    ?

    ?

    ?

    轉載于:https://www.cnblogs.com/infocodez/p/8449730.html

    總結

    以上是生活随笔為你收集整理的Android-入门学习笔记-使用 CursorLoader 加载数据的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。