صفحه اصلی » پایگاه دانش » برنامه نویسی اندروید » مقدمات » آموزش تامین کنندگان محتوا (Content Providers )در اندروید

فهرست آموزش برنامه نویسی اندروید

آموزش تامین کنندگان محتوا (Content Providers )در اندروید

۱۳۹۸/۰۸/۱۹ ۵۲

تامین کنندگان محتوا در اندروید (Android Content Providers )

یک مولفه تامین کننده­  محتوا (content providers)، در صورت درخواست، داده های یک اپلیکیشن را به سایر اپلیکیشن ها ارائه می دهد. این درخواست ها به وسیله­ ی متدهایی از کلاس ContentResolver مدیریت می شوند. یک تامین کننده­ محتوا می تواند از روش های مختلفی برای ذخیره­ داده های خود استفاده کند و داده می تواند در یک پایگاه داده، در فایل ها یا حتی بر روی یک شبکه ذخیره شود.

هر اپلیکیشن اندرویدی فرایندهای خود را با مجوز های مربوط به خودش اجرا می کند. این کار باعث میشود که داده های یک اپلیکیشن از سایر اپلیکیشن ها پنهان باشد. ولی گاهی اوقات لازم است که داده ای در بین اپلیکیشن ها به اشتراک گذاشته شود. اینجا جایی است که تامین کنندگان محتوا بسیار مفید واقع می شوند.

تامین کنندگان محتوا به شما اجازه می دهند که محتوای مورد نیاز را در یک جا متمرکز کنید و اپلیکیشن های بسیاری بتوانند در صورت نیاز به آن دسترسی داشته باشند. رفتار یک تامین کننده­ محتوا بسیار شبیه به یک پایگاه داده است که شما می توانید با استفاده از متدهای query()،update() ، insert() و delete() بر روی آن پرس و جو ایجاد کنید، محتوای آن را ویرایش کنید و همچنین محتوای آن را اضافه یا حذف کنید. در بسیاری از موارد این داده در یک پایگاه داده­ SQlite ذخیره می شود.

یک تامین کننده­ محتوا به صورت یک زیر کلاس از کلاس ContentProvider پیاده سازی می شود و باید مجموعه­ ی استانداردی از API ها را پیاده سازی کند که سایر اپلیکیشن ها را قادر به اجرای تراکنش ها می کند.

public class My Application extends  ContentProvider {
}

URI های محتوا

برای ارسال پرس و جو به یک تامین کننده ­ محتوا، شما باید رشته­  پرس و جو را به صورت یک URI با فرمت زیر، مشخص کنید.
<prefix>://<authority>/<data_type>/<id>

در اینجا جزئیات بخش های مختلف URI ارائه شده است .

Prefix (پیشوند) این بخش همیشه به صورت content:// تنظیم می شود.
Authority (منبع) این بخش نام تامین کننده­ی محتوا را تعیین می­کند. برای مثال contacts، browser و غیره. برای تامین کنندگان محتوای شخص ثالث، این بخش می تواند به صورت یک نام کاملا توصیفی مانند com.tutorialspoint.statusprovider باشد.
data_type (نوع داده) یک فایل جاوای جدیداین بخش نشان دهنده­ی نوع داده ای است که این تامین کننده­ی محتوای خاص ایجاد میکند. برای مثال، اگر شما همه­ی شماره تماس ها را از تامین کننده محتوای Contacts دریافت کنید، آنگاه مسیر داده people خواهد بود و URI آن شبیه به این خواهد بود: content://contacts/people
id (شناسه) این بخش رکورد خاص مورد تقاضا را مشخص می کند. برای مثال، اگر شما شماره تماس نفر ۵ ام را از تامین کننده محتوا درخواست کنید، آنگاه 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 دنبال کنیم.

مرحله توصیف
۱ از Eclipse IDE برای ایجاد یک اپلیکیشن اندرویدی استفاده کنید و آن را ، تحت پکیج com.example.mycontentprovider همراه با یک فعالیت خالی، MyContentProvider بنامید.
۲ این بخش نام تامین کننده­ محتوا را تعیین می­کند. برای مثال فایل فعالیت اصلی MainActivity.java را برای اضافه کردن متدهای جدید onClickAddName() و onClickRetrieveStudents() تغییر دهید.
۳ برای تعریف تامین کننده­ و متدهای مربوط به آن، یک فایل جاوای جدید به نام StudentsProvider.java تحت پکیج com.example.mycontentprovider ایجاد کنید.
۴ این بخش رکورد خاص مورد تقاضا را مشخص می کند. برای مثال، اگر شما شماره تماس نفر ۵ ام را از تامین کننده محتوا درخواست کنید، آنگاه تامین کننده­ محتوای خود را با استفاده از تگ در فایل AndroidManifest.xml پروژه تان ثبت کنید.
۵ این بخش رکورد خاص مورد تقاضا را مشخص می کند. برای مثال، اگر شما شماره تماس نفر ۵ ام را از تامین کننده محتوا درخواست کنید، آنگاه محتوای پیش فرض فایل res/layout/activity_main.xml را برای وارد کردن یک واسط کاربری کوچک برای اضافه کردن رکودهای مربوط به دانش آموزان، تغییر دهید.
۶ ثابت های مورد نیاز را در فایل res/values/strings.xml تعریف کنید.
۷ برای راه اندازی امولاتور اندروید اپلیکیشن را اجرا کنید و نتایج تغییرات اعمال شده در اپلیکیشن را بررسی کنید.

در بخش زیر محتوای تغییر یافته­ ی فایل فعالیت اصلی

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() پیاده سازی کردیم، انجام می شود.

 

دانشجویار نماد اعتماد به دانشجویار مجوز نشر دیجیتال لوگو شرکت به پرداخت ملت logo-samandehi مجوز سازمان فنی حرفه ای کشور
blackFriday

پیش از شروع جشنواره بلک فرایدی
خودت رو برای یک خرید برق آسا آماده کن!


بلک فرایدی!

برای شرکت در جشنواره بلک فرایدی لطفا ثبت نام کنید.

  از الان برای بلک فرایدی آماده شو - رزرو تخفیف 90% ، برای همه آموزش ها  صفحه جشنواره