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 های که  ایجاد  کردید را مشاهده می کنید

اشتراک داده بین برنامه در اندروید با  استفاده از Content Provicer

اشتراک داده بین برنامه در اندروید با  استفاده از Content Provicer

توضیحات

در اینجا  شما  تمام 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 ایجاد  کنید  و  لیست  کتاب ها دران   ذخیره  کنید برای  آسانی  شما    فقط اطلاعت  کتاب را  مانند  جدول  زیر  ذخیره  می کنید

اشتراک داده بین برنامه در اندروید با  استفاده از Content Provicer

پروژه   جدید  به نام 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 کلیک کنید

اشتراک داده بین برنامه در اندروید با  استفاده از Content Provicer

توضیحات

شما   ابتدا  یک  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);

نظرات (۰)

هيچ نظري هنوز ثبت نشده است
ارسال نظر آزاد است، اما اگر قبلا در بیان ثبت نام کرده اید می توانید ابتدا وارد شوید.
شما میتوانید از این تگهای html استفاده کنید:
<b> یا <strong>، <em> یا <i>، <u>، <strike> یا <s>، <sup>، <sub>، <blockquote>، <code>، <pre>، <hr>، <br>، <p>، <a href="" title="">، <span style="">، <div align="">
تجدید کد امنیتی