Content Providers trong Android


Content providers là thành phần cung cấp dữ liệu từ một ứng dụng đến một ứng dụng khác dựa trên các Request. Mỗi Request được xử lý bằng các phương thức của class ContentResolver. Một Content Provider có thể sử dụng các cách lưu trữ dữ liệu khác nhau, dữ liệu có thể được lưu trữ trong databases, file, thậm chí thông qua Network.

Mỗi ứng dụng Android chạy trong các tiến trình riêng của chính mình và nó có các điều khoản riêng của nó, điều mà giữ dữ liệu của ứng dụng ẩn với các ứng dụng khác. Tuy nhiên, thỉnh thoảng nó được yêu cầu chia sẻ dữ liệu đến các ứng dụng khác. Sử dụng Content Provider trong việc này rất hữu ích.

Content Providers cho phép bạn tập trung dữ liệu ở một nơi và các ứng dụng khác nhau sẽ truy xuất vào nó khi cần thiết. Content Provider hoạt động rất giống với một cơ sở dữ liệu, và bạn có thể truy vấn nó, chỉnh sửa nội dung, cũng như là thêm xóa các nội dung sử dụng các phương thức: insert(), update(), delete(), query(). Trong nhiều trường hợp dữ liệu được lưu trữ trong SQLite.

Content Provider sẽ kế thừa class ContentProvider và phải implement một chuẩn tập các APIs để cho phép các ứng dụng khác thực hiện xử lý các giao dịch.

public class MyContentProvider extends  ContentProvider {

}

Content URIs

Để truy vấn một Content Provider, bạn chỉ định chuỗi truy vấn theo hình thức của một URI  theo định dạng sau:

<prefix>://<authority>/<data_type>/<id>
  • <prefix>: Nó luôn được thiết lập là content://
  • <authority>: Chỉ định tên cụ thể của Content Provider (VD: contacts, browser,…). Đối với một số Content Provider khác bạn sẽ phải chỉ định tên đầy đủ (VD: com.laptrinhtuduy.statusprovider).
  • <data_type>: Chỉ rõ kiểu dữ liệu (VD: Để lấy tất cả các liên hệ trong Contacts Content Provider thì kiểu dữ liệu là people và URI sẽ là: content://contacts/people.
  • <id>: Chỉ định rõ một record (VD: Nếu bạn muốn lấy địa chỉ liên lạc thứ 5 trong Contacts Content Provider thì URI sẽ là: content://contacts/people/5.

Tạo Content Provider

Một số bước đơn giản để tạo Content Provider riêng của bạn:

  1. Đầu tiên cần tạo một class Conten Provider kế thừa class ContentProviderbase.
  2. Bạn cần định nghĩa địa chỉ URI cho Content Provider của bạn, nó sẽ được dùng để truy xuất nội dung.
  3. Bạn cần tạo một CSDL của riêng bạn để lưu các Content. Thông thường, Android sử dụng CSDL SQLite, cần phải Override phương thức onCreate() nó sẽ sử dụng phương thức SQLite Open Helper để tạo hoặc mở CSDL của provider. Khi ứng dụng của bạn khởi chạy, phương thức onCreate() sẽ xử lý các Content Providers của nó.
  4. Tiếp theo cần phải implement các truy vấn của Content Provider để xử lý các yêu cầu khác nhau về dữ liệu.
  5. Cuối cùng, đăng ký Content Provider của bạn bằng cách sử dụng nhãn <provider>.

Các phương thức cần được Override trong lớp Content Provider:

  • onCreate(): Phương thức này được gọi khi Provider được bắt đầu.
  • query(): Phương thức nhận yêu cầu từ Client. Kết quả được trả về như một đối tượng Cursor.
  • insert(): Phương thức chèn một dòng dữ liệu mới vào Content Provider.
  • delete(): Phương thức xóa một dòng dữ liệu đã tồn tại.
  • update(): Phương thức cập nhật một dòng dữ liệu nào đó đã tồn tại.
  • getType(): Phương thức trả về kiểu MIME của dữ liệu tại các URI.

Ví dụ: Ví dụ này sẽ giúp cho bạn biết cách tạo một Content Provider.

Tạo project với tên: ContentProviderExample

File: res/layout/activity_main.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical" >

    <TextView
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="Name"/>

    <EditText
        android:id="@+id/txtName"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content" />

    <TextView
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="Grade"/>

    <EditText
        android:id="@+id/txtGrade"
        android:layout_height="wrap_content"
        android:layout_width="fill_parent"/>

    <Button
        android:text="Add Name"
        android:id="@+id/btnAdd"
        android:layout_height="wrap_content"
        android:layout_width="fill_parent"
        android:onClick="onClickAddName"/>

    <Button
        android:text="Retrieve Students"
        android:id="@+id/btnRetrieve"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:onClick="onClickRetrieveStudents" />

</LinearLayout>

File: src/com.laptrinhtuduy.contentproviderexample/StudentsProvider.java

package com.laptrinhtuduy.contentproviderexample;

import java.sql.SQLData;
import java.util.HashMap;

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.SQLiteDatabase.CursorFactory;
import android.database.sqlite.SQLiteOpenHelper;
import android.database.sqlite.SQLiteQueryBuilder;
import android.net.Uri;
import android.text.TextUtils;

public class StudentsProvider extends ContentProvider{

	static final String PROVIDER_NAME = "com.laptrinhtuduy.provider.College";
	static final String URI = "content://" + PROVIDER_NAME + "/students";
	static final Uri CONTENT_URI = Uri.parse(URI);

	static final String _ID = "_id";
	static final String NAME = "name";
	static final String GRADE = "grade";

	private static HashMap<String, String> STUDENTS_PROJECTION_MAP;

	static final int STUDENTS = 1;
	static final int STUDENTS_ID = 2;

	static final UriMatcher uriMatcher;
	static{
		uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
		uriMatcher.addURI(PROVIDER_NAME, "students", STUDENTS);
		uriMatcher.addURI(PROVIDER_NAME, "students/#", STUDENTS_ID);
	}

	private SQLiteDatabase db;
	static final String DATABASE_NAME = "college";
	static final String STUDENTS_TABLE_NAME = "students";
	static final int DATABASE_VERSION = 1;
	static final String CREATE_DB_TABLE =
			"CREATE TABLE " + STUDENTS_TABLE_NAME +
			" (_id INTEGER PRIMARY KEY AUTOINCREMENT, " +
			"name TEXT NOT NULL, " +
			"grade TEXT NOT NULL);";

	private static class DatabaseHelper extends SQLiteOpenHelper {

		DatabaseHelper(Context context) {
			super(context, DATABASE_NAME, null, DATABASE_VERSION);
		}

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

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

	}

	@Override
	public int delete(Uri uri, String selection, String[] selectionArgs) {
		int count = 0;

		switch (uriMatcher.match(uri)){
		case STUDENTS:
			count = db.delete(STUDENTS_TABLE_NAME, selection, selectionArgs);
			break;
		case STUDENTS_ID:
			count = db.delete(STUDENTS_TABLE_NAME, _ID + "=" + uri.getPathSegments().get(1) +
					(!TextUtils.isEmpty(selection) ? " AND (" +
			        selection + ')': ""), selectionArgs);
			break;
		default:
			throw new IllegalArgumentException("Unknown URI " + uri);
		}
		getContext().getContentResolver().notifyChange(uri, null);
		return count;
	}

	@Override
	public String getType(Uri uri) {
		switch (uriMatcher.match(uri)) {
		case STUDENTS:
			return "vnd.android.cursor.dir/vnd.laptrinhtuduy.students";
		case STUDENTS_ID:
			return "vnd.android.cusor.item/vnd.laptrinhtuduy.students";
		default:
			throw new IllegalArgumentException("Unsupport URIL " + uri);
		}
	}

	@Override
	public Uri insert(Uri uri, ContentValues values) {
		long rowID = db.insert(STUDENTS_TABLE_NAME, "", values);
		if(rowID > 0){
			Uri _uri = ContentUris.withAppendedId(CONTENT_URI, rowID);
			getContext().getContentResolver().notifyChange(_uri, null);
			return _uri;
		}
		throw new SQLException("Failed to add a record into " + uri);
	}

	@Override
	public boolean onCreate() {
		Context context = getContext();
		DatabaseHelper dbHelper = new DatabaseHelper(context);
		db = dbHelper.getWritableDatabase();
		return (db == null) ? false:true;
	}

	@Override
	public Cursor query(Uri uri, String[] projection, String selection,
			String[] selectionArgs, String sortOrder) {
		SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
		qb.setTables(STUDENTS_TABLE_NAME);

		switch (uriMatcher.match(uri)) {
		case STUDENTS:
			qb.setProjectionMap(STUDENTS_PROJECTION_MAP);
			break;
		case STUDENTS_ID:
			qb.appendWhere(_ID + "=" + uri.getPathSegments().get(1) );
			break;
		default:
			throw new IllegalArgumentException("Unknown URI " + uri);
		}

		if(sortOrder == null || sortOrder == ""){
			sortOrder = NAME;
		}

		Cursor c = qb.query(db, projection, selection, selectionArgs, null, null, sortOrder);
		c.setNotificationUri(getContext().getContentResolver(), uri);
		return c;
	}

	@Override
	public int update(Uri uri, ContentValues values, String selection,
			String[] selectionArgs) {
		int count = 0;

		switch (uriMatcher.match(uri)){
		case STUDENTS:
			count = db.update(STUDENTS_TABLE_NAME, values, selection, selectionArgs);
			break;
		case STUDENTS_ID:
			count = db.update(STUDENTS_TABLE_NAME, values, _ID + "=" + uri.getPathSegments().get(1) +
					(!TextUtils.isEmpty(selection) ? " AND (" +
			        selection + ')': ""), selectionArgs);
			break;
		default:
			throw new IllegalArgumentException("Unknown URI " + uri);
		}
		getContext().getContentResolver().notifyChange(uri, null);
		return count;
	}

}

File: AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.laptrinhtuduy.contentproviderexample"
    android:versionCode="1"
    android:versionName="1.0" >

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

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name="com.laptrinhtuduy.contentproviderexample.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>

        <provider android:name="StudentsProvider"
            android:authorities="com.laptrinhtuduy.provider.College">
        </provider>

    </application>

</manifest>

File: src/com.laptrinhtuduy.contentproviderexample/MainActivity.java

package com.laptrinhtuduy.contentproviderexample;

import android.net.Uri;
import android.os.Bundle;
import android.app.Activity;
import android.content.ContentValues;
import android.database.Cursor;
import android.view.Menu;
import android.view.View;
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.activity_main);
	}

	@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;
	}

	public void onClickAddName(View view){
		ContentValues values = new ContentValues();

		values.put(StudentsProvider.NAME, ((EditText) findViewById(R.id.txtName)).getText().toString());
		values.put(StudentsProvider.GRADE, ((EditText) findViewById(R.id.txtGrade)).getText().toString());

		Uri uri = getContentResolver().insert(StudentsProvider.CONTENT_URI, values);

		Toast.makeText(getBaseContext(), uri.toString(), Toast.LENGTH_LONG).show();
	}

	public void onClickRetrieveStudents (View view){
		String URI = "content://com.laptrinhtuduy.provider.College/students";
		Uri students = Uri.parse(URI);
		Cursor c =  managedQuery(students, null, null, null, "name");
		if(c.moveToFirst()){
			do{
				Toast.makeText(this, c.getString(c.getColumnIndex(StudentsProvider._ID)) +
					", " + c.getString(c.getColumnIndex(StudentsProvider.NAME))	+
					", " + c.getString(c.getColumnIndex(StudentsProvider.GRADE)), Toast.LENGTH_LONG).show();
			}while (c.moveToNext());
		}
	}
}

Kết quả:

Khi bạn nhập dữ liệu và nhấn vào Button Add Name dữ liệu sẽ thêm thêm vào Database và xuất hiện thông báo:

Sau đó bạn nhấn vào Button Retrieve Students dữ liệu được lấy ra từ Database và hiển thị lên màn hình:

 

DOWNLOAD: SOURCE CODE

 

 

 

Dựa trên: tutorialspoint

Leave a comment