diff options
Diffstat (limited to 'docs/html/training/notepad/notepad-ex2.jd')
-rw-r--r-- | docs/html/training/notepad/notepad-ex2.jd | 645 |
1 files changed, 645 insertions, 0 deletions
diff --git a/docs/html/training/notepad/notepad-ex2.jd b/docs/html/training/notepad/notepad-ex2.jd new file mode 100644 index 0000000..1334d7a --- /dev/null +++ b/docs/html/training/notepad/notepad-ex2.jd @@ -0,0 +1,645 @@ +Rpage.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 the 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> + + |