1page.title=Notepad Exercise 2 2parent.title=Notepad Tutorial 3parent.link=index.html 4@jd:body 5 6 7<p><em>In this exercise, you will add a second Activity to your notepad application, to let the user 8create and edit notes. You will also allow the user to delete existing notes through a context menu. 9The new Activity assumes responsibility for creating new notes by 10collecting user input and packing it into a return Bundle provided by the intent. This exercise 11demonstrates:</em></p> 12<ul> 13<li><em>Constructing a new Activity and adding it to the Android manifest</em></li> 14<li><em>Invoking another Activity asynchronously using <code>startActivityForResult()</code></em></li> 15<li><em>Passing data between Activity in Bundle objects</em></li> 16<li><em>How to use a more advanced screen layout</em></li> 17<li><em>How to create a context menu</em></li> 18</ul> 19 20<div style="float:right;white-space:nowrap"> 21 [<a href="notepad-ex1.html">Exercise 1</a>] 22 <span style="color:#BBB;"> 23 [<a href="notepad-ex2.html" style="color:#DDD;">Exercise 2</a>] 24 </span> 25 [<a href="notepad-ex3.html">Exercise 3</a>] 26 [<a href="notepad-extra-credit.html">Extra Credit</a>] 27</div> 28 29<h2>Step 1</h2> 30 31<p>Create a new Android project using the sources from <code>Notepadv2</code> under the 32<code>NotepadCodeLab</code> folder, just like you did for the first exercise. If you see an error about 33<code>AndroidManifest.xml</code>, or some problems related to an 34<code>android.zip</code> file, right click on the project and select <strong>Android 35Tools</strong> > <strong>Fix Project Properties</strong>.</p> 36 37<p>Open the <code>Notepadv2</code> project and take a look around:</p> 38<ul> 39 <li> 40 Open and look at the <code>strings.xml</code> file under 41 <code>res/values</code> — there are several new strings which we will use 42 for our new functionality 43 </li> 44 <li> 45 Also, open and take a look at the top of the <code>Notepadv2</code> class, 46 you will notice several new constants have been defined along with a new <code>mNotesCursor</code> 47 field used to hold the cursor we are using. 48 </li> 49 <li> 50 Note also that the <code>fillData()</code> method has a few more comments and now uses 51 the new field to store the notes Cursor. The <code>onCreate()</code> method is 52 unchanged from the first exercise. Also notice that the member field used to store the 53 notes Cursor is now called <code>mNotesCursor</code>. The <code>m</code> denotes a member 54 field and is part of the Android coding style standards. 55 </li> 56 <li> 57 There are also a couple of new overridden methods 58 (<code>onCreateContextMenu()</code>, <code>onContextItemSelected()</code>, 59 <code>onListItemClick()</code> and <code>onActivityResult()</code>) 60 which we will be filling in below. 61 </li> 62</ul> 63 64 65<h2>Step 2</h2> 66 67<div class="sidebox"> 68<p>Context menus should always be used when performing actions upon specific elements in the UI. 69When you register a View to a context menu, the context menu is revealed by performing a "long-click" 70on the UI component (press and hold the touchscreen or highlight and hold down the selection key for about two seconds).</p> 71</div> 72 73<p>First, let's create the context menu that will allow users to delete individual notes. 74Open the Notepadv2 class.</p> 75 76<ol> 77 <li>In order for each list item in the ListView to register for the context menu, we call 78 <code>registerForContextMenu()</code> and pass it our ListView. So, at the very end of 79 the <code>onCreate()</code> method add this line: 80 <pre>registerForContextMenu(getListView());</pre> 81 <p>Because our Activity extends the ListActivity class, <code>getListView()</code> will return us 82 the local ListView object for the Activity. Now, each list item in this ListView will activate the 83 context menu. 84 <li> 85 Now fill in the <code>onCreateContextMenu()</code> method. This callback is similar to the other 86 menu callback used for the options menu. Here, we add just one line, which will add a menu item 87 to delete a note. Call <code>menu.add()</code> like so: 88 <pre> 89public boolean onCreateContextMenu(Menu menu, View v 90 ContextMenuInfo menuInfo) { 91 super.onCreateContextMenu(menu, v, menuInfo); 92 menu.add(0, DELETE_ID, 0, R.string.menu_delete); 93}</pre> 94 <p>The <code>onCreateContextMenu()</code> callback some passes other information in addition to the Menu object, 95 such as the View that has been triggered for the menu and 96 an extra object that may contain additional information about the object selected. However, we don't care about 97 these here, because we only have one kind of object in the Activity that uses context menus. In the next 98 step, we'll handle the menu item selection.</p> 99 </li> 100</ol> 101 102<h2>Step 3</h2> 103 <p>Now that the we've registered our ListView for a context menu and defined our context menu item, we need 104 to handle the callback when it is selected. For this, we need to identify the list ID of the 105 selected item, then delete it. So fill in the 106 <code>onContextItemSelected()</code> method like this:</p> 107<pre> 108public boolean onContextItemSelected(MenuItem item) { 109 switch(item.getItemId()) { 110 case DELETE_ID: 111 AdapterContextMenuInfo info = (AdapterContextMenuInfo) item.getMenuInfo(); 112 mDbHelper.deleteNote(info.id); 113 fillData(); 114 return true; 115 } 116 return super.onContextItemSelected(item); 117}</pre> 118<p>Here, we retrieve the {@link android.widget.AdapterView.AdapterContextMenuInfo AdapterContextMenuInfo} 119with {@link android.view.MenuItem#getMenuInfo()}. The <var>id</var> field of this object tells us 120the position of the item in the ListView. We then pass this to the <code>deleteNote()</code> 121method of our NotesDbAdapter and the note is deleted. That's it for the context menu — notes 122can now be deleted.</p> 123 124<h2 style="clear:right;">Step 4</h2> 125<div class="sidebox" style="border:2px solid #FFFFDD;float:right; 126 background-color:#FFFFEE;margin-right:0px; 127 margin-bottom:.5em;margin-top:1em;padding:0em;width:240px;"> 128 <h2 style="border:0;font-size:12px;padding:.5em .5em .5em 1em;margin:0; 129 background-color:#FFFFDD;">Starting Other Activities</h2> 130 <p style="padding-left:.5em;font-size:12px;margin:0; 131 padding:.0em .5em .5em 1em;">In this example our Intent uses a class name specifically. 132 As well as 133 <a href="{@docRoot}guide/appendix/faq/commontasks.html#intentexamples">starting intents</a> in 134 classes we already know about, be they in our own application or another 135 application, we can also create Intents without knowing exactly which 136 application will handle it.</p> 137 <p style="padding-left:.5em;font-size:12px;margin:0; 138 padding:.0em .5em .5em 1em;">For example, we might want to open a page in a 139 browser, and for this we still use 140 an Intent. But instead of specifying a class to handle it, we use 141 a predefined Intent constant, and a content URI that describes what we 142 want to do. See {@link android.content.Intent 143 android.content.Intent} for more information.</p> 144</div> 145 146 <p>Fill in the body of the <code>createNote()</code> method: 147 <p>Create a new <code>Intent</code> to create a note 148 (<code>ACTIVITY_CREATE</code>) using the <code>NoteEdit</code> class. 149 Then fire the Intent using the <code>startActivityForResult()</code> method 150 call:</p> 151 <pre style="overflow:auto"> 152Intent i = new Intent(this, NoteEdit.class); 153startActivityForResult(i, ACTIVITY_CREATE);</pre> 154 <p>This form of the Intent call targets a specific class in our Activity, in this case 155 <code>NoteEdit</code>. Since the Intent class will need to communicate with the Android 156 operating system to route requests, we also have to provide a Context (<code>this</code>).</p> 157 <p>The <code>startActivityForResult()</code> method fires the Intent in a way that causes a method 158 in our Activity to be called when the new Activity is completed. The method in our Activity 159 that receives the callback is called 160 <code>onActivityResult()</code> and we will implement it in a later step. The other way 161 to call an Activity is using <code>startActivity()</code> but this is a "fire-and-forget" way 162 of calling it — in this manner, our Activity is not informed when the Activity is completed, and there is 163 no way to return result information from the called Activity with <code>startActivity()</code>. 164 <p>Don't worry about the fact that <code>NoteEdit</code> doesn't exist yet, 165 we will fix that soon. </p> 166 </li> 167 168 169<h2>Step 5</h2> 170 171 <p>Fill in the body of the <code>onListItemClick()</code> override.</p> 172 <p><code>onListItemClick()</code> is a callback method that we'll override. It is called when 173 the user selects an item from the list. It is passed four parameters: the 174 <code>ListView</code> object it was invoked from, the <code>View</code> 175 inside the <code>ListView</code> that was clicked on, the 176 <code>position</code> in the list that was clicked, and the 177 <code>mRowId</code> of the item that was clicked. In this instance we can 178 ignore the first two parameters (we only have one <code>ListView</code> it 179 could be), and we ignore the <code>mRowId</code> as well. All we are 180 interested in is the <code>position</code> that the user selected. We use 181 this to get the data from the correct row, and bundle it up to send to 182 the <code>NoteEdit</code> Activity.</p> 183 <p>In our implementation of the callback, the method creates an 184 <code>Intent</code> to edit the note using 185 the <code>NoteEdit</code> class. It then adds data into the extras Bundle of 186 the Intent, which will be passed to the called Activity. We use it 187 to pass in the title and body text, and the <code>mRowId</code> for the note we are 188 editing. Finally, it will fire the Intent using the 189 <code>startActivityForResult()</code> method call. Here's the code that 190 belongs in <code>onListItemClick()</code>:</p> 191 <pre> 192super.onListItemClick(l, v, position, id); 193Cursor c = mNotesCursor; 194c.moveToPosition(position); 195Intent i = new Intent(this, NoteEdit.class); 196i.putExtra(NotesDbAdapter.KEY_ROWID, id); 197i.putExtra(NotesDbAdapter.KEY_TITLE, c.getString( 198 c.getColumnIndexOrThrow(NotesDbAdapter.KEY_TITLE))); 199i.putExtra(NotesDbAdapter.KEY_BODY, c.getString( 200 c.getColumnIndexOrThrow(NotesDbAdapter.KEY_BODY))); 201startActivityForResult(i, ACTIVITY_EDIT);</pre> 202 <ul> 203 <li> 204 <code>putExtra()</code> is the method to add items into the extras Bundle 205 to pass in to intent invocations. Here, we are 206 using the Bundle to pass in the title, body and mRowId of the note we want to edit. 207 </li> 208 <li> 209 The details of the note are pulled out from our query Cursor, which we move to the 210 proper position for the element that was selected in the list, with 211 the <code>moveToPosition()</code> method.</li> 212 <li>With the extras added to the Intent, we invoke the Intent on the 213 <code>NoteEdit</code> class by passing <code>startActivityForResult()</code> 214 the Intent and the request code. (The request code will be 215 returned to <code>onActivityResult</code> as the <code>requestCode</code> parameter.)</li> 216 </ul> 217 <p class="note"><b>Note:</b> We assign the mNotesCursor field to a local variable at the 218 start of the method. This is done as an optimization of the Android code. Accessing a local 219 variable is much more efficient than accessing a field in the Dalvik VM, so by doing this 220 we make only one access to the field, and five accesses to the local variable, making the 221 routine much more efficient. It is recommended that you use this optimization when possible.</p> 222 223 224<h2>Step 6</h2> 225 226<p>The above <code>createNote()</code> and <code>onListItemClick()</code> 227 methods use an asynchronous Intent invocation. We need a handler for the callback, so here we fill 228 in the body of the <code>onActivityResult()</code>. </p> 229<p><code>onActivityResult()</code> is the overridden method 230 which will be called when an Activity returns with a result. (Remember, an Activity 231 will only return a result if launched with <code>startActivityForResult</code>.) The parameters provided 232 to the callback are: </p> 233 <ul> 234 <li><code>requestCode</code> — the original request code 235 specified in the Intent invocation (either <code>ACTIVITY_CREATE</code> or 236 <code>ACTIVITY_EDIT</code> for us). 237 </li> 238 <li><code>resultCode</code> — the result (or error code) of the call, this 239 should be zero if everything was OK, but may have a non-zero code indicating 240 that something failed. There are standard result codes available, and you 241 can also create your own constants to indicate specific problems. 242 </li> 243 <li><code>intent</code> — this is an Intent created by the Activity returning 244 results. It can be used to return data in the Intent "extras." 245 </li> 246 </ul> 247 <p>The combination of <code>startActivityForResult()</code> and 248 <code>onActivityResult()</code> can be thought of as an asynchronous RPC 249 (remote procedure call) and forms the recommended way for an Activity to invoke 250 another and share services.</p> 251 <p>Here's the code that belongs in your <code>onActivityResult()</code>:</p> 252 <pre> 253super.onActivityResult(requestCode, resultCode, intent); 254Bundle extras = intent.getExtras(); 255 256switch(requestCode) { 257case ACTIVITY_CREATE: 258 String title = extras.getString(NotesDbAdapter.KEY_TITLE); 259 String body = extras.getString(NotesDbAdapter.KEY_BODY); 260 mDbHelper.createNote(title, body); 261 fillData(); 262 break; 263case ACTIVITY_EDIT: 264 Long mRowId = extras.getLong(NotesDbAdapter.KEY_ROWID); 265 if (mRowId != null) { 266 String editTitle = extras.getString(NotesDbAdapter.KEY_TITLE); 267 String editBody = extras.getString(NotesDbAdapter.KEY_BODY); 268 mDbHelper.updateNote(mRowId, editTitle, editBody); 269 } 270 fillData(); 271 break; 272}</pre> 273 274 <ul> 275 <li> 276 We are handling both the <code>ACTIVITY_CREATE</code> and 277 <code>ACTIVITY_EDIT</code> activity results in this method. 278 </li> 279 <li> 280 In the case of a create, we pull the title and body from the extras (retrieved from the 281 returned Intent) and use them to create a new note. 282 </li> 283 <li> 284 In the case of an edit, we pull the mRowId as well, and use that to update 285 the note in the database. 286 </li> 287 <li> 288 <code>fillData()</code> at the end ensures everything is up to date . 289 </li> 290 </ul> 291 292 293<h2>Step 7</h2> 294 295 <div class="sidebox" style="border:2px solid #FFFFDD;float:right; 296 background-color:#FFFFEE;margin-right:0px; 297 margin-bottom:.5em;margin-top:1em;padding:0em;width:240px;"> 298 <h2 style="border:0;font-size:12px;padding:.5em .5em .5em 1em;margin:0; 299 background-color:#FFFFDD;">The Art of Layout</h2> 300 <p style="padding-left:.5em;font-size:12px;margin:0; padding:.0em .5em .5em 1em;">The provided 301 note_edit.xml layout file is the most sophisticated one in the application we will be building, 302 but that doesn't mean it is even close to the kind of sophistication you will be likely to want 303 in real Android applications.</p> 304 <p style="padding-left:.5em;font-size:12px;margin:0; padding:.0em .5em .5em 1em;">Creating a 305 good UI is part art and part science, and the rest is work. Mastery of <a 306 href="{@docRoot}guide/topics/ui/declaring-layout.html">Declaring Layout</a> is an essential part of creating 307 a good looking Android application.</p> 308 <p style="padding-left:.5em;font-size:12px;margin:0; 309 padding:.0em .5em .5em 1em;">Take a look at the 310 <a href="{@docRoot}guide/tutorials/views/index.html">Hello Views</a> 311 for some example layouts and how to use them. The ApiDemos sample project is also a 312 great resource from which to learn how to create different layouts.</p> 313 </div> 314 315<p>Open the file <code>note_edit.xml</code> that has been provided and take a 316 look at it. This is the UI code for the Note Editor.</p> 317 <p>This is the most 318 sophisticated UI we have dealt with yet. The file is given to you to avoid 319 problems that may sneak in when typing the code. (The XML is very strict 320 about case sensitivity and structure, mistakes in these are the usual cause 321 of problems with layout.)</p> 322 <p>There is a new parameter used 323 here that we haven't seen before: <code>android:layout_weight</code> (in 324 this case set to use the value 1 in each case).</p> 325 <p><code>layout_weight</code> is used in LinearLayouts 326 to assign "importance" to Views within the layout. All Views have a default 327 <code>layout_weight</code> of zero, meaning they take up only as much room 328 on the screen as they need to be displayed. Assigning a value higher than 329 zero will split up the rest of the available space in the parent View, according 330 to the value of each View's <code>layout_weight</code> and its ratio to the 331 overall <code>layout_weight</code> specified in the current layout for this 332 and other View elements.</p> 333 <p>To give an example: let's say we have a text label 334 and two text edit elements in a horizontal row. The label has no 335 <code>layout_weight</code> specified, so it takes up the minimum space 336 required to render. If the <code>layout_weight</code> of each of the two 337 text edit elements is set to 1, the remaining width in the parent layout will 338 be split equally between them (because we claim they are equally important). 339 If the first one has a <code>layout_weight</code> of 1 340 and the second has a <code>layout_weight</code> of 2, then one third of the 341 remaining space will be given to the first, and two thirds to the 342 second (because we claim the second one is more important).</p> 343 <p>This layout also demonstrates how to nest multiple layouts 344 inside each other to achieve a more complex and pleasant layout. In this 345 example, a horizontal linear layout is nested inside the vertical one to 346 allow the title label and text field to be alongside each other, 347 horizontally.</p> 348 349 350<h2 style="clear:right;">Step 8</h2> 351 352 <p>Create a <code>NoteEdit</code> class that extends 353 <code>android.app.Activity</code>.</p> 354 <p>This is the first time we will have 355 created an Activity without the Android Eclipse plugin doing it for us. When 356 you do so, the <code>onCreate()</code> method is not automatically 357 overridden for you. It is hard to imagine an Activity that doesn't override 358 the <code>onCreate()</code> method, so this should be the first thing you do.</p> 359 <ol> 360 <li>Right click on the <code>com.android.demo.notepad2</code> package 361 in the Package Explorer, and select <strong>New</strong> > <strong>Class</strong> from the popup 362 menu.</li> 363 <li>Fill in <code>NoteEdit</code> for the <code>Name:</code> field in the 364 dialog.</li> 365 <li>In the <code>Superclass:</code> field, enter 366 <code>android.app.Activity</code> (you can also just type Activity and hit 367 Ctrl-Space on Windows and Linux or Cmd-Space on the Mac, to invoke code 368 assist and find the right package and class).</li> 369 <li>Click <strong>Finish</strong>.</li> 370 <li>In the resulting <code>NoteEdit</code> class, right click in the editor 371 window and select <strong>Source</strong> > <strong>Override/Implement Methods...</strong></li> 372 <li>Scroll down through the checklist in the dialog until you see 373 <code>onCreate(Bundle)</code> — and check the box next to it.</li> 374 <li>Click <strong>OK</strong>.<p>The method should now appear in your class.</p></li> 375 </ol> 376 377<h2>Step 9</h2> 378 379<p>Fill in the body of the <code>onCreate()</code> method for <code>NoteEdit</code>.</p> 380 381<p>This will set the title of our new Activity to say "Edit Note" (one 382 of the strings defined in <code>strings.xml</code>). It will also set the 383 content view to use our <code>note_edit.xml</code> layout file. We can then 384 grab handles to the title and body text edit views, and the confirm button, 385 so that our class can use them to set and get the note title and body, 386 and attach an event to the confirm button for when it is pressed by the 387 user.</p> 388 <p>We can then unbundle the values that were passed in to the Activity 389 with the extras Bundle attached to the calling Intent. We'll use them to pre-populate 390 the title and body text edit views so that the user can edit them. 391 Then we will grab and store the <code>mRowId</code> so we can keep 392 track of what note the user is editing.</p> 393 394 <ol> 395 <li> 396 Inside <code>onCreate()</code>, set up the layout:<br> 397 <pre>setContentView(R.layout.note_edit);</pre> 398 </li> 399 <li> 400 Find the edit and button components we need: 401 <p>These are found by the 402 IDs associated to them in the R class, and need to be cast to the right 403 type of <code>View</code> (<code>EditText</code> for the two text views, 404 and <code>Button</code> for the confirm button):</p> 405 <pre> 406mTitleText = (EditText) findViewById(R.id.title); 407mBodyText = (EditText) findViewById(R.id.body); 408Button confirmButton = (Button) findViewById(R.id.confirm);</pre> 409 <p>Note that <code>mTitleText</code> and <code>mBodyText</code> are member 410 fields (you need to declare them at the top of the class definition).</p> 411 </li> 412 <li>At the top of the class, declare a <code>Long mRowId</code> private field to store 413 the current <code>mRowId</code> being edited (if any). 414 </li> 415 <li>Continuing inside <code>onCreate()</code>, 416 add code to initialize the <code>title</code>, <code>body</code> and 417 <code>mRowId</code> from the extras Bundle in 418 the Intent (if it is present):<br> 419 <pre> 420mRowId = null; 421Bundle extras = getIntent().getExtras(); 422if (extras != null) { 423 String title = extras.getString(NotesDbAdapter.KEY_TITLE); 424 String body = extras.getString(NotesDbAdapter.KEY_BODY); 425 mRowId = extras.getLong(NotesDbAdapter.KEY_ROWID); 426 427 if (title != null) { 428 mTitleText.setText(title); 429 } 430 if (body != null) { 431 mBodyText.setText(body); 432 } 433}</pre> 434 <ul> 435 <li> 436 We are pulling the <code>title</code> and 437 <code>body</code> out of the 438 <code>extras</code> Bundle that was set from the 439 Intent invocation. 440 </li><li> 441 We also null-protect the text field setting (i.e., we don't want to set 442 the text fields to null accidentally).</li> 443 </ul> 444 </li> 445 <li> 446 Create an <code>onClickListener()</code> for the button: 447 <p>Listeners can be one of the more confusing aspects of UI 448 implementation, but 449 what we are trying to achieve in this case is simple. We want an 450 <code>onClick()</code> method to be called when the user presses the 451 confirm button, and use that to do some work and return the values 452 of the edited note to the Intent caller. We do this using something called 453 an anonymous inner class. This is a bit confusing to look at unless you 454 have seen them before, but all you really need to take away from this is 455 that you can refer to this code in the future to see how to create a 456 listener and attach it to a button. (Listeners are a common idiom 457 in Java development, particularly for user interfaces.) Here's the empty listener:<br> 458 <pre> 459confirmButton.setOnClickListener(new View.OnClickListener() { 460 461 public void onClick(View view) { 462 463 } 464 465});</pre> 466 </li> 467 </ol> 468<h2>Step 10</h2> 469 470<p>Fill in the body of the <code>onClick()</code> method of the <code>OnClickListener</code> created in the last step.</p> 471 472 <p>This is the code that will be run when the user clicks on the 473 confirm button. We want this to grab the title and body text from the edit 474 text fields, and put them into the return Bundle so that they can be passed 475 back to the Activity that invoked this <code>NoteEdit</code> Activity. If the 476 operation is an edit rather than a create, we also want to put the 477 <code>mRowId</code> into the Bundle so that the 478 <code>Notepadv2</code> class can save the changes back to the correct 479 note.</p> 480 <ol> 481 <li> 482 Create a <code>Bundle</code> and put the title and body text into it using the 483 constants defined in Notepadv2 as keys:<br> 484 <pre> 485Bundle bundle = new Bundle(); 486 487bundle.putString(NotesDbAdapter.KEY_TITLE, mTitleText.getText().toString()); 488bundle.putString(NotesDbAdapter.KEY_BODY, mBodyText.getText().toString()); 489if (mRowId != null) { 490 bundle.putLong(NotesDbAdapter.KEY_ROWID, mRowId); 491}</pre> 492 </li> 493 <li> 494 Set the result information (the Bundle) in a new Intent and finish the Activity: 495 <pre> 496Intent mIntent = new Intent(); 497mIntent.putExtras(bundle); 498setResult(RESULT_OK, mIntent); 499finish();</pre> 500 <ul> 501 <li>The Intent is simply our data carrier that carries our Bundle 502 (with the title, body and mRowId).</li> 503 <li>The <code>setResult()</code> method is used to set the result 504 code and return Intent to be passed back to the 505 Intent caller. In this case everything worked, so we return RESULT_OK for the 506 result code.</li> 507 <li>The <code>finish()</code> call is used to signal that the Activity 508 is done (like a return call). Anything set in the Result will then be 509 returned to the caller, along with execution control.</li> 510 </ul> 511 </li> 512 </ol> 513 <p>The full <code>onCreate()</code> method (plus supporting class fields) should 514 now look like this:</p> 515 <pre> 516private EditText mTitleText; 517private EditText mBodyText; 518private Long mRowId; 519 520@Override 521protected void onCreate(Bundle savedInstanceState) { 522 super.onCreate(savedInstanceState); 523 setContentView(R.layout.note_edit); 524 525 mTitleText = (EditText) findViewById(R.id.title); 526 mBodyText = (EditText) findViewById(R.id.body); 527 528 Button confirmButton = (Button) findViewById(R.id.confirm); 529 530 mRowId = null; 531 Bundle extras = getIntent().getExtras(); 532 if (extras != null) { 533 String title = extras.getString(NotesDbAdapter.KEY_TITLE); 534 String body = extras.getString(NotesDbAdapter.KEY_BODY); 535 mRowId = extras.getLong(NotesDbAdapter.KEY_ROWID); 536 537 if (title != null) { 538 mTitleText.setText(title); 539 } 540 if (body != null) { 541 mBodyText.setText(body); 542 } 543 } 544 545 confirmButton.setOnClickListener(new View.OnClickListener() { 546 547 public void onClick(View view) { 548 Bundle bundle = new Bundle(); 549 550 bundle.putString(NotesDbAdapter.KEY_TITLE, mTitleText.getText().toString()); 551 bundle.putString(NotesDbAdapter.KEY_BODY, mBodyText.getText().toString()); 552 if (mRowId != null) { 553 bundle.putLong(NotesDbAdapter.KEY_ROWID, mRowId); 554 } 555 556 Intent mIntent = new Intent(); 557 mIntent.putExtras(bundle); 558 setResult(RESULT_OK, mIntent); 559 finish(); 560 } 561 }); 562}</pre> 563 </li> 564 </ol> 565 566<h2>Step 11</h2> 567 568<div class="sidebox" style="border:2px solid #FFFFDD;float:right; 569 background-color:#FFFFEE;margin-right:0px; 570 margin-bottom:.5em;margin-top:1em;padding:0em;width:240px;"> 571 <h2 style="border:0;font-size:12px;padding:.5em .5em .5em 1em;margin:0; 572 background-color:#FFFFDD;">The All-Important Android Manifest File</h2> 573 <p style="padding-left:.5em;font-size:12px;margin:0; 574 padding:.0em .5em .5em 1em;">The AndroidManifest.xml file is the way in which Android sees your 575 application. This file defines the category of the application, where 576 it shows up (or even if it shows up) in the launcher or settings, what 577 activities, services, and content providers it defines, what intents it can 578 receive, and more. </p> 579 <p style="padding-left:.5em;font-size:12px;margin:0; 580 padding:.0em .5em .5em 1em;">For more information, see the reference document 581 <a href="{@docRoot}guide/topics/manifest/manifest-intro.html">The AndroidManifest.xml File</a></p> 582 </div> 583 584<p>Finally, the new Activity has to be defined in the manifest file:</p> 585 <p>Before the new Activity can be seen by Android, it needs its own 586 Activity entry in the <code>AndroidManifest.xml</code> file. This is to let 587 the system know that it is there and can be called. We could also specify 588 which IntentFilters the activity implements here, but we are going to skip 589 this for now and just let Android know that the Activity is 590 defined.</p> 591 <p>There is a Manifest editor included in the Eclipse plugin that makes it much easier 592 to edit the AndroidManifest file, and we will use this. If you prefer to edit the file directly 593 or are not using the Eclipse plugin, see the box at the end for information on how to do this 594 without using the new Manifest editor.<p> 595 <ol> 596 <li>Double click on the <code>AndroidManifest.xml</code> file in the package explorer to open it. 597 </li> 598 <li>Click the <strong>Application</strong> tab at the bottom of the Manifest editor.</li> 599 <li>Click <strong>Add...</strong> in the Application Nodes section. 600 <p>If you see a dialog with radiobuttons at the top, select the top radio button: 601 "Create a new element at the top level, in Application".</p></li> 602 <li>Make sure "(A) Activity" is selected in the selection pane of the dialog, and click <strong>OK</strong>.</li> 603 <li>Click on the new "Activity" node, in the Application Nodes section, then 604 type <code>.NoteEdit</code> into the <em>Name*</em> 605 field to the right. Press Return/Enter.</li> 606 </ol> 607 <p>The Android Manifest editor helps you add more complex entries into the AndroidManifest.xml 608 file, have a look around at some of the other options available (but be careful not to select 609 them otherwise they will be added to your Manifest). This editor should help you understand 610 and alter the AndroidManifest.xml file as you move on to more advanced Android applications.</p> 611 612 <p class="note">If you prefer to edit this file directly, simply open the 613 <code>AndroidManifest.xml</code> file and look at the source (use the 614 <code>AndroidManifest.xml</code> tab in the eclipse editor to see the source code directly). 615 Then edit the file as follows:<br> 616 <code><activity android:name=".NoteEdit"></activity></code><br><br> 617 This should be placed just below the line that reads:<br> 618 <code></activity></code> for the <code>.Notepadv2</code> activity.</p> 619 620<h2 style="clear:right;">Step 12</h2> 621 622<p>Now Run it!</p> 623<p>You should now be able to add real notes from 624the menu, as well as delete an existing one. Notice that in order to delete, you must 625first use the directional controls on the device to highlight the note. 626Furthermore, selecting a note title from the list should bring up the note 627editor to let you edit it. Press confirm when finished to save the changes 628back to the database. 629 630<h2>Solution and Next Steps</h2> 631 632<p>You can see the solution to this exercise in <code>Notepadv2Solution</code> 633from the zip file to compare with your own.</p> 634<p>Now try editing a note, and then hitting the back button on the emulator 635instead of the confirm button (the back button is below the menu button). You 636will see an error come up. Clearly our application still has some problems. 637Worse still, if you did make some changes and hit the back button, when you go 638back into the notepad to look at the note you changed, you will find that all 639your changes have been lost. In the next exercise we will fix these 640problems.</p> 641 642<p> 643Once you are ready, move on to <a href="notepad-ex3.html">Tutorial 644Exercise 3</a> where you will fix the problems with the back button and lost 645edits by introducing a proper life cycle into the NoteEdit Activity.</p> 646 647 648