Content Provider + SQLite Database in Android


Hôm nay Mình giới thiệu với các bạn về ContentProvider in Android. Bài trước mình hướng dẫn các bạn dùng SQlite database để lưu trữ data nhưng data này chỉ có thể truy cập trong package tạo ra nó.

Trong bài viết hôm nay mình sẻ hướng dẫn các bạn làm sao để chia sẻ data đến với các package khác nhau. Bằng cách sữ dụng content Provider. Và mình hướng dẫn các bạn tạo ra một Content Provider cho APP của mình.

References Content providerhttp://developer.android.com/reference/android/content/ContentProvider.html

Source code : Download

Note trước khi bước vào :

  • Content Provider (recommended) được đề cử cho việc chia sẻ data thông qua các Packages.
  • Content Provider no tương tự như database của chúng ta, chúng ta có thể query, edit, insert…and Data của chúng ta có thể là XML, Text, SQLite DB, thậm chí thông qua Network
  • Có 1 vài ContentProvider mặc định trong android như : Browser, CallLog, Contacts, MediaStore, Settings…

giải thích 1 số parameter in method managedQuery() khi chúng ta sử dụng trong bài viết:

Projections:

Đây là tham số thứ 2 khi ta truyền vào managedQuery() method . Nó dùng để xác định Column mà chúng ta muốn lấy , default is NULL là để get ALL các column trong  table trong  database.

Example : String[] projection new String[] {“ID”,”NAME”,”ADDRESS”} . Chúng ta get 3 column có tên là id, name, address trong table

Filter :

Filter là đại diện cho tham số thứ 3, 4 trong managedQuery() method. Đây củng chính là mệnh đề Where trong query khi chúng ta thao tác.

Example : Chúng ta sẻ lấy những ai có tên có chữ cái bắt đầu “H”.

thì chúng ta chỉ cần tạo ra String filterName =COLUMN_NAME + ” LIKE  ‘  H%  ‘  “; và gán nó vào trong query.

Cách thứ 2 : Trường hợp chúng ta có thể làm rỏ ràng hơn như sau :

String param3 = COLUMN_NAME + ”   LIKE   ?  “;

String[] param4 = new String[] {  “H%”  } = Thì điều kiện này sẻ gán vào < ?  > Tương tự bạn có thể nhiều ?-?-?  <=> String[] {“1″,”2″,”3”}

Sorting:

đây là tham số thứ 5 trong managedQuery() method. cho phép chúng ta Order by như trong SQL.

Example :

String param5 = COLUMN_NAME + ” DESC ” ; (OR = >ASC).

=============================================================

Ok chúng ta có thể bắt đầu trong việc tạo ra 1 Content Provider cho chính mình.

Bài viết này các bạn chịu khó xem 1 số comment trong code của mình .

Chúng ta có 1 table Person trong database dbTest như sau :

_ID Name ADDRESS
1 Kobee 24/3Y TN GV
2 Jenny 222/22 QT Q.1

 

Step 1 : Chúng ta tạo ra 1 class : PersonsProvider.java (Mình có giải thích trong các comment các bạn có gắng đọc hiểu nó nha)


package com.thaihoanghai.provider;

import android.content.ContentProvider;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.Context;
import android.content.UriMatcher;
import android.database.Cursor;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.database.sqlite.SQLiteQueryBuilder;
import android.net.Uri;
import android.text.TextUtils;
/**
 * Overview about this class. We will create class PersonsProvider extends ContentProvider
 * and override in this class are as follows:
 * 1 - getType()  : Returns the MINE type of the data at the given URI
 * 2 - onCreate() : Called when the provider is started
 * 3 - query()    : Receives a request from client, the result is returned is Cursor object
 * 4 - insert, update, delete : We will use in work in record in content provider. 
 * @author kobee
 *
 */
public class PersonsProvider extends ContentProvider{
	// Define constants within the PersonsProvider class
	public static final String PROVIDER_NAME = "thaihoanghai.wordpress.com";
	public static final Uri CONTENT_URI = Uri.parse("content://" + PROVIDER_NAME + "/persons");

	// These fields are column in database dbTest  
	public static final String _ID = "_id";
	public static final String NAME = "name";
	public static final String ADDRESS = "address";

	// build up a tree of UriMatcher objects ===================================
	// To known details look : http://developer.android.com/reference/android/content/UriMatcher.html
	private static final int PERSONS = 1;
	private static final int PERSON_ID = 2;

	private static final UriMatcher uriMatcher;
	// At here we will have two case : 
	// case 1 : content://thaihoanghai.wordpress.com/persons (get all record)
	// case 2 : content://thaihoanghai.wordpress.com/persons/2 (get record with _ID = 2)
	static{
		uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
		uriMatcher.addURI(PROVIDER_NAME, "persons", PERSONS);
		uriMatcher.addURI(PROVIDER_NAME, "persons/#", PERSON_ID);
	}
	//=========================================================================
	// for database use
	// My Database : dbTest 
	// My Table : Person   : _ID | Name  | Address
	//_____________________:  1  | Kobee | 24/3Y TN GV
	//_____________________:  2  | Jenny | N.12 QT G.1
	private SQLiteDatabase dbTest;
	private static final String DATABASE_NAME = "dbTest";
	private static final String DATABASE_TABLE = "Person";
	private static final int DATABASE_VERSION = 1;
	private static final String DATABASE_CREATE = "create table " + DATABASE_TABLE + 
			"(_id integer primary key autoincrement, " +
			"name text not null, address text not null);";

	// Your content provider uses a SQLite Database to store the persons.
	private static class DatabaseHelper extends SQLiteOpenHelper{
		public DatabaseHelper(Context context) {
			super(context, DATABASE_NAME, null, DATABASE_VERSION);
		}

		@Override
		public void onCreate(SQLiteDatabase db) {
			db.execSQL(DATABASE_CREATE);

		}

		@Override
		public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {			
			db.execSQL("DROP TABLE IF EXISTS " + DATABASE_TABLE);
			onCreate(db);
		}
	}

	/**
	 * getType() method uniquely describe the data type for your content provider
	 * Using the UriMatcher object.
	 * Note : 1-vnd.android.cursor.dir/vnd.thaihoanghai.persons  : to get 0->n record
	 *        2-vnd.android.cursor.item/vnd.thaihoanghai.persons : get only one record
	 */
	@Override
	public String getType(Uri uri) {
		switch (uriMatcher.match(uri)) {
		// get all book
		case PERSONS:
			return "vnd.android.cursor.dir/vnd.thaihoanghai.persons";
			// get a particular book
		case PERSON_ID:
			return "vnd.android.cursor.item/vnd.thaihoanghai.persons";
		default:
			throw new IllegalArgumentException("Unsupported URI " + uri);
		}

	}
	/**
	 * onCreate() method to open a connection to the database when the content 
	 * providers is started
	 */
	@Override
	public boolean onCreate() {
		Context context = getContext();
		DatabaseHelper dbHelper = new DatabaseHelper(context);
		dbTest = dbHelper.getWritableDatabase();
		return (dbTest == null) ? false : true;
	}

	/**
	 * This method allow clients to query for persons
	 */
	@Override
	public Cursor query(Uri uri, String[] projection, String selection, 
			String[] selectionArgs, String sortOrder) {
		SQLiteQueryBuilder sqlBuilder = new SQLiteQueryBuilder();
		sqlBuilder.setTables(DATABASE_TABLE);
		// get a particular book
		if(uriMatcher.match(uri) == PERSON_ID)		
			sqlBuilder.appendWhere(_ID + " = " + uri.getPathSegments().get(1));
		// check sort column Name is default
		if(sortOrder == null || sortOrder == "")
			sortOrder = NAME;
		Cursor c = sqlBuilder.query(dbTest, projection, selection, selectionArgs, null, null, sortOrder);
		// register to watch a content URI for changes
		c.setNotificationUri(getContext().getContentResolver(), uri);
		return c;
	}

	/**
	 * Method allow a new person inserted into the content provider
	 * Once the record is inserted successfully call the notifyChange() 
	 * method of the ContentResolver.
	 */
	@Override
	public Uri insert(Uri uri, ContentValues values) {
		// add a new book
		long rowID = dbTest.insert(DATABASE_TABLE, "", values);
		// if added successfully
		if(rowID > 0){
			Uri _uri = ContentUris.withAppendedId(CONTENT_URI, rowID);
			getContext().getContentResolver().notifyChange(_uri, null);
			return _uri;
		}
		throw new SQLException("Faild to insert row into " + uri);
	}

	/**
	 * similar with insert method
	 */
	@Override
	public int delete(Uri uri, String selection, String[] selectionArgs) {
		int count = 0;
		switch (uriMatcher.match(uri)) {
		case PERSONS:
			count = dbTest.delete(DATABASE_TABLE, selection, selectionArgs);
			break;
		case PERSON_ID:
			String id = uri.getPathSegments().get(1);
			count = dbTest.delete(DATABASE_TABLE, _ID + " = " + id + (!TextUtils.isEmpty(selection) ? " AND (" + selection + ')' : ""), selectionArgs);

		default: throw new IllegalArgumentException("Unknown URI " + uri);
		}
		getContext().getContentResolver().notifyChange(uri, null);
		return count;
	}

	/**
	 * similar with update method
	 */
	@Override
	public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
		int count = 0;
		switch (uriMatcher.match(uri)) {
		case PERSONS:
			count = dbTest.update(DATABASE_TABLE, values, selection, selectionArgs);
			break;
		case PERSON_ID:
			count = dbTest.update(DATABASE_TABLE, values, _ID + " = " + uri.getPathSegments().get(1) + (!TextUtils.isEmpty(selection) ? " AND (" + selection + ')' : ""), selectionArgs);
		default:
			throw new IllegalArgumentException("Unknown URI " + uri);
		}
		getContext().getContentResolver().notifyChange(uri, null);
		return count;
	}

}

Các bạn chú ý khai bào Provider in file manifest.xml của chúng ta

</pre>
<application
 android:allowBackup="true"
 android:icon="@drawable/ic_launcher"
 android:label="@string/app_name"
 android:theme="@style/AppTheme" >
 <activity
 android:name="com.thaihoanghai.provider.MainActivity"
 android:label="@string/app_name" >
 <intent-filter>
 <action android:name="android.intent.action.MAIN" />

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

<strong><provider</strong>
<strong> android:name="PersonsProvider"</strong>
<strong> android:authorities="thaihoanghai.wordpress.com" /></strong>
 </application>
<pre>

========================================================================
Chúng ta có thể test chương trình :
Layout main.xml của chúng ta :

</pre>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
 xmlns:tools="http://schemas.android.com/tools"
 android:id="@+id/LinearLayout1"
 android:layout_width="match_parent"
 android:layout_height="match_parent"
 android:orientation="vertical"
 tools:context=".MainActivity" >

<TextView
 android:id="@+id/textView1"
 android:layout_width="wrap_content"
 android:layout_height="wrap_content"
 android:text="Name"
 android:textAppearance="?android:attr/textAppearanceMedium" />

<EditText
 android:id="@+id/txtName"
 android:layout_width="match_parent"
 android:layout_height="wrap_content"
 android:ems="10" >

<requestFocus />
 </EditText>

<TextView
 android:id="@+id/textView2"
 android:layout_width="wrap_content"
 android:layout_height="wrap_content"
 android:text="Address"
 android:textAppearance="?android:attr/textAppearanceMedium" />

<EditText
 android:id="@+id/txtAddress"
 android:layout_width="match_parent"
 android:layout_height="wrap_content"
 android:ems="10"
 android:inputType="textMultiLine" />

<Button
 android:id="@+id/btnAdd"
 android:layout_width="match_parent"
 android:layout_height="wrap_content"
 android:text="Add Person" />

<Button
 android:id="@+id/btnRetrieve"
 android:layout_width="match_parent"
 android:layout_height="wrap_content"
 android:text="Retieve Persons" />

</LinearLayout>
<pre>

Tiếp theo là class MainActivity.java

package com.thaihoanghai.provider;

import android.app.Activity;
import android.content.ContentValues;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.util.Log;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;

public class MainActivity extends Activity {

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);

		Button btnAdd = (Button) findViewById(R.id.btnAdd);
		btnAdd.setOnClickListener(new OnClickListener() {

			@Override
			public void onClick(View arg0) {
				ContentValues values = new ContentValues();
				values.put(PersonsProvider.NAME, ((EditText)
						findViewById(R.id.txtName)).getText().toString());
				values.put(PersonsProvider.ADDRESS,((EditText)
						findViewById(R.id.txtAddress)).getText().toString());

				Uri uri = getContentResolver().insert(PersonsProvider.CONTENT_URI, values);
				Toast.makeText(getBaseContext(), uri.toString(), Toast.LENGTH_LONG).show();
			}
		});

		Button btnRetrieve = (Button) findViewById(R.id.btnRetrieve);
		btnRetrieve.setOnClickListener(new OnClickListener() {

			@SuppressWarnings("deprecation")
			@Override
			public void onClick(View v) {			
				Uri allContact = Uri.parse("content://thaihoanghai.wordpress.com/persons");
				Cursor c = managedQuery(allContact, null, null, null, "name desc");
				if(c.moveToFirst()){
					do {
						Log.v("MY_TAG", c.getString(c.getColumnIndex(PersonsProvider._ID))+ " - " + c.getString(c.getColumnIndex(PersonsProvider.NAME))+ " - " + c.getString(c.getColumnIndex(PersonsProvider.ADDRESS)));
					} while (c.moveToNext());
				}
			}
		});
	}

	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		// Inflate the menu; this adds items to the action bar if it is present.
		getMenuInflater().inflate(R.menu.main, menu);
		return true;
	}

}

khi Add person vào trong Content Provider các bạn có thể thấy :
d1

Khi nhấn Button Retrieve Contacts chúng ta sẻ get ALL person in content provider.
d1

Làm sao để có thể xem lại Database của chúng ta :
các bạn xem lại https://thaihoanghai.wordpress.com/2013/06/09/1598/ để dùng tool xem dbTest in
d1
Chúc các bạn thành công

2 Responses to “Content Provider + SQLite Database in Android”

  1. tam nguyen Says:

    chào bạn , tôi thấy bạn có rất nhiều bài viết về android , tôi muốn hỏi, Tôi đang sử dụng contentprovider để quản lý database , vậy tôi có thể dung đồng thời copy file database đc không ., copy từ filer assets ấy

  2. kobee Says:

    Mình không hiểu rỏ cây hỏi của bạn cho lắm….
    Nếu bạn muốn copy sqlite file từ asset folder đến database folder. đây là cách đơn giản nhất.
    InputStream in = getApplicationContext().getAssets().open(“path/file.sqlite”)
    OutputStream out = new FileOutputStream(“data/data/../db/..”);

    byte[] buffer = new byte[1024];
    int length;
    while ((length = in.read(buf)) > 0) {
    out.write(buf, 0, len);
    }


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: