1 /* 2 * Copyright (C) 2007 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.example.android.notepad; 18 19 import android.app.Activity; 20 import android.content.ContentValues; 21 import android.database.Cursor; 22 import android.net.Uri; 23 import android.os.Bundle; 24 import android.text.TextUtils; 25 import android.view.View; 26 import android.widget.EditText; 27 import android.widget.Toast; 28 29 /** 30 * This Activity allows the user to edit a note's title. It displays a floating window 31 * containing an EditText. 32 * 33 * NOTE: Notice that the provider operations in this Activity are taking place on the UI thread. 34 * This is not a good practice. It is only done here to make the code more readable. A real 35 * application should use the {@link android.content.AsyncQueryHandler} 36 * or {@link android.os.AsyncTask} object to perform operations asynchronously on a separate thread. 37 */ 38 public class TitleEditor extends Activity { 39 40 /** 41 * This is a special intent action that means "edit the title of a note". 42 */ 43 public static final String EDIT_TITLE_ACTION = "com.android.notepad.action.EDIT_TITLE"; 44 45 // Creates a projection that returns the note ID and the note contents. 46 private static final String[] PROJECTION = new String[] { 47 NotePad.Notes._ID, // 0 48 NotePad.Notes.COLUMN_NAME_TITLE, // 1 49 }; 50 51 // The position of the title column in a Cursor returned by the provider. 52 private static final int COLUMN_INDEX_TITLE = 1; 53 54 // An EditText object for preserving the edited title. 55 private EditText mText; 56 57 // A URI object for the note whose title is being edited. 58 private Uri mUri; 59 60 // The title that was last saved. 61 private String mSavedTitle; 62 63 /** 64 * This method is called by Android when the Activity is first started. From the incoming 65 * Intent, it determines what kind of editing is desired, and then does it. 66 */ 67 @Override 68 public void onCreate(Bundle savedInstanceState) { 69 super.onCreate(savedInstanceState); 70 71 // Set the View for this Activity object's UI. 72 setContentView(R.layout.title_editor); 73 74 // Gets the View ID for the EditText box 75 mText = (EditText) this.findViewById(R.id.title); 76 77 // Get the Intent that activated this Activity, and from it get the URI of the note whose 78 // title we need to edit. 79 mUri = getIntent().getData(); 80 81 /* 82 * Using the URI passed in with the triggering Intent, gets the note. 83 * 84 * Note: This is being done on the UI thread. It will block the thread until the query 85 * completes. In a sample app, going against a simple provider based on a local database, 86 * the block will be momentary, but in a real app you should use 87 * android.content.AsyncQueryHandler or android.os.AsyncTask. 88 */ 89 90 Cursor cursor = getContentResolver().query( 91 mUri, // The URI for the note that is to be retrieved. 92 PROJECTION, // The columns to retrieve 93 null, // No selection criteria are used, so no where columns are needed. 94 null, // No where columns are used, so no where values are needed. 95 null // No sort order is needed. 96 ); 97 98 if (cursor != null) { 99 100 // The Cursor was just retrieved, so its index is set to one record *before* the first 101 // record retrieved. This moves it to the first record. 102 cursor.moveToFirst(); 103 104 // Displays the current title text in the EditText object. 105 mText.setText(cursor.getString(COLUMN_INDEX_TITLE)); 106 } 107 } 108 109 /** 110 * This method is called when the Activity is about to come to the foreground. This happens 111 * when the Activity comes to the top of the task stack, OR when it is first starting. 112 * 113 * Displays the current title for the selected note. 114 */ 115 @Override 116 protected void onResume() { 117 super.onResume(); 118 } 119 120 /** 121 * This method is called when the Activity loses focus. 122 * 123 * While there is no need to override this method in this app, it is shown here to highlight 124 * that we are not saving any state in onPause, but have moved app state saving to onStop 125 * callback. 126 * In earlier versions of this app and popular literature it had been shown that onPause is good 127 * place to persist any unsaved work, however, this is not really a good practice because of how 128 * application and process lifecycle behave. 129 * As a general guideline apps should have a way of saving their business logic that does not 130 * solely rely on Activity (or other component) lifecyle state transitions. 131 * As a backstop you should save any app state, not saved during lifetime of the Activity, in 132 * onStop(). 133 * For a more detailed explanation of this recommendation please read 134 * <a href = "https://developer.android.com/guide/topics/processes/process-lifecycle.html"> 135 * Processes and Application Life Cycle </a>. 136 * <a href="https://developer.android.com/training/basics/activity-lifecycle/pausing.html"> 137 * Pausing and Resuming an Activity </a>. 138 */ 139 @Override 140 protected void onPause() { 141 super.onPause(); 142 } 143 144 /** 145 * This method is called when the Activity becomes invisible. 146 * 147 * For Activity objects that edit information, onStop() may be the one place where changes are 148 * saved. 149 * Updates the note with the text currently in the text box. 150 */ 151 @Override 152 protected void onStop() { 153 super.onStop(); 154 saveTitle(); 155 } 156 157 public void onClickOk(View v) { 158 saveTitle(); 159 finish(); 160 } 161 162 // Saves the title if required 163 private void saveTitle() { 164 165 if (!TextUtils.isEmpty(mText.getText())) { 166 167 String newTitle = mText.getText().toString(); 168 169 if (!newTitle.equals(mSavedTitle)) { 170 // Creates a values map for updating the provider. 171 ContentValues values = new ContentValues(); 172 173 // In the values map, sets the title to the current contents of the edit box. 174 values.put(NotePad.Notes.COLUMN_NAME_TITLE, newTitle); 175 176 /* 177 * Updates the provider with the note's new title. 178 * 179 * Note: This is being done on the UI thread. It will block the thread until the 180 * update completes. In a sample app, going against a simple provider based on a 181 * local database, the block will be momentary, but in a real app you should use 182 * android.content.AsyncQueryHandler or android.os.AsyncTask. 183 */ 184 getContentResolver().update( 185 mUri, // The URI for the note to update. 186 values, 187 // The values map containing the columns to update and the values to use. 188 null, // No selection criteria is used, so no "where" columns are needed. 189 null // No "where" columns are used, so no "where" values are needed. 190 ); 191 mSavedTitle = newTitle; 192 } 193 } else { 194 Toast.makeText(this, R.string.title_blank, Toast.LENGTH_SHORT).show(); 195 } 196 } 197 } 198