Android 手机便签(一)

项目准备:

1、LiveData与MVVM设计模式
2、Navigation导航的使用
3、RecyclerView
4、Dialog
5、滑动删除
6、按钮动画设计
7、@TypeConverter的使用
8、单例设计模式
9、数据可序列化
10、Room

项目简介:点击App首先进入广告页面,三秒后进入主页,也可以点击跳过直接进入首页。未添加数据时页面会显示无数据状态(下方未展示),点击主页下Add New按钮可进入详情页面添加标签。点击详情页右上方菜单按钮弹出save完成保存,再次从主页点击进入修改时菜单按钮的内容会变为delete和update两种按钮。
详情页面中可选择事件的重要性(也就是后方代码中所提到的优先级),以颜色(红,黄、绿)为标记。选择事务完成时间,添加或选择标签,事件的详细描述。
项目功能简单,却涵盖了丰富的知识点。
项目页面浏览:
主要有三个界面:广告页+标签显示页+添加详细内容页


image.png

整个项目框架


图片来源:https://developer.android.google.cn/training/dependency-injection/manual?hl=zh_cn

本项目只涉及到本地数据库Room的使用,并没有用到Retrofit从网络获取数据。

项目所需添加的gradle

在Project中
  id 'kotlin-kapt'
    id("androidx.navigation.safeargs.kotlin")
    id 'kotlin-parcelize'
 //room
    def room_version = "2.3.0"

    implementation("androidx.room:room-runtime:$room_version")
    annotationProcessor "androidx.room:room-compiler:$room_version"
    implementation("androidx.room:room-ktx:$room_version")
    kapt("androidx.room:room-compiler:$room_version")

    def  lifecycle_version = "2.4.0-alpha02"

    implementation("androidx.lifecycle:lifecycle-viewmodel-ktx:$lifecycle_version")
    implementation("androidx.lifecycle:lifecycle-livedata-ktx:$lifecycle_version")
    implementation("androidx.lifecycle:lifecycle-runtime-ktx:$lifecycle_version")

    //by viewModels
    implementation "androidx.activity:activity-ktx:1.2.0"
    implementation "androidx.fragment:fragment-ktx:1.3.0"

    //navigation
    implementation("androidx.navigation:navigation-fragment-ktx:2.3.5")
    implementation("androidx.navigation:navigation-ui-ktx:2.3.5")
    implementation 'com.nex3z:flow-layout:1.3.3'

android {
    buildFeatures{
        viewBinding true
        dataBinding true
    }
}

在Module中
 dependencies {  
        //classpath
        classpath("androidx.navigation:navigation-safe-args-gradle-plugin:2.3.5")
    }

数据库表的搭建

数据库表

Todo类中

/**
 *@Description
 *@Author PC
 *@QQ 1578684787
 */
@Parcelize   //实现序列化,使支持传递Custom Parcelize的数据
@Entity(tableName = "todo_table")
data class Todo(
    @PrimaryKey(autoGenerate = true)
    var id:Int,
    var title:String,
    var description: String, //内容
    var priority: Priority, //事务的重要性
    @Embedded
    var date: Date,//管理日期
    @Embedded
    var tag: Tag //管理标签
):Parcelable

/**
 * 标识事务的重要性
 */
enum class Priority{
    HIGH,MIDDLE,LOW
}

/**
 * 管理日期
 */
@Parcelize
data class Date(
    var year:Int,
    var month:Int,
    var day:Int
):Parcelable

/**
 * 管理标签
 */
@Parcelize
data class Tag(
    var text:String,
    var bgColor:String
):Parcelable

@Embedded的作用:将该注解的表格内容镶嵌到@Embedded所在的表中,但是这个表不能被单独创建字段。
@Parcelize为实现序列化,传递相应内容,后面将作详细介绍

Tag类中

@Entity(tableName = "tag_table")
data class TagData (
    @PrimaryKey(autoGenerate = true)
    val id:Int,
    val title:String,
    val bgColor:String
    )

搭建接口

/**
 *@Description
 *@Author PC
 *@QQ 1578684787
 */
@Dao
interface TodoDao {
    //插入todo
    @Insert(onConflict = OnConflictStrategy.REPLACE)
    suspend fun insertTodoData(todo: Todo)
    //获取todo数据
    @Query("select * from todo_table")
    fun getTodoDatas():LiveData<List<Todo>>
    //删除todo
    @Delete
    suspend fun deleteTodoData(todo: Todo)
    //删除所有todo
    @Query("delete from todo_table")
    suspend fun deleteAllTodoDatas()
    //更新数据
    @Update(onConflict = OnConflictStrategy.REPLACE)
    suspend fun updateTodoData(todo: Todo)

    /**
     * 标签操作
     */
    //插入标签
    @Insert(onConflict = OnConflictStrategy.REPLACE)
    suspend fun insertTag(tagData: TagData)

    //获取所有标签
    @Query("select * from tag_table")
    fun getAllTags():LiveData<TagData>
    //删除标签
    @Delete
    fun deleteTag(tagData: TagData)

}
/**
 *@Description
 *@Author PC
 *@QQ 1578684787
 */
@Dao
interface TagDao {
    //插入Tag
    @Insert(onConflict = OnConflictStrategy.REPLACE)
    suspend fun insertTag(tag: TagData)

    //删除tag
    @Delete
    suspend fun deleteTag(tag: TagData)
    //读取所有todo
    @Query("select * from tag_table")
    fun getAllTag():LiveData<List<TagData>>
}

创建TodoConverter解析器

因为我们所创建的Priority(事务的优先级)系统无法识别,所以创建解析器将Priority转换为字符串,在使用时再转换回我们自定义的Priority。
主要是@TypeConverter的使用
priority是我自己定义的枚举类型的数据,枚举中有个特殊的属性name将枚举转化为String类型
valueOf为枚举中特有的方法,将枚举值对应的name传递给它,就会转化为对应的枚举类型。

class TodoConverter {

    //将priority对象存入数据库时调用
    @TypeConverter
    fun priorityToString(priority: Priority):String{
        return priority.name
    }

    //从数据库中取出该数据时转化为Priority类型
    @TypeConverter
    fun stringToPriority(str:String):Priority{
        return Priority.valueOf(str)
    }
}

创建数据库类

使用单例的方式创建数据库类,保证数据库的唯一性,数据的一致性

@TypeConverters(TodoConverter::class)
@Database(
    entities = [Todo::class, TagData::class],
    version = 1,
    exportSchema = false
)
abstract class TodoDatabase:RoomDatabase() {
    abstract fun getTodoDao(): TodoDao
    abstract fun getTagDao(): TagDao

    //创建单例对象
    companion object {
        @Volatile
        private var INSTANCE: TodoDatabase? = null
        fun getDatabase(context: Context):TodoDatabase{
            if (INSTANCE != null){
                return INSTANCE!!
            }
            //创建对象
            synchronized(this){
                if (INSTANCE==null){
                    INSTANCE = Room.databaseBuilder(context,TodoDatabase::class.java,"todo.db"
                    ).build()
                }
            }
            return INSTANCE!!
        }
    }
}

创建TodoRepository

Repository作为伪数据仓库,外部在访问数据库的数据时通过该对象访问数据

class TodoRepository(context: Context) {
    private val todoDao = TodoDatabase.getDatabase(context).getTodoDao()
    private val tagDao = TodoDatabase.getDatabase(context).getTagDao()

    /**
     * TagDao
     */
    //插入Tag
    suspend fun insertTag(tag: TagData){
        tagDao.insertTag(tag)
    }

    //删除tag
    suspend fun deleteTagData(tag: TagData){
        tagDao.deleteTag(tag)
    }
    //删除所有todo
    fun getAllTags():LiveData<List<TagData>>{
        return tagDao.getAllTag()
    }

    /**
     * todoDao
     */
    //插入todo
    suspend fun insertTodoData(todo: Todo){
        todoDao.insertTodoData(todo)
    }
    //获取todo数据
    fun getTodoDatas():LiveData<List<Todo>>{
        return todoDao.getTodoDatas()
    }
    //删除todo
    suspend fun deleteTodoData(todo: Todo){
        todoDao.deleteTodoData(todo)
    }
    //删除所有todo
    suspend fun deleteAllTodoDatas(){
        todoDao.deleteAllTodoDatas()
    }
    //更新数据
    suspend fun updateTodoData(todo: Todo){
        todoDao.updateTodoData(todo)
    }

}

未完待续……
完整代码

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,324评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,356评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,328评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,147评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,160评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,115评论 1 296
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,025评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,867评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,307评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,528评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,688评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,409评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,001评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,657评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,811评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,685评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,573评论 2 353

推荐阅读更多精彩内容

  • 标签的全部设计 实现目标:点击详情页面的Add按钮添加标签会弹出创建标签的小窗口 添加后的标签会出现在详情页面中标...
    搬码人阅读 583评论 0 1
  • 创建RecyclerView 在设置标签(Tag)的背景色时遇到的问题:我不能直接设置标签的background,...
    搬码人阅读 377评论 0 1
  • 创建mainVIewModule 实现MVVM设计模式的重要环节,可在任意的fragment中监听todoData...
    搬码人阅读 491评论 0 2
  • 用两张图告诉你,为什么你的 App 会卡顿? - Android - 掘金 Cover 有什么料? 从这篇文章中你...
    hw1212阅读 12,712评论 2 59
  • 1,java 接口的意义: 规范,扩展,回调 规范:比如,有两个及上的的类拥有相同的方法,但是实现功能不一样,就可...
    漫唐阅读 966评论 0 6