In the second part of the tutorial we want to create the form to add new books to the library. We also need some mechanism to create new authors. In order to achieve all this, we need to utilize different form elements, that android provides and tweak them a little bit, to do exactly what we want.
The complete source code of this tutorial can be found at: http://androrm.com/src/downloads/book_tutorial.tar.gz.
Creating the form
First of all we need the layout for the form itself. So what do we want to achieve? We want to enter the name of the book. Also the authors should be selectable from a list of all authors, that we know. And last but not least, we also need to buttons. One to show a dialog to create a new author and one to save the book to the database. Entering text is easy. Android provides a class calledEditText, that will do exactly, what we need. We can also create the item for the authors pretty easy, by using the
Spinnerclass. All the other stuff in the following layout file is basically getting the items to their correct position. We use a
TableLayoutso that we can display a label in front of each editor and a
LinearLayoutto place a button at the bottom of the form.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical">
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_weight="1">
<TableLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<TableRow
android:layout_width="fill_parent"
android:layout_height="wrap_content">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="15dp"
android:text="Title" />
<EditText
android:id="@+id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:hint="Title..."
android:layout_weight="1" />
</TableRow>
<TableRow
android:layout_width="fill_parent"
android:layout_height="wrap_content">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="15dp"
android:text="Author" />
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_weight="1">
<Spinner
android:id="@+id/spinner"
android:layout_width="fill_parent"
android:layout_height="wrap_content" />
<Button
android:id="@+id/add_author"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="New Author" />
</LinearLayout>
</TableRow>
</TableLayout>
</LinearLayout>
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_weight="0">
<Button
android:id="@+id/save"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Save Book" />
</LinearLayout>
</LinearLayout>
Setting up the form elements
The Spinner
Now that we have created the layout, we need to implement the actual Activity. Create a plain activity and set its
contentViewto the layout file, we just created. For now, we don't need to change anything on the
EditTextwidget. But we want our authors to be displayed in the
Spinner. In order to achieve this, we have to first query the database for all authors. Do you think SQL right now? Forget it! This line does the job:
mAuthors = Author.objects(getApplicationContext()).all();Unfortunately android does not support
QuerySetsnatively ;) We need to provide the authors, as a list, that it can handle. calling
toList()on the
QuerySetdoes the job. Now we are able to set up the handler android needs in order to show the
Spinnercorrectly.
Spinner authors = (Spinner) findViewById(R.id.spinner); mSpinnerAdapter = new ArrayAdapterNow the spinner will show all the authors, we currently have in the database. But what happens, if there are no authors in the database?(getApplicationContext(), R.layout.spinner_item, mAuthors); authors.setAdapter(mSpinnerAdapter);
Adding authors
If we don't have an author in our database, we want to give the user the opportunity to add a new one on the fly. When a users clicks the "Add new author" button, a dialog should pop open, giving him the possibility, to enter the name of the new author. Achieving this is trickier, than you might think. We have to implement our oneDialogclass. But luckily the implementation is not very hard.
First of all (as always), we need to define the layout for the dialog. As we only want a very simplistic one, it is not very large.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:padding="15dp"
android:orientation="vertical">
<EditText
android:id="@+id/name"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:hint="Name..." />
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content" >
<Button
android:id="@+id/button_ok"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Save"
android:layout_weight="1" />
<Button
android:id="@+id/button_cancel"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Cancel"
android:layout_weight="1" />
</LinearLayout>
</LinearLayout>
Again, we define an EditText, so that the user is able to enter the name of the new author and we add two buttons, ok and cancel, giving him the opportunity to either save the new author or cancel.
public class AddAuthorDialog extends Dialog {
public AddAuthorDialog(Context context) {
super(context);
setContentView(R.layout.new_author_dialog);
setTitle("Add a new author");
registerOkButton();
registerCancelButton();
}
private void registerOkButton() {
final EditText name = (EditText) findViewById(R.id.name);
Button ok = (Button) findViewById(R.id.button_ok);
ok.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
String value = name.getText().toString();
if(value.trim().equals("")) {
return;
}
Author author = new Author();
author.setName(value);
author.save(getContext());
AddBook activity = (AddBook) getOwnerActivity();
activity.addAuthor(author);
name.setText("");
dismiss();
}
});
}
private void registerCancelButton() {
Button cancel = (Button) findViewById(R.id.button_cancel);
cancel.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
dismiss();
}
});
}
}
In the Dialogclass itself, note how the new author is being crated and saved using androrm. Also the owner activity, which is our form is notified, that a new author has been added, so it can update the
Spinner.
Author author = new Author();
author.setName(value);
author.save(getContext());
AddBook activity = (AddBook) getOwnerActivity();
activity.addAuthor(author);
We also had to assure, that no "empty" authors are saved. You see, that we check for an empty stringbefore we create and save the
Authorobject.
Creating the new book
The last step is very simple. If a user clicks on thesavebutton at the bottom of the form, a new book should be created and saved to the database. But before we blindly save books, we first have to check if an author has been selected and if the user has entered a title for the book. If the provided data is correct, we can go ahead and set-up and save the book.
Button saveBook = (Button) findViewById(R.id.save);
saveBook.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
EditText title = (EditText) findViewById(R.id.title);
String value = title.getText().toString();
if(value.trim().equals("")) {
showDialog(NO_TITLE);
} else {
if(mSelectedAuthor == null) {
mSelectedAuthor = mSpinnerAdapter.getItem(0);
}
Book book = new Book();
book.setTitle(value);
book.setAuthor(mSelectedAuthor);
book.save(getApplicationContext());
resetForm();
}
}
});
That's it! You created the form to create new books.