کامپوننت ارائه دهنده محتوا داده های یک برنامه را در صورت درخواست سایر برنامه ها در اختیار آنها قرار می دهد. چنین درخواست هایی بوسیله متدهای کلاس های ContentResolver انجام می شوند. ارائه دهنده محتوا می تواند از روش های مختلفی برای ذخیره اطلاعات خود استفاده کند و اطلاعات می توانند در پایگاه داده یک فایل و حتی روی شبکه ذخیره شوند.
گاهی اوقات لازم است تا داده ها در بین اپلیکیشن ها به اشتراک گذاشته شوند. در این موارد ارائه دهنده محتوا بسیار مفید است.
ارائه دهندگان محتوا به شما اجازه می دهند تا محتوا را در یک مکان متمرکز کنید و اپلیکیشن های متفاوت بسیاری در صورت نیاز به آن دسترسی داشته باشند. ارائه دهنده محتوا بسیار شبیه به یک پایگاه داده رفتار می کند که می توانید جست و جو یا query تعریف کنید، محتوای آن را ویرایش کنید، و همچنین محتوایی را اضافه و یا حذف کنید. برای انجام کارهای فوق می توانید از متدهای insert()،update()،delete()، و query() استفاده کنید. در اغلب موارد این داده ها در پایگاه داده SQLite ذخیره می شوند.
ارائه دهنده محتوا به عنوان یک زیر کلاس از کلاس ContentProvider پیاده سازی می شود و باید مطابق با مجموعه استاندارد های رابط های برنامه کاربردی (API) پیاده سازی شود تا ارائه دهنده محتوا بتواند با اپلیکیشن های دیگر تراکنش انجام دهد.
public class My Application extends ContentProvider { }
URI های محتوا
برای جست وجو در ارائه دهنده محتوا، شما باید رشته پرس و جو در قالب یک URI را مشخص کنید که فرمت آن در زیر آمده است.
<prefix>://<authority>/<data_type>/<id>
در جدول زیر جزئیات بخش های مختلف URI آورده شده است:
Sr.No |
Part & Description |
۱ |
prefix همیشه محتوا بعد از //: تنظیم می شود. |
۲ |
Authority این نام ارائه دهنده محتوا را مشخص می کند، برای مثال contacts, browser و غیره. برای ارائه دهندگان محتوای سه بخشی، این قسمت یکی از نام های کامل خواهد بود. برای مثال com.tutorialspoint.statusprovider |
۳ |
data_type این قسمت نوع داده ای که این تامین کننده محتوای خاص فراهم می کند را مشخص می کند. برای مثال اگر شما محتوای کل مخاطبین را از تامین کننده محتوای آن بگیرید مسیر (path) شما people و URI خواهد بود مشابه thiscontent://contacts/people |
۴ |
Id این قسمت رکورد خاص درخواست شده را مشخص می کند. برای مثال اگر بخواهید مخاطب شماره ۵ را از ارائه دهنده محتوای مخاطبین (Contacts ) جستو جو کنید URI بصورت زیر خواهد شد: content://contacts/people/5. |
ساختن ارائه دهنده محتوا
گام های ساده زیر مراحل ایجاد ارائه دهنده محتوا را نشان می دهد.
اول از همه شما نیاز به ایجاد یک کلاس ارائه دهنده محتوا که برگرفته از کلاس ContentProviderbaseclass دارید.
در گام دوم، شما نیاز به تعریف آدرس URI ارائه دهنده محتوا خود دارید که برای دسترسی به محتوا استفاده می شود.
بعد شما نیاز به ایجاد پایگاه داده خود برای نگه داشتن محتوا دارید. معمولا، آندروید از پایگاه داده SQLite استفاده می کند و با توجه به اینکه SQLite ازمتدهای Open Helper برای ساختن یا باز کردن پایگاه داده ارائه دهنده استفاده می کند لازم است فریم ورک متد ()onCreate را مورد استفاده قرار دهد. هنگامی که نرم افزار شما راه اندازی می شود، متد ()onCreate تمام ارائه دهندگان محتوایی را کهدرنخ اصلی برنامه فراخوانی کرده اید کنترل و اجرا می کند.
در گام بعد شما باید برای اجرای عملیات خاص پایگاه داده ، کوئری های ارائه دهنده محتوا را پیاده سازی کنید.
در نهایت ارائه دهنده محتوای خود را در فایل فعالیت (activity) خود با استفاده از تگ < در اینجا لیستی از متدهایی که شما نیاز به اورراید آنها در کلاس ارائه دهنده محتوا دارید تا ارائه دهنده محتوای شما کار کند آورده شده است:
()onCreate : این متد زمانی که ارائه دهنده محتوا شروع بکار می کند فراخوانی می شود.
query() : این متد یک درخواست از کاربر دریافت می کند. و نتیجه را به عنوان یک شیء Cursor بر می گرداند.
insert() : این متد یک رکورد جدید در ارائه دهنده محتوا درج می کند.
delete() : این متد رکوردی از ارائه دهنده محتوا را حذف می کند.
update() : این متد رکوردی از ارائه دهنده محتوا را به روز رسانی می کند.
getType() : این متد نوع MIME داده ها در URI داده شده را بر می گرداند.
مثال:
این مثال به شما توضیح می دهد که چگونه ContentProvider خود را ایجاد کنید. بنابراین اجازه دهد مراحل زیر همانند مثال ایجاد Hello World دنبال کنیم.
Step | Description |
۱ | شما باید از محیط اندروید استدیو استفاده کنید تا یک اپلیکیشن اندروید ایجاد کنید. یک اپلیکیشن با نام My Application تحت بسته com.example.MyApplication با blank Activity ایجاد کنید. |
۲ | فایل اکتیویتی اصلی MainActivity.java اصلاح می کنیم تا دو متد onClickAddName() و onClickRetrieveStudents() را اضافه کنیم. |
۳ | یک فایل جدید جاوا با نام StudentsProvider.java تحت بسته com.example.MyApplication تا فراهم کننده واقعی خودتان و متدهای مربوط به آن را تعریف کنید. |
۴ | content provider خودتان را در فایل AndroidManifest.xml با استفاده از تگ <provider…/> ثبت کنید. |
۵ | فایل res/layout/activity_main.xml را ویرایش کنید و یک GUI کوچک به آن برای افزودن رکورد دانش آموزان اضافه کنید. |
۶ | نیازی به ویرایش string.xml نیست. اندروید استدیو از آن محافظت می کند. |
۷ | اپلیکیشن را بر روی launch Android emulator اجرا کنید و نتیجه تغییرات انجام شده در اپلیکیشن خود را بررسی کنید. |
در زیر محتوای تغییر یافته فایل فعالیت اصلی src / com.example.MyApplication / 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.MyApplication ایجاد کنید و محتوای src/com.example.MyApplication/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>
مطمئن شوید محتوای فایل res/values/strings.xml بصورت زیر است:
<?xml version="1.0" encoding="utf-8"?> <resources> <string name="app_name">My Application</string> </resources>;
بیایید اپلیکیشن ایجاد شده را اجرا کنیم تا نتیجه را ببینیم. من فرض می کنم شما AVD خود را در هنگام نصب و راه اندازی محیط برنامه نویسی ایجاد کرده اید. برای اجرای برنامه از Android Studio IDE، یکی از فایل های فعالیت پروژه را باز کرده و بر روی آیکون Run در نوار ابزار کلیک کنید. اندروید استودیو برنامه را روی AVD شما نصب و آن را شروع می کند و اگر همه چیز با تنظیمات و اپلیکیشن شما خوب بود، آن پنجره شبیه ساز زیر را نمایش می دهد، لازم است صبر کنید چون ممکن بر اساس سرعت کامپیوتر شما کمی طول بکشد:
حالا بیایید نام دانش آموز و نمره او را وارد کنیم و در نهایت بر روی دکمه Add کلیک کنیم. این کار رکورد دانش آموز را به پایگاه داده اضافه خواهد کرد و سریع یک پیام در پایین URI ارائه دهنده محتوا همراه با شماره رکورد اضافه شده در پایگاه داده نمایش خواهد داد. این عملیات از متد insert() ما استفاده می کند. اجازه دهید این روند عملیات را چند بار تکرار کنیم تا چند دانش آموز دیگر را در پایگاه داده ارائه دهنده محتوا اضافه کنیم.
حالا شما توانسته اید فیلد های جدید اضافه کنید ، بیایید از Content Provider بخواهیم که نتیجه ها را به ما برگرداند ، پس روی دکمه ی Retrive student در برنامه کلیک کنید نتیجه های موجود در پایگاه داده یک به یک به شما نمایش داده خواهند شد در اینجاست که باید به اهمیت متد query() پی ببرید
همان گونه که ما اکتیویتی های افزودن و بازیابی رکورد را پیاده سازی کردیم، شما نیز می توانید اکتیویتی های حذف و به روز رسانی رکورد را پیاده سازی کنید.
همچنین شما با همین روش می توانید از ارائه دهنده های موجود محتوا، مانند Address Book استفاده کنید یا با به کار گیری مفاهیم ارائه دهنده ی محتوا یک پایگاه داده مطلوب بسازید و با استفاده از تمام عملیات های قابل اجرا روی یک پایگاه داده مانند خواندن و نوشتن، یک نرم افزار پویا ایجاد کنید.