美文网首页无名之辈的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 手机便签(一)

    项目准备: 1、LiveData与MVVM设计模式2、Navigation导航的使用3、RecyclerView4...

  • Android 手机便签(四)

    标签的全部设计 实现目标:点击详情页面的Add按钮添加标签会弹出创建标签的小窗口 添加后的标签会出现在详情页面中标...

  • Android 手机便签(二)

    创建mainVIewModule 实现MVVM设计模式的重要环节,可在任意的fragment中监听todoData...

  • Android 手机便签(三)

    创建RecyclerView 在设置标签(Tag)的背景色时遇到的问题:我不能直接设置标签的background,...

  • Android 开源App:发呆便签/SuperNote

    发呆便签/SuperNote 发呆便签/SuperNote是一款开源的Android便签,实现了主流便签的基本功能...

  • 【无戒学堂】介绍几款便签和存储类的工具

    今天介绍一下平时用的几个便签以及存储的工具,大概的都写写。 手机自带便签: 相信每一款手机里都有自带的一个便签功能...

  • Android平台便签软件分析评测

    本次分析评测基于Android平台,选取了三款有代表性的便签软件,分别是魅族便签、锤子便签(v2.0)、EverM...

  • 小米便签产品级的源码

    小米便签产品级的源码 源码简介 小米便签Android源码,可以再桌面创建widget。 源码截图 源码下载 源码下载

  • 来自手机便签

    老社长讲话 本来是名誉社长讲话的,前段时间都说还要来。没想到就在最近几天离开了。所以我来了。竭诚哀悼,衷心祝愿。 ...

  • 2020.03.26

    又到了定期整理手机便签的时候,打开便签,删删减减二十多分钟后,手机里只剩下十几条便签,都是计划、地址或者没写完的文...

网友评论

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

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