این کد لبه بخشی از دوره آموزشی 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: برنامه شروع را دانلود و اجرا کنید
- برنامه TrackMySleepQuality-Starter را از GitHub دانلود کنید.
- برنامه را بسازید و اجرا کنید. برنامه رابط کاربری بخش
SleepTrackerFragment
را نشان می دهد، اما داده ای ندارد. دکمه ها به ضربه ها پاسخ نمی دهند.
مرحله 2: برنامه شروع را بررسی کنید
- به فایل های Gradle نگاهی بیندازید:
- فایل پروژه Gradle
در فایلbuild.gradle
در سطح پروژه، به متغیرهایی که نسخه های کتابخانه را مشخص می کنند توجه کنید. نسخه های استفاده شده در برنامه استارتر به خوبی با هم کار می کنند و با این برنامه به خوبی کار می کنند. تا زمانی که این کد لبه را تمام کنید، ممکن است Android Studio از شما بخواهد که برخی از نسخه ها را به روز کنید. این به شما بستگی دارد که آیا می خواهید نسخه های موجود در برنامه را به روز کنید یا از آن استفاده کنید. اگر با خطاهای کامپایل "عجیب" مواجه شدید، سعی کنید از ترکیب نسخه های کتابخانه ای که برنامه راه حل نهایی استفاده می کند استفاده کنید. - فایل ماژول Gradle. به وابستگیهای ارائهشده برای همه کتابخانههای Android Jetpack، از جمله
Room
، و وابستگیهای کوروتینها توجه کنید.
- به بسته ها و UI نگاهی بیندازید. برنامه بر اساس عملکرد ساختار یافته است. این بسته حاوی فایلهای نگهدارنده است که در آن کد را در این سری از کدها اضافه خواهید کرد.
- بسته
database
، برای همه کدهای مربوط به پایگاه دادهRoom
. - بستههای
sleepquality
وsleeptracker
شامل قطعه، مدل view و کارخانه مدل view برای هر صفحه هستند .
- به فایل
Util.kt
نگاهی بیندازید، که حاوی توابعی برای کمک به نمایش داده های با کیفیت خواب است. برخی از کدها به دلیل ارجاع به یک مدل view که بعداً ایجاد می کنید، توضیح داده می شود. - به پوشه androidTest (
SleepDatabaseTest.kt
) نگاهی بیندازید. شما از این تست برای بررسی اینکه پایگاه داده طبق برنامه کار می کند استفاده خواهید کرد.
در اندروید، دادهها در کلاسهای داده نمایش داده میشوند و دادهها با استفاده از فراخوانی تابع قابل دسترسی و تغییر هستند. با این حال، در دنیای پایگاه داده، شما به نهادها و پرس و جو نیاز دارید.
- یک موجودیت یک شی یا مفهوم و خصوصیات آن را برای ذخیره در پایگاه داده نشان می دهد. یک کلاس موجودیت یک جدول را تعریف می کند و هر نمونه از آن کلاس نشان دهنده یک ردیف در جدول است. هر ویژگی یک ستون را تعریف می کند. در برنامه شما، نهاد اطلاعاتی در مورد یک شب خواب نگه می دارد.
- پرس و جو درخواست داده یا اطلاعات از جدول پایگاه داده یا ترکیبی از جداول یا درخواستی برای انجام عملی بر روی داده است. پرس و جوهای رایج برای دریافت، درج و به روز رسانی موجودیت ها هستند. برای مثال، میتوانید برای تمام شبهای خواب ثبت شده، مرتبسازیشده بر اساس زمان شروع، پرس و جو کنید.
Room
همه کار سختی را برای شما انجام می دهد تا از کلاس های داده Kotlin به موجودیت هایی که می توانند در جداول SQLite ذخیره شوند و از اعلان های تابع تا پرس و جوهای SQL را به دست آورید.
شما باید هر موجودیت را به عنوان یک کلاس داده مشروح، و تعاملات را به عنوان یک رابط مشروح شده، یک شی دسترسی به داده (DAO) تعریف کنید. Room
از این کلاس های حاشیه نویسی برای ایجاد جداول در پایگاه داده و پرس و جوهایی که روی پایگاه داده عمل می کنند استفاده می کند.
مرحله 1: موجودیت SleepNight را ایجاد کنید
در این کار، یک شب خواب را به عنوان یک کلاس داده مشروح تعریف می کنید.
برای یک شب خواب، باید زمان شروع، زمان پایان و رتبه بندی کیفیت را ثبت کنید.
و برای شناسایی منحصر به فرد شب به یک شناسه نیاز دارید.
- در بسته
database
، فایلSleepNight.kt
را پیدا کرده و باز کنید. - کلاس داده
SleepNight
را با پارامترهایی برای شناسه، زمان شروع (بر حسب میلی ثانیه)، زمان پایان (بر حسب میلی ثانیه) و رتبه بندی عددی کیفیت خواب ایجاد کنید.
- شما باید
sleepQuality
را مقداردهی اولیه کنید، بنابراین آن را روی-1
تنظیم کنید، که نشان می دهد هیچ داده با کیفیتی جمع آوری نشده است. - شما همچنین باید زمان پایان را مقداردهی اولیه کنید. آن را روی زمان شروع تنظیم کنید تا نشان دهد که هنوز زمان پایانی ثبت نشده است.
data class SleepNight(
var nightId: Long = 0L,
val startTimeMilli: Long = System.currentTimeMillis(),
var endTimeMilli: Long = startTimeMilli,
var sleepQuality: Int = -1
)
- قبل از اعلان کلاس، کلاس داده را با
@Entity
حاشیه نویسی کنید. نام جدول راdaily_sleep_quality_table
بگذارید. آرگومانtableName
اختیاری است، اما توصیه می شود. می توانید سایر استدلال ها را در مستندات جستجو کنید.
در صورت درخواست،Entity
و تمام حاشیه نویسی های دیگر را از کتابخانهandroidx
وارد کنید.
@Entity(tableName = "daily_sleep_quality_table")
data class SleepNight(...)
- برای شناسایی
nightId
به عنوان کلید اصلی، ویژگیnightId
را با@PrimaryKey
حاشیه نویسی کنید. پارامترautoGenerate
رویtrue
تنظیم کنید تاRoom
برای هر موجودیت شناسه تولید کند. این تضمین می کند که شناسه هر شب منحصر به فرد است.
@PrimaryKey(autoGenerate = true)
var nightId: Long = 0L,...
- ویژگی های باقی مانده را با
@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
)
- کد خود را بسازید و اجرا کنید تا مطمئن شوید که هیچ خطایی ندارد.
در این کار، یک شی دسترسی به داده (DAO) را تعریف می کنید. در اندروید، DAO روشهای آسانی را برای درج، حذف و بهروزرسانی پایگاه داده ارائه میکند.
هنگامی که از پایگاه داده Room
استفاده می کنید، با تعریف و فراخوانی توابع Kotlin در کد خود، پایگاه داده را پرس و جو می کنید. این توابع Kotlin به پرس و جوهای SQL نگاشت می شوند. شما آن نگاشتها را در یک DAO با استفاده از حاشیه نویسی تعریف می کنید و Room
کد لازم را ایجاد می کند.
یک DAO را به عنوان تعریف یک رابط سفارشی برای دسترسی به پایگاه داده خود در نظر بگیرید.
برای عملیات رایج پایگاه داده، کتابخانه Room
حاشیه نویسی های راحت را ارائه می دهد، مانند @Insert
، @Delete
و @Update
. برای هر چیز دیگری، حاشیه نویسی @Query
وجود دارد. می توانید هر درخواستی را که توسط SQLite پشتیبانی می شود بنویسید.
به عنوان یک امتیاز اضافی، هنگامی که پرس و جوهای خود را در Android Studio ایجاد می کنید، کامپایلر پرس و جوهای SQL شما را برای خطاهای نحوی بررسی می کند.
برای پایگاه داده ردیاب خواب شبهای خواب، باید بتوانید کارهای زیر را انجام دهید:
- درج شب های جدید
- برای بهروزرسانی زمان پایان و رتبهبندی کیفیت، یک شب موجود را بهروزرسانی کنید .
- یک شب خاص بر اساس کلید آن دریافت کنید .
- تمام شب ها را دریافت کنید تا بتوانید آنها را نمایش دهید.
- آخرین شب را دریافت کنید.
- تمام ورودی های پایگاه داده را حذف کنید .
مرحله 1: SleepDatabase DAO را ایجاد کنید
- در بسته
database
،SleepDatabaseDao.kt
باز کنید. - توجه داشته باشید که
interface
SleepDatabaseDao
با@Dao
حاشیه نویسی شده است. همه DAO ها باید با کلمه کلیدی@Dao
حاشیه نویسی شوند.
@Dao
interface SleepDatabaseDao {}
- در داخل بدنه رابط، یک حاشیه نویسی
@Insert
اضافه کنید. در زیر@Insert
، یک تابعinsert()
اضافه کنید که نمونه ای از کلاسEntity
SleepNight
را می گیرد. به عنوان استدلال آن
همین است.Room
همه کدهای لازم را برای درجSleepNight
در پایگاه داده تولید می کند. هنگامی کهinsert()
از کد Kotlin خود فرا می خوانید،Room
یک پرس و جوی SQL را برای درج موجودیت در پایگاه داده اجرا می کند. (توجه: می توانید تابع را هر چیزی که می خواهید فراخوانی کنید.)
@Insert
fun insert(night: SleepNight)
- برای یک
SleepNight
یک حاشیه نویسی@Update
با یک تابعupdate()
اضافه کنید. نهادی که بهروزرسانی میشود، نهادی است که دارای کلید مشابهی است که به آن ارسال شده است. میتوانید برخی یا همه ویژگیهای دیگر آن نهاد را بهروزرسانی کنید.
@Update
fun update(night: SleepNight)
هیچ حاشیه نویسی راحتی برای عملکرد باقی مانده وجود ندارد، بنابراین باید از حاشیه نویسی @Query
استفاده کنید و پرس و جوهای SQLite را تهیه کنید.
- یک حاشیه نویسی
@Query
با تابعget()
اضافه کنید که یکkey
Long
می گیرد آرگومان و یکSleepNight
قابل تهی را برمی گرداند. خطای یک پارامتر از دست رفته را خواهید دید.
@Query
fun get(key: Long): SleepNight?
- پرس و جو به عنوان پارامتر رشته ای به حاشیه نویسی ارائه می شود. یک پارامتر به
@Query
اضافه کنید. آن را بهString
تبدیل کنید که یک کوئری SQLite است.
- همه ستون ها را از جدول
daily_sleep_quality_table
انتخاب کنید -
WHERE
nightId
با آرگومانkey
: مطابقت دارد.
به:key
توجه کنید. برای ارجاع آرگومان های تابع از علامت دو نقطه در پرس و جو استفاده می کنید.
("SELECT * from daily_sleep_quality_table WHERE nightId = :key")
- یک
@Query
دیگر با یک تابعclear()
و یک جستجوی SQLite اضافه کنید تا همه چیز را ازdaily_sleep_quality_table
DELETE
. این پرس و جو خود جدول را حذف نمی کند.
حاشیهنویسی@Delete
یک مورد را حذف میکند و میتوانید از@Delete
استفاده کنید و فهرستی از شبها را برای حذف ارائه دهید. اشکال این است که شما باید آنچه را در جدول وجود دارد واکشی کنید یا بدانید. حاشیهنویسی@Delete
برای حذف ورودیهای خاص عالی است، اما برای پاک کردن همه ورودیهای یک جدول کارآمد نیست.
@Query("DELETE FROM daily_sleep_quality_table")
fun clear()
- یک
@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?
- یک
@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>>
- اگرچه هیچ تغییر قابل مشاهده ای نمی بینید، برنامه خود را اجرا کنید تا مطمئن شوید که هیچ خطایی ندارد.
در این کار، شما یک پایگاه داده Room
ایجاد می کنید که از Entity
و DAO که در کار قبلی ایجاد کرده اید استفاده می کند.
شما باید یک کلاس دارنده پایگاه داده انتزاعی ایجاد کنید که با @Database
حاشیه نویسی شده باشد. این کلاس یک متد دارد که اگر پایگاه داده وجود نداشته باشد نمونه ای از پایگاه داده را ایجاد می کند یا یک مرجع به پایگاه داده موجود برمی گرداند.
گرفتن یک پایگاه داده Room
کمی دخیل است، بنابراین قبل از شروع با کد، روند کلی در اینجا آمده است:
- یک کلاس
public abstract
ایجاد کنید کهextends RoomDatabase
. این کلاس به عنوان دارنده پایگاه داده عمل می کند. کلاس انتزاعی است، زیراRoom
پیاده سازی را برای شما ایجاد می کند. - کلاس را با
@Database
حاشیه نویسی کنید. در آرگومان ها، موجودیت های پایگاه داده را اعلام کرده و شماره نسخه را تنظیم کنید. - در داخل یک شی
companion
، یک متد یا ویژگی انتزاعی تعریف کنید که یکSleepDatabaseDao
برمی گرداند.Room
برای شما بدن تولید می کند. - شما فقط به یک نمونه از پایگاه داده
Room
برای کل برنامه نیاز دارید، بنابراینRoomDatabase
یک تکتونه کنید. - تنها در صورتی که پایگاه داده وجود نداشته باشد، از سازنده پایگاه داده
Room
برای ایجاد پایگاه داده استفاده کنید. در غیر این صورت، پایگاه داده موجود را برگردانید.
مرحله 1: ایجاد پایگاه داده
- در بسته
database
،SleepDatabase.kt
باز کنید. - در فایل، یک کلاس
abstract
به نامSleepDatabase
ایجاد کنید کهRoomDatabase
گسترش می دهد.
کلاس را با@Database
حاشیه نویسی کنید.
@Database()
abstract class SleepDatabase : RoomDatabase() {}
- خطای موجودیت ها و پارامترهای نسخه را مشاهده خواهید کرد. حاشیه نویسی
@Database
به چندین آرگومان نیاز دارد تاRoom
بتواند پایگاه داده را بسازد.
-
SleepNight
به عنوان تنها مورد با لیستentities
عرضه کنید. -
version
را به عنوان1
تنظیم کنید . هر زمان که شما طرح را تغییر دهید، باید شماره نسخه را افزایش دهید. -
exportSchema
رویfalse
قرار دهید تا نسخه پشتیبانگیری از تاریخچه نسخه طرحواره حفظ نشود.
entities = [SleepNight::class], version = 1, exportSchema = false
- پایگاه داده باید در مورد DAO بداند. در داخل بدنه کلاس، یک مقدار انتزاعی را اعلام کنید که
SleepDatabaseDao
برمی گرداند. شما می توانید چندین DAO داشته باشید.
abstract val sleepDatabaseDao: SleepDatabaseDao
- در زیر آن، یک شیء
companion
تعریف کنید. شیء companion به مشتریان اجازه می دهد تا بدون نمونه سازی کلاس به متدهای ایجاد یا دریافت پایگاه داده دسترسی داشته باشند. از آنجایی که تنها هدف این کلاس ارائه یک پایگاه داده است، هیچ دلیلی برای نمونه سازی آن وجود ندارد.
companion object {}
- در داخل شی
companion
، یک متغیر تهی پذیر خصوصیINSTANCE
برای پایگاه داده اعلام کنید و آن را بهnull
مقداردهی کنید. متغیرINSTANCE
یک مرجع به پایگاه داده، پس از ایجاد پایگاه داده نگه می دارد. این به شما کمک می کند تا از باز کردن مکرر اتصالات به پایگاه داده جلوگیری کنید که گران است.
INSTANCE
با @Volatile
حاشیه نویسی کنید. مقدار متغیر فرار هرگز در حافظه پنهان ذخیره نمی شود و تمام نوشتن و خواندن به حافظه اصلی و از آن انجام می شود. این کمک می کند مطمئن شوید که مقدار INSTANCE
همیشه به روز است و برای همه رشته های اجرایی یکسان است. این بدان معناست که تغییرات ایجاد شده توسط یک رشته به INSTANCE
برای همه رشتههای دیگر بلافاصله قابل مشاهده است، و شما موقعیتی را دریافت نمیکنید که مثلاً دو رشته هر کدام یک موجودیت مشابه را در حافظه پنهان بهروزرسانی کنند، که مشکل ایجاد میکند.
@Volatile
private var INSTANCE: SleepDatabase? = null
- در زیر
INSTANCE
، هنوز در داخل شیءcompanion
، یک متدgetInstance()
با پارامترContext
تعریف کنید که سازنده پایگاه داده به آن نیاز دارد. یک نوعSleepDatabase
را برگردانید. یک خطایی خواهید دید زیراgetInstance()
هنوز چیزی را بر نمی گرداند.
fun getInstance(context: Context): SleepDatabase {}
- داخل
getInstance()
یک بلوکsynchronized{}
اضافه کنید.this
را پاس کنید تا بتوانید به متن دسترسی داشته باشید.
چندین رشته به طور بالقوه می توانند به طور همزمان یک نمونه پایگاه داده را درخواست کنند که منجر به ایجاد دو پایگاه داده به جای یک پایگاه داده شود. این مشکل به احتمال زیاد در این نمونه برنامه اتفاق نمی افتد، اما برای یک برنامه پیچیده تر امکان پذیر است. بسته بندی کد برایsynchronized
پایگاه داده به این معنی است که تنها یک رشته اجرا در هر زمان می تواند وارد این بلوک کد شود، که مطمئن می شود پایگاه داده فقط یک بار مقداردهی اولیه می شود.
synchronized(this) {}
- در داخل بلوک همگامسازی شده، مقدار فعلی
INSTANCE
را در یکinstance
متغیر محلی کپی کنید. این برای استفاده از قابلیت پخش هوشمند است که فقط برای متغیرهای محلی در دسترس است.
var instance = INSTANCE
- در داخل بلوک
synchronized
، نمونهای را در انتهای بلوکsynchronized
return instance
. خطای عدم تطابق نوع بازگشتی را نادیده بگیرید. پس از اتمام کار هرگز نخواهید برگشت.
return instance
- بالای دستور
return
، یک دستورif
اضافه کنید تا بررسی کنید که آیاinstance
صفر است یا نه، یعنی هنوز پایگاه داده ای وجود ندارد.
if (instance == null) {}
- اگر
instance
null
است، از سازنده پایگاه داده برای دریافت پایگاه داده استفاده کنید. در بدنه دستورif
،Room.databaseBuilder
را فراخوانی کنید و متنی را که در آن ارسال کردید، کلاس پایگاه داده و یک نام برای پایگاه داده،sleep_history_database
ارائه کنید. برای حذف خطا، باید یک استراتژی مهاجرت وbuild()
در مراحل زیر اضافه کنید.
instance = Room.databaseBuilder(
context.applicationContext,
SleepDatabase::class.java,
"sleep_history_database")
- استراتژی مهاجرت مورد نیاز را به سازنده اضافه کنید.
.fallbackToDestructiveMigration()
استفاده کنید.
به طور معمول، شما باید یک شی مهاجرت را با یک استراتژی مهاجرت برای زمانی که طرحواره تغییر می کند ارائه دهید. یک شیء مهاجرتی ، شیئی است که تعریف میکند چگونه همه ردیفها را با طرحواره قدیمی بگیرید و آنها را به ردیفهایی در طرح جدید تبدیل کنید، به طوری که هیچ دادهای از بین نرود. مهاجرت فراتر از محدوده این کد آزمایشگاه است. یک راه حل ساده، تخریب و بازسازی پایگاه داده است، به این معنی که داده ها از بین می روند.
.fallbackToDestructiveMigration()
- در نهایت،
.build()
را فراخوانی کنید.
.build()
INSTANCE = instance
به عنوان مرحله نهایی داخل دستورif
اختصاص دهید.
INSTANCE = instance
- کد نهایی شما باید به شکل زیر باشد:
@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
}
}
}
}
- کد خود را بسازید و اجرا کنید.
شما اکنون تمام بلوک های سازنده برای کار با پایگاه داده Room
خود را دارید. این کد کامپایل می شود و اجرا می شود، اما شما هیچ راهی برای تشخیص کارکرد آن ندارید. بنابراین، این زمان خوبی برای اضافه کردن چند تست اساسی است.
مرحله 2: SleepDatabase را تست کنید
در این مرحله، تست های ارائه شده را برای بررسی کارکرد پایگاه داده خود اجرا می کنید. این کمک می کند تا اطمینان حاصل شود که پایگاه داده قبل از ساختن روی آن کار می کند. تست های ارائه شده پایه هستند. برای یک برنامه تولیدی، شما باید تمام عملکردها و پرس و جوها را در همه DAO ها اعمال کنید.
برنامه شروع کننده حاوی یک پوشه AndroidTest است. این پوشه AndroidTest شامل تستهای واحدی است که شامل ابزار دقیق اندروید میشود، که روشی فانتزی برای گفتن این است که تستها به چارچوب اندروید نیاز دارند، بنابراین باید آزمایشها را روی یک دستگاه فیزیکی یا مجازی اجرا کنید. البته، میتوانید تستهای واحد خالص را نیز ایجاد و اجرا کنید که شامل فریمورک اندروید نیست.
- در Android Studio، در پوشه androidTest ، فایل SleepDatabaseTest را باز کنید.
- برای لغو کامنت کد، همه کدهای نظر داده شده را انتخاب کنید و میانبر صفحه کلید
Cmd+/
یاControl+/
را فشار دهید. - به فایل نگاهی بیندازید.
در اینجا یک بررسی سریع از کد آزمایشی وجود دارد، زیرا این کد دیگری است که می توانید مجدداً از آن استفاده کنید:
-
SleepDabaseTest
یک کلاس آزمایشی است . - حاشیه نویسی
@RunWith
، اجرای آزمایشی را مشخص می کند، که برنامه ای است که تست ها را تنظیم و اجرا می کند. - در طول راهاندازی، تابع مشروح شده با
@Before
اجرا میشود و یکSleepDatabase
در حافظه باSleepDatabaseDao
ایجاد میکند. "In-Memory" به این معنی است که این پایگاه داده در سیستم فایل ذخیره نمی شود و پس از اجرای آزمایش ها حذف می شود. - همچنین هنگام ساخت پایگاه داده درون حافظه، کد روش دیگری را که مربوط به تست است،
allowMainThreadQueries
فراخوانی می کند. به طور پیش فرض، اگر سعی کنید کوئری ها را در رشته اصلی اجرا کنید، با خطا مواجه می شوید. این روش به شما اجازه می دهد تا تست هایی را روی رشته اصلی اجرا کنید که فقط باید در حین تست انجام دهید. - در یک روش آزمایشی که با
@Test
حاشیه نویسی شده است، یکSleepNight
را ایجاد، درج و بازیابی می کنید و اظهار می کنید که آنها یکسان هستند. اگر مشکلی پیش آمد، یک استثنا بیندازید. در یک تست واقعی، چندین@Test
خواهید داشت روش ها - وقتی تست انجام شد، تابع مشروح شده با
@After
برای بستن پایگاه داده اجرا می شود.
- روی فایل تست در پنجره Project کلیک راست کرده و Run 'SleepDatabaseTest' را انتخاب کنید.
- پس از اجرای تستها، در پنل SleepDatabaseTest تأیید کنید که تمام تستها قبول شدهاند.
از آنجایی که تمام تست ها گذرانده شده اند، اکنون چندین چیز را می دانید:
- پایگاه داده به درستی ایجاد می شود.
- می توانید یک
SleepNight
را در پایگاه داده وارد کنید. - می توانید
SleepNight
را برگردانید. -
SleepNight
ارزش مناسبی برای کیفیت دارد.
پروژه اندروید استودیو: TrackMySleepQualityRoomAndTesting
هنگام آزمایش یک پایگاه داده، باید تمام روش های تعریف شده در DAO را اعمال کنید. برای تکمیل تست ، تست هایی را اضافه و اجرا کنید تا روش های دیگر DAO را اعمال کنید.
- جداول خود را به عنوان کلاس های داده مشروح شده با
@Entity
تعریف کنید. ویژگی های حاشیه نویسی شده با@ColumnInfo
را به عنوان ستون در جداول تعریف کنید. - یک شی دسترسی به داده (DAO) را به عنوان یک رابط مشروح شده با
@Dao
تعریف کنید. DAO توابع Kotlin را به پرس و جوهای پایگاه داده نگاشت می کند. - از حاشیه نویسی برای تعریف توابع
@Insert
،@Delete
و@Update
استفاده کنید. - از حاشیه نویسی
@Query
با رشته پرس و جو SQLite به عنوان پارامتر برای هر جستار دیگر استفاده کنید. - یک کلاس انتزاعی ایجاد کنید که دارای تابع
getInstance()
باشد که پایگاه داده را برمی گرداند. - از تست های ابزاری برای آزمایش اینکه پایگاه داده و DAO شما مطابق انتظار کار می کنند استفاده کنید. می توانید از تست های ارائه شده به عنوان الگو استفاده کنید.
دوره بی ادبی:
مستندات برنامه نویس اندروید:
-
RoomDatabase
-
Database
(یادداشت ها) - میتوانید از درخواستهای خام با
Room
استفاده کنید -
Roomdatabase.Builder
- آموزش تست
- کلاس
SQLiteDatabase
-
Dao
- کتابخانه ماندگاری
Room
سایر اسناد و مقالات:
این بخش، تکالیف احتمالی را برای دانشآموزانی که در این آزمایشگاه کد به عنوان بخشی از دورهای که توسط یک مربی هدایت میشود، کار میکنند، فهرست میکند. این وظیفه مربی است که موارد زیر را انجام دهد:
- در صورت نیاز تکالیف را تعیین کنید.
- نحوه ارسال تکالیف را با دانش آموزان در میان بگذارید.
- تکالیف را نمره دهید.
مربیان میتوانند از این پیشنهادات به اندازهای که میخواهند استفاده کنند، و باید با خیال راحت هر تکلیف دیگری را که فکر میکنند مناسب است، محول کنند.
اگر به تنهایی از طریق این کدها کار می کنید، از این تکالیف برای آزمایش دانش خود استفاده کنید.
به این سوالات پاسخ دهید
سوال 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
را اجرا کنید.
شروع به درس بعدی:
برای پیوند به سایر کدهای این دوره، به صفحه فرود کد لبههای کد پایه 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: برنامه شروع را دانلود و اجرا کنید
- برنامه TrackMySleepQuality-Starter را از GitHub دانلود کنید.
- برنامه را بسازید و اجرا کنید. برنامه رابط کاربری بخش
SleepTrackerFragment
را نشان می دهد، اما داده ای ندارد. دکمه ها به ضربه ها پاسخ نمی دهند.
مرحله 2: برنامه شروع را بررسی کنید
- به فایل های Gradle نگاهی بیندازید:
- فایل پروژه Gradle
در فایلbuild.gradle
در سطح پروژه، به متغیرهایی که نسخه های کتابخانه را مشخص می کنند توجه کنید. نسخه های استفاده شده در برنامه استارتر به خوبی با هم کار می کنند و با این برنامه به خوبی کار می کنند. تا زمانی که این کد لبه را تمام کنید، ممکن است Android Studio از شما بخواهد که برخی از نسخه ها را به روز کنید. این به شما بستگی دارد که آیا می خواهید نسخه های موجود در برنامه را به روز کنید یا از آن استفاده کنید. اگر با خطاهای کامپایل "عجیب" مواجه شدید، سعی کنید از ترکیب نسخه های کتابخانه ای که برنامه راه حل نهایی استفاده می کند استفاده کنید. - فایل ماژول Gradle. به وابستگیهای ارائهشده برای همه کتابخانههای Android Jetpack، از جمله
Room
، و وابستگیهای کوروتینها توجه کنید.
- به بسته ها و UI نگاهی بیندازید. برنامه بر اساس عملکرد ساختار یافته است. این بسته حاوی فایلهای نگهدارنده است که در آن کد را در این سری از کدها اضافه خواهید کرد.
- بسته
database
، برای همه کدهای مربوط به پایگاه دادهRoom
. - بستههای
sleepquality
وsleeptracker
شامل قطعه، مدل view و کارخانه مدل view برای هر صفحه هستند .
- به فایل
Util.kt
نگاهی بیندازید، که حاوی توابعی برای کمک به نمایش داده های با کیفیت خواب است. برخی از کدها به دلیل ارجاع به یک مدل view که بعداً ایجاد می کنید، توضیح داده می شود. - به پوشه androidTest (
SleepDatabaseTest.kt
) نگاهی بیندازید. شما از این تست برای بررسی اینکه پایگاه داده طبق برنامه کار می کند استفاده خواهید کرد.
در اندروید، دادهها در کلاسهای داده نمایش داده میشوند و دادهها با استفاده از فراخوانی تابع قابل دسترسی و تغییر هستند. با این حال، در دنیای پایگاه داده، شما به نهادها و پرس و جو نیاز دارید.
- یک موجودیت یک شی یا مفهوم و خصوصیات آن را برای ذخیره در پایگاه داده نشان می دهد. یک کلاس موجودیت یک جدول را تعریف می کند و هر نمونه از آن کلاس نشان دهنده یک ردیف در جدول است. هر ویژگی یک ستون را تعریف می کند. در برنامه شما، نهاد اطلاعاتی در مورد یک شب خواب نگه می دارد.
- پرس و جو درخواست داده یا اطلاعات از جدول پایگاه داده یا ترکیبی از جداول یا درخواستی برای انجام عملی بر روی داده است. پرس و جوهای رایج برای دریافت، درج و به روز رسانی موجودیت ها هستند. برای مثال، میتوانید برای تمام شبهای خواب ثبت شده، مرتبسازیشده بر اساس زمان شروع، پرس و جو کنید.
Room
همه کار سختی را برای شما انجام می دهد تا از کلاس های داده Kotlin به موجودیت هایی که می توانند در جداول SQLite ذخیره شوند و از اعلان های تابع تا پرس و جوهای SQL را به دست آورید.
شما باید هر موجودیت را به عنوان یک کلاس داده مشروح، و تعاملات را به عنوان یک رابط مشروح شده، یک شی دسترسی به داده (DAO) تعریف کنید. Room
از این کلاس های حاشیه نویسی برای ایجاد جداول در پایگاه داده و پرس و جوهایی که روی پایگاه داده عمل می کنند استفاده می کند.
مرحله 1: موجودیت SleepNight را ایجاد کنید
در این کار، یک شب خواب را به عنوان یک کلاس داده مشروح تعریف می کنید.
برای یک شب خواب، باید زمان شروع، زمان پایان و رتبه بندی کیفیت را ثبت کنید.
و برای شناسایی منحصر به فرد شب به یک شناسه نیاز دارید.
- در بسته
database
، فایلSleepNight.kt
را پیدا کرده و باز کنید. - کلاس داده
SleepNight
را با پارامترهایی برای شناسه، زمان شروع (بر حسب میلی ثانیه)، زمان پایان (بر حسب میلی ثانیه) و رتبه بندی عددی کیفیت خواب ایجاد کنید.
- شما باید
sleepQuality
را مقداردهی اولیه کنید، بنابراین آن را روی-1
تنظیم کنید، که نشان می دهد هیچ داده با کیفیتی جمع آوری نشده است. - شما همچنین باید زمان پایان را مقداردهی اولیه کنید. آن را روی زمان شروع تنظیم کنید تا نشان دهد که هنوز زمان پایانی ثبت نشده است.
data class SleepNight(
var nightId: Long = 0L,
val startTimeMilli: Long = System.currentTimeMillis(),
var endTimeMilli: Long = startTimeMilli,
var sleepQuality: Int = -1
)
- قبل از اعلان کلاس، کلاس داده را با
@Entity
حاشیه نویسی کنید. نام جدول راdaily_sleep_quality_table
بگذارید. آرگومانtableName
اختیاری است، اما توصیه می شود. می توانید سایر استدلال ها را در مستندات جستجو کنید.
در صورت درخواست،Entity
و تمام حاشیه نویسی های دیگر را از کتابخانهandroidx
وارد کنید.
@Entity(tableName = "daily_sleep_quality_table")
data class SleepNight(...)
- برای شناسایی
nightId
به عنوان کلید اصلی، ویژگیnightId
را با@PrimaryKey
حاشیه نویسی کنید. پارامترautoGenerate
رویtrue
تنظیم کنید تاRoom
برای هر موجودیت شناسه تولید کند. این تضمین می کند که شناسه هر شب منحصر به فرد است.
@PrimaryKey(autoGenerate = true)
var nightId: Long = 0L,...
- ویژگی های باقی مانده را با
@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
)
- کد خود را بسازید و اجرا کنید تا مطمئن شوید که هیچ خطایی ندارد.
در این کار، یک شی دسترسی به داده (DAO) را تعریف می کنید. در اندروید، DAO روشهای آسانی را برای درج، حذف و بهروزرسانی پایگاه داده ارائه میکند.
هنگامی که از پایگاه داده Room
استفاده می کنید، با تعریف و فراخوانی توابع Kotlin در کد خود، پایگاه داده را پرس و جو می کنید. این توابع Kotlin به پرس و جوهای SQL نگاشت می شوند. شما آن نگاشتها را در یک DAO با استفاده از حاشیه نویسی تعریف می کنید و Room
کد لازم را ایجاد می کند.
یک DAO را به عنوان تعریف یک رابط سفارشی برای دسترسی به پایگاه داده خود در نظر بگیرید.
برای عملیات رایج پایگاه داده، کتابخانه Room
حاشیه نویسی های راحت را ارائه می دهد، مانند @Insert
، @Delete
و @Update
. برای هر چیز دیگری، حاشیه نویسی @Query
وجود دارد. می توانید هر درخواستی را که توسط SQLite پشتیبانی می شود بنویسید.
به عنوان یک امتیاز اضافی، هنگامی که پرس و جوهای خود را در Android Studio ایجاد می کنید، کامپایلر پرس و جوهای SQL شما را برای خطاهای نحوی بررسی می کند.
برای پایگاه داده ردیاب خواب شبهای خواب، باید بتوانید کارهای زیر را انجام دهید:
- درج شب های جدید
- برای بهروزرسانی زمان پایان و رتبهبندی کیفیت، یک شب موجود را بهروزرسانی کنید .
- یک شب خاص بر اساس کلید آن دریافت کنید .
- تمام شب ها را دریافت کنید تا بتوانید آنها را نمایش دهید.
- آخرین شب را دریافت کنید.
- تمام ورودی های پایگاه داده را حذف کنید .
مرحله 1: SleepDatabase DAO را ایجاد کنید
- در بسته
database
،SleepDatabaseDao.kt
باز کنید. - توجه کنید که
interface
SleepDatabaseDao
با@Dao
حاشیه نویسی شده است. همه DAO ها باید با کلمه کلیدی@Dao
حاشیه نویسی شوند.
@Dao
interface SleepDatabaseDao {}
- در داخل بدنه رابط ، حاشیه نویسی
@Insert
را اضافه کنید. در زیر@Insert
، یک تابعinsert()
اضافه کنید که نمونه ای ازSleepNight
ClassEntity
را در بر می گیرد به عنوان استدلال خود
همین است.Room
تمام کد لازم را برای وارد کردنSleepNight
در پایگاه داده ایجاد می کند. هنگامی که از کد Kotlin خودinsert()
تماس می گیرید ،Room
یک پرس و جو SQL را برای وارد کردن موجودیت در پایگاه داده اجرا می کند. (توجه: می توانید هر چیزی را که می خواهید با عملکرد تماس بگیرید.)
@Insert
fun insert(night: SleepNight)
- برای یک
SleepNight
یک یادداشت@Update
را با یک عملکردupdate()
اضافه کنید. موجودی که به روز شده است ، موجودی است که همان کلید را دارد که در آن منتقل شده است. می توانید برخی یا تمام خصوصیات دیگر موجودیت را به روز کنید.
@Update
fun update(night: SleepNight)
هیچ گونه حاشیه نویسی برای عملکرد باقی مانده وجود ندارد ، بنابراین شما باید از یادداشت های @Query
و عرضه SQLite استفاده کنید.
- یک یادداشت
@Query
را با یک عملکردget()
اضافه کنید که یکkey
Long
طول می کشد استدلال و یکSleepNight
قابل برگشت را برمی گرداند. خطایی برای یک پارامتر گمشده مشاهده خواهید کرد.
@Query
fun get(key: Long): SleepNight?
- پرس و جو به عنوان یک پارامتر رشته برای حاشیه نویسی تهیه می شود. یک پارامتر به
@Query
اضافه کنید. آن راString
درست کنید که یک پرس و جو sqlite باشد.
- همه ستون ها را از
daily_sleep_quality_table
انتخاب کنید -
WHERE
nightId
با: استدلالkey
مطابقت دارد.
توجه کنید:key
. شما از نماد روده بزرگ در پرس و جو برای آرگومان های مرجع در عملکرد استفاده می کنید.
("SELECT * from daily_sleep_quality_table WHERE nightId = :key")
- your
@Query
با یک عملکردclear()
و یک پرس و جو sqlite اضافه کنید تا همه چیز را ازdaily_sleep_quality_table
DELETE
. این پرس و جو خود جدول را حذف نمی کند.
حاشیه@Delete
delete یک مورد را حذف می کند ، و می توانید@Delete
استفاده کنید و لیستی از شبها را برای حذف تهیه کنید. اشکال این است که شما باید واکشی کنید یا بدانید که در جدول چیست. حاشیه نویسی@Delete
برای حذف ورودی های خاص عالی است ، اما برای پاک کردن تمام ورودی ها از یک جدول کارآمد نیست.
@Query("DELETE FROM daily_sleep_quality_table")
fun clear()
- با یک عملکرد
getTonight()
یک@Query
اضافه کنید.SleepNight
که توسطgetTonight()
قابل بازگشت است ، برگردانید تا عملکرد بتواند موردی را که جدول خالی است ، کنترل کند. (جدول در ابتدا خالی است و پس از پاک شدن داده ها.)
برای دریافت "امشب" از پایگاه داده ، یک پرس و جو SQLITE بنویسید که اولین عنصر لیستی از نتایج سفارش داده شده توسطnightId
را به ترتیب نزولی باز می گرداند. برای بازگشت تنها یک عنصرLIMIT 1
استفاده کنید.
@Query("SELECT * FROM daily_sleep_quality_table ORDER BY nightId DESC LIMIT 1")
fun getTonight(): SleepNight?
- یک عملکرد
@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>>
- اگرچه هیچ گونه تغییر قابل مشاهده ای را مشاهده نخواهید کرد ، برنامه خود را اجرا کنید تا مطمئن شوید که هیچ خطایی ندارد.
در این کار ، شما یک پایگاه داده Room
ایجاد می کنید که از Entity
و DAO که در کار قبلی ایجاد کرده اید استفاده می کند.
شما باید یک کلاس نگهدارنده پایگاه داده انتزاعی ایجاد کنید ، حاشیه نویسی با @Database
. این کلاس دارای یک روش است که در صورت وجود بانک اطلاعاتی ، نمونه ای از پایگاه داده را ایجاد می کند ، یا مرجع را به یک پایگاه داده موجود باز می گرداند.
گرفتن یک پایگاه داده Room
کمی درگیر است ، بنابراین در اینجا روند کلی قبل از شروع با کد وجود دارد:
- یک کلاس
public abstract
ایجاد کنید کهextends RoomDatabase
. این کلاس به عنوان دارنده بانک اطلاعاتی عمل می کند. کلاس انتزاعی است ، زیراRoom
پیاده سازی را برای شما ایجاد می کند. - کلاس را با
@Database
حاشیه نویسی کنید. در آرگومان ، اشخاص را برای پایگاه داده اعلام کرده و شماره نسخه را تنظیم کنید. - در داخل یک شی
companion
، یک روش انتزاعی یا خاصیتی را تعریف کنید که یکSleepDatabaseDao
برمی گرداند.Room
بدن را برای شما ایجاد می کند. - شما فقط به یک نمونه از پایگاه داده
Room
برای کل برنامه نیاز دارید ، بنابراینRoomDatabase
به یک مجرد تبدیل کنید. - از سازنده پایگاه داده
Room
استفاده کنید تا پایگاه داده ایجاد کنید در صورت عدم وجود بانک اطلاعاتی. در غیر این صورت ، پایگاه داده موجود را برگردانید.
مرحله 1: پایگاه داده را ایجاد کنید
- در بسته
database
،SleepDatabase.kt
باز کنید. - در پرونده ، یک کلاس
abstract
به نامSleepDatabase
ایجاد کنید کهRoomDatabase
گسترش می دهد.
کلاس را با@Database
حاشیه نویسی کنید.
@Database()
abstract class SleepDatabase : RoomDatabase() {}
- خطایی برای اشخاص گمشده و پارامترهای نسخه مشاهده خواهید کرد. حاشیه نویسی
@Database
به چندین استدلال نیاز دارد تاRoom
بتواند پایگاه داده را بسازد.
-
SleepNight
به عنوان تنها مورد با لیستentities
تهیه کنید. -
version
را به صورت1
تنظیم کنید . هر زمان که طرح را تغییر دهید ، باید شماره نسخه را افزایش دهید. -
exportSchema
بهfalse
تنظیم کنید ، تا از نسخه پشتیبان تهیه نسخه Schema استفاده نکنید.
entities = [SleepNight::class], version = 1, exportSchema = false
- این بانک اطلاعاتی باید در مورد DAO اطلاع داشته باشد. در داخل بدن کلاس ، یک مقدار انتزاعی را اعلام کنید که
SleepDatabaseDao
برمی گرداند. شما می توانید چندین DAO داشته باشید.
abstract val sleepDatabaseDao: SleepDatabaseDao
- در زیر آن ، یک شی
companion
را تعریف کنید. شیء همراه به مشتریان این امکان را می دهد تا بدون فوری کلاس ، به روشهای ایجاد یا گرفتن پایگاه داده دسترسی پیدا کنند. از آنجا که تنها هدف از این کلاس ارائه یک بانک اطلاعاتی است ، هیچ دلیلی برای فوری آن وجود ندارد.
companion object {}
- در داخل شیء
companion
، یک نمونه متغیر قابل تهی خصوصیINSTANCE
برای پایگاه داده اعلام کرده و آن را بهnull
تنظیم کنید. متغیرINSTANCE
، پس از ایجاد یک ، به پایگاه داده مراجعه می کند. این به شما کمک می کند تا به طور مکرر از اتصالات به پایگاه داده جلوگیری کنید که گران است.
نمونه INSTANCE
با @Volatile
. مقدار یک متغیر فرار هرگز ذخیره نمی شود و همه می نویسد و می خواند و از حافظه اصلی و از طریق حافظه اصلی انجام می شود. این به اطمینان حاصل می شود که مقدار INSTANCE
همیشه به روز است و برای همه موضوعات اجرا یکسان است. این بدان معناست که تغییرات ایجاد شده توسط یک موضوع به INSTANCE
بلافاصله برای همه موضوعات دیگر قابل مشاهده است ، و شما شرایطی را پیدا نمی کنید که مثلاً دو موضوع هر یک از یکسان را در یک حافظه نهان به روز کنید ، که این امر باعث ایجاد مشکل می شود.
@Volatile
private var INSTANCE: SleepDatabase? = null
- در زیر
INSTANCE
، هنوز هم در داخل شیءcompanion
، یک روشgetInstance()
را با یک پارامترContext
که سازنده پایگاه داده به آن نیاز دارد تعریف کنید. یک نوعSleepDatabase
برگردانید. خطایی را مشاهده خواهید کرد زیراgetInstance()
هنوز هیچ چیزی را برمی گرداند.
fun getInstance(context: Context): SleepDatabase {}
- در داخل
getInstance()
، یک بلوکsynchronized{}
اضافه کنید. درthis
عبور کنید تا بتوانید به متن دسترسی پیدا کنید.
موضوعات متعدد به طور بالقوه می توانند یک نمونه بانک اطلاعاتی را به طور همزمان درخواست کنند ، و در نتیجه دو پایگاه داده به جای یک. این مشکل به احتمال زیاد در این برنامه نمونه اتفاق نمی افتد ، اما برای یک برنامه پیچیده تر امکان پذیر است. بسته بندی کد برای به دست آوردن بانکsynchronized
به این معنی است که فقط یک موضوع اجرای در یک زمان می تواند این بلوک از کد را وارد کند ، که باعث می شود پایگاه داده فقط یک بار اولیه شود.
synchronized(this) {}
- در داخل بلوک هماهنگ شده ، مقدار فعلی
INSTANCE
را در یکinstance
متغیر محلی کپی کنید. این برای استفاده از بازیگران هوشمند است که فقط در دسترس متغیرهای محلی است.
var instance = INSTANCE
- در داخل بلوک
synchronized
،return instance
در انتهای بلوکsynchronized
. خطای عدم تطابق نوع بازگشت را نادیده بگیرید. پس از اتمام کار ، هرگز تهی نخواهید کرد.
return instance
- بالاتر از بیانیه
return
، یک عبارتif
را اضافه کنید تا بررسی کنید که آیاinstance
تهی است ، یعنی هنوز پایگاه داده ای وجود ندارد.
if (instance == null) {}
- اگر
instance
null
است ، برای تهیه یک پایگاه داده از سازنده پایگاه داده استفاده کنید. در بدنه بیانیهif
، repokeRoom.databaseBuilder
و زمینه ای را که در آن عبور کرده اید ، کلاس پایگاه داده و نامی برای بانک اطلاعاتی ،sleep_history_database
تهیه کنید. برای رفع خطا ، باید در مراحل زیر یک استراتژی مهاجرت اضافه کرده وbuild()
.
instance = Room.databaseBuilder(
context.applicationContext,
SleepDatabase::class.java,
"sleep_history_database")
- استراتژی مهاجرت مورد نیاز را به سازنده اضافه کنید. استفاده از
.fallbackToDestructiveMigration()
.
به طور معمول ، شما باید یک شیء مهاجرت را با یک استراتژی مهاجرت برای زمان تغییر طرح ارائه دهید. یک شیء مهاجرت یک شیء است که چگونه شما همه ردیف ها را با طرح قدیمی می گیرید و آنها را در طرح جدید به ردیف تبدیل می کنید ، به طوری که هیچ داده ای از بین نمی رود. مهاجرت فراتر از محدوده این CodeLab است. یک راه حل ساده نابودی و بازسازی بانک اطلاعاتی است ، به این معنی که داده ها از بین می روند.
.fallbackToDestructiveMigration()
- سرانجام ، تماس بگیرید
.build()
.
.build()
- به عنوان
INSTANCE = instance
به عنوان مرحله آخر در بیانیهif
اختصاص دهید.
INSTANCE = instance
- کد نهایی شما باید به این شکل باشد:
@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
}
}
}
}
- کد خود را بسازید و اجرا کنید.
شما اکنون تمام بلوک های ساختمانی را برای کار با پایگاه داده Room
خود دارید. این کد کامپایل و اجرا می شود ، اما شما هیچ راهی برای گفتن اینکه آیا واقعاً کار می کند ، ندارید. بنابراین ، این زمان خوبی برای اضافه کردن برخی از تست های اساسی است.
مرحله 2: SleepDatabase را آزمایش کنید
در این مرحله ، شما تست هایی را برای تأیید اینکه پایگاه داده شما کار می کند ، انجام داده اید. این به اطمینان حاصل می شود که پایگاه داده قبل از ساختن آن کار کند. تست های ارائه شده اساسی هستند. برای یک برنامه تولید ، شما تمام کارکردها و نمایش داده ها را در تمام DAO ها انجام می دهید.
برنامه استارت شامل یک پوشه AndroidTest است. این پوشه AndroidTest شامل تست های واحد است که شامل ابزار دقیق Android است ، این یک روش جالب برای گفتن است که آزمایشات به چارچوب Android نیاز دارند ، بنابراین شما باید آزمایشات را روی یک دستگاه فیزیکی یا مجازی اجرا کنید. البته ، شما همچنین می توانید تست های واحد خالص را که شامل چارچوب Android نیست ، ایجاد و اجرا کنید.
- در Android Studio ، در پوشه AndroidTest ، پرونده SleepDatabasetest را باز کنید.
- برای نادیده گرفتن کد ، تمام کد اظهار نظر را انتخاب کرده و میانبر
Cmd+/
یاControl+/
صفحه کلید را فشار دهید. - به پرونده نگاهی بیندازید.
در اینجا سریع کد آزمایش وجود دارد ، زیرا این یک قطعه دیگر از کد است که می توانید از آن استفاده کنید:
-
SleepDabaseTest
یک کلاس تست است . - حاشیه نویسی
@RunWith
Runner Test را مشخص می کند ، این برنامه ای است که تست ها را تنظیم و اجرا می کند. - در حین راه اندازی ، عملکرد حاشیه نویسی با
@Before
اجرا می شود ، و باSleepDatabaseDao
یکSleepDatabase
در حافظه ایجاد می کند. "در حافظه" به این معنی است که این پایگاه داده در سیستم پرونده ذخیره نمی شود و پس از اجرای تست ها حذف می شود. - همچنین هنگام ساختن بانک اطلاعاتی در حافظه ، کد یک روش خاص تست را ،
allowMainThreadQueries
می نامد. به طور پیش فرض ، اگر سعی می کنید نمایش داده شد را روی موضوع اصلی اجرا کنید ، خطایی دریافت می کنید. این روش به شما امکان می دهد تست ها را روی موضوع اصلی اجرا کنید ، که فقط باید در حین آزمایش انجام دهید. - در یک روش آزمایشی که با
@Test
حاشیه نویسی شده است ، شما یکSleepNight
ایجاد می کنید ، درج و بازیابی می کنید و ادعا می کنید که آنها یکسان هستند. اگر مشکلی پیش آمد ، یک استثنا را پرتاب کنید. در یک تست واقعی ، شما چندین@Test
خواهید داشت روش ها - هنگام انجام آزمایش ، عملکردی که با
@After
حاشیه نویسی شده است برای بستن پایگاه داده اجرا می شود.
- بر روی پرونده تست در صفحه پروژه راست کلیک کرده و اجرای "SleepDatabasetest" را انتخاب کنید.
- پس از انجام آزمایشات ، در صفحه Sleepdatabasetest که تمام آزمایشات گذرانده اند ، تأیید کنید.
از آنجا که تمام تست ها گذشت ، شما اکنون چندین چیز را می دانید:
- بانک اطلاعاتی به درستی ایجاد می شود.
- می توانید یک
SleepNight
در پایگاه داده وارد کنید. - می توانید شب
SleepNight
برگردانید. -
SleepNight
ارزش صحیحی برای کیفیت دارد.
پروژه استودیوی Android: TrackMysLeepQualityRoomAndTesting
هنگام آزمایش یک پایگاه داده ، باید تمام روشهای تعریف شده در DAO را اعمال کنید. برای تکمیل آزمایش ، تست ها را اضافه و انجام دهید تا روشهای دیگر DAO را انجام دهید.
- جداول خود را به عنوان کلاسهای داده حاشیه نویسی با
@Entity
تعریف کنید. ویژگی های حاشیه نویسی با@ColumnInfo
را به عنوان ستون در جداول تعریف کنید. - یک شی دسترسی به داده (DAO) را به عنوان رابط حاشیه ای با
@Dao
تعریف کنید. DAO توابع Kotlin را به نمایش داده های پایگاه داده نقشه می کند. - برای تعریف
@Insert
،@Delete
و@Update
از حاشیه نویسی استفاده کنید. - از حاشیه نویسی
@Query
با یک رشته پرس و جو SQLITE به عنوان یک پارامتر برای هر پرس و جو دیگر استفاده کنید. - یک کلاس انتزاعی ایجاد کنید که دارای یک تابع
getInstance()
باشد که یک پایگاه داده را برمی گرداند. - برای آزمایش اینکه پایگاه داده و DAO همانطور که انتظار می رود کار می کنند ، از تست های ابزار استفاده کنید. می توانید از تست های ارائه شده به عنوان الگوی استفاده کنید.
دوره بی ادبی:
اسناد توسعه دهنده اندرویدی:
-
RoomDatabase
-
Database
(حاشیه نویسی) - می توانید از نمایش داده های خام با
Room
استفاده کنید -
Roomdatabase.Builder
- آموزش تست
- کلاس
SQLiteDatabase
-
Dao
- کتابخانه توری
Room
سایر مستندات و مقالات:
این بخش، تکالیف احتمالی را برای دانشآموزانی که در این آزمایشگاه کد به عنوان بخشی از دورهای که توسط یک مربی هدایت میشود، کار میکنند، فهرست میکند. این وظیفه مربی است که موارد زیر را انجام دهد:
- در صورت نیاز تکالیف را تعیین کنید.
- نحوه ارسال تکالیف را با دانش آموزان در میان بگذارید.
- تکالیف را نمره دهید.
مربیان میتوانند از این پیشنهادات به اندازهای که میخواهند استفاده کنند، و باید با خیال راحت هر تکلیف دیگری را که فکر میکنند مناسب است، محول کنند.
اگر به تنهایی از طریق این کدها کار می کنید، از این تکالیف برای آزمایش دانش خود استفاده کنید.
به این س 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
را اجرا کنید.
شروع به درس بعدی:
برای پیوند به سایر کدهای این دوره، به صفحه فرود کد لبههای کد پایه Android Kotlin Fundamentals مراجعه کنید.