یک مؤلفه Content Providerها، دادههای یک برنامه را در صورت درخواست به برنامههای دیگر ارائه میکند. چنین درخواست هایی توسط متدهای کلاس ContentResolver رسیدگی می شود. یک Content Provider میتواند از روشهای مختلفی برای ذخیره دادههای خود استفاده کند و دادهها را میتوان در یک پایگاه داده، در فایلها یا حتی از طریق شبکه ذخیره کرد.
گاهی اوقات لازم است داده ها را در بین برنامه ها به اشتراک بگذارید. اینجاست که Content Providerها بسیار مفید می شوند.
Content Providerها به شما این امکان را می دهند که محتوا را در یک مکان متمرکز کنید و برنامه های مختلفی در صورت نیاز به آن دسترسی داشته باشند. یک Content Providers بسیار شبیه به یک پایگاه داده عمل میکند که میتوانید آن را جستجو کنید، محتوای آن را ویرایش کنید، و همچنین با استفاده از متدهای insert()، update()، delete() و query() محتوا را اضافه یا حذف کنید. در بیشتر موارد این داده ها در پایگاه داده SQlite ذخیره می شوند.
یک Content Providers بهعنوان یک زیر کلاس از کلاس ContentProvider پیادهسازی میشود و باید مجموعه استانداردی از APIها را پیادهسازی کند که سایر برنامهها را قادر به انجام تراکنشها کند.
public class My Application extends ContentProvider { }
Content URIs
برای جستجو در یک Content Provider، متن جستجو را به شکل یک URI مشخص می کنید که فرمت زیر را دارد:
<prefix>://<authority>/<data_type>/<id>
در ادامه جزئیات بخش های مختلف URI را آورده ایم :
قسمت و توضیحات | ردیف |
prefix
این همیشه روی content:// تنظیم شده است. |
1 |
authority
این نام Content Provider، برای مثال مخاطبین، مرورگر و غیره را مشخص میکند. برای Content Providerها شخص ثالث، این نام میتواند نام کاملاً واجد شرایط باشد، مانند com.7cloner.statusprovider |
2 |
data_type
این نشان دهنده نوع داده ای است که این Provider خاص ارائه می دهد. برای مثال، اگر همه مخاطبین را از Content Provider مخاطبین دریافت میکنید، مسیر داده افراد خواهد بود و URI شبیه به thiscontent://contacts/people خواهد بود. |
3 |
id
این رکورد خاص درخواست شده را مشخص می کند. به عنوان مثال، اگر به دنبال شماره تماس 5 در Content Provider مخاطبین هستید، URI شبیه به این شکل است: content://contacts/people/5 |
4 |
ایجاد Content Provider
این کار شامل چندین مرحله ساده برای ایجاد Content Provider است.
- اول از همه باید یک کلاس Content Provider ایجاد کنید که کلاس پایه ContentProvider را ارث بری کرده است.
- دوم، شما باید آدرس URI ارائه دهنده محتوای خود را که برای دسترسی به محتوا استفاده می شود، تعریف کنید.
- در مرحله بعد باید پایگاه داده خود را برای حفظ محتوا ایجاد کنید. معمولاً اندروید از پایگاه داده SQLite استفاده می کند و فریمورک باید متد onCreate() را override کند که بتواند از متدهای SQLite Open Helper برای ایجاد یا باز کردن پایگاه داده Provider استفاده کند. هنگامی که برنامه شما راه اندازی می شود، کنترل کننده, متد ()onCreate هر یک از ContentProviderها را در Thread اصلی برنامه فراخوانی می کند.
- حالا باید queryهای Content Provider را برای انجام عملیات های مختلف دیتابیس خاص طراحی کنید.
- در نهایت با استفاده از تگ <provider>، میتوانید ContentProvider خود را در فایل اکتیویتی خود ثبت کنید.
در اینجا لیستی از متدهایی که باید در کلاس Content Provider بازنویسی (override) کنید تا Content Provider شما کار کند:
- onCreate() این متد زمانی فراخوانی می شود که Provider راه اندازی شود.
- query() این متد یک درخواست از مشتری دریافت می کند. نتیجه به عنوان یک شی Cursor است.
- insert() این متد یک رکورد جدید را در Content Provider وارد می کند.
- delete() این متد یک رکورد موجود را از Content Provider حذف می کند.
- update() این متد یک رکورد موجود را از Content Provider بروزرسانی می کند.
- getType() این متد نوع MIME دادها را در URI اعلامی برمی گرداند.
مثال
این مثال کامل نشان میدهد که چگونه ContentProvider خود را ایجاد کنیم. برای انجام اینکار مراحل زیر را دنبال کنید و اقدام به اجرای برنامه کنید :
توضیحات | ردیف |
یک پروژه جدید با پکیج نیم دلخواه در اندروید استودیو ایجاد کنید. | 1 |
کدهای فایل MainActivity.java را مطابق کدهای زیر تغییر بدهید. | 2 |
یک فایل جدید بنام StudentsProvider.java ایجاد کنید و کدهای آن را مطابق کدهایی زیر تغییر بدهید. | 3 |
با استفاده از تگ <provider…/>، کلاس ContentProvider خود را در فایل AndroidManifest.xml خود ثبت کنید. | 4 |
کد های فایل activity_main.xml را مطابق کدهای زیر تغییر بدهید. | 5 |
برنامه خود را میتوانید روی یک شبیه ساز و تلفن واقعی تست کنید. | 6 |
فایل MainActivity.java
package com.foray.articlelib; import android.annotation.SuppressLint; import android.content.ContentValues; import android.database.Cursor; import android.net.Uri; import android.os.Bundle; import android.util.Log; import android.view.View; import android.widget.EditText; import android.widget.Toast; import androidx.appcompat.app.AppCompatActivity; public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); } public void onClickAddName(View view) { // ایجاد یک رکورد دانش آموز جدید try { 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(); }catch (Exception e){ Log.e("7cloner", e.getMessage()); } } @SuppressLint("Range") public void onClickRetrieveStudents(View view) { // بازیابی یک دانش آموز String URL = "content://com.foray.articlelib.StudentsProvider"; Uri students = Uri.parse(URL); Cursor c = getContentResolver().query(students, null, null, null, null); if (c.moveToFirst()) { do{ String data = c.getString(c.getColumnIndex(StudentsProvider._ID)) + ", " + c.getString(c.getColumnIndex( StudentsProvider.NAME)) + ", " + c.getString(c.getColumnIndex( StudentsProvider.GRADE)); Toast.makeText(this, data, Toast.LENGTH_SHORT).show(); ((EditText)findViewById(R.id.editText)).setText(data); } while (c.moveToNext()); } c.close(); } }
کلاس StudentsProvider.java
package com.foray.articlelib; 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 java.util.HashMap; public class StudentsProvider extends ContentProvider { static final String PROVIDER_NAME = "com.foray.articlelib.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); } /** * اعلان های ثابت خاص پایگاه داده */ private SQLiteDatabase db; static final String DATABASE_NAME = "College"; static final String STUDENTS_TABLE_NAME = "students"; static final int DATABASE_VERSION = 1; static final String CREATE_DB_TABLE = " CREATE TABLE " + STUDENTS_TABLE_NAME + " (_id INTEGER PRIMARY KEY AUTOINCREMENT, " + " name TEXT NOT NULL, " + " grade TEXT NOT NULL);"; /** * کلاس کمکی که در واقع ایجاد و مدیریت می کند * مخزن داده های اساسی ارائه دهنده. */ private static class DatabaseHelper extends SQLiteOpenHelper { DatabaseHelper(Context context){ super(context, DATABASE_NAME, null, DATABASE_VERSION); } @Override public void onCreate(SQLiteDatabase db) { db.execSQL(CREATE_DB_TABLE); } @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { db.execSQL("DROP TABLE IF EXISTS " + STUDENTS_TABLE_NAME); onCreate(db); } } @Override public boolean onCreate() { Context context = getContext(); DatabaseHelper dbHelper = new DatabaseHelper(context); /** * یک پایگاه داده قادر به نوشتن ایجاد کنید که آن را فعال کند * ایجاد اگر از قبل وجود نداشته باشد. */ db = dbHelper.getWritableDatabase(); return (db == null)? false:true; } @Override public Uri insert(Uri uri, ContentValues values) { /** * ایجاد یک دانش آموز جدید */ long rowID = db.insert( STUDENTS_TABLE_NAME, "", values); /** * اگر رکورد با موفقیت اضافه شود */ if (rowID > 0) { Uri _uri = ContentUris.withAppendedId(CONTENT_URI, rowID); getContext().getContentResolver().notifyChange(_uri, null); return _uri; } throw new SQLException("خطا در اضافه کردن رکورد : " + 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 == ""){ /** * به طور پیش فرض نام دانش آموزان را مرتب کنید */ sortOrder = NAME; } Cursor c = qb.query(db, projection, selection, selectionArgs,null, null, sortOrder); /** * برای مشاهده URI محتوا برای تغییرات ثبت نام کنید */ 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("ناشناس 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("ناشناس URI " + uri ); } getContext().getContentResolver().notifyChange(uri, null); return count; } @Override public String getType(Uri uri) { switch (uriMatcher.match(uri)){ /** * دریافت تمامی رکورد های دانش آموزان */ case STUDENTS: return "vnd.android.cursor.dir/vnd.example.students"; /** * دریافت یک دانش آموزش خاص */ case STUDENT_ID: return "vnd.android.cursor.item/vnd.example.students"; default: throw new IllegalArgumentException("پشتیبانی نمی شود URI: " + uri); } } }
گرافیک فایل activity_main.xml
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:padding="32dp"> <TextView android:id="@+id/textView1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentTop="true" android:layout_centerHorizontal="true" android:text="Content provider" android:textSize="30dp" /> <TextView android:id="@+id/textView2" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_below="@+id/textView1" android:layout_centerHorizontal="true" android:text="7Cloner.com" android:textColor="#009688" android:textSize="30dp" /> <ImageView android:layout_width="wrap_content" android:layout_height="150dp" android:id="@+id/imageButton" android:src="@drawable/abc" android:layout_below="@+id/textView2" android:layout_centerHorizontal="true" /> <EditText android:id="@+id/editText" android:layout_width="wrap_content" android:layout_height="wrap_content" android:enabled="false" android:layout_below="@id/imageButton" android:layout_alignStart="@id/imageButton" android:layout_alignEnd="@id/imageButton" /> <EditText android:id="@+id/editText2" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_below="@id/editText" android:layout_alignStart="@id/editText" android:layout_alignEnd="@id/editText" android:hint="نام" 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/editText2" android:layout_alignStart="@id/editText2" android:layout_alignEnd="@id/editText2" android:hint="مقطع تحصیلی" android:textColorHint="@android:color/holo_blue_bright" /> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/button2" android:text="افزودن دانش آموز" android:layout_below="@+id/editText3" android:layout_alignEnd="@+id/editText3" android:layout_alignStart="@+id/editText3" android:onClick="onClickAddName"/> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="بازیابی دانش آموز" android:id="@+id/button" android:layout_below="@+id/button2" android:layout_alignEnd="@+id/button2" android:layout_alignStart="@+id/button2" android:onClick="onClickRetrieveStudents"/> </RelativeLayout>
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.foray.articlelib"> <uses-permission android:name="android.permission.CAMERA" /> <application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/Theme.ArticleLib"> <activity android:name=".MainActivity" android:exported="true"> <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.foray.articlelib.StudentsProvider" android:exported="false" /> </application> </manifest>
سر آخر بعد از ثبت تمامی تغییرات بالا میتوانید برنامه را اجرا کنید و نتیجه به این صورت خواهد بود :
در تصویر بالا میتوانید نتیجه کار را ببینید و حالا هر برنامه ای با اجرا دستور بازیابی میتواند اطلاعات مربوط به یک یا چند دانش آموز را از برنامه شما دریافت کند.