美文网首页无名之辈的Android之路
Android 手机便签(一)

Android 手机便签(一)

作者: 搬码人 | 来源:发表于2021-08-17 21:57 被阅读0次

    项目准备:

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

    未完待续……
    完整代码

    相关文章

      网友评论

        本文标题:Android 手机便签(一)

        本文链接:https://www.haomeiwen.com/subject/oznibltx.html