Content Provider ها
بسم الله الرحمن الرحیم
Content Provider ها
فصل هفتم
در پایان این فصل با موارد زیر آشنا می شوید:
- Content Provider ها چه هستند؟
- چطور Content Provider ها در اندروید استفاده کنید.
بسم الله الرحمن الرحیم
Content Provider ها
فصل هفتم
در پایان این فصل با موارد زیر آشنا می شوید:
- Content Provider ها چه هستند؟
- چطور Content Provider ها در اندروید استفاده کنید.
- چه طور Content Provider خودتان را ایجاد و استفاده کنید
در فصل قبل شما ی با انواع روش های ذخیره سازی داده های ماندگاری آشنا شدده اید از قبیل SharedPreferences ، فایل ها و SQLite . زمانی که از دیتابیس استفاده می کردید اشترا ک داده های چالش بزرگی بود زیر دیتابیس فقط در برنامه که آن را ایجاد کردید قابل دسترسی بود.
در این قسمت شما راهی را برای اشتراک داده بین کاربران از طریق Content Provider ها یاد می گیرید. شما یاد می گیرید چگونه از Content Provider ها که از قبل ساخته شده است (Built-in) استفاده کنید. همچنین از contentProvider خودتان را ایجاد کنید.
اشتراک داده ها در اندروید
در اندروید از Content Provider ها برای اشتراک داده ها بین برنامه های مختلف استفاده می شود. Content Provider ها را همانند یک منبع داده (Data Store) تصور کنید که داده های ذخیره شد در ان به برنامه که از آن استفاده می کند وابسته نمی باشد. و این مهم است که چگونه برنامه ها می تواند با استفاده از یک رابط برنامه سازگار به ان دسترسی داشته باشند.content Provider ها بسیار شبیه دیتابیس عمل می کنند شما می توانید از Query بگیرید آن را ویرایشو حذف- و به روز رسانی کنید. بر خلاف دیتابیس ها Content Provider ها را های زیادی برای ذخیر ه داده هایشان دارند مانند ذخیره در فایل ها د ر دیتابیس و حتا ذخیره در شبکه.
اندروید(Android ships) Content Provider ها مفیدی را فراهم می کند از جمله موارد زیر :
- Browser- ذخیره داده ه از قبیل bookmark ها history ها و مواردی از این قبیل
- CallLog- ذخیره داه ها از قبیل تماس ها از دست رفته- جزئیات تماس و موارد از این قبیل
- Contacts- ذخیره contact ها
- MediaStore- ذخیره دادهای رسانه ای از قبیل صدا - تصویر – ویدئو
- Settings- تنظیمات دستگاه و preferences ذخیره می کنید
در کنار بسیاری از content Provider ها پیش ساخته شما می توانید Content Provider خوتان را ایجاد کنید
برای query گرفتن از Content Provider ها شما می توان دستورات queryخود را در یک URI, تعیین کنید.. قالبب URI به صورت زیر می باشد
<standard_prefix>://<authority>/<data_path>/<id>
انواع قسمت های URI به صورت زیر مباشد
- standard prefi x برای content Provider ها که همیشه content:// می باشد
- authority- که نام content Provider زا تعیین می کنید به عنوان مثال contacts برای content Provider Contacts که به از قبل وجود دارد می باشد. برای content Provider های که دیگران ایجاد می کنند شما باید نام به صورت fully qualifi ed به صورت کامل وارد کنید مانند com.wrox.provider or net.learn2develop.provider
- data path-نوع درخواست را تعیین می کند به عنوان مثال اگر شما تمام contact های Contact Content Provider را می خواهید باید people وارد کنید و uri به صورت content://contacts/people.می باشد
- id- رکورد مورد نظر را تعیین می کند به عنوان مثال اگر شما contact شماره 2 را می خواهید به صورت زیر وارد می کنیدcontent:// contacts/people/2
در جدول زیر مثال های مشاهده می کنید
query |
توضیحات |
content://media/internal/images |
لیست تمام فایل ها عکس در حافطه داخلی را بر می گرداند |
content://media/external/images |
لیست تمام فایل ها عکس در حافطه خارجی(SDcard) را بر می گرداند |
content://call_log/calls |
لیست تمام ثبت شده Call Log در بر می گرداند |
content://browser/bookmarks |
لیست تمام bookmark در Browser را بر می گرداند |
استفاده از Content Provider ها
بهترین را ه برای فهمیدن content Provider هلا استفاده از به صورت عملی می باشد. که در زیر آن را با یک مثال شرح می دهیم.
پروژه جدیدی به نام Provider. ایجاد کنید
فایل main.xml به صورت زیر تغییر دهید
<?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" >
<ListView
android:id="@+id/android:list"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:stackFromBottom="false"
android:transcriptMode="normal" />
<TextView
android:id="@+id/contactName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textStyle="bold" />
<TextView
android:id="@+id/contactID"
android:layout_width="fill_parent"
android:layout_height="wrap_content" />
</LinearLayout>
فایل ProviderActivity.java به صورت زیر تغییر دهید
package com.MehrdadJavidi.Provider;
import android.app.ListActivity;
import android.content.CursorLoader;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.provider.ContactsContract;
import android.widget.CursorAdapter;
import android.widget.SimpleCursorAdapter;
public class ProviderActivity extends ListActivity {
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Uri allContacts = Uri.parse("content://contacts/people");
Cursor c;
if (android.os.Build.VERSION.SDK_INT < 11) {
// ---before Honeycomb---
c = managedQuery(allContacts, null, null, null, null);
} else {
// ---Honeycomb and later---
CursorLoader cursorLoader = new CursorLoader(this, allContacts,
null, null, null, null);
c = cursorLoader.loadInBackground();
}
String[] columns = new String[] {
ContactsContract.Contacts.DISPLAY_NAME,
ContactsContract.Contacts._ID };
int[] views = new int[] { R.id.contactName, R.id.contactID };
SimpleCursorAdapter adapter;
if (android.os.Build.VERSION.SDK_INT < 11) {
// ---before Honeycomb---
adapter = new SimpleCursorAdapter(this, R.layout.activity_main, c, columns,
views);
} else {
// ---Honeycomb and later---
adapter = new SimpleCursorAdapter(this, R.layout.activity_main, c, columns,
views, CursorAdapter.FLAG_REGISTER_CONTENT_OBSERVER);
}
this.setListAdapter(adapter);
}
}
دستور زیر را در فایل AndroidManifest.xml وارد کنید
<?xml version=“1.0“ encoding=“utf-8“?>
<manifest xmlns:android=“http://schemas.android.com/apk/res/android“
package=”net.learn2develop.Provider”
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.MehrdadJavidi.usingintent"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk android:minSdkVersion="14" />
<uses-permission android:name="android.permission.READ_CONTACTS" />
<application
android:icon="@drawable/ic_launcher"
android:label="@string/app_name" >
<activity
android:name=".ProviderActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
AVD را اجرا کنید و چند contact, اضافه کنید برای این کار برنامه Phone application اجرا کنید
سپس دکمه منو را بزنید و سپس New contact را انتخاب کنید و اطلاعت افراد از قبیل name, phone number, and e-mail address وارد نمایید
برنامه را اجرا کنید شما contact های که ایجاد کردید را مشاهده می کنید
توضیحات
در اینجا شما تمام Contact های ذخیره شده در Contacts application را باز یابی و سپس آن ها را در listView نمایش دادید.
اول شما URI دسترسی به Contact ها را تعیین کردید
Uri allContacts = Uri.parse(“content://contacts/people”);
قدم بعدی شما نسخه دستگاهی که برنامه در آن در حال اجرا را هست را تعیین کردید.
Cursor c;
if (android.os.Build.VERSION.SDK_INT < 11) {
// ---before Honeycomb---
c = managedQuery(allContacts, null, null, null, null);
} else {
// ---Honeycomb and later---
CursorLoader cursorLoader = new CursorLoader(this, allContacts,
null, null, null, null);
c = cursorLoader.loadInBackground();
}
اگر برنامه در دستگاهی که قبل از Honeycomb استفاده می کند (مقدار android.os.Build.VERSION .SDK_INT کنتر از 11 باشد) شما از متد managedQuery() مربوط به Activity استفاده می کنید که cursor. را دریافت و مدیریت می کنید.
دستور
c = managedQuery(allContacts, null, null, null, null);
با دستور زیر برابر است
CursorLoader cursorLoader = new CursorLoader(this, allContacts,
null, null, null, null);
c = cursorLoader.loadInBackground();
متد getContentResolver() یک شی از ContentResolver بر می گرداند , و به شما کم می کند تا URI را با content Provider مناسب را فراهم آوریم.
با این حال اغاز اندروید های با API level 11 , (Honeycomb و جدیدتر ) ,متد managedQuery() دیگر استفاده نمی شود (هر چند که هنوز در دسترس و پیشنهاد می شود که استفاده نشود)
برای اندروید های با Api Level 11و بالاتر از کلاس CursorLoader استفاده کنید
CursorLoader cursorLoader = new CursorLoader(
this,
allContacts,
null,
null,
null ,
null);
c = cursorLoader.loadInBackground();
کلاس CursorLoader تنها با اندروید نسخه API level 11 و بالا تر در دسترس می باشد query مر بوط به cursor را در به یک Thraed در پس زمینه اجرا می کند .و از این که Ui برنامه به حالت بلاک (هنگ) برود و شی SimpleCursorAdapter عملیات map کردن cursor به TextViews یا ImageViews) را در فایل Xml (main.xml) انجام میدهید
String[] columns = new String[] {
ContactsContract.Contacts.DISPLAY_NAME,
ContactsContract.Contacts._ID };
int[] views = new int[] { R.id.contactName, R.id.contactID };
SimpleCursorAdapter adapter;
if (android.os.Build.VERSION.SDK_INT < 11) {
// ---before Honeycomb---
adapter = new SimpleCursorAdapter(this, R.layout.activity_main, c, columns,
views);
} else {
// ---Honeycomb and later---
adapter = new SimpleCursorAdapter(this, R.layout.activity_main, c, columns,
views, CursorAdapter.FLAG_REGISTER_CONTENT_OBSERVER);
}
this.setListAdapter(adapter);
شبیه متد managedQuery() ,یکی از سازند ه های کلاس SimpleCursorAdapter می تواند مقدار دهی کنید برای Honeycomb و دستگا های جدید تر شما باید یک سازند اضافی را برای کلاس SimpleCursorAdapter مقدار دهی کنید
adapter = new SimpleCursorAdapter(this, R.layout.activity_main, c, columns,
views, CursorAdapter.FLAG_REGISTER_CONTENT_OBSERVER);
نکته مهم این است که شما باید permesion با نام READ_ CONTACTS برای دسترسی به Contact ها در فایل AndroidManifest.xml بدهید
دستورات query ثابت از پیش تعریف شده
در کنار دستورات Query همراه URI, شما می توانید Query های ثابت که از قبل تعریف شده است استفاده کنید به عنوان مثال شما می توانید به جای URI زیر
Uri allContacts = Uri.parse(“content://contacts/people”);
شما می توانید از دستور زیر استفاده کنید
Uri allContacts = ContactsContract.Contacts.CONTENT_URI;
در زیر مثال های از Query های از پیش تعریف شده است زیر را مشاهده می کنید
- Browser.BOOKMARKS_URI
- Browser.SEARCHES_URI
- CallLog.CONTENT_URI
- MediaStore.Images.Media.INTERNAL_CONTENT_URI
- MediaStore.Images.Media.EXTERNAL_CONTENT_URI
- Settings.CONTENT_URI
اگر شما می خواهید اولین Contact بر گردانید شما ID را تعیین می کنید مانند زیر
Uri allContacts = Uri.parse(“content://contacts/people/1”);
شما به می توانید از ثابت های تعریف شده همراه با متدwithAppendedId() در کلاسContentUris استفاده کنید مانند زیر
import android.content.ContentUris;
...
Uri allContacts = ContentUris.withAppendedId(
ContactsContract.Contacts.CONTENT_URI, 1);
در کنار نمایش داده داده های به ListView شما می توانید نتایج شی Cursor را در خروجی مانند زیر چاپ کنید
package com.MehrdadJavidi.Provider;
import android.app.ListActivity;
import android.content.CursorLoader;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.provider.ContactsContract;
import android.widget.CursorAdapter;
import android.widget.SimpleCursorAdapter;
import android.util.Log;
public class ProviderActivity extends ListActivity {
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Uri allContacts = ContactsContract.Contacts.CONTENT_URI;
...
...
if (android.os.Build.VERSION.SDK_INT <11) {
//---before Honeycomb---
adapter = new SimpleCursorAdapter(
this, R.layout.main, c, columns, views);
} else {
//---Honeycomb and later---
adapter = new SimpleCursorAdapter(
this, R.layout.main, c, columns, views,
CursorAdapter.FLAG_REGISTER_CONTENT_OBSERVER);
}
this.setListAdapter(adapter);
PrintContacts(c);
}
private void PrintContacts(Cursor c)
{
if (c.moveToFirst()) {
do{
String contactID = c.getString(c.getColumnIndex(
ContactsContract.Contacts._ID));
String contactDisplayName =
c.getString(c.getColumnIndex(
ContactsContract.Contacts.DISPLAY_NAME));
Log.v("Content Providers", contactID + ", " +
contactDisplayName);
} while (c.moveToNext());
}
}
}
متدPrintContacts( موارد زیر را در پنجرهLogCat چاپ می کند
12-13 08:32:50.471: V/Content Providers(12346): 1, Wei-Meng Lee
12-13 08:32:50.471: V/Content Providers(12346): 2, Linda Chen
12-13 08:32:50.471: V/Content Providers(12346): 3, Joanna Yip
ID و Name هر Contact ی که در برنامه Contacts Application ذخیره شده را چاپ می کند در اینجا شما با ontactsContract.Contacts._ID بهID و با ContactsContract.Contacts.DISPLAY_NAME به Nameآن دسترسی داشته اید اگر شما می خواهید لیست شما هر تلفن های را دسترسی داشته باشید شما باید یک query دیگر ار بنویسید زیرا شماره تلفن های در جدول دیگر ذخیره شده است.
private void PrintContacts(Cursor c)
{
if (c.moveToFirst()) {
do{
String contactID = c.getString(c.getColumnIndex(
ContactsContract.Contacts._ID));
String contactDisplayName =
c.getString(c.getColumnIndex(
ContactsContract.Contacts.DISPLAY_NAME));
Log.v("Content Providers", contactID + ", " +
contactDisplayName);
//---get phone number---
int hasPhone =
c.getInt(c.getColumnIndex(
ContactsContract.Contacts.HAS_PHONE_NUMBER));
if (hasPhone == 1) {
Cursor phoneCursor =
getContentResolver().query(
ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null,
ContactsContract.CommonDataKinds.Phone.CONTACT_ID + " = " +
contactID, null, null);
while (phoneCursor.moveToNext()) {
Log.v("Content Providers",
phoneCursor.getString(
phoneCursor.getColumnIndex(
ContactsContract.CommonDataKinds.Phone.NUMBER)));
}
phoneCursor.close();
}
} while (c.moveToNext());
}
برای دسترسی به شماره تلفن یک contact شما باید Query دیگری که URI ان در ContactsContract.CommonDataKinds.Phone.CONTENT_URI ذخیره شده به کا رگیرید |
در کد قبل شما با فیلد ContactsContract.Contacts.HAS_PHONE_NUMBERچک کردید که آیا Contact شماره تلفن دارد یا خیر اگر contact حداقل یک شماره تلفن داشت سپس شما query مورد نظر را بر اساس ID ان contact انجام دادید
زمانی که شماره تلفن (ها) را باز یابی کردیدمی توانید آن ها را چاپ کنید که نتیجه مانند زیر می شود.
12-13 08:59:31.881: V/Content Providers(13351): 1, Wei-Meng Lee
12-13 08:59:32.311: V/Content Providers(13351): +651234567
12-13 08:59:32.321: V/Content Providers(13351): 2, Linda Chen
12-13 08:59:32.511: V/Content Providers(13351): +1 876-543-21
12-13 08:59:32.545: V/Content Providers(13351): 3, Joanna Yip
12-13 08:59:32.641: V/Content Providers(13351): +239 846 5522
Projections
دومین پارامتر متدmanagedQuery() ( سومین پارامتر برای کلاس CursorLoader) تعیین می کند که چند ستون از جدول همراه با این query بر گردانده شود. این پارامتر در مثال های قبلی null: داده ایم
Cursor c;
if (android.os.Build.VERSION.SDK_INT <11) {
//---before Honeycomb---
c = managedQuery(allContacts, null, null, null, null);
} else {
//---Honeycomb and later---
CursorLoader cursorLoader = new CursorLoader(
this,
allContacts,
null,
null,
null ,
null);
c = cursorLoader.loadInBackground();
}
شما می توانید دقیقا مشخص کنید که چه ستون های می خواهید بر گردانده شود.
String[] projection = new String[]
{ContactsContract.Contacts._ID,
ContactsContract.Contacts.DISPLAY_NAME,
ContactsContract.Contacts.HAS_PHONE_NUMBER};
Cursor c;
if (android.os.Build.VERSION.SDK_INT <11) {
//---before Honeycomb---
c = managedQuery(allContacts, projection, null, null, null);
} else {
//---Honeycomb and later---
CursorLoader cursorLoader = new CursorLoader(
this,
allContacts,
projection,
null,
null ,
null);
c = cursorLoader.loadInBackground();
}
در مثال بالا شما _ID, DISPLAY_NAME, and HAS_PHONE_NUMBER تعیین کرده اید
Filtering
چهارمین پارامتر در متد managedQuery() ( پنجمین پارامتر در کلاس CursorLoader) شما می توانید دستورWHERE مربوط به Sql استفاده کنید که نتایج را Query را فیلتر میکند
به عنوان مثال contact های که آخر نام آنها Lee”: می باشد فیلتر می کنید .
Cursor c;
if (android.os.Build.VERSION.SDK_INT <11) {
//---before Honeycomb---
c = managedQuery(allContacts, projection,
ContactsContract.Contacts.DISPLAY_NAME + " LIKE '%Lee'", null, null);
} else {
//---Honeycomb and later---
CursorLoader cursorLoader = new CursorLoader(
this,
allContacts,
projection,
ContactsContract.Contacts.DISPLAY_NAME + " LIKE '%Lee'",
null ,
null);
c = cursorLoader.loadInBackground();
}
در اینجا شما میتوانید پارامتر سوم برای متد managedQuery() پارامتر چهارم برای کلاس CursorLoader شامل دستورت sql برای جستوجوی نام های که نام آنها شاملLee”). می باشند
شما می توانید از سازند های دیگر برای این متد و کلاس استفاده کنید مانند زیر:
Cursor c;
if (android.os.Build.VERSION.SDK_INT <11) {
//---before Honeycomb---
c = managedQuery(allContacts, projection,
ContactsContract.Contacts.DISPLAY_NAME + " LIKE ?",
new String[] {"%Lee"}, null);
} else {
//---Honeycomb and later---
CursorLoader cursorLoader = new CursorLoader(
this,
allContacts,
projection,
ContactsContract.Contacts.DISPLAY_NAME + " LIKE ?",
new String[] {"%Lee"},
null);
c = cursorLoader.loadInBackground();
}
Sorting
آخرین پارامتر متد managedQuery() و کلاس CursorLoader شما قادر می سازد نحو ه ی مرتب سازی را با دستور SQL ORDER BY تعیین کنید مانند مثال زیر:
Cursor c;
if (android.os.Build.VERSION.SDK_INT <11) {
//---before Honeycomb---
c = managedQuery(allContacts, projection,
ContactsContract.Contacts.DISPLAY_NAME + " LIKE ?",
new String[] {"%Lee"},
ContactsContract.Contacts.DISPLAY_NAME + " ASC");
} else {
//---Honeycomb and later---
CursorLoader cursorLoader = new CursorLoader(
this,
allContacts,
projection,
ContactsContract.Contacts.DISPLAY_NAME + " LIKE ?",
new String[] {"%Lee"},
ContactsContract.Contacts.DISPLAY_NAME + " ASC");
c = cursorLoader.loadInBackground();
}
ساخت Content Provider خودتان
ساختن Content Provider در اندروید بسیار آسان است تنها چیزی که لازم داریم آن است که کلاس ContentProvider مشتق بگیرید و متد ها آن را تعریف کنید.
دراین قسمت شما یاد می گیرید که چگونه یک ContentProvider ایجاد کنید و لیست کتاب ها دران ذخیره کنید برای آسانی شما فقط اطلاعت کتاب را مانند جدول زیر ذخیره می کنید
پروژه جدید به نام ContentProviders. ایجاد کنید
در فولدر src کلاس جدید به نام BooksProvider. ایجاد کنید و دستورات زیر در آن وارد کنید
package com.MehrdadJavidi.ContentProviders;
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;
import android.util.Log;
public class BooksProvider extends ContentProvider {
static final String PROVIDER_NAME = "net.learn2develop.provider.Books";
static final Uri CONTENT_URI = Uri.parse("content://" + PROVIDER_NAME
+ "/books");
static final String _ID = "_id";
static final String TITLE = "title";
static final String ISBN = "isbn";
static final int BOOKS = 1;
static final int BOOK_ID = 2;
private static final UriMatcher uriMatcher;
static {
uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
uriMatcher.addURI(PROVIDER_NAME, "books", BOOKS);
uriMatcher.addURI(PROVIDER_NAME, "books/#", BOOK_ID);
}
// ---for database use---
SQLiteDatabase booksDB;
static final String DATABASE_NAME = "Books";
static final String DATABASE_TABLE = "titles";
static final int DATABASE_VERSION = 1;
static final String DATABASE_CREATE = "create table " + DATABASE_TABLE
+ " (_id integer primary key autoincrement, "
+ "title text not null, isbn 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(DATABASE_CREATE);
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
Log.w("Content provider database",
"Upgrading database from version " + oldVersion + " to "
+ newVersion + ", which will destroy all old data");
db.execSQL("DROP TABLE IF EXISTS titles");
onCreate(db);
}
}
@Override
public int delete(Uri arg0, String arg1, String[] arg2) {
// arg0 = uri
// arg1 = selection
// arg2 = selectionArgs
int count=0;
switch (uriMatcher.match(arg0)){
case BOOKS:
count = booksDB.delete(
DATABASE_TABLE,
arg1,
arg2);
break;
case BOOK_ID:
String id = arg0.getPathSegments().get(1);
count = booksDB.delete(
DATABASE_TABLE,
_ID + " = " + id +
(!TextUtils.isEmpty(arg1) ? " AND (" +
arg1 + ‘)’ : ""),
arg2);
break;
default: throw new IllegalArgumentException("Unknown URI " + arg0);
}
getContext().getContentResolver().notifyChange(arg0, null);
return count;
}
@Override
public String getType(Uri uri) {
switch (uriMatcher.match(uri)) {
// ---get all books---
case BOOKS:
return "vnd.android.cursor.dir/vnd.learn2develop.books ";
// ---get a particular book---
case BOOK_ID:
return "vnd.android.cursor.item/vnd.learn2develop.books ";
default:
throw new IllegalArgumentException("Unsupported URI: " + uri);
}
}
@Override
public Uri insert(Uri uri, ContentValues values) {
// ---add a new book---
long rowID = booksDB.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("Failed to insert row into " + uri);
}
@Override
public boolean onCreate() {
Context context = getContext();
DatabaseHelper dbHelper = new DatabaseHelper(context);
booksDB = dbHelper.getWritableDatabase();
return (booksDB == null) ? false : true;
}
@Override
public Cursor query(Uri uri, String[] projection, String selection,
String[] selectionArgs, String sortOrder) {
SQLiteQueryBuilder sqlBuilder = new SQLiteQueryBuilder();
sqlBuilder.setTables(DATABASE_TABLE);
if (uriMatcher.match(uri) == BOOK_ID)
// ---if getting a particular book---
sqlBuilder.appendWhere(_ID + " = " + uri.getPathSegments().get(1));
if (sortOrder == null || sortOrder == "")
sortOrder = TITLE;
Cursor c = sqlBuilder.query(booksDB, projection, selection,
selectionArgs, null, null, sortOrder);
// ---register to watch a content URI for changes---
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 BOOKS:
count = booksDB.update(DATABASE_TABLE, values, selection,
selectionArgs);
break;
case BOOK_ID:
count = booksDB.update(
DATABASE_TABLE,
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;
}
}
و فایل AndroidManifest.xml به صورت زیر تغییر دهید
manifest xmlns:android=“http://schemas.android.com/apk/res/android“
package=”net.learn2develop.ContentProviders”
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.MehrdadJavidi.usingintent"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk android:minSdkVersion="14" />
<application
android:icon="@drawable/ic_launcher"
android:label="@string/app_name" >
<activity
android:name=".ContentProvidersActivity"
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="BooksProvider"
android:authorities="com.MehrdadJavidi.provider.Books" >
</provider>
</application>
</manifest>
توضیحات
شما ابتدا یک کلاس به نام BooksProvider ایجاد کردید که از کلاس ContentProvider مشتق شده است متد های زیادی در این کلاس است مانند متد های زیر :
- getType() – داده MIME رابرای داده های URI بر می گرداند
- onCreate() – زمانی که Content Provider شروع می شود فراخوانی می شود.
- query() – درخواست از کلاینت را دریافت می کند نتیجه را یک شی Cursor بر می گرداند
- insert() – یک رکور جدید در Content Provider درج می کند
- delete() – یک رکورد از Content Provider حذف می کند
- update()-یک رکورد را در به روز رسانی می کند (ویرایش می کند)
در داخل Content Provider شما آزاد هستید که تصمیم بگیرید که به چه طریق می خواهید داده های خود را ذخیره کنید در یک فایل , د ر فایل xml یا در یک دیتابیس
یا حتی در یک Web Service . در اینجا ما از دیتابیس SqLite استفاده میکنیم که در فصل قبل آن را شرح دادیم.پ
شما ثابت های زیر را در BooksProvider تعریف کردید.
static final String PROVIDER_NAME = "com.MehrdadJavidi.provider.Books";
static final Uri CONTENT_URI = Uri.parse("content://" + PROVIDER_NAME
+ "/books");
static final String _ID = "_id";
static final String TITLE = "title";
static final String ISBN = "isbn";
static final int BOOKS = 1;
static final int BOOK_ID = 2;
private static final UriMatcher uriMatcher;
static {
uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
uriMatcher.addURI(PROVIDER_NAME, "books", BOOKS);
uriMatcher.addURI(PROVIDER_NAME, "books/#", BOOK_ID);
}
// ---for database use---
SQLiteDatabase booksDB;
static final String DATABASE_NAME = "Books";
static final String DATABASE_TABLE = "titles";
static final int DATABASE_VERSION = 1;
static final String DATABASE_CREATE = "create table " + DATABASE_TABLE
+ " (_id integer primary key autoincrement, "
+ "title text not null, isbn text not null);";
شما در کد بالا مشاهده می کنید که از شیUriMatcher برای تبدیل محتوای URI و سپس از طریق ContentResolver. به content Provider ارسال می شود.
به عنوان مثال دستور زیر تمام کتاب های Content Provider را بر میگرداند
content://com.MehrdadJavidi.provider.Books/books
و دستور زیر کتاب با کد 5 را بر می گرداند.
content://com.MehrdadJavidi.provider.Books/books/5
Content Provider شما از SqLite برای ذخبره کتاب های استفاده می کند توجه کنید که شما از SQLiteOpenHelper برای مدیریت دیتابیس استفاد می کنید
private static class DatabaseHelper extends SQLiteOpenHelper {
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) {
Log.w("Content provider database",
"Upgrading database from version " + oldVersion + " to "
+ newVersion + ", which will destroy all old data");
db.execSQL("DROP TABLE IF EXISTS titles");
onCreate(db);
}
}
بعدی شما متدgetType() را override کرده اید که به طور خاص نوع داده برای content Provider را توصیف میکند. با استفاده از شی UriMatcher شما
vnd.android.cursor.item/vnd.MehrdadJavidi.books برای بازگرداند یک کتاب استفاده می کنید و vnd.android.cursor.dir/vnd.MehrdadJavidi.books برای برگرداندن تمام کتاب ها استفاده میکنید.
@Override
public String getType(Uri uri) {
switch (uriMatcher.match(uri)) {
// ---get all books---
case BOOKS:
return "vnd.android.cursor.dir/vnd.MehrdadJavidi.books ";
// ---get a particular book---
case BOOK_ID:
return "vnd.android.cursor.item/vnd.MehrdadJavidi.books ";
default:
throw new IllegalArgumentException("Unsupported URI: " + uri);
}
}
سپس شما متد onCreate() را استفاده کردید که از ان برای باز کردن یک Connection برای دیتایس استفاده کرده اید
public boolean onCreate() {
Context context = getContext();
DatabaseHelper dbHelper = new DatabaseHelper(context);
booksDB = dbHelper.getWritableDatabase();
return (booksDB == null) ? false : true;
}
سپس متدquery() را ovveride کردید که به کلاینت اجازه میدهد از کتاب های query بگیرید.
@Override
public Cursor query(Uri uri, String[] projection, String selection,
String[] selectionArgs, String sortOrder) {
SQLiteQueryBuilder sqlBuilder = new SQLiteQueryBuilder();
sqlBuilder.setTables(DATABASE_TABLE);
if (uriMatcher.match(uri) == BOOK_ID)
// ---if getting a particular book---
sqlBuilder.appendWhere(_ID + " = " + uri.getPathSegments().get(1));
if (sortOrder == null || sortOrder == "")
sortOrder = TITLE;
Cursor c = sqlBuilder.query(booksDB, projection, selection,
selectionArgs, null, null, sortOrder);
// ---register to watch a content URI for changes---
c.setNotificationUri(getContext().getContentResolver(), uri);
return c;
}
به طور پیش فرش کتاب های بازگردنده شده بر اساس title مرتب می شوند که نتیجه Query یک Cursor میباشد
برای اضافه کردن کتاب به content Provider شما متدinsert() راovveride کردید
@Override
public Uri insert(Uri uri, ContentValues values) {
// ---add a new book---
long rowID = booksDB.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("Failed to insert row into " + uri);
}
زمانی که رکورد با موفقیت درج شد شما متدnotifyChange() را ContentResolver. فراخوانی کردید این Notify نشان می دهد که رکورد ثبت شده است.
برای حذف کتاب شما متد delete()را override کردید
@Override
public int delete(Uri arg0, String arg1, String[] arg2) {
// arg0 = uri
// arg1 = selection
// arg2 = selectionArgs
int count=0;
switch (uriMatcher.match(arg0)){
case BOOKS:
count = booksDB.delete(
DATABASE_TABLE,
arg1,
arg2);
break;
case BOOK_ID:
String id = arg0.getPathSegments().get(1);
count = booksDB.delete(
DATABASE_TABLE,
_ID + " = " + id +
(!TextUtils.isEmpty(arg1) ? " AND (" +
arg1 + ')' : ""),
arg2);
break;
default: throw new IllegalArgumentException("Unknown URI " + arg0);
}
getContext().getContentResolver().notifyChange(arg0, null);
return count;
}
مانند قبل شما متدnotifyChange() از ContentResolver را بعد از حذف فراخوانی کردید ه این Notify ثبت شده نشان میدهد که رکورد حذف شده است.
و در اخر هم شما متدupdate() را override کردید
@Override
public int update(Uri uri, ContentValues values, String selection,
String[] selectionArgs) {
int count = 0;
switch (uriMatcher.match(uri)) {
case BOOKS:
count = booksDB.update(DATABASE_TABLE, values, selection,
selectionArgs);
break;
case BOOK_ID:
count = booksDB.update(
DATABASE_TABLE,
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;
}
مانند قبل شما متدnotifyChange() از ContentResolver را بعد از ویرایش فراخوانی کردید ه این Notify ثبت شده نشان میدهد که رکورد به روز رسانی شده است.
ودر آخر هم شما برای ثبت Content Provider خود باید فایل AndroidManifest.xml را با اضافه کردن provider> تغییر دهید
<provider
android:name="BooksProvider"
android:authorities="com.MehrdadJavidi.provider.Books" >
</provider
استفاده از Content Provider
حالا که شما content Provider خود را ایجاد کردید زمان آن رسید ه که ان را د ر برنامه خود استفاده کنید.
در پروژه قبلی که ساختید فایل main.xmlبه صورت زیر تغیر دهید
<?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" >
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="ISBN" />
<EditText
android:id="@+id/txtISBN"
android:layout_width="fill_parent"
android:layout_height="wrap_content" />
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Title" />
<EditText
android:id="@+id/txtTitle"
android:layout_width="fill_parent"
android:layout_height="wrap_content" />
<Button
android:id="@+id/btnAdd"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:onClick="onClickAddTitle"
android:text="Add title" />
<Button
android:id="@+id/btnRetrieve"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:onClick="onClickRetrieveTitles"
android:text="Retrieve titles" />
</LinearLayout>?
فایل ContentProvidersActivity.java به صورت زیر تغییر دهید
package com.MehrdadJavidi.ContentProviders;
import android.app.Activity;
import android.content.ContentValues;
import android.content.CursorLoader;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.view.View;
import android.widget.EditText;
import android.widget.Toast;
public class ContentProvidersActivity extends Activity {
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
public void onClickAddTitle(View view) {
// ---add a book---
ContentValues values = new ContentValues();
values.put(BooksProvider.TITLE,
((EditText) findViewById(R.id.txtTitle)).getText().toString());
values.put(BooksProvider.ISBN, ((EditText) findViewById(R.id.txtISBN))
.getText().toString());
Uri uri = getContentResolver()
.insert(BooksProvider.CONTENT_URI, values);
Toast.makeText(getBaseContext(), uri.toString(), Toast.LENGTH_LONG)
.show();
}
public void onClickRetrieveTitles(View view) {
//---retrieve the titles---
Uri allTitles = Uri.parse(
"content://com.MehrdadJavidi.provider.Books/books”);
Cursor c;
if (android.os.Build.VERSION.SDK_INT <11) {
//---before Honeycomb---
c = managedQuery(allTitles, null, null, null,
"title desc”);
} else {
//---Honeycomb and later---
CursorLoader cursorLoader = new CursorLoader(
this,
allTitles, null, null, null,
"title desc”);
c = cursorLoader.loadInBackground();
}
if (c.moveToFirst()) {
do{
Toast.makeText(this,
c.getString(c.getColumnIndex(
BooksProvider._ID)) + ", " +
c.getString(c.getColumnIndex(
BooksProvider.TITLE)) + ", " +
c.getString(c.getColumnIndex(
BooksProvider.ISBN)),
Toast.LENGTH_SHORT).show();
} while (c.moveToNext());
}
}
}
برنامه را با زدن F11 اجرا کنید
اطاعات خواسته شده را اضافه کنید و Add title را کلیک کنید
با کلاس Toast پیغام نمایش می دهیم که نشان دهنده URI کتاب اضافه شده می باشد
برای باز یابی تمام title های کتاب ها شما بر روی
Retrieve titles کلیک کنید
توضیحات
شما ابتدا یک activity ایجاد کردید که کاربر میتواند اطلاعات کتاب را Content Provider که ساخته اید را وارد نماید.
شما برای اضافه کردن کتاب ابتدا یک شی از ContentValues ایجاد کردید که اطلاعات کتاب را در بر می گیرد.
ContentValues values = new ContentValues();
values.put(BooksProvider.TITLE,
((EditText) findViewById(R.id.txtTitle)).getText().toString());
values.put(BooksProvider.ISBN, ((EditText) findViewById(R.id.txtISBN))
.getText().toString());
Uri uri = getContentResolver()
.insert(BooksProvider.CONTENT_URI, values);
Toast.makeText(getBaseContext(), uri.toString(), Toast.LENGTH_LONG)
.show();
توجه کنید که از انجا که Content Provider در یک package یگسان می باشد از BooksProvider .TITLE و BooksProvider.ISBN برای فیلد های Title و ISBN استفاده کردید
اگر شما بخواهید از این Content Provider در یک package دیگر استفاده کنید شما نمی توانید از ثابت های استفاده کنید بلکه باید به طور مستقیم نام فیلد هارا بیان کنید .
ContentValues values = new ContentValues();
values.put("title", ((EditText)
findViewById(R.id.txtTitle)).getText().toString());
values.put("isbn", ((EditText)
findViewById(R.id.txtISBN)).getText().toString());
Uri uri = getContentResolver().insert(
Uri.parse(
"content://com.MehrdadJavidi.provider.Books/books"),
values);
همچنین برای Package های خارجی شما باید URI را به صورت کامل بیان کنید
Uri.parse( "content://com.MehrdadJavidi.provider.Books/books"),
//---retrieve the titles---
Uri allTitles = Uri.parse(
"content://com.MehrdadJavidi.provider.Books/books");
Cursor c;
if (android.os.Build.VERSION.SDK_INT <11) {
//---before Honeycomb---
c = managedQuery(allTitles, null, null, null,
"title desc");
} else {
//---Honeycomb and later---
CursorLoader cursorLoader = new CursorLoader(
this,
allTitles, null, null, null,
"title desc");
c = cursorLoader.loadInBackground();
}
if (c.moveToFirst()) {
do{
Toast.makeText(this,
c.getString(c.getColumnIndex(
BooksProvider._ID)) + ", " +
c.getString(c.getColumnIndex(
BooksProvider.TITLE)) + ", " +
c.getString(c.getColumnIndex(
BooksProvider.ISBN)),
Toast.LENGTH_SHORT).show();
} while (c.moveToNext());
}
در کد قبل شما نتایج بر گردانده شده را بر اساس فیلد title نزولی مرتب کرده اید.
اگر شما بخواهید اطلاعات کتاب را با متد update() به روز رسانی کنید Id کتاب را همرا URI تعیین می کنید
ContentValues editedValues = new ContentValues();
editedValues.put(BooksProvider.TITLE, "Android Tips and Tricks");
getContentResolver().update(
Uri.parse(
"content://com.MehrdadJavidi.provider.Books/books/2"),
editedValues,
null,
null);
اگر شما بخواهید کتاب را با متد delete() حذف کنید Id کتاب را همرا URI تعیین می کنید
//---delete a title---
getContentResolver().delete(
Uri.parse("content:// com.MehrdadJavidi.provider.Books/books/2"),
null, null);
برای حذف همه ای کتاب شما به صورت زیر استفاده می کنید و ID را نمی نویسید.
//---delete all titles---
getContentResolver().delete(
Uri.parse("content:// com.MehrdadJavidi.provider.Books/books"),
null, null);