storage Penyimpanan media privat Sampai aplikasi di-uninstall/clear data. Shared storage Penyimpanan media publik Tetap ada walaupun di-uninstall/clear data. Preference Key-Value Sampai aplikasi di-uninstall/clear data. Database Tabel data lokal Sampai aplikasi di-uninstall/clear data.
data yang hanya dipakai oleh aplikasi kamu aja. ◦ JSON ◦ Plan text ◦ Specific file 2. Shared Storage : Untuk menyimpan data yang bisa dishare ke yang lain. ◦ Media (foto, audio, video) ◦ Downloaded Document
Create Instance val editor: SharedPreferences.Editor = sharedPref.edit() editor.putString(NAME, "Arif") editor.putInt(AGE, 22) editor.apply() // OR : editor.commit() • Save Data var name = sharedPref.getString(NAME, "") var name = sharedPref.getInt(AGE, 0) • Get Data
✅ (hanya untuk membaca perubahan suatu nilai, via Listener) ✅ (via Flow) ✅ (via Flow) Synchronous API ✅ (namun non-safe thread ketika dipanggil dalam UI thread) ❌ ❌ Aman Ketika Dipanggil dalam UI Thread ❌ ✅ (dijalankan melalui Dispacter.IO secara otomatis) ✅ (dijalankan melalui Dispacter.IO secara otomatis) Memberitahu Jika Terjadi Eror ❌ ✅ ✅ Aman dari Runtime Exception ❌ ✅ ✅ Memiliki Transactional API ❌ ✅ ✅ Menangani Migrasi Data ❌ ✅ (dari SharedPreferences) ✅ (dari SharedPreferences) Type Safety ❌ ❌ ✅ (menggunakan Protocol Buffer)
offline 2. Menyimpan cache sementara data online ◦ Tetap bisa digunakan walaupun offline ◦ Lebih cepat ◦ Mengurangi request server ◦ Hemat baterai ◦ Hemat kuota
A Handbook of Agile Software Craftsmanship Robert C. Martin Programming 434 2 A Brief History of Time Stephen Hawking Science 212 3 Rich Dad, Poor Dad Robert T. Kiyosaki Business 195 4 The 7 Habits of Highly Effective People Stephen Covey Self-help 372 5 The Rainbow Troops Andrea Hirata Novel 304
companion object { val TABLE_NAME = "book" val COLUMN_TITLE = "title" val COLUMN_AUTHOR = "author" val COLUMN_GENRE = "genre" val COLUMN_PAGES = "pages" } } } id title author genre pages
val dbHelper: BooksHelper = BooksHelper(this) val db: SQLiteDatabase = dbHelper.getWritableDatabase() // Create a new map of values, where column names are the keys val values = ContentValues() values.put(BookEntry.COLUMN_TITLE, "Clean Code") values.put(BookEntry.COLUMN_AUTHOR, "Robert C. Martin") values.put(BookEntry.COLUMN_GENRE, "Programming") values.put(BookEntry.COLUMN_PAGES, 434) // Insert the new row, returning the primary key value of the new row val newRowId: Long = db.insert(BookEntry.TABLE_NAME, null, values)
Time Check Boilerplate Cukup perlu banyak kode Lebih simpel dan mudah Support LiveData/Flow Perlu konfigurasi tambahan Native Support Change Schema Cukup Sulit Cukup mudah Get Java Object Perlu Cursor Bisa Langsung
• 1 instance = 1 baris data • Member variable = Nama kolom @Entity(tableName = "book") data class BookEntity( @PrimaryKey (autoGenerate=true) val id: Int, @ColumnInfo(name = "title") val title: String?, @ColumnInfo(name = "author") val author: String?, @ColumnInfo(name = "genre") val genre: String?, @ColumnInfo(name = "pages") val pagesNumber: Int? )
BY id ASC") fun getAll(): LiveData<List<BookEntity>> @Query("SELECT * FROM book ORDER BY RANDOM() LIMIT 1") fun getRandomBook(): BookEntity @Query("SELECT * FROM book WHERE title LIKE :title OR author LIKE :author") fun findByTitleOrAuthor(title: String, author: String): List<BookEntity> @Insert(onConflict = OnConflictStrategy.IGNORE) fun insert(book: BookEntity) @Update fun update(book: BookEntity) @Delete fun delete(book: BookEntity) }
userName, book.name AS bookName " + "FROM user, book " + "WHERE user.id = book.user_id" ) fun loadUserAndBookNames(): LiveData<List<UserBook>> } data class UserBook(val userName: String?, val bookName: String?) @Query( "SELECT * FROM user" + "JOIN book ON user.id = book.user_id" ) fun loadUserAndBookNames(): Map<User, List<Book>> Using Multimap ✨