ذخیره انواع غیر ابتدایی جاوا (non-primitive types) با استفاده از Type Converters
جمعبندی
اگر با برنامه نویسی اندروید آشنایی داشته باشید، احتمالاً نام کتابخانه Room به گوشتان خورده است. اگر بخواهید با دیتابیس در اندروید ارتباط برقرار کنید و با آن کار کنید، ما به شما کتابخانه Room را پیشنهاد میکنیم. شما در مقاله آموزش Room در اندروید، با کلیه عملیات CRUD و جزییات مربوط به استفاده از این کتابخانه شگفت انگیز در پروژههای خود آشنا میشوید. ما در طول این آموزش، یک برنامه برای ذخیره مخاطبان را ایجاد خواهیم کرد.
بهترین راه برای یادگیری که ما به شما پیشنهاد میکنیم این است که پروژه را کامل انجام دهید. ابتدا، یک پروژه جدید ایجاد کنید و کار با کتابخانه Room را همراه با مقاله آموزش Room در اندروید ما شروع کنید. در صورتی که در هر کجای این آموزش به مشکل برخورد کردید، میتوانید از کد کامل این برنامه در Github استفاده کنید. در صورتی که با SQLite در اندروید آشنا نیستید، به شما پیشنهاد میکنیم دربارهی آن پیش از شروع این مقاله مطالعه کنید.
در تصویر زیر رابط کاربری (UI) برنامه به شما نشان داده شده است:
کتابخانه Room چیست؟
Room یک object relational mapper) ORM) برای پایگاه داده SQLite در اندروید و بخشی از کامپوننتهای معماری است که توسط گوگل منتشر شده است. در هسته آن، تمامی کدهایی که در رابطه با Room مینویسید در نهایت به کد SQLite تبدیل میشوند. Room به شما این امکان را میدهد تا با سرعت بیشتری پایگاه داده را در اندروید ایجاد کرده و بتوانید با آن کار کنید. میتوانید به Room به عنوان یک لایه انتزاعی بر روی پایگاه داده داخلی SQLite نگاه کنید.
راه اندازی یک پروژه جدید با Room
یک پروژه جدید در اندروید استودیو ایجاد کنید.
در فایل build.gradle سطح اپ، وابستگیهای زیر را اضافه کنید.
در بخش repositories در فایل build.gradle سطح پروژه خود، اطمینان حاصل کنید که ()google اضافه شده است.
repositories {
google()
jcenter()
}
اکنون پروژه را همگام سازی کنید.اکنون، پروژه شما آماده کار با Room است.
ایجاد اسکیما (Creating Schema)
در Room نیازی به نوشتن کلاس SQLiteOpenHelper یا نوشتن کوئری برای ایجاد جدول نیست. Room جداول را به طور خودکار برای شما ایجاد میکند. در Room ما یک کلاس POJO ساده تعریف کرده و آن را با Entity@ حاشیه نویسی (annotations) میکنیم.
در اینجا ما یک کلاس مدل برای مخاطب با تمامی حاشیه نویسیهای مورد نیاز را ایجاد خواهیم کرد.
@Entity(tableName = "contact")
public class Contact {
private String firstName;
private String lastName;
@PrimaryKey
@NonNull
private String phoneNumber;
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
@NonNull
public String getPhoneNumber() {
return phoneNumber;
}
public void setPhoneNumber(@NonNull String phoneNumber) {
this.phoneNumber = phoneNumber;
}
}
همانطور که میبینید، این یک کلاس ساده جاوا با حاشیه نویسی میباشد و دستورات پیچیدهای ندارد.
ما با حاشیه نویسی Entity@ یک جدول با نام سفارشی ایجاد کردهایم. اگر نام یک جدول را ارائه ندهید، Room از نام کلاس به عنوان نام جدول استفاده میکند یعنی "Contact" (با C بزرگ).
وقتی یک کلاس را با Entity@ حاشیه نویسی میکنید، باید یک سازنده (constructor) بدون آرگومان ارائه دهید. در اینجا چون ما هیچ سازندهای ارائه ندادهایم، java به طور خودکار سازنده پیش فرض (بدون آرگومان) را در زمان کامپایل وارد میکند.
اگر یک کلاس با Entity@ حاشیه نویسی شده باشد، باید یک کلید اصلی را با استفاده از حاشیه نویسی PrimaryKey مشخص کنید. در اینجا ما از phoneNumber به عنوان کلید اصلی استفاده میکنیم.
Room کلاس Contact ما را میگیرد و یک جدول با فیلدهای ارائه شده به عنوان ستون ایجاد میکند.
اگر در شرایطی نمیخواهید فیلدی در طرح جدول در نظر گرفته شود، فقط آن را با Ignore@ حاشیه نویسی کنید.
به طور پیشفرض در Room از نام فیلدها استفاده میشود، فیلدها نام ستونها در جداول هستند، اما میتوانید با استفاده از حاشیه نویسی ("ColumnInfo (name = "phone@ در قسمت هر فیلد، این مورد را تغییر دهید.
ایجاد data access object) DAO)
اکنون ما یک DAO برای انجام عملیات در جدول خود ایجاد خواهیم کرد. میتوانید نگاهی عمیق به مفهوم DAO بیندازید، به طور خلاصه DAO فقط یک کلاس انتزاعی است که مجموعهای از عملیات مربوط به یک شی را تعریف میکند.
در زیر یک interface) DAO) ساده با عملگر CRUD در Contact آورده شده است.
@Dao
public interface ContactDAO {
@Insert
public void insert(Contact... contacts);
@Update
public void update(Contact... contacts);
@Delete
public void delete(Contact contact);
}
برای ایجاد DAO، باید یک اینترفیس ایجاد کنید و آن را با Dao حاشیه نویسی کنید.
عملیات اضافه کردن (Insert)
برای ایجاد یک عملیات درج یا اضافه کردن، فقط متدی را تعریف کنید که (Contact contacts) را به عنوان یک پارامتر بگیرید و متد را با Insert@ حاشیه نویسی کنید.
عملیات بروزرسانی (Update)
مشابه با همان کاری که برای عملیات اضافه کردن انجام دادید، برای ایجاد یک عملیات بروزرسانی، فقط متدی را تعریف کنید که (Contact contacts) را به عنوان یک پارامتر بگیرید و متد را با Update@ حاشیه نویسی کنید.
عملیات پاک کردن (Delete)
مانند کارهای قبلی، برای ایجاد یک عملیات پاک کردن، فقط متدی را تعریف کنید که (Contact contacts) را به عنوان یک پارامتر بگیرید و متد را با Delete@ حاشیه نویسی کنید.
کار با کوئریها
در حالی که Room دارای حاشیه نویسی برای عملیات ساده در پایگاه داده است، اما همچنین امکان سفارشی سازی کوئریهای نوشته شده را نیز فراهم میکند. بنابراین اگر میخواستید تمام مخاطبین را به دست آورید، یک کوئری مانند زیر مینویسید.
@Query("SELECT * FROM contact")
public List<Contact> getContacts();
از حاشیه نویسی Query@ استفاده کنید و کوئری مورد نظرتان را اجرا کنید. از آنجا که ما تمام مخاطبین موجود در جدول را میخواهیم، نوع بازگشتی به لیست مخاطبین را، <List<Contact تنظیم میکنیم. Room همه این کارها را در پشت صحنه انجام میدهد، Room، کوئری را اجرا میکند، نتیجه مکان نما را به لیست تبدیل میکند و لیست را به شما باز میگرداند.
حال فرض کنید میخواهید برای به دست آوردن اطلاعات تماس مرتبط با یک شماره تلفن خاص، کوئری بنویسید. در اینجا نحوه نوشتن این متد و کوئری آورده شده است:
@Query("SELECT * FROM contact WHERE phoneNumber = :number")
public Contact getContactWithId(String number);
phoneNumber را در آرگومانهای متد منتقل کرده و با پیشوند نام پارامتر با : (دونقطه) از آن در داخل کوئری استفاده کنید. نوع بازگشتی در اینجا Contact است زیرا ما به دنبال یک contact هستیم.
در زیر کد کامل اینترفیسDAO آورده شده است:
@Dao
public interface ContactDAO {
@Insert
public void insert(Contact... contacts);
@Update
public void update(Contact... contacts);
@Delete
public void delete(Contact contact);
@Query("SELECT * FROM contact")
public List<Contact> getContacts();
@Query("SELECT * FROM contact WHERE phoneNumber = :number")
public Contact getContactWithId(String number);
}
Room از این اینترفیس استفاده میکند و تمامی متدها را برای شما پیاده سازی میکند، تنها کاری که شما باید انجام دهید این است که عملیات را با استفاده از حاشیه نویسی مناسب مشخص کنید.
ایجاد پایگاه داده
حال تنها کاری که ما باید انجام دهیم این است که تمام کلاسها و اینترفیسهای فوق را به هم ارتباط دهیم. برای این منظور ما یک کلاس انتزاعی به نام AppDatabase ایجاد خواهیم کرد که RoomDatabase را گسترش میدهد. این کلاسی خواهد بود که به ما امکان پیاده سازی رابط DAO را میدهد.
@Database(entities = {Contact.class}, version = 1)
public abstract class AppDatabase extends RoomDatabase {
public abstract ContactDAO getContactDAO();
}
شما باید این کلاس انتزاعی را با Database@ حاشیه نویسی کنید و تمام موجودیتهایی را که ایجاد کردهاید و همچنین نسخه پایگاه داده را مشخص کنید.
شما یک متد انتزاعی با نوع بازگشت ContactDAO مشخص خواهید کرد. Room با اجرای کامل این کلاس انتزاعی همراه با همه متدهای انتزاعی مشخص، به ما امکان توسعه میدهد.
اکنون هر کجا که نمونهای از AppDatabase را میخواهید، کد زیر را بنویسید.
AppDatabase database = Room.databaseBuilder(this, AppDatabase.class, "db-contacts")
.allowMainThreadQueries() //Allows room to do operation on main thread
.build()
()Room.databaseBuilder سه آرگومان را میگیرد:
ارجاعی به Context که در این مثال از this استفاده شده.
استفاده از کلاس پایگاه داده انتزاعی برای بازگرداندن نمونه.
نام پایگاه داده.
میتوانید مشاهده کنید که ما یک متد ()allowMainThreadQueries را روی سازنده (Builder) فراخوانی کردهایم، زیرا به طور پیش فرض Room به شما اجازه نمیدهد کوئریها را در MainThread اجرا کنید و مجبورید آنها را روی یک Background Thread اجرا کنید.
بنابراین ما از روش ()allowMainThreadQueries ارائه شده توسط Room استفاده میکنیم که به شما اجازه میدهد تا نمایش دادهها در MainThread اجرا شوند.
پس از دریافت نمونه AppDatabase، اکنون میتوانید ContactDAO را با فراخوانی ()getContactDAO که قبلاً تعریف کردهاید دریافت کنید و فراخوانی متدهای CRUD تعریف شده را شروع کنید.
ContactDAO contactDAO = database.getContactDAO();
//Inserting a contact
Contact contact = new Contact();
contact.setFirstName("Gurleen");
contact.setLastName("Sethi");
contact.setPhoneNumber("1234567890");
contactDAO.insert(contact);
//Fetching all contacts
List<Contact> contact = contactDAO.getContacts();
//Getting a single contact and updating it
Contact contact = contactDAO.getContactWithId("1234567890");
contact.setFirstName("Kevin");
contact.setLastName("Brew");
contactDAO.update(contact);
ذخیره انواع غیر ابتدایی جاوا (non-primitive types) با استفاده از Type Converters
در Room فقط میتوانید انواع ابتدایی (primitive) زبان را ذخیره کنید. اگر میخواهید یک نوع غیر ابتدایی مانند یک لیست یا تاریخ را ذخیره کنید، باید یک نوع مبدل برای آن تهیه کنید. با TypeConverter به Room میگویید که چگونه نوع غیر اولیه را به نوع اولیه تبدیل کند. ما یک فیلد تاریخ ایجاد شده از نوع Date را در مدل Contact خود اضافه خواهیم کرد.
@Entity(tableName = "contact")
public class Contact {
private String firstName;
private String lastName;
@PrimaryKey
@NonNull
private String phoneNumber;
private Date createdDate;
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
@NonNull
public String getPhoneNumber() {
return phoneNumber;
}
public void setPhoneNumber(@NonNull String phoneNumber) {
this.phoneNumber = phoneNumber;
}
public Date getCreatedDate() {
return createdDate;
}
public void setCreatedDate(Date createdDate) {
this.createdDate = createdDate;
}
}
اگر سعی کنید این کد را بدون ارائه مبدل نوع اجرا کنید، Room هنگام کامپایل خطا میدهد.
در این پروژه ما مبدل را برای نوع Date فراهم خواهیم کرد و تاریخ را به long تبدیل خواهیم کرد. هنگام نوشتن مبدل، شما باید هر دو روش را ارائه دهید، در این پروژه یعنی، یک مبدل که Date را به Long تبدیل میکند و دیگری که Long را به Date تبدیل میکند.
public class DateTypeConverter {
@TypeConverter
public long convertDateToLong(Date date) {
return date.getTime();
}
@TypeConverter
public Date convertLongToDate(long time) {
return new Date(time);
}
}
میبینید که ما یک کلاس جدید به نام DateTypeConverter با متدهای مورد نیاز ایجاد کردهایم. حال باید به Room بگوییم که از این نوع مبدل استفاده کند. در کلاس AppDatabase ما باید بگوییم که از کدام نوع مبدل استفاده کنیم. این کار را با استفاده از حاشیه نویسی TypeConverters@ انجام میدهیم.
@Database(entities = {Contact.class}, version = 1)
@TypeConverters({DateTypeConverter.class})
public abstract class AppDatabase extends RoomDatabase {
public abstract ContactDAO getContactDAO();
}
اکنون میتوانید بدون هیچ مشکلی برنامه را اجرا کنید.
جمعبندی
در این مقاله ما با آموزش Room در اندروید و ویژگیهای آن همراه شما بودیم، ما بهترین راه برای یادگیری کتابخانه Room را پیشنهاد کردیم و امیدواریم از این راه بتوانید کتابخانه Room را فرا گرفته و با آن کار کنید. خوشحال میشویم سوالات و نظرات خود را در مورد این آموزش با ما و کاربران سون لرن به اشتراک بگذارید.
اگر به یادگیری بیشتر در زمینهی اندروید علاقه داری، با شرکت در دورهی آموزش برنامه نویسی اندروید در کمتر از یکسال به یک توسعهدهنده اندروید همه فن حریف تبدیل میشوی که آمادهی استخدام، دریافت پروژه و حتی پیادهسازی اپلیکیشن خودت هستی.
من تازه کارم ندونستم این کدها را در کلاسهای مجزا باید بنویسم یا نه یکجا بنویسم
نازنین کریمی مقدم۰۴ مرداد ۱۴۰۰، ۱۱:۲۱
درود. بابت تاخیر در پاسخگویی ازتون پوزش میطلبیم.
در قدم اول سعی کنید اول به مفاهیم پایه مسلط بشید بعد به سراغ آموزشهای پیشرفتهتر بیاید تا زمان زیادی ازتون هدر نره.
شما میتونید همه این موارد رو در یک فایل بنویسید که کار ناپسندی است، هرجا کلاس جدید یا اینترفیسی تعریف شده در مقاله در یک فایل جدا بنویسید و اگر دیدید بالای کدی کلاس تعریف نشده بود یعنی باید اون رو در کلاسی که قبل کد تعریف کردیم بنویسید.
samin۲۷ خرداد ۱۴۰۰، ۰۷:۲۲
با تشکر از شما برای ترجمه این مقاله ، اما کاش کامل بود ، منظور من تمام پروژه و قسمت لایهها و کار با لیست است ، اگرچه در صفحه اصلی هم اموزش کامل نیست .
میثم۰۲ مهر ۱۳۹۹، ۲۲:۴۵
سلام
خیلی ممنون بابت این مطلب کاربردی، فقط اگه امکانش هست TypeConverter از نوع لیست هم یه مثال بزنید، آبجکت نباشه لیست باشه باید چیکار کرد؟
امیر حسین حیدری۰۷ مهر ۱۳۹۹، ۰۷:۱۱
سلام دوست عزیز از اینکه مقاله براتون مفید بوده خوش حالیم
انشالله در ادامه به مطلبی که اشاره کردید پاسخ میدیم
شروع رایگان یادگیری برنامه نویسی
کلیک کنید 👇
دوره الفبای برنامه نویسی با هدف انتخاب زبان برنامه نویسی مناسب برای شما و پاسخگویی به سوالات متداول در شروع یادگیری موقتا رایگان شد: