هیچ دوره ای در سبد آموزش شما وجود ندارد
آموزش تامین کنندگان محتوا (Content Providers )در اندروید
صفحه نخستتامین کنندگان محتوا در اندروید (Android Content Providers )

هر اپلیکیشن اندرویدی فرایندهای خود را با مجوز های مربوط به خودش اجرا می کند. این کار باعث میشود که داده های یک اپلیکیشن از سایر اپلیکیشن ها پنهان باشد. ولی گاهی اوقات لازم است که داده ای در بین اپلیکیشن ها به اشتراک گذاشته شود. اینجا جایی است که تامین کنندگان محتوا بسیار مفید واقع می شوند.
تامین کنندگان محتوا به شما اجازه می دهند که محتوای مورد نیاز را در یک جا متمرکز کنید و اپلیکیشن های بسیاری بتوانند در صورت نیاز به آن دسترسی داشته باشند. رفتار یک تامین کننده محتوا بسیار شبیه به یک پایگاه داده است که شما می توانید با استفاده از متدهای query()،update() ، insert() و delete() بر روی آن پرس و جو ایجاد کنید، محتوای آن را ویرایش کنید و همچنین محتوای آن را اضافه یا حذف کنید. در بسیاری از موارد این داده در یک پایگاه داده SQlite ذخیره می شود.
یک تامین کننده محتوا به صورت یک زیر کلاس از کلاس ContentProvider پیاده سازی می شود و باید مجموعه ی استانداردی از API ها را پیاده سازی کند که سایر اپلیکیشن ها را قادر به اجرای تراکنش ها می کند.
public class My Application extends ContentProvider { }
URI های محتوا
<prefix>://<authority>/<data_type>/<id>
در اینجا جزئیات بخش های مختلف URI ارائه شده است .
Prefix (پیشوند) | این بخش همیشه به صورت content:// تنظیم می شود. |
Authority (منبع) | این بخش نام تامین کنندهی محتوا را تعیین میکند. برای مثال contacts، browser و غیره. برای تامین کنندگان محتوای شخص ثالث، این بخش می تواند به صورت یک نام کاملا توصیفی مانند com.tutorialspoint.statusprovider باشد. |
data_type (نوع داده) | یک فایل جاوای جدیداین بخش نشان دهندهی نوع داده ای است که این تامین کنندهی محتوای خاص ایجاد میکند. برای مثال، اگر شما همهی شماره تماس ها را از تامین کننده محتوای Contacts دریافت کنید، آنگاه مسیر داده people خواهد بود و URI آن شبیه به این خواهد بود: content://contacts/people |
id (شناسه) | این بخش رکورد خاص مورد تقاضا را مشخص می کند. برای مثال، اگر شما شماره تماس نفر 5 ام را از تامین کننده محتوا درخواست کنید، آنگاه URI شبیه به این خواهد شد: content://contacts/people/5 |
ایجاد تامین کننده ی محتوا
این بخش شامل تعدادی گام ساده برای ایجاد تامین کننده محتوای مربوط به خودتان است.
- اول از همه، شما باید یک کلاس Content Provider را ایجاد کنید که کلاس ContentProviderbase class را توسعه (extend) می دهد.
- در گام دوم، شما باید آدرس UIR مربوط به تامین کننده محتوای خود را تعریف کنید که برای دسترسی به محتوا مورد استفاده قرار می گیرد.
- سپس، شما باید پایگاه داده خود را برای ذخیره محتوا ایجاد کنید. معمولا اندروید از پایگاه داده SQLite استفاده می کند و فریم ورک نیازمند override کردن متد onCreate() است، که از متد SQLite Open Helper ، برای ایجاد یا بازکردن پایگاه داده تامین کننده محتوا استفاده میکند. زمانیکه اپلیکیشن شما راه اندازی می شود، گرداننده (hander) مربوط به متد onCreate() هر کدام از Content Provider های آن، در نخ اجرایی اصلی اپلیکیشن فراخوانی می شوند.
- پس از آن شما باید پرس و جو های Content Provider را برای اجرای عملیات مختلف مربوط به پایگاه داده، پیاده سازی کنید.
- در نهایت، باید با استفاده از تگ < provider> ، Content Provider خود را در فایل فعالیت خود ثبت کنید.
در اینجا متدهایی در کلاس Content Provider ، که شما باید برای کار کردن Content Provider خودتان، آنها را override کنید، لیست شده اند.
- onCreate() این متد زمانی فراخوانی می شود که تامین کننده شروع به کار می کند.
- query() این متد درخواستی را از یک کلاینت دریافت می کند، نتیجه به صورت یک شی Cursor برگردانده می شود.
- insert() این متد یک رکورد جدید را در یک تامین کننده محتوا درج می کند.
- delete() این متد یک رکورد موجود را از یک تامین کننده محتوا حذف می کند.
- update() این متد یک رکورد موجود را در یک تامین کننده محتوا به روز رسانی می کند.
- getType() این متد نوع MIME داده را در URI مورد نظر برمی گرداند.
مثال:
این مثال توضیح می دهد که شما چگونه می توانید ContentProvider خودتان را ایجاد کنید. بیایید مراحل زیر را شبیه به مراحل ایجاد Hello World Example دنبال کنیم.
مرحله | توصیف |
1 | از Eclipse IDE برای ایجاد یک اپلیکیشن اندرویدی استفاده کنید و آن را ، تحت پکیج com.example.mycontentprovider همراه با یک فعالیت خالی، MyContentProvider بنامید. |
2 | این بخش نام تامین کننده محتوا را تعیین میکند. برای مثال فایل فعالیت اصلی MainActivity.java را برای اضافه کردن متدهای جدید onClickAddName() و onClickRetrieveStudents() تغییر دهید. |
3 | برای تعریف تامین کننده و متدهای مربوط به آن، یک فایل جاوای جدید به نام StudentsProvider.java تحت پکیج com.example.mycontentprovider ایجاد کنید. |
4 | این بخش رکورد خاص مورد تقاضا را مشخص می کند. برای مثال، اگر شما شماره تماس نفر 5 ام را از تامین کننده محتوا درخواست کنید، آنگاه تامین کننده محتوای خود را با استفاده از تگ در فایل AndroidManifest.xml پروژه تان ثبت کنید. |
5 | این بخش رکورد خاص مورد تقاضا را مشخص می کند. برای مثال، اگر شما شماره تماس نفر 5 ام را از تامین کننده محتوا درخواست کنید، آنگاه محتوای پیش فرض فایل res/layout/activity_main.xml را برای وارد کردن یک واسط کاربری کوچک برای اضافه کردن رکودهای مربوط به دانش آموزان، تغییر دهید. |
6 | ثابت های مورد نیاز را در فایل res/values/strings.xml تعریف کنید. |
7 | برای راه اندازی امولاتور اندروید اپلیکیشن را اجرا کنید و نتایج تغییرات اعمال شده در اپلیکیشن را بررسی کنید. |
در بخش زیر محتوای تغییر یافته ی فایل فعالیت اصلی
src/com.example.mycontentprovider/MainActivity.java ارائه شده است. این فایل می تواند شامل هر کدام از متدهای اصلی چرخه حیات باشد. ما دو متد جدید onClickAddName() و onClickRetrieveStudents() را برای مدیریت تعامل کاربر با اپلیکیشن، اضافه کرده ایم.
package com.example.MyApplication; import android.net.Uri; import android.os.Bundle; import android.app.Activity; import android.content.ContentValues; import android.content.CursorLoader; 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); } public void onClickAddName(View view) { // Add a new student record ContentValues values = new ContentValues(); values.put(StudentsProvider.NAME, ((EditText)findViewById(R.id.editText2)).getText().toString()); values.put(StudentsProvider.GRADE, ((EditText)findViewById(R.id.editText3)).getText().toString()); Uri uri = getContentResolver().insert( StudentsProvider.CONTENT_URI, values); Toast.makeText(getBaseContext(), uri.toString(), Toast.LENGTH_LONG).show(); } public void onClickRetrieveStudents(View view) { // Retrieve student records String URL = "content://com.example.MyApplication.StudentsProvider"; Uri students = Uri.parse(URL); 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_SHORT).show(); } while (c.moveToNext()); } } }
فایل جدید StudentsProvider.java را تحت پکیج com.example.mycontentprovider ایجاد کنید . در بخش زیر محتوی فایل src/com.example.mycontentprovider/StudentsProvider.java ارائه شده است.
package com.example.MyApplication; 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.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.example.MyApplication.StudentsProvider"; static final String URL = "content://" + PROVIDER_NAME + "/students"; static final Uri CONTENT_URI = Uri.parse(URL); 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 STUDENT_ID = 2; static final UriMatcher uriMatcher; static{ uriMatcher = new UriMatcher(UriMatcher.NO_MATCH); uriMatcher.addURI(PROVIDER_NAME, "students", STUDENTS); uriMatcher.addURI(PROVIDER_NAME, "students/#", STUDENT_ID); } /** * Database specific constant declarations */ 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);"; /** * Helper class that actually creates and manages * the provider's underlying data repository. */ 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 boolean onCreate() { Context context = getContext(); DatabaseHelper dbHelper = new DatabaseHelper(context); /** * Create a write able database which will trigger its * creation if it doesn't already exist. */ db = dbHelper.getWritableDatabase(); return (db == null)? false:true; } @Override public Uri insert(Uri uri, ContentValues values) { /** * Add a new student record */ long rowID = db.insert( STUDENTS_TABLE_NAME, "", values); /** * If record is added successfully */ 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 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 STUDENT_ID: qb.appendWhere( _ID + "=" + uri.getPathSegments().get(1)); break; default: } if (sortOrder == null || sortOrder == ""){ /** * By default sort on student names */ sortOrder = NAME; } Cursor c = qb.query(db, projection, selection, selectionArgs,null, null, sortOrder); /** * register to watch a content URI for changes */ c.setNotificationUri(getContext().getContentResolver(), uri); return c; } @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 STUDENT_ID: String id = uri.getPathSegments().get(1); count = db.delete( STUDENTS_TABLE_NAME, _ID + " = " + id + (!TextUtils.isEmpty(selection) ? " AND (" + selection + ')' : ""), selectionArgs); break; default: throw new IllegalArgumentException("Unknown URI " + uri); } getContext().getContentResolver().notifyChange(uri, null); return count; } @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 STUDENT_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; } @Override public String getType(Uri uri) { switch (uriMatcher.match(uri)){ /** * Get all student records */ case STUDENTS: return "vnd.android.cursor.dir/vnd.example.students"; /** * Get a particular student */ case STUDENT_ID: return "vnd.android.cursor.item/vnd.example.students"; default: throw new IllegalArgumentException("Unsupported URI: " + uri); } } }
در بخش زیر محتوای تغییر یافته ی فایل AndroidManifest.xml ارائه شده است. در اینجا ما تگ را برای وارد کردن تامین کننده محتوایمان اضافه کرده ایم.
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.MyApplication"> <application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:supportsRtl="true" android:theme="@style/AppTheme"> <activity android:name=".MainActivity"> <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.example.MyApplication.StudentsProvider"/> </application> </manifest>
در بخش زیر محتوای فایل res/layout/activity_main.xml برای ایجاد دو دکمه جهت اضافه کردن نام دانش آموزان و بازیابی دانش آموزان، آورده شده است.
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" tools:context="com.example.MyApplication.MainActivity"> <TextView android:id="@+id/textView1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Content provider" android:layout_alignParentTop="true" android:layout_centerHorizontal="true" android:textSize="30dp" /> <TextView android:id="@+id/textView2" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Tutorials point " android:textColor="#ff87ff09" android:textSize="30dp" android:layout_below="@+id/textView1" android:layout_centerHorizontal="true" /> <ImageButton android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/imageButton" android:src="@drawable/abc" android:layout_below="@+id/textView2" android:layout_centerHorizontal="true" /> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/button2" android:text="Add Name" android:layout_below="@+id/editText3" android:layout_alignRight="@+id/textView2" android:layout_alignEnd="@+id/textView2" android:layout_alignLeft="@+id/textView2" android:layout_alignStart="@+id/textView2" android:onClick="onClickAddName"/> <EditText android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/editText" android:layout_below="@+id/imageButton" android:layout_alignRight="@+id/imageButton" android:layout_alignEnd="@+id/imageButton" /> <EditText android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/editText2" android:layout_alignTop="@+id/editText" android:layout_alignLeft="@+id/textView1" android:layout_alignStart="@+id/textView1" android:layout_alignRight="@+id/textView1" android:layout_alignEnd="@+id/textView1" android:hint="Name" android:textColorHint="@android:color/holo_blue_light" /> <EditText android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/editText3" android:layout_below="@+id/editText" android:layout_alignLeft="@+id/editText2" android:layout_alignStart="@+id/editText2" android:layout_alignRight="@+id/editText2" android:layout_alignEnd="@+id/editText2" android:hint="Grade" android:textColorHint="@android:color/holo_blue_bright" /> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Retrive student" android:id="@+id/button" android:layout_below="@+id/button2" android:layout_alignRight="@+id/editText3" android:layout_alignEnd="@+id/editText3" android:layout_alignLeft="@+id/button2" android:layout_alignStart="@+id/button2" android:onClick="onClickRetrieveStudents"/> </RelativeLayout> Make sure you have following content of res/values/strings.xml file: <?xml version="1.0" encoding="utf-8"?> <resources> <string name="app_name">My Application</string> </resources>;
مطمئن شوید که فایل res/values/strings.xml شما دارای محتوای زیر است.
<?xml version="1.0" encoding="utf-8"?> <resources> <string name="app_name">My Application</string> </resources>;
اکنون می خواهیم اپلیکیشن MyContentProvider را اجرا کنیم. من فرض می کنم که شما AVD خود را در زمان نصب محیط ایجاد کرده باشید. برای اجرای اپلیکیشن از Eclipse ، یکی از فایل های فعالیت پروژه ی خود را باز کنید و بر روی آیکن Run از نوار ابزار کلیک کنید. Eclipse ، اپلیکیش را بر روی AVD شما نصب می کند و آن را آغاز می کند، و در صورتی که همه ی موارد مربوط به تنظیمات و برنامه شما درست باشد، صفحه امولاتور زیر برای شما نمایش داده می شود، شکیبا باشید چون این کار بسته به سرعت کامپیوتر شما قدری زمان می برد.
اکنون فیلدهای Name و Grade دانش آموز را پر کنید و نهایتا بر روی دکمه AddName کلیک کنید. این کار رکورد دانش آموز را به پایگاه داده اضافه می کند و یک پیام آنی در انتهای صفحه نمایش ظاهر می شود که نشان دهندهی URI مربوط به ContentProvider همراه با شماره رکورد اضافه شده به پایگاه داده است. این عملیات از متد insert() استفاده می کند. این کار را برای اضافه کردن تعدادی دانش آموز به پایگاه داده ی تامین کننده محتوا تکرار کنید.
بعد از اینکه رکوردها را به پایگاه داده اضافه کردید، اکنون وقت آن است که از ContentProvider درخواست کنید که این رکوردها را به شما برگرداند. بر روی دکمه RetrieveStudents کلیک کند، این کار تمام رکودهای موجود را واکشی کرده و آنها را یک به یک برای شما نمایش می دهد. این کار با توجه به آنچه که ما در متد query() پیاده سازی کردیم، انجام می شود.