Added a database working in LRU (#43)

Co-authored-by: Joachim Dunant <joachim.dunant@epfl.ch>
This commit is contained in:
Sanimys 2020-03-12 23:27:40 +01:00 committed by GitHub
parent de314dc9de
commit 2d7020fd21
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 252 additions and 5 deletions

View File

@ -44,7 +44,7 @@ android {
}
apply plugin: 'kotlin-kapt'
}
dependencies {
@ -65,6 +65,10 @@ dependencies {
implementation "androidx.browser:browser:1.2.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") {
exclude group: "com.android.support"

View File

@ -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)
}
}

View File

@ -1,5 +1,6 @@
package com.h.pixeldroid
import android.app.Activity
import android.content.Intent
import android.os.Bundle
import android.view.MenuItem
@ -19,6 +20,7 @@ import com.h.pixeldroid.motions.OnSwipeListener
class MainActivity : AppCompatActivity(), NavigationView.OnNavigationItemSelectedListener {
private lateinit var drawerLayout: DrawerLayout
private val newPostsActivityRequestCode = Activity.RESULT_OK
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
@ -69,7 +71,7 @@ class MainActivity : AppCompatActivity(), NavigationView.OnNavigationItemSelecte
supportFragmentManager.beginTransaction().replace(R.id.fragment_container, fragment).commit()
}
/*
/**
When clicking in the drawer menu, go to the corresponding activity
*/
override fun onNavigationItemSelected(@NonNull item: MenuItem): Boolean {
@ -83,7 +85,7 @@ class MainActivity : AppCompatActivity(), NavigationView.OnNavigationItemSelecte
return true
}
/*
/**
Launches the given activity and put it as the current one
*/
private fun launchActivity(activity: AppCompatActivity) {
@ -91,8 +93,8 @@ class MainActivity : AppCompatActivity(), NavigationView.OnNavigationItemSelecte
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() {
if(drawerLayout.isDrawerOpen(GravityCompat.START)){

View File

@ -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
}
}
}
}

View File

@ -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()
}
}

View File

@ -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)
}

View File

@ -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?
)

View File

@ -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()
}
}
}

View File

@ -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>

View File

@ -17,4 +17,12 @@
<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>