Added a database working in LRU (#43)
Co-authored-by: Joachim Dunant <joachim.dunant@epfl.ch>
This commit is contained in:
parent
de314dc9de
commit
2d7020fd21
|
@ -44,7 +44,7 @@ android {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
apply plugin: 'kotlin-kapt'
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
|
@ -65,6 +65,10 @@ dependencies {
|
||||||
implementation "androidx.browser:browser:1.2.0"
|
implementation "androidx.browser:browser:1.2.0"
|
||||||
implementation 'com.google.android.material:material:1.1.0'
|
implementation 'com.google.android.material:material:1.1.0'
|
||||||
|
|
||||||
|
def room_version = "2.2.4"
|
||||||
|
implementation "androidx.room:room-runtime:$room_version"
|
||||||
|
kapt "androidx.room:room-compiler:$room_version"
|
||||||
|
implementation "androidx.room:room-ktx:$room_version"
|
||||||
|
|
||||||
implementation("com.github.bumptech.glide:glide:4.11.0") {
|
implementation("com.github.bumptech.glide:glide:4.11.0") {
|
||||||
exclude group: "com.android.support"
|
exclude group: "com.android.support"
|
||||||
|
|
|
@ -0,0 +1,69 @@
|
||||||
|
package com.h.pixeldroid
|
||||||
|
|
||||||
|
import androidx.test.core.app.ApplicationProvider
|
||||||
|
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||||
|
import com.h.pixeldroid.db.AppDatabase
|
||||||
|
import com.h.pixeldroid.db.PostDao
|
||||||
|
import com.h.pixeldroid.db.PostEntity
|
||||||
|
import com.h.pixeldroid.utils.*
|
||||||
|
import org.junit.After
|
||||||
|
import org.junit.Assert
|
||||||
|
import org.junit.Before
|
||||||
|
import org.junit.Test
|
||||||
|
import org.junit.runner.RunWith
|
||||||
|
import java.util.Calendar
|
||||||
|
|
||||||
|
@RunWith(AndroidJUnit4::class)
|
||||||
|
class AppDatabaseTest {
|
||||||
|
private var postDao: PostDao? = null
|
||||||
|
private var db: AppDatabase? = null
|
||||||
|
private var postTest = PostEntity(1, "test", date= Calendar.getInstance().time)
|
||||||
|
|
||||||
|
@Before
|
||||||
|
fun setup() {
|
||||||
|
AppDatabase.TEST_MODE = true
|
||||||
|
db = AppDatabase.getDatabase(ApplicationProvider.getApplicationContext())
|
||||||
|
postDao = db?.postDao()
|
||||||
|
postDao?.insertAll(postTest)
|
||||||
|
}
|
||||||
|
|
||||||
|
@After
|
||||||
|
fun tearDown() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testInsertPostItem() {
|
||||||
|
Assert.assertEquals(postTest.domain, postDao?.getById(postTest.uid)!!.domain)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testDeleteAll(){
|
||||||
|
postDao?.deleteAll()
|
||||||
|
Assert.assertEquals(postDao?.getPostsCount(), 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testUtilsInsertAll() {
|
||||||
|
val postTest2 = PostEntity(2, "test", date= Calendar.getInstance().time)
|
||||||
|
DatabaseUtils.insertAllPosts(db!!, postTest, postTest2)
|
||||||
|
|
||||||
|
Assert.assertEquals(postTest.domain, postDao?.getById(postTest.uid)!!.domain)
|
||||||
|
Assert.assertEquals(postTest2.domain, postDao?.getById(postTest2.uid)!!.domain)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testUtilsLRU() {
|
||||||
|
for(i in 1..db!!.MAX_NUMBER_OF_POSTS) {
|
||||||
|
DatabaseUtils.insertAllPosts(db!!, PostEntity(i, i.toString(), date= Calendar.getInstance().time))
|
||||||
|
}
|
||||||
|
|
||||||
|
Assert.assertEquals("1", postDao?.getById(1)!!.domain)
|
||||||
|
Assert.assertEquals(db?.MAX_NUMBER_OF_POSTS, postDao?.getPostsCount())
|
||||||
|
|
||||||
|
DatabaseUtils.insertAllPosts(db!!, PostEntity(0, "0", date= Calendar.getInstance().time))
|
||||||
|
Assert.assertEquals(db?.MAX_NUMBER_OF_POSTS, postDao?.getPostsCount())
|
||||||
|
val eldestPost = postDao?.getById(1)
|
||||||
|
Assert.assertEquals(null, eldestPost)
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,5 +1,6 @@
|
||||||
package com.h.pixeldroid
|
package com.h.pixeldroid
|
||||||
|
|
||||||
|
import android.app.Activity
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.view.MenuItem
|
import android.view.MenuItem
|
||||||
|
@ -19,6 +20,7 @@ import com.h.pixeldroid.motions.OnSwipeListener
|
||||||
class MainActivity : AppCompatActivity(), NavigationView.OnNavigationItemSelectedListener {
|
class MainActivity : AppCompatActivity(), NavigationView.OnNavigationItemSelectedListener {
|
||||||
|
|
||||||
private lateinit var drawerLayout: DrawerLayout
|
private lateinit var drawerLayout: DrawerLayout
|
||||||
|
private val newPostsActivityRequestCode = Activity.RESULT_OK
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
|
@ -69,7 +71,7 @@ class MainActivity : AppCompatActivity(), NavigationView.OnNavigationItemSelecte
|
||||||
supportFragmentManager.beginTransaction().replace(R.id.fragment_container, fragment).commit()
|
supportFragmentManager.beginTransaction().replace(R.id.fragment_container, fragment).commit()
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/**
|
||||||
When clicking in the drawer menu, go to the corresponding activity
|
When clicking in the drawer menu, go to the corresponding activity
|
||||||
*/
|
*/
|
||||||
override fun onNavigationItemSelected(@NonNull item: MenuItem): Boolean {
|
override fun onNavigationItemSelected(@NonNull item: MenuItem): Boolean {
|
||||||
|
@ -83,7 +85,7 @@ class MainActivity : AppCompatActivity(), NavigationView.OnNavigationItemSelecte
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/**
|
||||||
Launches the given activity and put it as the current one
|
Launches the given activity and put it as the current one
|
||||||
*/
|
*/
|
||||||
private fun launchActivity(activity: AppCompatActivity) {
|
private fun launchActivity(activity: AppCompatActivity) {
|
||||||
|
@ -91,8 +93,8 @@ class MainActivity : AppCompatActivity(), NavigationView.OnNavigationItemSelecte
|
||||||
startActivity(intent)
|
startActivity(intent)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/**
|
||||||
Closes the drawer if we are clicking behind it
|
Closes the drawer if it is open, when we press the back button
|
||||||
*/
|
*/
|
||||||
override fun onBackPressed() {
|
override fun onBackPressed() {
|
||||||
if(drawerLayout.isDrawerOpen(GravityCompat.START)){
|
if(drawerLayout.isDrawerOpen(GravityCompat.START)){
|
||||||
|
|
|
@ -0,0 +1,41 @@
|
||||||
|
package com.h.pixeldroid.db
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import androidx.room.Database
|
||||||
|
import androidx.room.Room
|
||||||
|
import androidx.room.RoomDatabase
|
||||||
|
import androidx.room.TypeConverters
|
||||||
|
|
||||||
|
@Database(entities = [PostEntity::class], version = 1)
|
||||||
|
@TypeConverters(Converters::class)
|
||||||
|
abstract class AppDatabase : RoomDatabase() {
|
||||||
|
abstract fun postDao(): PostDao
|
||||||
|
val MAX_NUMBER_OF_POSTS = 100
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
// Singleton prevents multiple instances of database opening at the
|
||||||
|
// same time.
|
||||||
|
@Volatile
|
||||||
|
private var INSTANCE: AppDatabase? = null
|
||||||
|
var TEST_MODE = false
|
||||||
|
|
||||||
|
fun getDatabase(context: Context): AppDatabase {
|
||||||
|
|
||||||
|
return INSTANCE ?: synchronized(this) {
|
||||||
|
var instance: AppDatabase? = null
|
||||||
|
|
||||||
|
// To be able to create a temporary database that flushes when tests are over
|
||||||
|
instance = if (TEST_MODE) {
|
||||||
|
Room.inMemoryDatabaseBuilder(context, AppDatabase::class.java).allowMainThreadQueries().build()
|
||||||
|
} else {
|
||||||
|
Room.databaseBuilder(
|
||||||
|
context.applicationContext, AppDatabase::class.java, "posts_database"
|
||||||
|
).build()
|
||||||
|
}
|
||||||
|
|
||||||
|
INSTANCE = instance
|
||||||
|
return instance
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,16 @@
|
||||||
|
package com.h.pixeldroid.db
|
||||||
|
|
||||||
|
import androidx.room.TypeConverter
|
||||||
|
import java.util.Date
|
||||||
|
|
||||||
|
class Converters {
|
||||||
|
@TypeConverter
|
||||||
|
fun fromTimestamp(value: Long?): Date? {
|
||||||
|
return value?.let { Date(it) }
|
||||||
|
}
|
||||||
|
|
||||||
|
@TypeConverter
|
||||||
|
fun dateToTimestamp(date: Date?): Long? {
|
||||||
|
return date?.time?.toLong()
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,36 @@
|
||||||
|
package com.h.pixeldroid.db
|
||||||
|
|
||||||
|
import androidx.lifecycle.LiveData
|
||||||
|
import androidx.room.Dao
|
||||||
|
import androidx.room.Delete
|
||||||
|
import androidx.room.Insert
|
||||||
|
import androidx.room.OnConflictStrategy.REPLACE
|
||||||
|
import androidx.room.Query
|
||||||
|
import java.util.Date
|
||||||
|
|
||||||
|
@Dao
|
||||||
|
interface PostDao {
|
||||||
|
@Query("SELECT * FROM posts")
|
||||||
|
fun getAll(): LiveData<List<PostEntity>>
|
||||||
|
|
||||||
|
@Query("SELECT * FROM posts WHERE uid = :postId")
|
||||||
|
fun getById(postId: Int): PostEntity
|
||||||
|
|
||||||
|
@Query("SELECT count(*) FROM posts")
|
||||||
|
fun getPostsCount(): Int
|
||||||
|
|
||||||
|
@Query("UPDATE posts SET date = :date WHERE uid = :postId")
|
||||||
|
fun addDateToPost(postId: Int, date: Date)
|
||||||
|
|
||||||
|
@Query("DELETE FROM posts")
|
||||||
|
fun deleteAll()
|
||||||
|
|
||||||
|
@Query("DELETE FROM posts WHERE date IN (SELECT min(date) FROM posts) ")
|
||||||
|
fun deleteOldestPost(): Int
|
||||||
|
|
||||||
|
@Insert(onConflict = REPLACE)
|
||||||
|
fun insertAll(vararg posts: PostEntity)
|
||||||
|
|
||||||
|
@Delete
|
||||||
|
fun delete(post: PostEntity)
|
||||||
|
}
|
|
@ -0,0 +1,17 @@
|
||||||
|
package com.h.pixeldroid.db
|
||||||
|
|
||||||
|
import androidx.room.ColumnInfo;
|
||||||
|
import androidx.room.Entity;
|
||||||
|
import androidx.room.PrimaryKey;
|
||||||
|
import java.util.Date
|
||||||
|
|
||||||
|
@Entity(tableName= "posts")
|
||||||
|
data class PostEntity(
|
||||||
|
@PrimaryKey val uid: Int,
|
||||||
|
@ColumnInfo(name = "domain") val domain: String? = "",
|
||||||
|
@ColumnInfo(name = "username") val username: String? = "",
|
||||||
|
@ColumnInfo(name = "display name") val displayName: String? = "",
|
||||||
|
@ColumnInfo(name = "accountID") val accountID: Int? = -1,
|
||||||
|
@ColumnInfo(name = "image url") val ImageURL: String? = "",
|
||||||
|
@ColumnInfo(name = "date") val date: Date?
|
||||||
|
)
|
|
@ -0,0 +1,45 @@
|
||||||
|
package com.h.pixeldroid.utils
|
||||||
|
|
||||||
|
import com.h.pixeldroid.db.AppDatabase
|
||||||
|
import com.h.pixeldroid.db.PostEntity
|
||||||
|
import java.util.Calendar
|
||||||
|
|
||||||
|
class DatabaseUtils {
|
||||||
|
companion object {
|
||||||
|
/**
|
||||||
|
* Inserts one post into the specified database,
|
||||||
|
* after it has checked the LRU
|
||||||
|
*/
|
||||||
|
fun insertPost(db: AppDatabase, post: PostEntity) {
|
||||||
|
if (!IsInsertable(db)) {
|
||||||
|
removeEldestPost(db)
|
||||||
|
}
|
||||||
|
|
||||||
|
db.postDao().addDateToPost(post.uid, Calendar.getInstance().time)
|
||||||
|
db.postDao().insertAll(post)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Inserts multiple posts into the specified database
|
||||||
|
*/
|
||||||
|
fun insertAllPosts(db: AppDatabase, vararg posts: PostEntity) {
|
||||||
|
posts.forEach { insertPost(db, it) }
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if we can add one post into the database
|
||||||
|
* or if it is full
|
||||||
|
*/
|
||||||
|
private fun IsInsertable(db: AppDatabase): Boolean {
|
||||||
|
return db.postDao().getPostsCount() + 1 <= db.MAX_NUMBER_OF_POSTS
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes the eldest post from the database
|
||||||
|
*/
|
||||||
|
private fun removeEldestPost(db: AppDatabase) {
|
||||||
|
db.postDao().deleteOldestPost()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,9 @@
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="24dp"
|
||||||
|
android:height="24dp"
|
||||||
|
android:viewportWidth="24.0"
|
||||||
|
android:viewportHeight="24.0">
|
||||||
|
<path
|
||||||
|
android:fillColor="#FF000000"
|
||||||
|
android:pathData="M19,13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z"/>
|
||||||
|
</vector>
|
|
@ -17,4 +17,12 @@
|
||||||
|
|
||||||
<style name="AppTheme.PopupOverlay" parent="ThemeOverlay.AppCompat.Light" />
|
<style name="AppTheme.PopupOverlay" parent="ThemeOverlay.AppCompat.Light" />
|
||||||
|
|
||||||
|
<style name="posts_title">
|
||||||
|
<item name="android:layout_width">match_parent</item>
|
||||||
|
<item name="android:layout_marginBottom">8dp</item>
|
||||||
|
<item name="android:paddingLeft">8dp</item>
|
||||||
|
<item name="android:background">@android:color/holo_orange_light</item>
|
||||||
|
<item name="android:textAppearance">@android:style/TextAppearance.Large</item>
|
||||||
|
</style>
|
||||||
|
|
||||||
</resources>
|
</resources>
|
||||||
|
|
Loading…
Reference in New Issue