2014年1月2日 星期四

Android SQL Database Adapter

First of all, to manage data in a private database in your Android phone/tablet, we will use SQLite as it is embedded into every Android device.
We need to import android.database.sqlite for access to those classes of SQLite to manage your database in your apps.


DBAdapter.java
package com.example.sample_db_adapter;

import java.math.BigDecimal;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.util.Log;

public class DBAdapter {
    public static final BigDecimal decimal_multiplier = new BigDecimal(100);
    public static final SimpleDateFormat dateFormat_dmy = new SimpleDateFormat("dd/MM/yyyy");
    private static final String TAG = "myDBAdapter";

    private static final String DATABASE_NAME = "mybookstore";
    private static final int DATABASE_VERSION = 1;

    private static final String TB_BOOK_M = "book_master";
    public static final String BOOK_M_KEY_ID = "book_id";
    public static final String BOOK_M_NAME = "name";
    public static final String BOOK_M_CAT = "category";
    public static final String BOOK_M_AUTHOR = "author";
    public static final String BOOK_M_PRICE = "price";
    public static final String BOOK_M_CREATED_BY = "created_by";
    public static final String BOOK_M_CREATED_ON = "created_on";
    public static final String BOOK_M_CHANGED_BY = "changed_by";
    public static final String BOOK_M_CHANGED_ON = "changed_on";

    private static final String TB_BOOK_M_CREATE = "create TABLE IF NOT EXISTS "
        + TB_BOOK_M + " ("
        + BOOK_M_KEY_ID + " integer primary key autoincrement, "
        + BOOK_M_NAME + " text, "
        + BOOK_M_CAT + " text, "
        + BOOK_M_AUTHOR + " text, "
        + BOOK_M_PRICE + " integer, "
        + BOOK_M_CREATED_BY + " text, "
        + BOOK_M_CREATED_ON + " integer, "
        + BOOK_M_CHANGED_BY + " text, "
        + BOOK_M_CHANGED_ON + " integer ); ";

    /**
     * Tailor make our own SQLiteOpenHelper and override the onCreate and
     * onUpgrade function
     */
    private static class DatabaseHelper extends SQLiteOpenHelper {
        DatabaseHelper(Context context) {
            super(context, DATABASE_NAME, null, DATABASE_VERSION);
        }

        @Override
        public void onCreate(SQLiteDatabase db) {
            Log.d(TAG, "onCreate");
            db.execSQL(TB_BOOK_M_CREATE);

        }

        @Override
        public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
            Log.w(TAG, "Upgrading database from version " + oldVersion + " to "
                    + newVersion + ", which will destroy all old data");
            onCreate(db);
        }
    }

    private DatabaseHelper mDbHelper;
    private SQLiteDatabase mDb;
    private final Context mCtx;

    /**
     * Constructor - takes the context to allow the database to be
     * opened/created
     */
    public DBAdapter(Context ctx) {
        this.mCtx = ctx;
    }

    /**
     * Open the Traffic database. If it cannot be opened, try to create a new
     * instance of the database. If it cannot be created, throw an exception to
     * signal the failure
     */
    public DBAdapter open() throws SQLException {
        mDbHelper = new DatabaseHelper(mCtx);
        mDb = mDbHelper.getWritableDatabase();
        return this;
    }
    
    public void createDB() {
        try{
            mDbHelper.onCreate(mDb);
        } catch (Exception e){
            Log.d(TAG, e.toString());
        }
    }
    
    public void upgrade() {
        try{
            mDbHelper = new DatabaseHelper(mCtx);
            mDb = mDbHelper.getWritableDatabase();
            mDbHelper.onUpgrade(mDb, 1, 2);
        } catch (Exception e){
            Log.d(TAG, e.toString());
        }
    }
    
    /**
     * Insert a record in table, index(ID) of the record will be returned
     * If index <= 0, that means the insert failed
     */    
    public long BOOK_M_create(String NAME, String CAT, String AUTHOR, double PRICE, String CREATED_BY, String CREATED_ON, String CHANGED_BY, String CHANGED_ON ) {
        // I prefer to store 'Date' into database in terms of number
        //   It will be better for sorting and comparison
        // The following is to turn a date with predefined format "dd/MM/yyyy" into time millis
        Date createDate = null;
        Long createMillis = null;
        Date changeDate = null;
        Long changeMillis = null;                    
        try {
            createDate = dateFormat_dmy.parse(CREATED_ON);
            createMillis = createDate.getTime();
            changeDate = dateFormat_dmy.parse(CHANGED_ON);
            changeMillis = changeDate.getTime();                        
        } catch (ParseException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
            Log.e("E",e.toString());
            createMillis = java.lang.System.currentTimeMillis();
            changeMillis = java.lang.System.currentTimeMillis();
        }    
    
        return BOOK_M_create(NAME, CAT, AUTHOR, PRICE, CREATED_BY, createMillis, CHANGED_BY, changeMillis );
    }
    
    public long BOOK_M_create(String NAME, String CAT, String AUTHOR, double PRICE, String CREATED_BY, long CREATED_ON, String CHANGED_BY, long CHANGED_ON ) {
        // Better to store number into database as integer
        //   Add extra handling with self defined variable 'decimal_multiplier' 
        //   during read/write of the number. Here I turn a double into an integer
        //   and store the integer into database
        // When handling numbers with decimal places
        //   DO NOT attempt to do +-*/ for double, float or anything that similar
        //   The result is not accurate, from web you can have lots of examples
        //   Instead you should use BigDecimal as follows
        BigDecimal price_bd = new BigDecimal(PRICE).multiply(decimal_multiplier);
        int price_int = price_bd.intValue();

        ContentValues Values = new ContentValues();
        Values.put(BOOK_M_NAME , NAME);
        Values.put(BOOK_M_CAT , CAT);
        Values.put(BOOK_M_AUTHOR , AUTHOR);
        Values.put(BOOK_M_PRICE , price_int);
        Values.put(BOOK_M_CREATED_BY , CREATED_BY);
        Values.put(BOOK_M_CREATED_ON , CREATED_ON);
        Values.put(BOOK_M_CHANGED_BY , CHANGED_BY);
        Values.put(BOOK_M_CHANGED_ON , CHANGED_ON);
        return mDb.insert(TB_BOOK_M , null, Values);
    }    
    
    /**
     * Update a record in table, index(ID) of the record will be returned
     * If index <= 0, that means the update failed
     */        
    public long BOOK_M_update(long ID, String NAME, String CAT, String AUTHOR, double PRICE, String CREATED_BY, String CREATED_ON, String CHANGED_BY, String CHANGED_ON ) {
        Date createDate = null;
        Long createMillis = null;
        Date changeDate = null;
        Long changeMillis = null;                    
        try {
            createDate = dateFormat_dmy.parse(CREATED_ON);
            createMillis = createDate.getTime();
            changeDate = dateFormat_dmy.parse(CHANGED_ON);
            changeMillis = changeDate.getTime();                        
        } catch (ParseException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
            Log.e("E",e.toString());
            createMillis = java.lang.System.currentTimeMillis();
            changeMillis = java.lang.System.currentTimeMillis();
        }    
    
        return BOOK_M_update(ID, NAME, CAT, AUTHOR, PRICE, CREATED_BY, createMillis, CHANGED_BY, changeMillis );
    }
    
    public long BOOK_M_update(long ID, String NAME, String CAT, String AUTHOR, double PRICE, String CREATED_BY, long CREATED_ON, String CHANGED_BY, long CHANGED_ON ) {
        BigDecimal price_bd = new BigDecimal(PRICE).multiply(decimal_multiplier);
        int price_int = price_bd.intValue();
        
        ContentValues Values = new ContentValues();
        Values.put(BOOK_M_NAME , NAME);
        Values.put(BOOK_M_CAT , CAT);
        Values.put(BOOK_M_AUTHOR , AUTHOR);
        Values.put(BOOK_M_PRICE , price_int);
        Values.put(BOOK_M_CREATED_BY , CREATED_BY);
        Values.put(BOOK_M_CREATED_ON , CREATED_ON);
        Values.put(BOOK_M_CHANGED_BY , CHANGED_BY);
        Values.put(BOOK_M_CHANGED_ON , CHANGED_ON);
    
        return mDb.update(TB_BOOK_M, Values, BOOK_M_KEY_ID + "='" + ID + "'", null);
    }    

    public Cursor BOOK_M_fetch(long ID) throws SQLException {
        Cursor mCursor =
              mDb.query(true, TB_BOOK_M, 
                      new String[] {BOOK_M_KEY_ID, BOOK_M_NAME, BOOK_M_CAT, BOOK_M_AUTHOR, BOOK_M_PRICE, 
                      BOOK_M_CREATED_BY, BOOK_M_CREATED_ON, BOOK_M_CHANGED_BY, BOOK_M_CHANGED_ON}, 
                      BOOK_M_KEY_ID + "=" + ID, null, null, null, null, null);
        if (mCursor != null) {
            mCursor.moveToFirst();
        }
        return mCursor;
    }
    
    public Cursor BOOK_M_fetchAll() {
        return mDb.query(TB_BOOK_M, 
                new String[] {BOOK_M_KEY_ID, BOOK_M_NAME, BOOK_M_CAT, BOOK_M_AUTHOR, BOOK_M_PRICE, 
                BOOK_M_CREATED_BY, BOOK_M_CREATED_ON, BOOK_M_CHANGED_BY, BOOK_M_CHANGED_ON}, 
                null, null, null, null, null);     
    }
    
    public long BOOK_M_clear() {
        return mDb.delete(TB_BOOK_M, null, null);
    }
}
Here we create our own class DatabaseHelper extending SQLiteOpenHelper and put our own create and update SQL statement inside. The above include some basic operation of the database.
Note that SQLite does not have datatype 'Datetime'. To store a 'Date' into database, you can either choose to store in 'String' or turn it into milliseconds and store in 'Integer'. I prefer the latter one as it is easier for sorting, comparison and range select.
Besides, I prefer not to store double/float into database. Anyway this is my personal choice, not a rule.

Book.java
package com.example.sample_db_adapter;

import java.math.BigDecimal;

import android.database.Cursor;

public class Book {
    public long key_id;
    public String name;
    public String cat; 
    public String author; 
    public BigDecimal price;
    public String created_by;
    public long created_on;
    public String changed_by;
    public long changed_on;
    
    public Book(long key_id){
        this.key_id = key_id;
        if (key_id != 0){
            Cursor c = MainActivity.myDBAdapter.BOOK_M_fetch(key_id);
            setBook(c);
        }
        else{
            iniBook();
        }
    }
    
    public void iniBook(){
        this.cat = "";
        this.author = "";
        this.price = BigDecimal.valueOf(0);
        this.created_by = "";
        this.created_on = 0;
        this.changed_by = "";
        this.changed_on = 0;        
    }
    
    public void setBook(Cursor c){
        this.name = c.getString(c.getColumnIndex(DBAdapter.BOOK_M_NAME));
        this.cat = c.getString(c.getColumnIndex(DBAdapter.BOOK_M_CAT));
        this.author = c.getString(c.getColumnIndex(DBAdapter.BOOK_M_AUTHOR));
        this.price = 
            BigDecimal.valueOf(c.getInt(c.getColumnIndex(DBAdapter.BOOK_M_PRICE)));
        this.price = this.price.divide(DBAdapter.decimal_multiplier);
        this.created_by = c.getString(c.getColumnIndex(DBAdapter.BOOK_M_CREATED_BY));
        this.created_on = c.getInt(c.getColumnIndex(DBAdapter.BOOK_M_CREATED_ON));
        this.changed_by = c.getString(c.getColumnIndex(DBAdapter.BOOK_M_CHANGED_BY));
        this.changed_on = c.getInt(c.getColumnIndex(DBAdapter.BOOK_M_CHANGED_ON));
    }
}
Then create a class Book to store the data from database and act as a bridge between your apps and the database.

MainActivity.java
package com.example.sample_db_adapter;

import java.util.ArrayList;

import android.os.Bundle;
import android.os.Parcelable;
import android.app.Activity;
import android.content.Intent;
import android.database.Cursor;
import android.util.Log;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.ListView;
import android.widget.Toast;

public class MainActivity extends Activity {
    static public DBAdapter myDBAdapter;
    static final public String user = "Admin";
    
    private Button btn_add;
    private Button btn_ini_book_list;
    private Button btn_clear_book_list;
    private ListView listView_books;
    
    private ArrayList<Book> myBookList;
    private static Parcelable list_state;
    
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        findViews();
        setListener();
        setValues();        
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.activity_main, menu);
        return true;
    }
    
    @Override
    protected void onSaveInstanceState(Bundle outState) {
        try{
            super.onSaveInstanceState(outState);
            // to save the current position of view of the list
            list_state = listView_books.onSaveInstanceState();
        }
        catch(Exception ex){
            Log.e("onSaveInstanceState", ex.toString());
        }
    }
    
    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
        super.onActivityResult(requestCode, resultCode, intent);        

        switch(requestCode) {       
        default:
            setBookList();
            break;
        }
        // restore to the previous position of view of the list
        listView_books.onRestoreInstanceState(list_state);
    }
    
    private void findViews() {
        btn_add = (Button) findViewById(R.id.btn_add);
        btn_ini_book_list = (Button) findViewById(R.id.btn_ini_book_list);
        btn_clear_book_list = (Button) findViewById(R.id.btn_clear_book_list);
        listView_books = (ListView) findViewById(R.id.listView_books);
    }
    
    private void setValues() {
        myDBAdapter = (new DBAdapter(this));
        myDBAdapter.open();
        myDBAdapter.createDB();
        
        setBookList();
    }
    
    /**
     * Get full book list from database
     * Put the list into 'listView_books'
     */    
    private void setBookList(){
        myBookList = new ArrayList<Book>();
        Cursor temp_c = null; 
        try {
            temp_c = myDBAdapter.BOOK_M_fetchAll();
            temp_c.moveToFirst();    
            while (!temp_c.isAfterLast()) {
                Book book = new Book(temp_c.getLong(temp_c.getColumnIndex(DBAdapter.BOOK_M_KEY_ID)));
                myBookList.add(book);
                temp_c.moveToNext();
            }
        }
        catch (Exception ex){
            Log.e("MainActivity", ex.toString());
        }
        finally{
            if (temp_c != null){
                temp_c.close();
            }
        }
        String[] book_array = new String[myBookList.size()];
        for (int i = 0; i < myBookList.size(); i++){
            book_array[i] = myBookList.get(i).name;
        }
        listView_books.setAdapter(new ArrayAdapter(this, android.R.layout.simple_list_item_1, book_array));
    }

    private void setListener() {
        // Listen for button clicks
        btn_add.setOnClickListener(btn_add_click);
        btn_ini_book_list.setOnClickListener(btn_ini_book_list_click);
        btn_clear_book_list.setOnClickListener(btn_clear_book_list_click);
        listView_books.setOnItemClickListener(listView_book_click);
    }

    private OnClickListener btn_ini_book_list_click = new OnClickListener() {
        public void onClick(View v) {
            // TODO Auto-generated method stub
            try {
                myDBAdapter.BOOK_M_create(
                        "Rich Dad Poor Dad", "Finance", "Robert Kiyosaki", 332.24, 
                        user, java.lang.System.currentTimeMillis(), 
                        user, java.lang.System.currentTimeMillis());
                myDBAdapter.BOOK_M_create(
                        "Tuesdays with Morrie", "Philosophy", "Mitch Albom and Jesus Dominguez", 236.13, 
                        user, java.lang.System.currentTimeMillis(), 
                        user, java.lang.System.currentTimeMillis());
                myDBAdapter.BOOK_M_create(
                        "The Five People You Meet in Heaven", "Philosophy", "Mitch Albom", 178.07, 
                        user, java.lang.System.currentTimeMillis(), 
                        user, java.lang.System.currentTimeMillis());
                myDBAdapter.BOOK_M_create(
                        "Sherlock Holmes", "Detective", "Arthur Conan Doyle", 189.2, 
                        user, java.lang.System.currentTimeMillis(), 
                        user, java.lang.System.currentTimeMillis());
                myDBAdapter.BOOK_M_create(
                        "Romance of the Three Kingdoms", "History", "Luo Guanzhong", 269.03, 
                        user, java.lang.System.currentTimeMillis(), 
                        user, java.lang.System.currentTimeMillis());
                myDBAdapter.BOOK_M_create(
                        "Harry Potter", "Fantasy", "J. K. Rowling", 199.7, 
                        user, java.lang.System.currentTimeMillis(), 
                        user, java.lang.System.currentTimeMillis());

            }
            catch (Exception ex){
                Log.e("MainActivity", ex.toString());
            }
            finally{

            }
            setBookList(); // refresh the listview of book list
        }
    };
    
    private OnClickListener btn_clear_book_list_click = new OnClickListener() {
        public void onClick(View v) {
            // TODO Auto-generated method stub
            try {
                myDBAdapter.BOOK_M_clear();
            }
            catch (Exception ex){
                Log.e("MainActivity", ex.toString());
            }
            finally{

            }
            setBookList(); // refresh the listview of book list
        }
    };    
    
    private OnClickListener btn_add_click = new OnClickListener() {
        public void onClick(View v) {
            // TODO Auto-generated method stub
            go_book_maintain(0);
        }
    };
    
    private OnItemClickListener listView_book_click = new OnItemClickListener() {
        public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
            Toast.makeText(MainActivity.this, myBookList.get(position).name, Toast.LENGTH_SHORT).show();
            go_book_maintain(myBookList.get(position).key_id);
        }        
    };
    
    private void go_book_maintain(long myBookID){
        Bundle b = new Bundle();
        b.putLong("myBookID", myBookID);    
        Intent i = new Intent(this, BookMaintainActivity.class);
        i.putExtras(b);
        startActivityForResult(i, 0);
    }
}
Here comes to our MainActivity, quite simple and self explained. There are 4 actions in total:
- Initialize book list: Insert initial records into DB -> Get records from DB -> Refresh listview
- Clear book list: Clear all records in DB -> Get records from DB -> Refresh listview
- Add a new book: Go to BookMaintainActivity.class to add a single book record into DB
- Update an existing book: Go to BookMaintainActivity.class to update a single book record into DB

* While proceeding to BookMaintainActivity.class, we use startActivityForResult here as we want to do something when user return to MainActivity.class from BookMaintainActivity.class. In onActivityResult it states action to do after receiving result from BookMaintainActivity.class. Here we simply do the following:
Get records from DB -> Refresh listview

activity_main.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/LinearLayout2"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content" >

        <Button
            android:id="@+id/btn_add"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Add Book" />


        <Button
            android:id="@+id/btn_ini_book_list"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Ini List" />


        <Button
            android:id="@+id/btn_clear_book_list"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Clear List" />

    </LinearLayout>


    <ListView
        android:id="@+id/listView_books"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" >

    </ListView>

</LinearLayout>

BookMaintainActivity.java
package com.example.sample_db_adapter;

import java.math.BigDecimal;

import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;

public class BookMaintainActivity extends Activity {
    private EditText tb_name;
    private EditText tb_cat;
    private EditText tb_author;
    private EditText tb_price;
    
    private Button btn_save;
    private Button btn_cancel;
    
    private Book myBook;
    
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.book_maintain);
        
        Bundle extras = getIntent().getExtras();        
        myBook = new Book(extras != null ? extras.getLong("myBookID") : 0);
        
        findViews();
        setListener();
        setValues();        
    }
    
    private void findViews() {
        tb_name = (EditText) findViewById(R.id.tb_name);
        tb_cat = (EditText) findViewById(R.id.tb_cat);
        tb_author = (EditText) findViewById(R.id.tb_author);
        tb_price = (EditText) findViewById(R.id.tb_price);

        btn_save = (Button) findViewById(R.id.btn_save);
        btn_cancel = (Button) findViewById(R.id.btn_cancel);
    }

    private void setValues() {
        tb_name.setText(myBook.name);
        tb_cat.setText(myBook.cat);
        tb_author.setText(myBook.author);
        tb_price.setText(myBook.price.toString());
    }    
    
    private void setListener() {
        // Listen for button clicks
        btn_save.setOnClickListener(btnSaveOnClickListener);
        btn_cancel.setOnClickListener(btnCancelOnClickListener);
    }

    private Button.OnClickListener btnSaveOnClickListener = new Button.OnClickListener(){
        public void onClick(View v) {
            // TODO Auto-generated method stub
            updateBookGUI();
            
            if (myBook.key_id == 0){ // add new book
                MainActivity.myDBAdapter.BOOK_M_create(
                    myBook.name, myBook.cat, myBook.author, myBook.price.doubleValue(), 
                    myBook.created_by, myBook.created_on, myBook.changed_by, myBook.changed_on);
            }
            else{ // update old book
                MainActivity.myDBAdapter.BOOK_M_update(
                    myBook.key_id, myBook.name, myBook.cat, myBook.author, myBook.price.doubleValue(), 
                    myBook.created_by, myBook.created_on, myBook.changed_by, myBook.changed_on);
            }
            finish();
        }
    };
    
    private Button.OnClickListener btnCancelOnClickListener = new Button.OnClickListener(){
        public void onClick(View v) {
            // TODO Auto-generated method stub
            finish();
        }
    };    
    
    /**
     * Update the current class 'myBook' from GUI (input of editbox)
     */
    private void updateBookGUI(){
        myBook.name = tb_name.getText().toString();
        myBook.cat = tb_cat.getText().toString();
        myBook.author = tb_author.getText().toString();
        myBook.price = new BigDecimal(tb_price.getText().toString());
        myBook.changed_by = MainActivity.user;
        myBook.changed_on = java.lang.System.currentTimeMillis();
        if (myBook.key_id == 0){
            myBook.created_by = MainActivity.user;
            myBook.created_on = java.lang.System.currentTimeMillis();
        }
    }
}
Function updateBookGUI is to put all data from GUI screen back to our own class myBook. Then we will use it to deal with the DB.
finish() is used to 'Finish' the current activity and go back to the former activity.

book_maintain.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

    <TableLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content" >

        <TableRow
            android:id="@+id/tableRow1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" >

            <TextView
                android:id="@+id/textView1"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_weight="0.4"
                android:text="Name" />


            <EditText
                android:id="@+id/tb_name"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_weight="0.6"
                android:ems="10"
                android:inputType="textCapSentences" >

                <requestFocus />
            </EditText>

        </TableRow>

        <TableRow
            android:id="@+id/tableRow2"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" >

            <TextView
                android:id="@+id/textView2"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_weight="0.4"
                android:text="Category" />


            <EditText
                android:id="@+id/tb_cat"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_weight="0.6"
                android:ems="10"
                android:inputType="textCapSentences" >

   </EditText>
        </TableRow>

        <TableRow
            android:id="@+id/tableRow3"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" >

            <TextView
                android:id="@+id/textView3"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_weight="0.4"
                android:text="Author" />


            <EditText
                android:id="@+id/tb_author"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_weight="0.6"
                android:ems="10"
                android:inputType="textPersonName" >

   </EditText>
        </TableRow>

        <TableRow
            android:id="@+id/tableRow4"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" >
            <TextView
                android:id="@+id/textView4"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_weight="0.4"
                android:text="Price" />


            <EditText
                android:id="@+id/tb_price"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_weight="0.6"
                android:ems="10"
                android:inputType="numberDecimal" >

   </EditText>            
        </TableRow>
    </TableLayout>


    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content" >


        <Button
            android:id="@+id/btn_save"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="0.5"
            android:text="Save" />


        <Button
            android:id="@+id/btn_cancel"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="0.5"
            android:text="Cancel" />

    </LinearLayout>
    
</LinearLayout>    

AndroidManifest.xml
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.sample_db_adapter"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="8"
        android:targetSdkVersion="15" />

    <application
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name=".MainActivity"
            android:label="@string/title_activity_main" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <activity android:name="BookMaintainActivity" />
    </application>

</manifest>
Remember to add <activity android:name="BookMaintainActivity" /> for the new activity you created

Result:

After clicking the button "Ini List", our pre-defined list appears

Click "Add Book", it direct us to the page of BookMaintainActivity

Input the information, click "Save", we go back to MainActivity. Now you can see there is one new book called "Test" (Just added by us)

Click on the book "Test", it direct us to edit the information of the book.

Change the name of the book from "Test" to "Test222", click "Save". Note that the book list has been updated

Click "Clear List", all data is cleared. The book list disappeared

沒有留言:

張貼留言