Android Kotlin Fundamentals 06.1: ایجاد پایگاه داده اتاق، Android Kotlin Fundamentals 06.1: ایجاد پایگاه داده اتاق

این کد لبه بخشی از دوره آموزشی Android Kotlin Fundamentals است. اگر به ترتیب روی کدها کار کنید، بیشترین ارزش را از این دوره خواهید گرفت. همه کد لبه های دوره در صفحه فرود کد لبه های Android Kotlin Fundamentals فهرست شده اند.

مقدمه

بیشتر برنامه‌ها داده‌هایی دارند که حتی پس از بستن برنامه توسط کاربر، باید حفظ شوند. برای مثال، برنامه ممکن است فهرست پخش، فهرستی از اقلام بازی، سوابق هزینه‌ها و درآمد، فهرستی از صورت‌های فلکی، یا داده‌های خواب را در طول زمان ذخیره کند. معمولاً از یک پایگاه داده برای ذخیره داده های پایدار استفاده می کنید.

Room یک کتابخانه پایگاه داده است که بخشی از Android Jetpack است. Room بسیاری از کارهای راه اندازی و پیکربندی یک پایگاه داده را بر عهده می گیرد و این امکان را برای برنامه شما فراهم می کند تا با استفاده از فراخوانی های تابع معمولی با پایگاه داده تعامل داشته باشد. در زیر هود، Room یک لایه انتزاعی در بالای پایگاه داده SQLite است. اصطلاحات Room ، و نحو پرس و جو برای پرس و جوهای پیچیده تر، از مدل SQLite پیروی می کنند.

تصویر زیر نشان می دهد که چگونه پایگاه داده Room با معماری کلی توصیه شده در این دوره مطابقت دارد.

آنچه از قبل باید بدانید

شما باید با این موارد آشنا باشید:

  • ساخت یک رابط کاربری اولیه (UI) برای یک برنامه اندروید
  • استفاده از فعالیت ها، قطعات و نماها.
  • پیمایش بین قطعات و استفاده از Safe Args (یک افزونه Gradle) برای انتقال داده ها بین قطعات.
  • مدل‌ها، کارخانه‌های مشاهده مدل، و LiveData و ناظران آن را مشاهده کنید. این مباحث مولفه های معماری در یک کدآلب قبلی در این دوره پوشش داده شده است.
  • درک اولیه از پایگاه داده SQL و زبان SQLite. برای یک مرور کلی یا تازه‌سازی به SQLite Primer مراجعه کنید.

چیزی که یاد خواهید گرفت

  • نحوه ایجاد و تعامل با پایگاه داده Room برای ماندگاری داده ها.
  • نحوه ایجاد یک کلاس داده که یک جدول را در پایگاه داده تعریف می کند.
  • نحوه استفاده از یک شی دسترسی به داده (DAO) برای نگاشت توابع Kotlin به پرس و جوهای SQL.
  • چگونه آزمایش کنیم که آیا پایگاه داده شما کار می کند یا خیر.

کاری که خواهی کرد

  • یک پایگاه داده Room با یک رابط برای داده های خواب شبانه ایجاد کنید.
  • پایگاه داده را با استفاده از تست های ارائه شده تست کنید.

در این نرم افزار کد، بخش پایگاه داده یک برنامه را می سازید که کیفیت خواب را ردیابی می کند. این برنامه از یک پایگاه داده برای ذخیره داده های خواب در طول زمان استفاده می کند.

این برنامه دارای دو صفحه است که با قطعات نشان داده شده است، همانطور که در شکل زیر نشان داده شده است.

اولین صفحه نمایش داده شده در سمت چپ دارای دکمه هایی برای شروع و توقف ردیابی است. صفحه نمایش تمام داده های خواب کاربر را نشان می دهد. دکمه Clear تمام داده هایی را که برنامه برای کاربر جمع آوری کرده است برای همیشه حذف می کند.

صفحه دوم، نشان داده شده در سمت راست، برای انتخاب رتبه بندی کیفیت خواب است. در برنامه، امتیاز به صورت عددی نشان داده می شود. برای اهداف توسعه، برنامه هم نمادهای چهره و هم معادل های عددی آنها را نشان می دهد.

جریان کاربر به شرح زیر است:

  • کاربر برنامه را باز می کند و با صفحه ردیابی خواب نمایش داده می شود.
  • کاربر روی دکمه Start ضربه می زند. این زمان شروع را ثبت کرده و نمایش می دهد. دکمه Start غیرفعال است و دکمه Stop فعال است.
  • کاربر روی دکمه Stop ضربه می زند. این کار زمان پایان را ثبت می کند و صفحه با کیفیت خواب را باز می کند.
  • کاربر یک نماد کیفیت خواب را انتخاب می کند. صفحه بسته می شود و صفحه ردیابی زمان پایان خواب و کیفیت خواب را نشان می دهد. دکمه Stop غیرفعال و دکمه Start فعال است. برنامه برای یک شب دیگر آماده است.
  • دکمه Clear هر زمان که داده ای در پایگاه داده وجود داشته باشد فعال می شود. هنگامی که کاربر روی دکمه Clear ضربه می‌زند، تمام داده‌های او بدون مراجعه پاک می‌شوند - "آیا مطمئن هستید؟" وجود ندارد. پیام

این برنامه از معماری ساده شده استفاده می کند، همانطور که در زیر در زمینه معماری کامل نشان داده شده است. این برنامه فقط از اجزای زیر استفاده می کند:

  • کنترلر رابط کاربری
  • مشاهده مدل و LiveData
  • پایگاه داده اتاق

مرحله 1: برنامه شروع را دانلود و اجرا کنید

  1. برنامه TrackMySleepQuality-Starter را از GitHub دانلود کنید.
  2. برنامه را بسازید و اجرا کنید. برنامه رابط کاربری بخش SleepTrackerFragment را نشان می دهد، اما داده ای ندارد. دکمه ها به ضربه ها پاسخ نمی دهند.

مرحله 2: برنامه شروع را بررسی کنید

  1. به فایل های Gradle نگاهی بیندازید:
  • فایل پروژه Gradle
    در فایل build.gradle در سطح پروژه، به متغیرهایی که نسخه های کتابخانه را مشخص می کنند توجه کنید. نسخه های استفاده شده در برنامه استارتر به خوبی با هم کار می کنند و با این برنامه به خوبی کار می کنند. تا زمانی که این کد لبه را تمام کنید، ممکن است Android Studio از شما بخواهد که برخی از نسخه ها را به روز کنید. این به شما بستگی دارد که آیا می خواهید نسخه های موجود در برنامه را به روز کنید یا از آن استفاده کنید. اگر با خطاهای کامپایل "عجیب" مواجه شدید، سعی کنید از ترکیب نسخه های کتابخانه ای که برنامه راه حل نهایی استفاده می کند استفاده کنید.
  • فایل ماژول Gradle. به وابستگی‌های ارائه‌شده برای همه کتابخانه‌های Android Jetpack، از جمله Room ، و وابستگی‌های کوروتین‌ها توجه کنید.
  1. به بسته ها و UI نگاهی بیندازید. برنامه بر اساس عملکرد ساختار یافته است. این بسته حاوی فایل‌های نگهدارنده است که در آن کد را در این سری از کدها اضافه خواهید کرد.
  • بسته database ، برای همه کدهای مربوط به پایگاه داده Room .
  • بسته‌های sleepquality و sleeptracker شامل قطعه، مدل view و کارخانه مدل view برای هر صفحه هستند .
  1. به فایل Util.kt نگاهی بیندازید، که حاوی توابعی برای کمک به نمایش داده های با کیفیت خواب است. برخی از کدها به دلیل ارجاع به یک مدل view که بعداً ایجاد می کنید، توضیح داده می شود.
  2. به پوشه androidTest ( SleepDatabaseTest.kt ) نگاهی بیندازید. شما از این تست برای بررسی اینکه پایگاه داده طبق برنامه کار می کند استفاده خواهید کرد.

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

  • یک موجودیت یک شی یا مفهوم و خصوصیات آن را برای ذخیره در پایگاه داده نشان می دهد. یک کلاس موجودیت یک جدول را تعریف می کند و هر نمونه از آن کلاس نشان دهنده یک ردیف در جدول است. هر ویژگی یک ستون را تعریف می کند. در برنامه شما، نهاد اطلاعاتی در مورد یک شب خواب نگه می دارد.
  • پرس و جو درخواست داده یا اطلاعات از جدول پایگاه داده یا ترکیبی از جداول یا درخواستی برای انجام عملی بر روی داده است. پرس و جوهای رایج برای دریافت، درج و به روز رسانی موجودیت ها هستند. برای مثال، می‌توانید برای تمام شب‌های خواب ثبت شده، مرتب‌سازی‌شده بر اساس زمان شروع، پرس و جو کنید.

Room همه کار سختی را برای شما انجام می دهد تا از کلاس های داده Kotlin به موجودیت هایی که می توانند در جداول SQLite ذخیره شوند و از اعلان های تابع تا پرس و جوهای SQL را به دست آورید.

شما باید هر موجودیت را به عنوان یک کلاس داده مشروح، و تعاملات را به عنوان یک رابط مشروح شده، یک شی دسترسی به داده (DAO) تعریف کنید. Room از این کلاس های حاشیه نویسی برای ایجاد جداول در پایگاه داده و پرس و جوهایی که روی پایگاه داده عمل می کنند استفاده می کند.

مرحله 1: موجودیت SleepNight را ایجاد کنید

در این کار، یک شب خواب را به عنوان یک کلاس داده مشروح تعریف می کنید.

برای یک شب خواب، باید زمان شروع، زمان پایان و رتبه بندی کیفیت را ثبت کنید.

و برای شناسایی منحصر به فرد شب به یک شناسه نیاز دارید.

  1. در بسته database ، فایل SleepNight.kt را پیدا کرده و باز کنید.
  2. کلاس داده SleepNight را با پارامترهایی برای شناسه، زمان شروع (بر حسب میلی ثانیه)، زمان پایان (بر حسب میلی ثانیه) و رتبه بندی عددی کیفیت خواب ایجاد کنید.
  • شما باید sleepQuality را مقداردهی اولیه کنید، بنابراین آن را روی -1 تنظیم کنید، که نشان می دهد هیچ داده با کیفیتی جمع آوری نشده است.
  • شما همچنین باید زمان پایان را مقداردهی اولیه کنید. آن را روی زمان شروع تنظیم کنید تا نشان دهد که هنوز زمان پایانی ثبت نشده است.
data class SleepNight(
       var nightId: Long = 0L,
       val startTimeMilli: Long = System.currentTimeMillis(),
       var endTimeMilli: Long = startTimeMilli,
       var sleepQuality: Int = -1
)
  1. قبل از اعلان کلاس، کلاس داده را با @Entity حاشیه نویسی کنید. نام جدول را daily_sleep_quality_table بگذارید. آرگومان tableName اختیاری است، اما توصیه می شود. می توانید سایر استدلال ها را در مستندات جستجو کنید.

    در صورت درخواست، Entity و تمام حاشیه نویسی های دیگر را از کتابخانه androidx وارد کنید.
@Entity(tableName = "daily_sleep_quality_table")
data class SleepNight(...)
  1. برای شناسایی nightId به عنوان کلید اصلی، ویژگی nightId را با @PrimaryKey حاشیه نویسی کنید. پارامتر autoGenerate روی true تنظیم کنید تا Room برای هر موجودیت شناسه تولید کند. این تضمین می کند که شناسه هر شب منحصر به فرد است.
@PrimaryKey(autoGenerate = true)
var nightId: Long = 0L,...
  1. ویژگی های باقی مانده را با @ColumnInfo حاشیه نویسی کنید. مطابق شکل زیر نام ویژگی ها را با استفاده از پارامترها سفارشی کنید.
import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.PrimaryKey

@Entity(tableName = "daily_sleep_quality_table")
data class SleepNight(
       @PrimaryKey(autoGenerate = true)
       var nightId: Long = 0L,

       @ColumnInfo(name = "start_time_milli")
       val startTimeMilli: Long = System.currentTimeMillis(),

       @ColumnInfo(name = "end_time_milli")
       var endTimeMilli: Long = startTimeMilli,

       @ColumnInfo(name = "quality_rating")
       var sleepQuality: Int = -1
)
  1. کد خود را بسازید و اجرا کنید تا مطمئن شوید که هیچ خطایی ندارد.

در این کار، یک شی دسترسی به داده (DAO) را تعریف می کنید. در اندروید، DAO روش‌های آسانی را برای درج، حذف و به‌روزرسانی پایگاه داده ارائه می‌کند.

هنگامی که از پایگاه داده Room استفاده می کنید، با تعریف و فراخوانی توابع Kotlin در کد خود، پایگاه داده را پرس و جو می کنید. این توابع Kotlin به پرس و جوهای SQL نگاشت می شوند. شما آن نگاشتها را در یک DAO با استفاده از حاشیه نویسی تعریف می کنید و Room کد لازم را ایجاد می کند.

یک DAO را به عنوان تعریف یک رابط سفارشی برای دسترسی به پایگاه داده خود در نظر بگیرید.

برای عملیات رایج پایگاه داده، کتابخانه Room حاشیه نویسی های راحت را ارائه می دهد، مانند @Insert ، @Delete و @Update . برای هر چیز دیگری، حاشیه نویسی @Query وجود دارد. می توانید هر درخواستی را که توسط SQLite پشتیبانی می شود بنویسید.

به عنوان یک امتیاز اضافی، هنگامی که پرس و جوهای خود را در Android Studio ایجاد می کنید، کامپایلر پرس و جوهای SQL شما را برای خطاهای نحوی بررسی می کند.

برای پایگاه داده ردیاب خواب شب‌های خواب، باید بتوانید کارهای زیر را انجام دهید:

  • درج شب های جدید
  • برای به‌روزرسانی زمان پایان و رتبه‌بندی کیفیت، یک شب موجود را به‌روزرسانی کنید .
  • یک شب خاص بر اساس کلید آن دریافت کنید .
  • تمام شب ها را دریافت کنید تا بتوانید آنها را نمایش دهید.
  • آخرین شب را دریافت کنید.
  • تمام ورودی های پایگاه داده را حذف کنید .

مرحله 1: SleepDatabase DAO را ایجاد کنید

  1. در بسته database ، SleepDatabaseDao.kt باز کنید.
  2. توجه داشته باشید که interface SleepDatabaseDao با @Dao حاشیه نویسی شده است. همه DAO ها باید با کلمه کلیدی @Dao حاشیه نویسی شوند.
@Dao
interface SleepDatabaseDao {}
  1. در داخل بدنه رابط، یک حاشیه نویسی @Insert اضافه کنید. در زیر @Insert ، یک تابع insert() اضافه کنید که نمونه ای از کلاس Entity SleepNight را می گیرد. به عنوان استدلال آن

    همین است. Room همه کدهای لازم را برای درج SleepNight در پایگاه داده تولید می کند. هنگامی که insert() از کد Kotlin خود فرا می خوانید، Room یک پرس و جوی SQL را برای درج موجودیت در پایگاه داده اجرا می کند. (توجه: می توانید تابع را هر چیزی که می خواهید فراخوانی کنید.)
@Insert
fun insert(night: SleepNight)
  1. برای یک SleepNight یک حاشیه نویسی @Update با یک تابع update() اضافه کنید. نهادی که به‌روزرسانی می‌شود، نهادی است که دارای کلید مشابهی است که به آن ارسال شده است. می‌توانید برخی یا همه ویژگی‌های دیگر آن نهاد را به‌روزرسانی کنید.
@Update
fun update(night: SleepNight)

هیچ حاشیه نویسی راحتی برای عملکرد باقی مانده وجود ندارد، بنابراین باید از حاشیه نویسی @Query استفاده کنید و پرس و جوهای SQLite را تهیه کنید.

  1. یک حاشیه نویسی @Query با تابع get() اضافه کنید که یک key Long می گیرد آرگومان و یک SleepNight قابل تهی را برمی گرداند. خطای یک پارامتر از دست رفته را خواهید دید.
@Query
fun get(key: Long): SleepNight?
  1. پرس و جو به عنوان پارامتر رشته ای به حاشیه نویسی ارائه می شود. یک پارامتر به @Query اضافه کنید. آن را به String تبدیل کنید که یک کوئری SQLite است.
  • همه ستون ها را از جدول daily_sleep_quality_table انتخاب کنید
  • WHERE nightId با آرگومان key : مطابقت دارد.

    به :key توجه کنید. برای ارجاع آرگومان های تابع از علامت دو نقطه در پرس و جو استفاده می کنید.
("SELECT * from daily_sleep_quality_table WHERE nightId = :key")
  1. یک @Query دیگر با یک تابع clear() و یک جستجوی SQLite اضافه کنید تا همه چیز را از daily_sleep_quality_table DELETE . این پرس و جو خود جدول را حذف نمی کند.

    حاشیه‌نویسی @Delete یک مورد را حذف می‌کند و می‌توانید از @Delete استفاده کنید و فهرستی از شب‌ها را برای حذف ارائه دهید. اشکال این است که شما باید آنچه را در جدول وجود دارد واکشی کنید یا بدانید. حاشیه‌نویسی @Delete برای حذف ورودی‌های خاص عالی است، اما برای پاک کردن همه ورودی‌های یک جدول کارآمد نیست.
@Query("DELETE FROM daily_sleep_quality_table")
fun clear()
  1. یک @Query با تابع getTonight() اضافه کنید. SleepNight را که توسط getTonight() برگردانده شده است تهی کنید تا تابع بتواند مواردی را که جدول خالی است کنترل کند. (جدول در ابتدا و پس از پاک شدن داده ها خالی است.)

    برای دریافت "tonight" از پایگاه داده، یک پرس و جوی SQLite بنویسید که اولین عنصر لیستی از نتایج را که بر اساس nightId مرتب شده اند به ترتیب نزولی برمی گرداند. از LIMIT 1 برای برگرداندن تنها یک عنصر استفاده کنید.
@Query("SELECT * FROM daily_sleep_quality_table ORDER BY nightId DESC LIMIT 1")
fun getTonight(): SleepNight?
  1. یک @Query با تابع getAllNights() اضافه کنید:
  • از پرس و جوی SQLite بخواهید همه ستون ها را از daily_sleep_quality_table به ترتیب نزولی برگرداند.
  • از getAllNights() لیستی از موجودیت های SleepNight را به عنوان LiveData بازگردانید. Room این LiveData را برای شما به‌روز نگه می‌دارد، به این معنی که فقط یک بار باید صریحاً داده‌ها را دریافت کنید.
  • ممکن است لازم باشد LiveData از androidx.lifecycle.LiveData وارد کنید.
@Query("SELECT * FROM daily_sleep_quality_table ORDER BY nightId DESC")
fun getAllNights(): LiveData<List<SleepNight>>
  1. اگرچه هیچ تغییر قابل مشاهده ای نمی بینید، برنامه خود را اجرا کنید تا مطمئن شوید که هیچ خطایی ندارد.

در این کار، شما یک پایگاه داده Room ایجاد می کنید که از Entity و DAO که در کار قبلی ایجاد کرده اید استفاده می کند.

شما باید یک کلاس دارنده پایگاه داده انتزاعی ایجاد کنید که با @Database حاشیه نویسی شده باشد. این کلاس یک متد دارد که اگر پایگاه داده وجود نداشته باشد نمونه ای از پایگاه داده را ایجاد می کند یا یک مرجع به پایگاه داده موجود برمی گرداند.

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

  • یک کلاس public abstract ایجاد کنید که extends RoomDatabase . این کلاس به عنوان دارنده پایگاه داده عمل می کند. کلاس انتزاعی است، زیرا Room پیاده سازی را برای شما ایجاد می کند.
  • کلاس را با @Database حاشیه نویسی کنید. در آرگومان ها، موجودیت های پایگاه داده را اعلام کرده و شماره نسخه را تنظیم کنید.
  • در داخل یک شی companion ، یک متد یا ویژگی انتزاعی تعریف کنید که یک SleepDatabaseDao برمی گرداند. Room برای شما بدن تولید می کند.
  • شما فقط به یک نمونه از پایگاه داده Room برای کل برنامه نیاز دارید، بنابراین RoomDatabase یک تکتونه کنید.
  • تنها در صورتی که پایگاه داده وجود نداشته باشد، از سازنده پایگاه داده Room برای ایجاد پایگاه داده استفاده کنید. در غیر این صورت، پایگاه داده موجود را برگردانید.

مرحله 1: ایجاد پایگاه داده

  1. در بسته database ، SleepDatabase.kt باز کنید.
  2. در فایل، یک کلاس abstract به نام SleepDatabase ایجاد کنید که RoomDatabase گسترش می دهد.

    کلاس را با @Database حاشیه نویسی کنید.
@Database()
abstract class SleepDatabase : RoomDatabase() {}
  1. خطای موجودیت ها و پارامترهای نسخه را مشاهده خواهید کرد. حاشیه نویسی @Database به چندین آرگومان نیاز دارد تا Room بتواند پایگاه داده را بسازد.
  • SleepNight به عنوان تنها مورد با لیست entities عرضه کنید.
  • version را به عنوان 1 تنظیم کنید . هر زمان که شما طرح را تغییر دهید، باید شماره نسخه را افزایش دهید.
  • exportSchema روی false قرار دهید تا نسخه پشتیبان‌گیری از تاریخچه نسخه طرحواره حفظ نشود.
entities = [SleepNight::class], version = 1, exportSchema = false
  1. پایگاه داده باید در مورد DAO بداند. در داخل بدنه کلاس، یک مقدار انتزاعی را اعلام کنید که SleepDatabaseDao برمی گرداند. شما می توانید چندین DAO داشته باشید.
abstract val sleepDatabaseDao: SleepDatabaseDao
  1. در زیر آن، یک شیء companion تعریف کنید. شیء companion به مشتریان اجازه می دهد تا بدون نمونه سازی کلاس به متدهای ایجاد یا دریافت پایگاه داده دسترسی داشته باشند. از آنجایی که تنها هدف این کلاس ارائه یک پایگاه داده است، هیچ دلیلی برای نمونه سازی آن وجود ندارد.
 companion object {}
  1. در داخل شی companion ، یک متغیر تهی پذیر خصوصی INSTANCE برای پایگاه داده اعلام کنید و آن را به null مقداردهی کنید. متغیر INSTANCE یک مرجع به پایگاه داده، پس از ایجاد پایگاه داده نگه می دارد. این به شما کمک می کند تا از باز کردن مکرر اتصالات به پایگاه داده جلوگیری کنید که گران است.

INSTANCE با @Volatile حاشیه نویسی کنید. مقدار متغیر فرار هرگز در حافظه پنهان ذخیره نمی شود و تمام نوشتن و خواندن به حافظه اصلی و از آن انجام می شود. این کمک می کند مطمئن شوید که مقدار INSTANCE همیشه به روز است و برای همه رشته های اجرایی یکسان است. این بدان معناست که تغییرات ایجاد شده توسط یک رشته به INSTANCE برای همه رشته‌های دیگر بلافاصله قابل مشاهده است، و شما موقعیتی را دریافت نمی‌کنید که مثلاً دو رشته هر کدام یک موجودیت مشابه را در حافظه پنهان به‌روزرسانی کنند، که مشکل ایجاد می‌کند.

@Volatile
private var INSTANCE: SleepDatabase? = null
  1. در زیر INSTANCE ، هنوز در داخل شیء companion ، یک متد getInstance() با پارامتر Context تعریف کنید که سازنده پایگاه داده به آن نیاز دارد. یک نوع SleepDatabase را برگردانید. یک خطایی خواهید دید زیرا getInstance() هنوز چیزی را بر نمی گرداند.
fun getInstance(context: Context): SleepDatabase {}
  1. داخل getInstance() یک بلوک synchronized{} اضافه کنید. this را پاس کنید تا بتوانید به متن دسترسی داشته باشید.

    چندین رشته به طور بالقوه می توانند به طور همزمان یک نمونه پایگاه داده را درخواست کنند که منجر به ایجاد دو پایگاه داده به جای یک پایگاه داده شود. این مشکل به احتمال زیاد در این نمونه برنامه اتفاق نمی افتد، اما برای یک برنامه پیچیده تر امکان پذیر است. بسته بندی کد برای synchronized پایگاه داده به این معنی است که تنها یک رشته اجرا در هر زمان می تواند وارد این بلوک کد شود، که مطمئن می شود پایگاه داده فقط یک بار مقداردهی اولیه می شود.
synchronized(this) {}
  1. در داخل بلوک همگام‌سازی شده، مقدار فعلی INSTANCE را در یک instance متغیر محلی کپی کنید. این برای استفاده از قابلیت پخش هوشمند است که فقط برای متغیرهای محلی در دسترس است.
var instance = INSTANCE
  1. در داخل بلوک synchronized ، نمونه‌ای را در انتهای بلوک synchronized return instance . خطای عدم تطابق نوع بازگشتی را نادیده بگیرید. پس از اتمام کار هرگز نخواهید برگشت.
return instance
  1. بالای دستور return ، یک دستور if اضافه کنید تا بررسی کنید که آیا instance صفر است یا نه، یعنی هنوز پایگاه داده ای وجود ندارد.
if (instance == null) {}
  1. اگر instance null است، از سازنده پایگاه داده برای دریافت پایگاه داده استفاده کنید. در بدنه دستور if ، Room.databaseBuilder را فراخوانی کنید و متنی را که در آن ارسال کردید، کلاس پایگاه داده و یک نام برای پایگاه داده، sleep_history_database ارائه کنید. برای حذف خطا، باید یک استراتژی مهاجرت و build() در مراحل زیر اضافه کنید.
instance = Room.databaseBuilder(
                           context.applicationContext,
                           SleepDatabase::class.java,
                           "sleep_history_database")
  1. استراتژی مهاجرت مورد نیاز را به سازنده اضافه کنید. .fallbackToDestructiveMigration() استفاده کنید.

    به طور معمول، شما باید یک شی مهاجرت را با یک استراتژی مهاجرت برای زمانی که طرحواره تغییر می کند ارائه دهید. یک شیء مهاجرتی ، شیئی است که تعریف می‌کند چگونه همه ردیف‌ها را با طرحواره قدیمی بگیرید و آنها را به ردیف‌هایی در طرح جدید تبدیل کنید، به طوری که هیچ داده‌ای از بین نرود. مهاجرت فراتر از محدوده این کد آزمایشگاه است. یک راه حل ساده، تخریب و بازسازی پایگاه داده است، به این معنی که داده ها از بین می روند.
.fallbackToDestructiveMigration()
  1. در نهایت، .build() را فراخوانی کنید.
.build()
  1. INSTANCE = instance به عنوان مرحله نهایی داخل دستور if اختصاص دهید.
INSTANCE = instance
  1. کد نهایی شما باید به شکل زیر باشد:
@Database(entities = [SleepNight::class], version = 1, exportSchema = false)
abstract class SleepDatabase : RoomDatabase() {

   abstract val sleepDatabaseDao: SleepDatabaseDao

   companion object {

       @Volatile
       private var INSTANCE: SleepDatabase? = null

       fun getInstance(context: Context): SleepDatabase {
           synchronized(this) {
               var instance = INSTANCE

               if (instance == null) {
                   instance = Room.databaseBuilder(
                           context.applicationContext,
                           SleepDatabase::class.java,
                           "sleep_history_database"
                   )
                           .fallbackToDestructiveMigration()
                           .build()
                   INSTANCE = instance
               }
               return instance
           }
       }
   }
}
  1. کد خود را بسازید و اجرا کنید.

شما اکنون تمام بلوک های سازنده برای کار با پایگاه داده Room خود را دارید. این کد کامپایل می شود و اجرا می شود، اما شما هیچ راهی برای تشخیص کارکرد آن ندارید. بنابراین، این زمان خوبی برای اضافه کردن چند تست اساسی است.

مرحله 2: SleepDatabase را تست کنید

در این مرحله، تست های ارائه شده را برای بررسی کارکرد پایگاه داده خود اجرا می کنید. این کمک می کند تا اطمینان حاصل شود که پایگاه داده قبل از ساختن روی آن کار می کند. تست های ارائه شده پایه هستند. برای یک برنامه تولیدی، شما باید تمام عملکردها و پرس و جوها را در همه DAO ها اعمال کنید.

برنامه شروع کننده حاوی یک پوشه AndroidTest است. این پوشه AndroidTest شامل تست‌های واحدی است که شامل ابزار دقیق اندروید می‌شود، که روشی فانتزی برای گفتن این است که تست‌ها به چارچوب اندروید نیاز دارند، بنابراین باید آزمایش‌ها را روی یک دستگاه فیزیکی یا مجازی اجرا کنید. البته، می‌توانید تست‌های واحد خالص را نیز ایجاد و اجرا کنید که شامل فریمورک اندروید نیست.

  1. در Android Studio، در پوشه androidTest ، فایل SleepDatabaseTest را باز کنید.
  2. برای لغو کامنت کد، همه کدهای نظر داده شده را انتخاب کنید و میانبر صفحه کلید Cmd+/ یا Control+/ را فشار دهید.
  3. به فایل نگاهی بیندازید.

در اینجا یک بررسی سریع از کد آزمایشی وجود دارد، زیرا این کد دیگری است که می توانید مجدداً از آن استفاده کنید:

  • SleepDabaseTest یک کلاس آزمایشی است .
  • حاشیه نویسی @RunWith ، اجرای آزمایشی را مشخص می کند، که برنامه ای است که تست ها را تنظیم و اجرا می کند.
  • در طول راه‌اندازی، تابع مشروح شده با @Before اجرا می‌شود و یک SleepDatabase در حافظه با SleepDatabaseDao ایجاد می‌کند. "In-Memory" به این معنی است که این پایگاه داده در سیستم فایل ذخیره نمی شود و پس از اجرای آزمایش ها حذف می شود.
  • همچنین هنگام ساخت پایگاه داده درون حافظه، کد روش دیگری را که مربوط به تست است، allowMainThreadQueries فراخوانی می کند. به طور پیش فرض، اگر سعی کنید کوئری ها را در رشته اصلی اجرا کنید، با خطا مواجه می شوید. این روش به شما اجازه می دهد تا تست هایی را روی رشته اصلی اجرا کنید که فقط باید در حین تست انجام دهید.
  • در یک روش آزمایشی که با @Test حاشیه نویسی شده است، یک SleepNight را ایجاد، درج و بازیابی می کنید و اظهار می کنید که آنها یکسان هستند. اگر مشکلی پیش آمد، یک استثنا بیندازید. در یک تست واقعی، چندین @Test خواهید داشت روش ها
  • وقتی تست انجام شد، تابع مشروح شده با @After برای بستن پایگاه داده اجرا می شود.
  1. روی فایل تست در پنجره Project کلیک راست کرده و Run 'SleepDatabaseTest' را انتخاب کنید.
  2. پس از اجرای تست‌ها، در پنل SleepDatabaseTest تأیید کنید که تمام تست‌ها قبول شده‌اند.

از آنجایی که تمام تست ها گذرانده شده اند، اکنون چندین چیز را می دانید:

  • پایگاه داده به درستی ایجاد می شود.
  • می توانید یک SleepNight را در پایگاه داده وارد کنید.
  • می توانید SleepNight را برگردانید.
  • SleepNight ارزش مناسبی برای کیفیت دارد.

پروژه اندروید استودیو: TrackMySleepQualityRoomAndTesting

هنگام آزمایش یک پایگاه داده، باید تمام روش های تعریف شده در DAO را اعمال کنید. برای تکمیل تست ، تست هایی را اضافه و اجرا کنید تا روش های دیگر DAO را اعمال کنید.

  • جداول خود را به عنوان کلاس های داده مشروح شده با @Entity تعریف کنید. ویژگی های حاشیه نویسی شده با @ColumnInfo را به عنوان ستون در جداول تعریف کنید.
  • یک شی دسترسی به داده (DAO) را به عنوان یک رابط مشروح شده با @Dao تعریف کنید. DAO توابع Kotlin را به پرس و جوهای پایگاه داده نگاشت می کند.
  • از حاشیه نویسی برای تعریف توابع @Insert ، @Delete و @Update استفاده کنید.
  • از حاشیه نویسی @Query با رشته پرس و جو SQLite به عنوان پارامتر برای هر جستار دیگر استفاده کنید.
  • یک کلاس انتزاعی ایجاد کنید که دارای تابع getInstance() باشد که پایگاه داده را برمی گرداند.
  • از تست های ابزاری برای آزمایش اینکه پایگاه داده و DAO شما مطابق انتظار کار می کنند استفاده کنید. می توانید از تست های ارائه شده به عنوان الگو استفاده کنید.

دوره بی ادبی:

مستندات برنامه نویس اندروید:

سایر اسناد و مقالات:

این بخش، تکالیف احتمالی را برای دانش‌آموزانی که در این آزمایشگاه کد به عنوان بخشی از دوره‌ای که توسط یک مربی هدایت می‌شود، کار می‌کنند، فهرست می‌کند. این وظیفه مربی است که موارد زیر را انجام دهد:

  • در صورت نیاز تکالیف را تعیین کنید.
  • نحوه ارسال تکالیف را با دانش آموزان در میان بگذارید.
  • تکالیف را نمره دهید.

مربیان می‌توانند از این پیشنهادات به اندازه‌ای که می‌خواهند استفاده کنند، و باید با خیال راحت هر تکلیف دیگری را که فکر می‌کنند مناسب است، محول کنند.

اگر به تنهایی از طریق این کدها کار می کنید، از این تکالیف برای آزمایش دانش خود استفاده کنید.

به این سوالات پاسخ دهید

سوال 1

چگونه نشان می دهید که یک کلاس یک موجودیت را برای ذخیره در پایگاه داده Room نشان می دهد؟

  • کلاس را گسترش دهید DatabaseEntity .
  • کلاس را با @Entity حاشیه نویسی کنید.
  • کلاس را با @Database حاشیه نویسی کنید.
  • کلاس را گسترش دهید RoomEntity و همچنین کلاس را با @Room حاشیه نویسی کنید.

سوال 2

DAO (شیء دسترسی به داده) رابطی است که Room از آن برای نگاشت توابع Kotlin به کوئری های پایگاه داده استفاده می کند.

چگونه نشان می دهید که یک رابط یک DAO برای پایگاه داده Room را نشان می دهد؟

  • رابط را گسترش دهید RoomDAO .
  • رابط را گسترش دهید EntityDao ، سپس متد DaoConnection() پیاده سازی کنید.
  • رابط کاربری را با @Dao حاشیه نویسی کنید.
  • رابط را با @RoomConnection حاشیه نویسی کنید.

سوال 3

کدام یک از عبارات زیر در مورد پایگاه داده Room درست است؟ همه موارد کاربردی را انتخاب کنید.

  • می توانید جداول را برای پایگاه داده Room به عنوان کلاس های داده مشروح تعریف کنید.
  • اگر LiveData از یک پرس و جو برگردانید، Room در صورت تغییر LiveData LiveData برای شما به روز نگه می دارد.
  • هر پایگاه داده Room باید یک و تنها یک DAO داشته باشد.
  • برای شناسایی یک کلاس به عنوان پایگاه داده Room ، آن را به زیر کلاس RoomDatabase تبدیل کنید و آن را با @Database حاشیه نویسی کنید.

سوال 4

کدام یک از حاشیه نویسی های زیر را می توانید در رابط @Dao خود استفاده کنید؟ همه موارد کاربردی را انتخاب کنید.

  • @Get
  • @Update
  • @Insert
  • @Query

سوال 5

چگونه می توانید بررسی کنید که پایگاه داده شما کار می کند؟ همه موارد کاربردی را انتخاب کنید.

  • تست های ابزاری را بنویسید.
  • نوشتن و اجرای برنامه را تا نمایش داده ها ادامه دهید.
  • فراخوانی متدهای موجود در رابط DAO را با فراخوانی متدهای معادل در کلاس Entity جایگزین کنید.
  • تابع verifyDatabase() ارائه شده توسط کتابخانه Room را اجرا کنید.

شروع به درس بعدی: 6.2 کوروتین ها و اتاق

برای پیوند به سایر کدهای این دوره، به صفحه فرود کد لبه‌های کد پایه Android Kotlin Fundamentals مراجعه کنید.

،

این کد لبه بخشی از دوره آموزشی Android Kotlin Fundamentals است. اگر به ترتیب روی کدها کار کنید، بیشترین ارزش را از این دوره خواهید گرفت. همه کد لبه های دوره در صفحه فرود کد لبه های Android Kotlin Fundamentals فهرست شده اند.

مقدمه

بیشتر برنامه‌ها داده‌هایی دارند که حتی پس از بستن برنامه توسط کاربر، باید حفظ شوند. برای مثال، برنامه ممکن است فهرست پخش، فهرستی از اقلام بازی، سوابق هزینه‌ها و درآمد، فهرستی از صورت‌های فلکی، یا داده‌های خواب را در طول زمان ذخیره کند. معمولاً از یک پایگاه داده برای ذخیره داده های پایدار استفاده می کنید.

Room یک کتابخانه پایگاه داده است که بخشی از Android Jetpack است. Room بسیاری از کارهای راه اندازی و پیکربندی یک پایگاه داده را بر عهده می گیرد و این امکان را برای برنامه شما فراهم می کند تا با استفاده از فراخوانی های تابع معمولی با پایگاه داده تعامل داشته باشد. در زیر هود، Room یک لایه انتزاعی در بالای پایگاه داده SQLite است. اصطلاحات Room ، و نحو پرس و جو برای پرس و جوهای پیچیده تر، از مدل SQLite پیروی می کنند.

تصویر زیر نشان می دهد که چگونه پایگاه داده Room با معماری کلی توصیه شده در این دوره مطابقت دارد.

آنچه از قبل باید بدانید

شما باید با این موارد آشنا باشید:

  • ساخت یک رابط کاربری اولیه (UI) برای یک برنامه اندروید
  • استفاده از فعالیت ها، قطعات و نماها.
  • پیمایش بین قطعات و استفاده از Safe Args (یک افزونه Gradle) برای انتقال داده ها بین قطعات.
  • مدل‌ها، کارخانه‌های مشاهده مدل، و LiveData و ناظران آن را مشاهده کنید. این مباحث مولفه های معماری در یک کدآلب قبلی در این دوره پوشش داده شده است.
  • درک اولیه از پایگاه داده SQL و زبان SQLite. برای یک مرور کلی یا تازه‌سازی به SQLite Primer مراجعه کنید.

چیزی که یاد خواهید گرفت

  • نحوه ایجاد و تعامل با پایگاه داده Room برای ماندگاری داده ها.
  • نحوه ایجاد یک کلاس داده که یک جدول را در پایگاه داده تعریف می کند.
  • نحوه استفاده از یک شی دسترسی به داده (DAO) برای نگاشت توابع Kotlin به پرس و جوهای SQL.
  • چگونه آزمایش کنیم که آیا پایگاه داده شما کار می کند یا خیر.

کاری که خواهی کرد

  • یک پایگاه داده Room با یک رابط برای داده های خواب شبانه ایجاد کنید.
  • پایگاه داده را با استفاده از تست های ارائه شده تست کنید.

در این نرم افزار کد، بخش پایگاه داده یک برنامه را می سازید که کیفیت خواب را ردیابی می کند. این برنامه از یک پایگاه داده برای ذخیره داده های خواب در طول زمان استفاده می کند.

این برنامه دارای دو صفحه است که با قطعات نشان داده شده است، همانطور که در شکل زیر نشان داده شده است.

اولین صفحه نمایش داده شده در سمت چپ دارای دکمه هایی برای شروع و توقف ردیابی است. صفحه نمایش تمام داده های خواب کاربر را نشان می دهد. دکمه Clear تمام داده هایی را که برنامه برای کاربر جمع آوری کرده است برای همیشه حذف می کند.

صفحه دوم، نشان داده شده در سمت راست، برای انتخاب رتبه بندی کیفیت خواب است. در برنامه، امتیاز به صورت عددی نشان داده می شود. برای اهداف توسعه، برنامه هم نمادهای چهره و هم معادل های عددی آنها را نشان می دهد.

جریان کاربر به شرح زیر است:

  • کاربر برنامه را باز می کند و با صفحه ردیابی خواب نمایش داده می شود.
  • کاربر روی دکمه Start ضربه می زند. این زمان شروع را ثبت کرده و نمایش می دهد. دکمه Start غیرفعال است و دکمه Stop فعال است.
  • کاربر روی دکمه Stop ضربه می زند. این کار زمان پایان را ثبت می کند و صفحه با کیفیت خواب را باز می کند.
  • کاربر یک نماد کیفیت خواب را انتخاب می کند. صفحه بسته می شود و صفحه ردیابی زمان پایان خواب و کیفیت خواب را نشان می دهد. دکمه Stop غیرفعال و دکمه Start فعال است. برنامه برای یک شب دیگر آماده است.
  • دکمه Clear هر زمان که داده ای در پایگاه داده وجود داشته باشد فعال می شود. هنگامی که کاربر روی دکمه Clear ضربه می‌زند، تمام داده‌های او بدون مراجعه پاک می‌شوند - "آیا مطمئن هستید؟" وجود ندارد. پیام

این برنامه از معماری ساده شده استفاده می کند، همانطور که در زیر در زمینه معماری کامل نشان داده شده است. این برنامه فقط از اجزای زیر استفاده می کند:

  • کنترلر رابط کاربری
  • مشاهده مدل و LiveData
  • پایگاه داده اتاق

مرحله 1: برنامه شروع را دانلود و اجرا کنید

  1. برنامه TrackMySleepQuality-Starter را از GitHub دانلود کنید.
  2. برنامه را بسازید و اجرا کنید. برنامه رابط کاربری بخش SleepTrackerFragment را نشان می دهد، اما داده ای ندارد. دکمه ها به ضربه ها پاسخ نمی دهند.

مرحله 2: برنامه شروع را بررسی کنید

  1. به فایل های Gradle نگاهی بیندازید:
  • فایل پروژه Gradle
    در فایل build.gradle در سطح پروژه، به متغیرهایی که نسخه های کتابخانه را مشخص می کنند توجه کنید. نسخه های استفاده شده در برنامه استارتر به خوبی با هم کار می کنند و با این برنامه به خوبی کار می کنند. تا زمانی که این کد لبه را تمام کنید، ممکن است Android Studio از شما بخواهد که برخی از نسخه ها را به روز کنید. این به شما بستگی دارد که آیا می خواهید نسخه های موجود در برنامه را به روز کنید یا از آن استفاده کنید. اگر با خطاهای کامپایل "عجیب" مواجه شدید، سعی کنید از ترکیب نسخه های کتابخانه ای که برنامه راه حل نهایی استفاده می کند استفاده کنید.
  • فایل ماژول Gradle. به وابستگی‌های ارائه‌شده برای همه کتابخانه‌های Android Jetpack، از جمله Room ، و وابستگی‌های کوروتین‌ها توجه کنید.
  1. به بسته ها و UI نگاهی بیندازید. برنامه بر اساس عملکرد ساختار یافته است. این بسته حاوی فایل‌های نگهدارنده است که در آن کد را در این سری از کدها اضافه خواهید کرد.
  • بسته database ، برای همه کدهای مربوط به پایگاه داده Room .
  • بسته‌های sleepquality و sleeptracker شامل قطعه، مدل view و کارخانه مدل view برای هر صفحه هستند .
  1. به فایل Util.kt نگاهی بیندازید، که حاوی توابعی برای کمک به نمایش داده های با کیفیت خواب است. برخی از کدها به دلیل ارجاع به یک مدل view که بعداً ایجاد می کنید، توضیح داده می شود.
  2. به پوشه androidTest ( SleepDatabaseTest.kt ) نگاهی بیندازید. شما از این تست برای بررسی اینکه پایگاه داده طبق برنامه کار می کند استفاده خواهید کرد.

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

  • یک موجودیت یک شی یا مفهوم و خصوصیات آن را برای ذخیره در پایگاه داده نشان می دهد. یک کلاس موجودیت یک جدول را تعریف می کند و هر نمونه از آن کلاس نشان دهنده یک ردیف در جدول است. هر ویژگی یک ستون را تعریف می کند. در برنامه شما، نهاد اطلاعاتی در مورد یک شب خواب نگه می دارد.
  • پرس و جو درخواست داده یا اطلاعات از جدول پایگاه داده یا ترکیبی از جداول یا درخواستی برای انجام عملی بر روی داده است. پرس و جوهای رایج برای دریافت، درج و به روز رسانی موجودیت ها هستند. برای مثال، می‌توانید برای تمام شب‌های خواب ثبت شده، مرتب‌سازی‌شده بر اساس زمان شروع، پرس و جو کنید.

Room همه کار سختی را برای شما انجام می دهد تا از کلاس های داده Kotlin به موجودیت هایی که می توانند در جداول SQLite ذخیره شوند و از اعلان های تابع تا پرس و جوهای SQL را به دست آورید.

شما باید هر موجودیت را به عنوان یک کلاس داده مشروح، و تعاملات را به عنوان یک رابط مشروح شده، یک شی دسترسی به داده (DAO) تعریف کنید. Room از این کلاس های حاشیه نویسی برای ایجاد جداول در پایگاه داده و پرس و جوهایی که روی پایگاه داده عمل می کنند استفاده می کند.

مرحله 1: موجودیت SleepNight را ایجاد کنید

در این کار، یک شب خواب را به عنوان یک کلاس داده مشروح تعریف می کنید.

برای یک شب خواب، باید زمان شروع، زمان پایان و رتبه بندی کیفیت را ثبت کنید.

و برای شناسایی منحصر به فرد شب به یک شناسه نیاز دارید.

  1. در بسته database ، فایل SleepNight.kt را پیدا کرده و باز کنید.
  2. کلاس داده SleepNight را با پارامترهایی برای شناسه، زمان شروع (بر حسب میلی ثانیه)، زمان پایان (بر حسب میلی ثانیه) و رتبه بندی عددی کیفیت خواب ایجاد کنید.
  • شما باید sleepQuality را مقداردهی اولیه کنید، بنابراین آن را روی -1 تنظیم کنید، که نشان می دهد هیچ داده با کیفیتی جمع آوری نشده است.
  • شما همچنین باید زمان پایان را مقداردهی اولیه کنید. آن را روی زمان شروع تنظیم کنید تا نشان دهد که هنوز زمان پایانی ثبت نشده است.
data class SleepNight(
       var nightId: Long = 0L,
       val startTimeMilli: Long = System.currentTimeMillis(),
       var endTimeMilli: Long = startTimeMilli,
       var sleepQuality: Int = -1
)
  1. قبل از اعلان کلاس، کلاس داده را با @Entity حاشیه نویسی کنید. نام جدول را daily_sleep_quality_table بگذارید. آرگومان tableName اختیاری است، اما توصیه می شود. می توانید سایر استدلال ها را در مستندات جستجو کنید.

    در صورت درخواست، Entity و تمام حاشیه نویسی های دیگر را از کتابخانه androidx وارد کنید.
@Entity(tableName = "daily_sleep_quality_table")
data class SleepNight(...)
  1. برای شناسایی nightId به عنوان کلید اصلی، ویژگی nightId را با @PrimaryKey حاشیه نویسی کنید. پارامتر autoGenerate روی true تنظیم کنید تا Room برای هر موجودیت شناسه تولید کند. این تضمین می کند که شناسه هر شب منحصر به فرد است.
@PrimaryKey(autoGenerate = true)
var nightId: Long = 0L,...
  1. ویژگی های باقی مانده را با @ColumnInfo حاشیه نویسی کنید. مطابق شکل زیر نام ویژگی ها را با استفاده از پارامترها سفارشی کنید.
import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.PrimaryKey

@Entity(tableName = "daily_sleep_quality_table")
data class SleepNight(
       @PrimaryKey(autoGenerate = true)
       var nightId: Long = 0L,

       @ColumnInfo(name = "start_time_milli")
       val startTimeMilli: Long = System.currentTimeMillis(),

       @ColumnInfo(name = "end_time_milli")
       var endTimeMilli: Long = startTimeMilli,

       @ColumnInfo(name = "quality_rating")
       var sleepQuality: Int = -1
)
  1. کد خود را بسازید و اجرا کنید تا مطمئن شوید که هیچ خطایی ندارد.

در این کار، یک شی دسترسی به داده (DAO) را تعریف می کنید. در اندروید، DAO روش‌های آسانی را برای درج، حذف و به‌روزرسانی پایگاه داده ارائه می‌کند.

هنگامی که از پایگاه داده Room استفاده می کنید، با تعریف و فراخوانی توابع Kotlin در کد خود، پایگاه داده را پرس و جو می کنید. این توابع Kotlin به پرس و جوهای SQL نگاشت می شوند. شما آن نگاشتها را در یک DAO با استفاده از حاشیه نویسی تعریف می کنید و Room کد لازم را ایجاد می کند.

یک DAO را به عنوان تعریف یک رابط سفارشی برای دسترسی به پایگاه داده خود در نظر بگیرید.

برای عملیات رایج پایگاه داده، کتابخانه Room حاشیه نویسی های راحت را ارائه می دهد، مانند @Insert ، @Delete و @Update . برای هر چیز دیگری، حاشیه نویسی @Query وجود دارد. می توانید هر درخواستی را که توسط SQLite پشتیبانی می شود بنویسید.

به عنوان یک امتیاز اضافی، هنگامی که پرس و جوهای خود را در Android Studio ایجاد می کنید، کامپایلر پرس و جوهای SQL شما را برای خطاهای نحوی بررسی می کند.

برای پایگاه داده ردیاب خواب شب‌های خواب، باید بتوانید کارهای زیر را انجام دهید:

  • درج شب های جدید
  • برای به‌روزرسانی زمان پایان و رتبه‌بندی کیفیت، یک شب موجود را به‌روزرسانی کنید .
  • یک شب خاص بر اساس کلید آن دریافت کنید .
  • تمام شب ها را دریافت کنید تا بتوانید آنها را نمایش دهید.
  • آخرین شب را دریافت کنید.
  • تمام ورودی های پایگاه داده را حذف کنید .

مرحله 1: SleepDatabase DAO را ایجاد کنید

  1. در بسته database ، SleepDatabaseDao.kt باز کنید.
  2. توجه کنید که interface SleepDatabaseDao با @Dao حاشیه نویسی شده است. همه DAO ها باید با کلمه کلیدی @Dao حاشیه نویسی شوند.
@Dao
interface SleepDatabaseDao {}
  1. در داخل بدنه رابط ، حاشیه نویسی @Insert را اضافه کنید. در زیر @Insert ، یک تابع insert() اضافه کنید که نمونه ای از SleepNight Class Entity را در بر می گیرد به عنوان استدلال خود

    همین است. Room تمام کد لازم را برای وارد کردن SleepNight در پایگاه داده ایجاد می کند. هنگامی که از کد Kotlin خود insert() تماس می گیرید ، Room یک پرس و جو SQL را برای وارد کردن موجودیت در پایگاه داده اجرا می کند. (توجه: می توانید هر چیزی را که می خواهید با عملکرد تماس بگیرید.)
@Insert
fun insert(night: SleepNight)
  1. برای یک SleepNight یک یادداشت @Update را با یک عملکرد update() اضافه کنید. موجودی که به روز شده است ، موجودی است که همان کلید را دارد که در آن منتقل شده است. می توانید برخی یا تمام خصوصیات دیگر موجودیت را به روز کنید.
@Update
fun update(night: SleepNight)

هیچ گونه حاشیه نویسی برای عملکرد باقی مانده وجود ندارد ، بنابراین شما باید از یادداشت های @Query و عرضه SQLite استفاده کنید.

  1. یک یادداشت @Query را با یک عملکرد get() اضافه کنید که یک key Long طول می کشد استدلال و یک SleepNight قابل برگشت را برمی گرداند. خطایی برای یک پارامتر گمشده مشاهده خواهید کرد.
@Query
fun get(key: Long): SleepNight?
  1. پرس و جو به عنوان یک پارامتر رشته برای حاشیه نویسی تهیه می شود. یک پارامتر به @Query اضافه کنید. آن را String درست کنید که یک پرس و جو sqlite باشد.
  • همه ستون ها را از daily_sleep_quality_table انتخاب کنید
  • WHERE nightId با: استدلال key مطابقت دارد.

    توجه کنید :key . شما از نماد روده بزرگ در پرس و جو برای آرگومان های مرجع در عملکرد استفاده می کنید.
("SELECT * from daily_sleep_quality_table WHERE nightId = :key")
  1. your @Query با یک عملکرد clear() و یک پرس و جو sqlite اضافه کنید تا همه چیز را از daily_sleep_quality_table DELETE . این پرس و جو خود جدول را حذف نمی کند.

    حاشیه @Delete delete یک مورد را حذف می کند ، و می توانید @Delete استفاده کنید و لیستی از شبها را برای حذف تهیه کنید. اشکال این است که شما باید واکشی کنید یا بدانید که در جدول چیست. حاشیه نویسی @Delete برای حذف ورودی های خاص عالی است ، اما برای پاک کردن تمام ورودی ها از یک جدول کارآمد نیست.
@Query("DELETE FROM daily_sleep_quality_table")
fun clear()
  1. با یک عملکرد getTonight() یک @Query اضافه کنید. SleepNight که توسط getTonight() قابل بازگشت است ، برگردانید تا عملکرد بتواند موردی را که جدول خالی است ، کنترل کند. (جدول در ابتدا خالی است و پس از پاک شدن داده ها.)

    برای دریافت "امشب" از پایگاه داده ، یک پرس و جو SQLITE بنویسید که اولین عنصر لیستی از نتایج سفارش داده شده توسط nightId را به ترتیب نزولی باز می گرداند. برای بازگشت تنها یک عنصر LIMIT 1 استفاده کنید.
@Query("SELECT * FROM daily_sleep_quality_table ORDER BY nightId DESC LIMIT 1")
fun getTonight(): SleepNight?
  1. یک عملکرد @Query getAllNights() اضافه کنید:
  • از پرس و جو SQLITE بخواهید تمام ستون ها را از daily_sleep_quality_table بازگرداند ، که به ترتیب نزولی سفارش داده شده است.
  • getAllNights() لیستی از اشخاص SleepNight به عنوان LiveData برگردانید. Room این LiveData را برای شما به روز می کند ، این بدان معنی است که شما فقط باید یک بار صریح داده ها را دریافت کنید.
  • ممکن است شما نیاز به وارد کردن LiveData از androidx.lifecycle.LiveData داشته باشید.
@Query("SELECT * FROM daily_sleep_quality_table ORDER BY nightId DESC")
fun getAllNights(): LiveData<List<SleepNight>>
  1. اگرچه هیچ گونه تغییر قابل مشاهده ای را مشاهده نخواهید کرد ، برنامه خود را اجرا کنید تا مطمئن شوید که هیچ خطایی ندارد.

در این کار ، شما یک پایگاه داده Room ایجاد می کنید که از Entity و DAO که در کار قبلی ایجاد کرده اید استفاده می کند.

شما باید یک کلاس نگهدارنده پایگاه داده انتزاعی ایجاد کنید ، حاشیه نویسی با @Database . این کلاس دارای یک روش است که در صورت وجود بانک اطلاعاتی ، نمونه ای از پایگاه داده را ایجاد می کند ، یا مرجع را به یک پایگاه داده موجود باز می گرداند.

گرفتن یک پایگاه داده Room کمی درگیر است ، بنابراین در اینجا روند کلی قبل از شروع با کد وجود دارد:

  • یک کلاس public abstract ایجاد کنید که extends RoomDatabase . این کلاس به عنوان دارنده بانک اطلاعاتی عمل می کند. کلاس انتزاعی است ، زیرا Room پیاده سازی را برای شما ایجاد می کند.
  • کلاس را با @Database حاشیه نویسی کنید. در آرگومان ، اشخاص را برای پایگاه داده اعلام کرده و شماره نسخه را تنظیم کنید.
  • در داخل یک شی companion ، یک روش انتزاعی یا خاصیتی را تعریف کنید که یک SleepDatabaseDao برمی گرداند. Room بدن را برای شما ایجاد می کند.
  • شما فقط به یک نمونه از پایگاه داده Room برای کل برنامه نیاز دارید ، بنابراین RoomDatabase به یک مجرد تبدیل کنید.
  • از سازنده پایگاه داده Room استفاده کنید تا پایگاه داده ایجاد کنید در صورت عدم وجود بانک اطلاعاتی. در غیر این صورت ، پایگاه داده موجود را برگردانید.

مرحله 1: پایگاه داده را ایجاد کنید

  1. در بسته database ، SleepDatabase.kt باز کنید.
  2. در پرونده ، یک کلاس abstract به نام SleepDatabase ایجاد کنید که RoomDatabase گسترش می دهد.

    کلاس را با @Database حاشیه نویسی کنید.
@Database()
abstract class SleepDatabase : RoomDatabase() {}
  1. خطایی برای اشخاص گمشده و پارامترهای نسخه مشاهده خواهید کرد. حاشیه نویسی @Database به چندین استدلال نیاز دارد تا Room بتواند پایگاه داده را بسازد.
  • SleepNight به عنوان تنها مورد با لیست entities تهیه کنید.
  • version را به صورت 1 تنظیم کنید . هر زمان که طرح را تغییر دهید ، باید شماره نسخه را افزایش دهید.
  • exportSchema به false تنظیم کنید ، تا از نسخه پشتیبان تهیه نسخه Schema استفاده نکنید.
entities = [SleepNight::class], version = 1, exportSchema = false
  1. این بانک اطلاعاتی باید در مورد DAO اطلاع داشته باشد. در داخل بدن کلاس ، یک مقدار انتزاعی را اعلام کنید که SleepDatabaseDao برمی گرداند. شما می توانید چندین DAO داشته باشید.
abstract val sleepDatabaseDao: SleepDatabaseDao
  1. در زیر آن ، یک شی companion را تعریف کنید. شیء همراه به مشتریان این امکان را می دهد تا بدون فوری کلاس ، به روشهای ایجاد یا گرفتن پایگاه داده دسترسی پیدا کنند. از آنجا که تنها هدف از این کلاس ارائه یک بانک اطلاعاتی است ، هیچ دلیلی برای فوری آن وجود ندارد.
 companion object {}
  1. در داخل شیء companion ، یک نمونه متغیر قابل تهی خصوصی INSTANCE برای پایگاه داده اعلام کرده و آن را به null تنظیم کنید. متغیر INSTANCE ، پس از ایجاد یک ، به پایگاه داده مراجعه می کند. این به شما کمک می کند تا به طور مکرر از اتصالات به پایگاه داده جلوگیری کنید که گران است.

نمونه INSTANCE با @Volatile . مقدار یک متغیر فرار هرگز ذخیره نمی شود و همه می نویسد و می خواند و از حافظه اصلی و از طریق حافظه اصلی انجام می شود. این به اطمینان حاصل می شود که مقدار INSTANCE همیشه به روز است و برای همه موضوعات اجرا یکسان است. این بدان معناست که تغییرات ایجاد شده توسط یک موضوع به INSTANCE بلافاصله برای همه موضوعات دیگر قابل مشاهده است ، و شما شرایطی را پیدا نمی کنید که مثلاً دو موضوع هر یک از یکسان را در یک حافظه نهان به روز کنید ، که این امر باعث ایجاد مشکل می شود.

@Volatile
private var INSTANCE: SleepDatabase? = null
  1. در زیر INSTANCE ، هنوز هم در داخل شیء companion ، یک روش getInstance() را با یک پارامتر Context که سازنده پایگاه داده به آن نیاز دارد تعریف کنید. یک نوع SleepDatabase برگردانید. خطایی را مشاهده خواهید کرد زیرا getInstance() هنوز هیچ چیزی را برمی گرداند.
fun getInstance(context: Context): SleepDatabase {}
  1. در داخل getInstance() ، یک بلوک synchronized{} اضافه کنید. در this عبور کنید تا بتوانید به متن دسترسی پیدا کنید.

    موضوعات متعدد به طور بالقوه می توانند یک نمونه بانک اطلاعاتی را به طور همزمان درخواست کنند ، و در نتیجه دو پایگاه داده به جای یک. این مشکل به احتمال زیاد در این برنامه نمونه اتفاق نمی افتد ، اما برای یک برنامه پیچیده تر امکان پذیر است. بسته بندی کد برای به دست آوردن بانک synchronized به این معنی است که فقط یک موضوع اجرای در یک زمان می تواند این بلوک از کد را وارد کند ، که باعث می شود پایگاه داده فقط یک بار اولیه شود.
synchronized(this) {}
  1. در داخل بلوک هماهنگ شده ، مقدار فعلی INSTANCE را در یک instance متغیر محلی کپی کنید. این برای استفاده از بازیگران هوشمند است که فقط در دسترس متغیرهای محلی است.
var instance = INSTANCE
  1. در داخل بلوک synchronized ، return instance در انتهای بلوک synchronized . خطای عدم تطابق نوع بازگشت را نادیده بگیرید. پس از اتمام کار ، هرگز تهی نخواهید کرد.
return instance
  1. بالاتر از بیانیه return ، یک عبارت if را اضافه کنید تا بررسی کنید که آیا instance تهی است ، یعنی هنوز پایگاه داده ای وجود ندارد.
if (instance == null) {}
  1. اگر instance null است ، برای تهیه یک پایگاه داده از سازنده پایگاه داده استفاده کنید. در بدنه بیانیه if ، repoke Room.databaseBuilder و زمینه ای را که در آن عبور کرده اید ، کلاس پایگاه داده و نامی برای بانک اطلاعاتی ، sleep_history_database تهیه کنید. برای رفع خطا ، باید در مراحل زیر یک استراتژی مهاجرت اضافه کرده و build() .
instance = Room.databaseBuilder(
                           context.applicationContext,
                           SleepDatabase::class.java,
                           "sleep_history_database")
  1. استراتژی مهاجرت مورد نیاز را به سازنده اضافه کنید. استفاده از .fallbackToDestructiveMigration() .

    به طور معمول ، شما باید یک شیء مهاجرت را با یک استراتژی مهاجرت برای زمان تغییر طرح ارائه دهید. یک شیء مهاجرت یک شیء است که چگونه شما همه ردیف ها را با طرح قدیمی می گیرید و آنها را در طرح جدید به ردیف تبدیل می کنید ، به طوری که هیچ داده ای از بین نمی رود. مهاجرت فراتر از محدوده این CodeLab است. یک راه حل ساده نابودی و بازسازی بانک اطلاعاتی است ، به این معنی که داده ها از بین می روند.
.fallbackToDestructiveMigration()
  1. سرانجام ، تماس بگیرید .build() .
.build()
  1. به عنوان INSTANCE = instance به عنوان مرحله آخر در بیانیه if اختصاص دهید.
INSTANCE = instance
  1. کد نهایی شما باید به این شکل باشد:
@Database(entities = [SleepNight::class], version = 1, exportSchema = false)
abstract class SleepDatabase : RoomDatabase() {

   abstract val sleepDatabaseDao: SleepDatabaseDao

   companion object {

       @Volatile
       private var INSTANCE: SleepDatabase? = null

       fun getInstance(context: Context): SleepDatabase {
           synchronized(this) {
               var instance = INSTANCE

               if (instance == null) {
                   instance = Room.databaseBuilder(
                           context.applicationContext,
                           SleepDatabase::class.java,
                           "sleep_history_database"
                   )
                           .fallbackToDestructiveMigration()
                           .build()
                   INSTANCE = instance
               }
               return instance
           }
       }
   }
}
  1. کد خود را بسازید و اجرا کنید.

شما اکنون تمام بلوک های ساختمانی را برای کار با پایگاه داده Room خود دارید. این کد کامپایل و اجرا می شود ، اما شما هیچ راهی برای گفتن اینکه آیا واقعاً کار می کند ، ندارید. بنابراین ، این زمان خوبی برای اضافه کردن برخی از تست های اساسی است.

مرحله 2: SleepDatabase را آزمایش کنید

در این مرحله ، شما تست هایی را برای تأیید اینکه پایگاه داده شما کار می کند ، انجام داده اید. این به اطمینان حاصل می شود که پایگاه داده قبل از ساختن آن کار کند. تست های ارائه شده اساسی هستند. برای یک برنامه تولید ، شما تمام کارکردها و نمایش داده ها را در تمام DAO ها انجام می دهید.

برنامه استارت شامل یک پوشه AndroidTest است. این پوشه AndroidTest شامل تست های واحد است که شامل ابزار دقیق Android است ، این یک روش جالب برای گفتن است که آزمایشات به چارچوب Android نیاز دارند ، بنابراین شما باید آزمایشات را روی یک دستگاه فیزیکی یا مجازی اجرا کنید. البته ، شما همچنین می توانید تست های واحد خالص را که شامل چارچوب Android نیست ، ایجاد و اجرا کنید.

  1. در Android Studio ، در پوشه AndroidTest ، پرونده SleepDatabasetest را باز کنید.
  2. برای نادیده گرفتن کد ، تمام کد اظهار نظر را انتخاب کرده و میانبر Cmd+/ یا Control+/ صفحه کلید را فشار دهید.
  3. به پرونده نگاهی بیندازید.

در اینجا سریع کد آزمایش وجود دارد ، زیرا این یک قطعه دیگر از کد است که می توانید از آن استفاده کنید:

  • SleepDabaseTest یک کلاس تست است .
  • حاشیه نویسی @RunWith Runner Test را مشخص می کند ، این برنامه ای است که تست ها را تنظیم و اجرا می کند.
  • در حین راه اندازی ، عملکرد حاشیه نویسی با @Before اجرا می شود ، و با SleepDatabaseDao یک SleepDatabase در حافظه ایجاد می کند. "در حافظه" به این معنی است که این پایگاه داده در سیستم پرونده ذخیره نمی شود و پس از اجرای تست ها حذف می شود.
  • همچنین هنگام ساختن بانک اطلاعاتی در حافظه ، کد یک روش خاص تست را ، allowMainThreadQueries می نامد. به طور پیش فرض ، اگر سعی می کنید نمایش داده شد را روی موضوع اصلی اجرا کنید ، خطایی دریافت می کنید. این روش به شما امکان می دهد تست ها را روی موضوع اصلی اجرا کنید ، که فقط باید در حین آزمایش انجام دهید.
  • در یک روش آزمایشی که با @Test حاشیه نویسی شده است ، شما یک SleepNight ایجاد می کنید ، درج و بازیابی می کنید و ادعا می کنید که آنها یکسان هستند. اگر مشکلی پیش آمد ، یک استثنا را پرتاب کنید. در یک تست واقعی ، شما چندین @Test خواهید داشت روش ها
  • هنگام انجام آزمایش ، عملکردی که با @After حاشیه نویسی شده است برای بستن پایگاه داده اجرا می شود.
  1. بر روی پرونده تست در صفحه پروژه راست کلیک کرده و اجرای "SleepDatabasetest" را انتخاب کنید.
  2. پس از انجام آزمایشات ، در صفحه Sleepdatabasetest که تمام آزمایشات گذرانده اند ، تأیید کنید.

از آنجا که تمام تست ها گذشت ، شما اکنون چندین چیز را می دانید:

  • بانک اطلاعاتی به درستی ایجاد می شود.
  • می توانید یک SleepNight در پایگاه داده وارد کنید.
  • می توانید شب SleepNight برگردانید.
  • SleepNight ارزش صحیحی برای کیفیت دارد.

پروژه استودیوی Android: TrackMysLeepQualityRoomAndTesting

هنگام آزمایش یک پایگاه داده ، باید تمام روشهای تعریف شده در DAO را اعمال کنید. برای تکمیل آزمایش ، تست ها را اضافه و انجام دهید تا روشهای دیگر DAO را انجام دهید.

  • جداول خود را به عنوان کلاسهای داده حاشیه نویسی با @Entity تعریف کنید. ویژگی های حاشیه نویسی با @ColumnInfo را به عنوان ستون در جداول تعریف کنید.
  • یک شی دسترسی به داده (DAO) را به عنوان رابط حاشیه ای با @Dao تعریف کنید. DAO توابع Kotlin را به نمایش داده های پایگاه داده نقشه می کند.
  • برای تعریف @Insert ، @Delete و @Update از حاشیه نویسی استفاده کنید.
  • از حاشیه نویسی @Query با یک رشته پرس و جو SQLITE به عنوان یک پارامتر برای هر پرس و جو دیگر استفاده کنید.
  • یک کلاس انتزاعی ایجاد کنید که دارای یک تابع getInstance() باشد که یک پایگاه داده را برمی گرداند.
  • برای آزمایش اینکه پایگاه داده و DAO همانطور که انتظار می رود کار می کنند ، از تست های ابزار استفاده کنید. می توانید از تست های ارائه شده به عنوان الگوی استفاده کنید.

دوره بی ادبی:

اسناد توسعه دهنده اندرویدی:

سایر مستندات و مقالات:

این بخش، تکالیف احتمالی را برای دانش‌آموزانی که در این آزمایشگاه کد به عنوان بخشی از دوره‌ای که توسط یک مربی هدایت می‌شود، کار می‌کنند، فهرست می‌کند. این وظیفه مربی است که موارد زیر را انجام دهد:

  • در صورت نیاز تکالیف را تعیین کنید.
  • نحوه ارسال تکالیف را با دانش آموزان در میان بگذارید.
  • تکالیف را نمره دهید.

مربیان می‌توانند از این پیشنهادات به اندازه‌ای که می‌خواهند استفاده کنند، و باید با خیال راحت هر تکلیف دیگری را که فکر می‌کنند مناسب است، محول کنند.

اگر به تنهایی از طریق این کدها کار می کنید، از این تکالیف برای آزمایش دانش خود استفاده کنید.

به این س questions الات پاسخ دهید

سوال 1

چگونه نشان می دهید که یک کلاس نمایانگر یک موجودیت برای ذخیره در یک پایگاه داده Room است؟

  • کلاس را توسعه دهید تا DatabaseEntity گسترش دهد.
  • کلاس را با @Entity حاشیه نویسی کنید.
  • کلاس را با @Database حاشیه نویسی کنید.
  • کلاس را RoomEntity گسترش دهید و همچنین کلاس را با @Room حاشیه نویسی کنید.

سوال 2

DAO (شی دسترسی به داده) رابط کاربری است که Room برای نقشه برداری توابع کوتلین به نمایش داده های پایگاه داده استفاده می کند.

چگونه نشان می دهید که یک رابط کاربری DAO را برای یک پایگاه داده Room نشان می دهد؟

  • رابط RoomDAO را گسترش دهید.
  • رابط را گسترش دهید EntityDao ، سپس روش DaoConnection() را پیاده سازی کنید.
  • رابط کاربری را با @Dao حاشیه نویسی کنید.
  • رابط کاربری را با @RoomConnection حاشیه نویسی کنید.

سوال 3

کدام یک از گفته های زیر در مورد پایگاه داده Room صادق است؟ همه موارد کاربردی را انتخاب کنید.

  • می توانید جداول را برای یک پایگاه داده Room به عنوان کلاسهای داده حاشیه نویسی تعریف کنید.
  • اگر LiveData از یک پرس و جو برگردانید ، در صورت تغییر LiveData ، Room LiveData را برای شما به روز می کند.
  • هر پایگاه داده Room باید یک و تنها یک دائو داشته باشد.
  • برای شناسایی یک کلاس به عنوان یک پایگاه داده Room ، آن را به زیر کلاس RoomDatabase تبدیل کرده و آن را با @Database حاشیه نویسی کنید.

سوال 4

از کدام یک از حاشیه های زیر می توانید در رابط @Dao خود استفاده کنید؟ همه موارد کاربردی را انتخاب کنید.

  • @Get
  • @Update
  • @Insert
  • @Query

سوال 5

چگونه می توانید تأیید کنید که پایگاه داده شما در حال کار است؟ همه موارد کاربردی را انتخاب کنید.

  • تست های سازنده را بنویسید.
  • نوشتن و اجرای برنامه را ادامه دهید تا زمانی که داده ها را نشان دهد.
  • تماس ها را به روش های موجود در رابط DAO با تماس با روشهای معادل در کلاس Entity جایگزین کنید.
  • عملکرد verifyDatabase() ارائه شده توسط کتابخانه Room را اجرا کنید.

شروع به درس بعدی: 6.2 Coroutines و اتاق

برای پیوند به سایر کدهای این دوره، به صفحه فرود کد لبه‌های کد پایه Android Kotlin Fundamentals مراجعه کنید.