| excludeFromSuggestions=true |
| page.title=Notepad Exercise 2 |
| parent.title=Notepad Tutorial |
| parent.link=index.html |
| @jd:body |
| |
| |
| <p><em>In this exercise, you will add a second Activity to your notepad application, to let the user |
| create and edit notes. You will also allow the user to delete existing notes through a context menu. |
| The new Activity assumes responsibility for creating new notes by |
| collecting user input and packing it into a return Bundle provided by the intent. This exercise |
| demonstrates:</em></p> |
| <ul> |
| <li><em>Constructing a new Activity and adding it to the Android manifest</em></li> |
| <li><em>Invoking another Activity asynchronously using <code>startActivityForResult()</code></em></li> |
| <li><em>Passing data between Activity in Bundle objects</em></li> |
| <li><em>How to use a more advanced screen layout</em></li> |
| <li><em>How to create a context menu</em></li> |
| </ul> |
| |
| <div style="float:right;white-space:nowrap"> |
| [<a href="notepad-ex1.html">Exercise 1</a>] |
| <span style="color:#BBB;"> |
| [<a href="notepad-ex2.html" style="color:#DDD;">Exercise 2</a>] |
| </span> |
| [<a href="notepad-ex3.html">Exercise 3</a>] |
| [<a href="notepad-extra-credit.html">Extra Credit</a>] |
| </div> |
| |
| <h2>Step 1</h2> |
| |
| <p>Create a new Android project using the sources from <code>Notepadv2</code> under the |
| <code>NotepadCodeLab</code> folder, just like you did for the first exercise. If you see an error about |
| <code>AndroidManifest.xml</code>, or some problems related to an |
| <code>android.zip</code> file, right click on the project and select <strong>Android |
| Tools</strong> > <strong>Fix Project Properties</strong>.</p> |
| |
| <p>Open the <code>Notepadv2</code> project and take a look around:</p> |
| <ul> |
| <li> |
| Open and look at the <code>strings.xml</code> file under |
| <code>res/values</code> — there are several new strings which we will use |
| for our new functionality |
| </li> |
| <li> |
| Also, open and take a look at the top of the <code>Notepadv2</code> class, |
| you will notice several new constants have been defined along with a new <code>mNotesCursor</code> |
| field used to hold the cursor we are using. |
| </li> |
| <li> |
| Note also that the <code>fillData()</code> method has a few more comments and now uses |
| the new field to store the notes Cursor. The <code>onCreate()</code> method is |
| unchanged from the first exercise. Also notice that the member field used to store the |
| notes Cursor is now called <code>mNotesCursor</code>. The <code>m</code> denotes a member |
| field and is part of the Android coding style standards. |
| </li> |
| <li> |
| There are also a couple of new overridden methods |
| (<code>onCreateContextMenu()</code>, <code>onContextItemSelected()</code>, |
| <code>onListItemClick()</code> and <code>onActivityResult()</code>) |
| which we will be filling in below. |
| </li> |
| </ul> |
| |
| |
| <h2>Step 2</h2> |
| <div class="sidebox-wrapper"> |
| <div class="sidebox"> |
| <p>Context menus should always be used when performing actions upon specific elements in the UI. |
| When you register a View to a context menu, the context menu is revealed by performing a "long-click" |
| on the UI component (press and hold the touchscreen or highlight and hold down the selection key for about two seconds).</p> |
| </div> |
| </div> |
| |
| <p>First, let's create the context menu that will allow users to delete individual notes. |
| Open the Notepadv2 class.</p> |
| |
| <ol> |
| <li>In order for each list item in the ListView to register for the context menu, we call |
| <code>registerForContextMenu()</code> and pass it our ListView. So, at the very end of |
| the <code>onCreate()</code> method add this line: |
| <pre>registerForContextMenu(getListView());</pre> |
| <p>Because our Activity extends the ListActivity class, <code>getListView()</code> will return us |
| the local ListView object for the Activity. Now, each list item in this ListView will activate the |
| context menu. |
| <li> |
| Now fill in the <code>onCreateContextMenu()</code> method. This callback is similar to the other |
| menu callback used for the options menu. Here, we add just one line, which will add a menu item |
| to delete a note. Call <code>menu.add()</code> like so: |
| <pre> |
| public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) { |
| super.onCreateContextMenu(menu, v, menuInfo); |
| menu.add(0, DELETE_ID, 0, R.string.menu_delete); |
| }</pre> |
| <p>The <code>onCreateContextMenu()</code> callback passes some other information in addition to the Menu object, |
| such as the View that has been triggered for the menu and |
| an extra object that may contain additional information about the object selected. However, we don't care about |
| these here, because we only have one kind of object in the Activity that uses context menus. In the next |
| step, we'll handle the menu item selection.</p> |
| </li> |
| </ol> |
| |
| <h2>Step 3</h2> |
| <p>Now that we've registered our ListView for a context menu and defined our context menu item, we need |
| to handle the callback when it is selected. For this, we need to identify the list ID of the |
| selected item, then delete it. So fill in the |
| <code>onContextItemSelected()</code> method like this:</p> |
| <pre> |
| public boolean onContextItemSelected(MenuItem item) { |
| switch(item.getItemId()) { |
| case DELETE_ID: |
| AdapterContextMenuInfo info = (AdapterContextMenuInfo) item.getMenuInfo(); |
| mDbHelper.deleteNote(info.id); |
| fillData(); |
| return true; |
| } |
| return super.onContextItemSelected(item); |
| }</pre> |
| <p>Here, we retrieve the {@link android.widget.AdapterView.AdapterContextMenuInfo AdapterContextMenuInfo} |
| with {@link android.view.MenuItem#getMenuInfo()}. The <var>id</var> field of this object tells us |
| the position of the item in the ListView. We then pass this to the <code>deleteNote()</code> |
| method of our NotesDbAdapter and the note is deleted. That's it for the context menu — notes |
| can now be deleted.</p> |
| |
| <h2 style="clear:right;">Step 4</h2> |
| <div class="sidebox-wrapper"> |
| <div class="sidebox"> |
| <h2>Starting Other Activities</h2> |
| <p>In this example our Intent uses a class name specifically. |
| As well as |
| <a href="{@docRoot}resources/faq/commontasks.html#intentexamples">starting intents</a> in |
| classes we already know about, be they in our own application or another |
| application, we can also create Intents without knowing exactly which |
| application will handle it.</p> |
| <p>For example, we might want to open a page in a |
| browser, and for this we still use |
| an Intent. But instead of specifying a class to handle it, we use |
| a predefined Intent constant, and a content URI that describes what we |
| want to do. See {@link android.content.Intent |
| android.content.Intent} for more information.</p> |
| </div> |
| </div> |
| |
| <p>Fill in the body of the <code>createNote()</code> method: |
| <p>Create a new <code>Intent</code> to create a note |
| (<code>ACTIVITY_CREATE</code>) using the <code>NoteEdit</code> class. |
| Then fire the Intent using the <code>startActivityForResult()</code> method |
| call:</p> |
| <pre style="overflow:auto"> |
| Intent i = new Intent(this, NoteEdit.class); |
| startActivityForResult(i, ACTIVITY_CREATE);</pre> |
| <p>This form of the Intent call targets a specific class in our Activity, in this case |
| <code>NoteEdit</code>. Since the Intent class will need to communicate with the Android |
| operating system to route requests, we also have to provide a Context (<code>this</code>).</p> |
| <p>The <code>startActivityForResult()</code> method fires the Intent in a way that causes a method |
| in our Activity to be called when the new Activity is completed. The method in our Activity |
| that receives the callback is called |
| <code>onActivityResult()</code> and we will implement it in a later step. The other way |
| to call an Activity is using <code>startActivity()</code> but this is a "fire-and-forget" way |
| of calling it — in this manner, our Activity is not informed when the Activity is completed, and there is |
| no way to return result information from the called Activity with <code>startActivity()</code>. |
| <p>Don't worry about the fact that <code>NoteEdit</code> doesn't exist yet, |
| we will fix that soon. </p> |
| </li> |
| |
| |
| <h2>Step 5</h2> |
| |
| <p>Fill in the body of the <code>onListItemClick()</code> override.</p> |
| <p><code>onListItemClick()</code> is a callback method that we'll override. It is called when |
| the user selects an item from the list. It is passed four parameters: the |
| <code>ListView</code> object it was invoked from, the <code>View</code> |
| inside the <code>ListView</code> that was clicked on, the |
| <code>position</code> in the list that was clicked, and the |
| <code>mRowId</code> of the item that was clicked. In this instance we can |
| ignore the first two parameters (we only have one <code>ListView</code> it |
| could be), and we ignore the <code>mRowId</code> as well. All we are |
| interested in is the <code>position</code> that the user selected. We use |
| this to get the data from the correct row, and bundle it up to send to |
| the <code>NoteEdit</code> Activity.</p> |
| <p>In our implementation of the callback, the method creates an |
| <code>Intent</code> to edit the note using |
| the <code>NoteEdit</code> class. It then adds data into the extras Bundle of |
| the Intent, which will be passed to the called Activity. We use it |
| to pass in the title and body text, and the <code>mRowId</code> for the note we are |
| editing. Finally, it will fire the Intent using the |
| <code>startActivityForResult()</code> method call. Here's the code that |
| belongs in <code>onListItemClick()</code>:</p> |
| <pre> |
| super.onListItemClick(l, v, position, id); |
| Cursor c = mNotesCursor; |
| c.moveToPosition(position); |
| Intent i = new Intent(this, NoteEdit.class); |
| i.putExtra(NotesDbAdapter.KEY_ROWID, id); |
| i.putExtra(NotesDbAdapter.KEY_TITLE, c.getString( |
| c.getColumnIndexOrThrow(NotesDbAdapter.KEY_TITLE))); |
| i.putExtra(NotesDbAdapter.KEY_BODY, c.getString( |
| c.getColumnIndexOrThrow(NotesDbAdapter.KEY_BODY))); |
| startActivityForResult(i, ACTIVITY_EDIT);</pre> |
| <ul> |
| <li> |
| <code>putExtra()</code> is the method to add items into the extras Bundle |
| to pass in to intent invocations. Here, we are |
| using the Bundle to pass in the title, body and mRowId of the note we want to edit. |
| </li> |
| <li> |
| The details of the note are pulled out from our query Cursor, which we move to the |
| proper position for the element that was selected in the list, with |
| the <code>moveToPosition()</code> method.</li> |
| <li>With the extras added to the Intent, we invoke the Intent on the |
| <code>NoteEdit</code> class by passing <code>startActivityForResult()</code> |
| the Intent and the request code. (The request code will be |
| returned to <code>onActivityResult</code> as the <code>requestCode</code> parameter.)</li> |
| </ul> |
| <p class="note"><b>Note:</b> We assign the mNotesCursor field to a local variable at the |
| start of the method. This is done as an optimization of the Android code. Accessing a local |
| variable is much more efficient than accessing a field in the Dalvik VM, so by doing this |
| we make only one access to the field, and five accesses to the local variable, making the |
| routine much more efficient. It is recommended that you use this optimization when possible.</p> |
| |
| |
| <h2>Step 6</h2> |
| |
| <p>The above <code>createNote()</code> and <code>onListItemClick()</code> |
| methods use an asynchronous Intent invocation. We need a handler for the callback, so here we fill |
| in the body of the <code>onActivityResult()</code>. </p> |
| <p><code>onActivityResult()</code> is the overridden method |
| which will be called when an Activity returns with a result. (Remember, an Activity |
| will only return a result if launched with <code>startActivityForResult</code>.) The parameters provided |
| to the callback are: </p> |
| <ul> |
| <li><code>requestCode</code> — the original request code |
| specified in the Intent invocation (either <code>ACTIVITY_CREATE</code> or |
| <code>ACTIVITY_EDIT</code> for us). |
| </li> |
| <li><code>resultCode</code> — the result (or error code) of the call, this |
| should be zero if everything was OK, but may have a non-zero code indicating |
| that something failed. There are standard result codes available, and you |
| can also create your own constants to indicate specific problems. |
| </li> |
| <li><code>intent</code> — this is an Intent created by the Activity returning |
| results. It can be used to return data in the Intent "extras." |
| </li> |
| </ul> |
| <p>The combination of <code>startActivityForResult()</code> and |
| <code>onActivityResult()</code> can be thought of as an asynchronous RPC |
| (remote procedure call) and forms the recommended way for an Activity to invoke |
| another and share services.</p> |
| <p>Here's the code that belongs in your <code>onActivityResult()</code>:</p> |
| <pre> |
| super.onActivityResult(requestCode, resultCode, intent); |
| Bundle extras = intent.getExtras(); |
| |
| switch(requestCode) { |
| case ACTIVITY_CREATE: |
| String title = extras.getString(NotesDbAdapter.KEY_TITLE); |
| String body = extras.getString(NotesDbAdapter.KEY_BODY); |
| mDbHelper.createNote(title, body); |
| fillData(); |
| break; |
| case ACTIVITY_EDIT: |
| Long mRowId = extras.getLong(NotesDbAdapter.KEY_ROWID); |
| if (mRowId != null) { |
| String editTitle = extras.getString(NotesDbAdapter.KEY_TITLE); |
| String editBody = extras.getString(NotesDbAdapter.KEY_BODY); |
| mDbHelper.updateNote(mRowId, editTitle, editBody); |
| } |
| fillData(); |
| break; |
| }</pre> |
| |
| <ul> |
| <li> |
| We are handling both the <code>ACTIVITY_CREATE</code> and |
| <code>ACTIVITY_EDIT</code> activity results in this method. |
| </li> |
| <li> |
| In the case of a create, we pull the title and body from the extras (retrieved from the |
| returned Intent) and use them to create a new note. |
| </li> |
| <li> |
| In the case of an edit, we pull the mRowId as well, and use that to update |
| the note in the database. |
| </li> |
| <li> |
| <code>fillData()</code> at the end ensures everything is up to date . |
| </li> |
| </ul> |
| |
| |
| <h2>Step 7</h2> |
| |
| <div class="sidebox-wrapper"> |
| <div class="sidebox"> |
| <h2>The Art of Layout</h2> |
| <p>The provided |
| note_edit.xml layout file is the most sophisticated one in the application we will be building, |
| but that doesn't mean it is even close to the kind of sophistication you will be likely to want |
| in real Android applications.</p> |
| <p>Creating a |
| good UI is part art and part science, and the rest is work. Mastery of <a |
| href="{@docRoot}guide/topics/ui/declaring-layout.html">XML Layouts</a> is an essential part of |
| creating |
| a good looking Android application.</p> |
| <p>Take a look at the |
| <a href="{@docRoot}resources/tutorials/views/index.html">Hello Views</a> |
| for some example layouts and how to use them. The ApiDemos sample project is also a |
| great resource from which to learn how to create different layouts.</p> |
| </div> |
| </div> |
| |
| <p>Open the file <code>note_edit.xml</code> that has been provided and take a |
| look at it. This is the UI code for the Note Editor.</p> |
| <p>This is the most |
| sophisticated UI we have dealt with yet. The file is given to you to avoid |
| problems that may sneak in when typing the code. (The XML is very strict |
| about case sensitivity and structure, mistakes in these are the usual cause |
| of problems with layout.)</p> |
| <p>There is a new parameter used |
| here that we haven't seen before: <code>android:layout_weight</code> (in |
| this case set to use the value 1 in each case).</p> |
| <p><code>layout_weight</code> is used in LinearLayouts |
| to assign "importance" to Views within the layout. All Views have a default |
| <code>layout_weight</code> of zero, meaning they take up only as much room |
| on the screen as they need to be displayed. Assigning a value higher than |
| zero will split up the rest of the available space in the parent View, according |
| to the value of each View's <code>layout_weight</code> and its ratio to the |
| overall <code>layout_weight</code> specified in the current layout for this |
| and other View elements.</p> |
| <p>To give an example: let's say we have a text label |
| and two text edit elements in a horizontal row. The label has no |
| <code>layout_weight</code> specified, so it takes up the minimum space |
| required to render. If the <code>layout_weight</code> of each of the two |
| text edit elements is set to 1, the remaining width in the parent layout will |
| be split equally between them (because we claim they are equally important). |
| If the first one has a <code>layout_weight</code> of 1 |
| and the second has a <code>layout_weight</code> of 2, then one third of the |
| remaining space will be given to the first, and two thirds to the |
| second (because we claim the second one is more important).</p> |
| <p>This layout also demonstrates how to nest multiple layouts |
| inside each other to achieve a more complex and pleasant layout. In this |
| example, a horizontal linear layout is nested inside the vertical one to |
| allow the title label and text field to be alongside each other, |
| horizontally.</p> |
| |
| |
| <h2 style="clear:right;">Step 8</h2> |
| |
| <p>Create a <code>NoteEdit</code> class that extends |
| <code>android.app.Activity</code>.</p> |
| <p>This is the first time we will have |
| created an Activity without the Android Eclipse plugin doing it for us. When |
| you do so, the <code>onCreate()</code> method is not automatically |
| overridden for you. It is hard to imagine an Activity that doesn't override |
| the <code>onCreate()</code> method, so this should be the first thing you do.</p> |
| <ol> |
| <li>Right click on the <code>com.android.demo.notepad2</code> package |
| in the Package Explorer, and select <strong>New</strong> > <strong>Class</strong> from the popup |
| menu.</li> |
| <li>Fill in <code>NoteEdit</code> for the <code>Name:</code> field in the |
| dialog.</li> |
| <li>In the <code>Superclass:</code> field, enter |
| <code>android.app.Activity</code> (you can also just type Activity and hit |
| Ctrl-Space on Windows and Linux or Cmd-Space on the Mac, to invoke code |
| assist and find the right package and class).</li> |
| <li>Click <strong>Finish</strong>.</li> |
| <li>In the resulting <code>NoteEdit</code> class, right click in the editor |
| window and select <strong>Source</strong> > <strong>Override/Implement Methods...</strong></li> |
| <li>Scroll down through the checklist in the dialog until you see |
| <code>onCreate(Bundle)</code> — and check the box next to it.</li> |
| <li>Click <strong>OK</strong>.<p>The method should now appear in your class.</p></li> |
| </ol> |
| |
| <h2>Step 9</h2> |
| |
| <p>Fill in the body of the <code>onCreate()</code> method for <code>NoteEdit</code>.</p> |
| |
| <p>This will set the title of our new Activity to say "Edit Note" (one |
| of the strings defined in <code>strings.xml</code>). It will also set the |
| content view to use our <code>note_edit.xml</code> layout file. We can then |
| grab handles to the title and body text edit views, and the confirm button, |
| so that our class can use them to set and get the note title and body, |
| and attach an event to the confirm button for when it is pressed by the |
| user.</p> |
| <p>We can then unbundle the values that were passed in to the Activity |
| with the extras Bundle attached to the calling Intent. We'll use them to pre-populate |
| the title and body text edit views so that the user can edit them. |
| Then we will grab and store the <code>mRowId</code> so we can keep |
| track of what note the user is editing.</p> |
| |
| <ol> |
| <li> |
| Inside <code>onCreate()</code>, set up the layout:<br> |
| <pre>setContentView(R.layout.note_edit);</pre> |
| </li> |
| <li> |
| Change the Activity title to the "Edit Note" string: |
| <pre>setTitle(R.string.edit_note);</pre> |
| </li> |
| <li> |
| Find the {@link android.widget.EditText} and {@link android.widget.Button} components we need: |
| <p>These are found by the |
| IDs associated to them in the R class, and need to be cast to the right |
| type of <code>View</code> (<code>EditText</code> for the two text views, |
| and <code>Button</code> for the confirm button):</p> |
| <pre> |
| mTitleText = (EditText) findViewById(R.id.title); |
| mBodyText = (EditText) findViewById(R.id.body); |
| Button confirmButton = (Button) findViewById(R.id.confirm);</pre> |
| <p>Note that <code>mTitleText</code> and <code>mBodyText</code> are member |
| fields (you need to declare them at the top of the class definition).</p> |
| </li> |
| <li>At the top of the class, declare a <code>Long mRowId</code> private field to store |
| the current <code>mRowId</code> being edited (if any). |
| </li> |
| <li>Continuing inside <code>onCreate()</code>, |
| add code to initialize the <code>title</code>, <code>body</code> and |
| <code>mRowId</code> from the extras Bundle in |
| the Intent (if it is present):<br> |
| <pre> |
| mRowId = null; |
| Bundle extras = getIntent().getExtras(); |
| if (extras != null) { |
| String title = extras.getString(NotesDbAdapter.KEY_TITLE); |
| String body = extras.getString(NotesDbAdapter.KEY_BODY); |
| mRowId = extras.getLong(NotesDbAdapter.KEY_ROWID); |
| |
| if (title != null) { |
| mTitleText.setText(title); |
| } |
| if (body != null) { |
| mBodyText.setText(body); |
| } |
| }</pre> |
| <ul> |
| <li> |
| We are pulling the <code>title</code> and |
| <code>body</code> out of the |
| <code>extras</code> Bundle that was set from the |
| Intent invocation. |
| </li><li> |
| We also null-protect the text field setting (i.e., we don't want to set |
| the text fields to null accidentally).</li> |
| </ul> |
| </li> |
| <li> |
| Create an <code>onClickListener()</code> for the button: |
| <p>Listeners can be one of the more confusing aspects of UI |
| implementation, but |
| what we are trying to achieve in this case is simple. We want an |
| <code>onClick()</code> method to be called when the user presses the |
| confirm button, and use that to do some work and return the values |
| of the edited note to the Intent caller. We do this using something called |
| an anonymous inner class. This is a bit confusing to look at unless you |
| have seen them before, but all you really need to take away from this is |
| that you can refer to this code in the future to see how to create a |
| listener and attach it to a button. (Listeners are a common idiom |
| in Java development, particularly for user interfaces.) Here's the empty listener:<br> |
| <pre> |
| confirmButton.setOnClickListener(new View.OnClickListener() { |
| |
| public void onClick(View view) { |
| |
| } |
| |
| });</pre> |
| </li> |
| </ol> |
| <h2>Step 10</h2> |
| |
| <p>Fill in the body of the <code>onClick()</code> method of the <code>OnClickListener</code> created in the last step.</p> |
| |
| <p>This is the code that will be run when the user clicks on the |
| confirm button. We want this to grab the title and body text from the edit |
| text fields, and put them into the return Bundle so that they can be passed |
| back to the Activity that invoked this <code>NoteEdit</code> Activity. If the |
| operation is an edit rather than a create, we also want to put the |
| <code>mRowId</code> into the Bundle so that the |
| <code>Notepadv2</code> class can save the changes back to the correct |
| note.</p> |
| <ol> |
| <li> |
| Create a <code>Bundle</code> and put the title and body text into it using the |
| constants defined in Notepadv2 as keys:<br> |
| <pre> |
| Bundle bundle = new Bundle(); |
| |
| bundle.putString(NotesDbAdapter.KEY_TITLE, mTitleText.getText().toString()); |
| bundle.putString(NotesDbAdapter.KEY_BODY, mBodyText.getText().toString()); |
| if (mRowId != null) { |
| bundle.putLong(NotesDbAdapter.KEY_ROWID, mRowId); |
| }</pre> |
| </li> |
| <li> |
| Set the result information (the Bundle) in a new Intent and finish the Activity: |
| <pre> |
| Intent mIntent = new Intent(); |
| mIntent.putExtras(bundle); |
| setResult(RESULT_OK, mIntent); |
| finish();</pre> |
| <ul> |
| <li>The Intent is simply our data carrier that carries our Bundle |
| (with the title, body and mRowId).</li> |
| <li>The <code>setResult()</code> method is used to set the result |
| code and return Intent to be passed back to the |
| Intent caller. In this case everything worked, so we return RESULT_OK for the |
| result code.</li> |
| <li>The <code>finish()</code> call is used to signal that the Activity |
| is done (like a return call). Anything set in the Result will then be |
| returned to the caller, along with execution control.</li> |
| </ul> |
| </li> |
| </ol> |
| <p>The full <code>onCreate()</code> method (plus supporting class fields) should |
| now look like this:</p> |
| <pre> |
| private EditText mTitleText; |
| private EditText mBodyText; |
| private Long mRowId; |
| |
| @Override |
| protected void onCreate(Bundle savedInstanceState) { |
| super.onCreate(savedInstanceState); |
| 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 = null; |
| Bundle extras = getIntent().getExtras(); |
| if (extras != null) { |
| String title = extras.getString(NotesDbAdapter.KEY_TITLE); |
| String body = extras.getString(NotesDbAdapter.KEY_BODY); |
| mRowId = extras.getLong(NotesDbAdapter.KEY_ROWID); |
| |
| if (title != null) { |
| mTitleText.setText(title); |
| } |
| if (body != null) { |
| mBodyText.setText(body); |
| } |
| } |
| |
| confirmButton.setOnClickListener(new View.OnClickListener() { |
| |
| public void onClick(View view) { |
| Bundle bundle = new Bundle(); |
| |
| bundle.putString(NotesDbAdapter.KEY_TITLE, mTitleText.getText().toString()); |
| bundle.putString(NotesDbAdapter.KEY_BODY, mBodyText.getText().toString()); |
| if (mRowId != null) { |
| bundle.putLong(NotesDbAdapter.KEY_ROWID, mRowId); |
| } |
| |
| Intent mIntent = new Intent(); |
| mIntent.putExtras(bundle); |
| setResult(RESULT_OK, mIntent); |
| finish(); |
| } |
| }); |
| }</pre> |
| </li> |
| </ol> |
| |
| <h2>Step 11</h2> |
| |
| <div class="sidebox-wrapper"> |
| <div class="sidebox"> |
| <h2>The All-Important Android Manifest File</h2> |
| <p>The AndroidManifest.xml file is the way in which Android sees your |
| application. This file defines the category of the application, where |
| it shows up (or even if it shows up) in the launcher or settings, what |
| activities, services, and content providers it defines, what intents it can |
| receive, and more. </p> |
| <p>For more information, see the reference document |
| <a href="{@docRoot}guide/topics/manifest/manifest-intro.html">The AndroidManifest.xml |
| File</a></p> |
| </div> |
| </div> |
| |
| <p>Finally, the new Activity has to be defined in the manifest file:</p> |
| <p>Before the new Activity can be seen by Android, it needs its own |
| Activity entry in the <code>AndroidManifest.xml</code> file. This is to let |
| the system know that it is there and can be called. We could also specify |
| which IntentFilters the activity implements here, but we are going to skip |
| this for now and just let Android know that the Activity is |
| defined.</p> |
| <p>There is a Manifest editor included in the Eclipse plugin that makes it much easier |
| to edit the AndroidManifest file, and we will use this. If you prefer to edit the file directly |
| or are not using the Eclipse plugin, see the box at the end for information on how to do this |
| without using the new Manifest editor.<p> |
| <ol> |
| <li>Double click on the <code>AndroidManifest.xml</code> file in the package explorer to open it. |
| </li> |
| <li>Click the <strong>Application</strong> tab at the bottom of the Manifest editor.</li> |
| <li>Click <strong>Add...</strong> in the Application Nodes section. |
| <p>If you see a dialog with radiobuttons at the top, select the top radio button: |
| "Create a new element at the top level, in Application".</p></li> |
| <li>Make sure "(A) Activity" is selected in the selection pane of the dialog, and click <strong>OK</strong>.</li> |
| <li>Click on the new "Activity" node, in the Application Nodes section, then |
| type <code>.NoteEdit</code> into the <em>Name*</em> |
| field to the right. Press Return/Enter.</li> |
| </ol> |
| <p>The Android Manifest editor helps you add more complex entries into the AndroidManifest.xml |
| file, have a look around at some of the other options available (but be careful not to select |
| them otherwise they will be added to your Manifest). This editor should help you understand |
| and alter the AndroidManifest.xml file as you move on to more advanced Android applications.</p> |
| |
| <p class="note">If you prefer to edit this file directly, simply open the |
| <code>AndroidManifest.xml</code> file and look at the source (use the |
| <code>AndroidManifest.xml</code> tab in the eclipse editor to see the source code directly). |
| Then edit the file as follows:<br> |
| <code><activity android:name=".NoteEdit" /></code><br><br> |
| This should be placed just below the line that reads:<br> |
| <code></activity></code> for the <code>.Notepadv2</code> activity.</p> |
| |
| <h2 style="clear:right;">Step 12</h2> |
| |
| <p>Now Run it!</p> |
| <p>You should now be able to add real notes from |
| the menu, as well as delete an existing one. Notice that in order to delete, you must |
| first use the directional controls on the device to highlight the note. |
| Furthermore, selecting a note title from the list should bring up the note |
| editor to let you edit it. Press confirm when finished to save the changes |
| back to the database. |
| |
| <h2>Solution and Next Steps</h2> |
| |
| <p>You can see the solution to this exercise in <code>Notepadv2Solution</code> |
| from the zip file to compare with your own.</p> |
| <p>Now try editing a note, and then hitting the back button on the emulator |
| instead of the confirm button (the back button is below the menu button). You |
| will see an error come up. Clearly our application still has some problems. |
| Worse still, if you did make some changes and hit the back button, when you go |
| back into the notepad to look at the note you changed, you will find that all |
| your changes have been lost. In the next exercise we will fix these |
| problems.</p> |
| |
| <p> |
| Once you are ready, move on to <a href="notepad-ex3.html">Tutorial |
| Exercise 3</a> where you will fix the problems with the back button and lost |
| edits by introducing a proper life cycle into the NoteEdit Activity.</p> |
| |
| |