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:
- Đầu tiên cần tạo một class Conten Provider kế thừa class ContentProviderbase.
- 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.
- 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ó.
- 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.
- 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:
Dựa trên: tutorialspoint