Kotlin开发安卓APP笔记实战-写个简易记事本(逻辑)

元旦前事情不少,拖到现在才写,有点尴尬。写了代码才知道前一篇写的笔记有些不正确,在这一篇笔记慢慢指出来,也不更新前一篇笔记了。学习就是这样一个发现错误并改正错误的过程。
先看最终效果图
Kotlin开发安卓APP笔记实战-写个简易记事本(逻辑)_第1张图片
Kotlin开发安卓APP笔记实战-写个简易记事本(逻辑)_第2张图片
由于工作关系,RecyclerView没有画分割线,如果需要的话可以参考郭神的Android RecyclerView 使用完全解析 体验艺术般的控件
用到的返回和保存按钮图标在图标查询网下载

创建一个DbHelper类连接数据库并初始化数据库结构

package cn.bestmk.note

import android.content.Context
import android.database.sqlite.SQLiteDatabase
import android.database.sqlite.SQLiteOpenHelper

/**
 * Created by 醉猫 on 2017/12/26.
 */

class DBHelper(context: Context) : SQLiteOpenHelper(context, DB_NAME, null, DB_VERSION) {
    override fun onCreate(sqLiteDatabase: SQLiteDatabase) {
        // create table if not exists note(ID INT PRIMARY KEY NOT NULL,createtime TIMESTAMP NOT NULL,chagetime TIMESTAMP,title CHAR(255) NOT NULL,content TEXT NOT NULL);
        val sql = "create table if not exists $TABLE_NAME(ID INTEGER PRIMARY KEY AUTOINCREMENT,createtime TIMESTAMP NOT NULL,chagetime TIMESTAMP,title CHAR(255) NOT NULL,content TEXT NOT NULL);"
        sqLiteDatabase.execSQL(sql)
    }
    override fun onUpgrade(sqLiteDatabase: SQLiteDatabase, oldVersion: Int, newVersion: Int) {
        val sql = "DROP TABLE IF EXISTS " + TABLE_NAME
        sqLiteDatabase.execSQL(sql)
        onCreate(sqLiteDatabase)
    }
    //声明静态变量
    companion object {
        private val DB_VERSION = 1
        private val DB_NAME = "note.db"
        private val TABLE_NAME = "note"
    }
}

从代码中看出这里的sql语句和上一篇笔记(ID INT PRIMARY KEY NOT NULL)并不一致,这里是ID INTEGER PRIMARY KEY AUTOINCREMENT,前面的语句是设置ID为主键并且不能为空,后面是ID为主键,并且自动增长,越是细节的地方越容易出错。

创建一个NoteBean保存笔记数据,可以理解为kotlin的Javabean

package cn.bestmk.note

/**
 * Created by 醉猫 on 2017/12/29.
 */

class NoteBean {
    var id: Int = 0
    var createTime: Long = 0
    var chageTime: Long = 0
    var title: String? = null
    var content: String? = null
}

创建一个NoteManager管理笔记(增删改查)

package cn.bestmk.note

import android.content.Context
import android.database.sqlite.SQLiteDatabase
import android.util.Log

/**
 * Created by 醉猫 on 2017/12/27.
 */
class NoteManager(contxt: Context){
    val db:SQLiteDatabase
    init {
        db= DBHelper(contxt).writableDatabase
    }

    /**
     * 添加一条笔记
     */
    fun addNote(title:String,content:String){
        var nowtime=System.currentTimeMillis()
        var sql="insert into note (createtime, chagetime, title,content) values ($nowtime,$nowtime,'$title','$content')"
        db.execSQL(sql)
    }

    /**
     * 删除一条笔记
     */
    fun deleteNote(id:Int){
        var sql="delete from note where ID=$id"
        db.execSQL(sql)
    }

    /**
     * 修改一条笔记
     */
    fun chageNote(id:Int,title: String,content: String){
        var nowtime=System.currentTimeMillis()
        var sql="update note set title='$title',content='$content',chagetime='$nowtime' where ID=$id"
        db.execSQL(sql)
    }

    /**
     * 查询笔记
     */
    fun queryNote(id: Int):NoteBean{
        val bean=NoteBean()
        var sql="select * from note where ID=$id"
        var cursor=db.rawQuery(sql,null) //执行查询语句
        if (cursor.moveToNext()){
            bean.id=cursor.getInt(0) //获取id
            bean.createTime=cursor.getLong(1) //获取创建时间
            bean.chageTime=cursor.getLong(2)//获取上次修改时间
            bean.title=cursor.getString(3)//获取标题
            bean.content=cursor.getString(4)//获取内容
        }
        return bean
    }

    /**
     * 查询所有笔记
     */
    fun queryNotes():ArrayList{
        val list: ArrayList = arrayListOf()//创建集合
        var sql="select * from note" //构建查询语句
        var cursor=db.rawQuery(sql,null) //执行查询语句
        while (cursor.moveToNext()){ //设置循环语句
            val bean=NoteBean()
            bean.id=cursor.getInt(0) //获取id
            bean.createTime=cursor.getLong(1) //获取创建时间
            bean.chageTime=cursor.getLong(2)//获取上次修改时间
            bean.title=cursor.getString(3)//获取标题
            bean.content=cursor.getString(4)//获取内容
            list.add(bean) //添加一条笔记到集合
        }
        return list
    }
}

注释写得比较详细,就不再多说

为RecyclerView创建一个适配器NoteAdapter.kt

package cn.bestmk.note

import android.app.AlertDialog
import android.content.Context
import android.content.DialogInterface
import android.content.Intent
import android.support.v7.widget.RecyclerView
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.LinearLayout
import android.widget.TextView
import android.widget.Toast
import cn.bestmk.note.NoteAdapter.ViewHolder

import org.w3c.dom.Text
import java.text.SimpleDateFormat
import java.util.*

/**
 * Created by 醉猫 on 2017/12/29.
 */

class NoteAdapter(var context:Context,var mData: ArrayList?) : RecyclerView.Adapter.ViewHolder>() {

    fun updateData(data: ArrayList) {
        this.mData = data
        notifyDataSetChanged()
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
        // 实例化展示的view
        val v = LayoutInflater.from(parent.context).inflate(R.layout.item, parent, false)
        // 实例化viewholder
        return ViewHolder(v)
    }

    override fun onBindViewHolder(holder: ViewHolder, position: Int) {
        var sdFormat= SimpleDateFormat("yyyy-MM-dd HH:mm:ss")//时间转换器
        // 绑定数据
        holder.tv_title.setText(mData!![position].title)
        holder.tv_createtime.setText("创建时间:"+sdFormat.format(Date(mData!![position].createTime)))//显示转换后的创建时间
        holder.tv_chagetime.setText("修改时间:"+sdFormat.format(Date(mData!![position].chageTime)))//显示转换后的创建时间
        holder.itemView.setOnClickListener { view ->
            val intent=Intent(context,EditActivity::class.java)
            intent.putExtra("ID", mData!![position].id) //向EditActivity传递ID
            context.startActivity(intent)
        }
        holder.itemView.setOnLongClickListener(object :View.OnLongClickListener{
            override fun onLongClick(p0: View?): Boolean {
                AlertDialog.Builder(context).setTitle("骚气的提示") .setMessage("是否要删除本条笔记").setPositiveButton("是",object :DialogInterface.OnClickListener{
                    override fun onClick(p0: DialogInterface?, p1: Int) {
                        NoteManager(context).deleteNote(position)//删除笔记
                        mData!!.removeAt(position)//更新集合数据
                        updateData(mData!!)//刷新页面数据
                        Toast.makeText(context,"删除成功",Toast.LENGTH_LONG).show()
                    }
                }).setNegativeButton("取消",null).show()
                return false
            }
        })
    }

    override fun getItemCount(): Int {
        return if (mData == null) 0 else mData!!.size
    }

    class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {

        internal var tv_title: TextView
        internal var tv_createtime: TextView
        internal var tv_chagetime: TextView

        init {
            tv_title = itemView.findViewById(R.id.tv_title)
            tv_createtime = itemView.findViewById(R.id.tv_createtime)
            tv_chagetime = itemView.findViewById(R.id.tv_chagetime)
        }
    }
}

MainActivity.kt

package cn.bestmk.note

import android.content.Intent
import android.os.Bundle
import android.support.design.widget.Snackbar
import android.support.v7.app.AppCompatActivity
import android.support.v7.widget.LinearLayoutManager
import android.support.v7.widget.RecyclerView
import android.widget.AdapterView

import kotlinx.android.synthetic.main.activity_main.*

class MainActivity : AppCompatActivity() {
    lateinit var nm: NoteManager //声明笔记管理器
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        setSupportActionBar(toolbar)

        nm = NoteManager(this)//初始化笔记管理器
        rv.layoutManager = LinearLayoutManager(this) as RecyclerView.LayoutManager?//设置布局管理器

        //右下悬浮按钮事件
        fab.setOnClickListener { view ->
            var intent = Intent(this@MainActivity, EditActivity::class.java)
            startActivity(intent)
        }
    }
    //在onStart中设置适配器,每次显示MainActivity都会更新一次数据
    override fun onStart() {
        rv.adapter = NoteAdapter(this, nm.queryNotes())//设置适配器
        super.onStart()
    }
}

EditActivity.kt

package cn.bestmk.note

import android.app.AlertDialog
import android.content.DialogInterface
import android.support.v7.app.AppCompatActivity
import android.os.Bundle
import android.text.Editable
import android.text.TextWatcher
import android.view.KeyEvent
import android.view.Menu
import android.widget.Toast
import kotlinx.android.synthetic.main.activity_edit.*

class EditActivity : AppCompatActivity() {
    lateinit var nm: NoteManager
    var ID: Int = -1 //ID
    var ischage = false
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_edit)

        setSupportActionBar(toolbar)//为当前的Activity设置标题栏
        nm = NoteManager(this)//获取笔记管理器实例
        title = ""

        ID = intent.getIntExtra("ID", -1)//获取ID,设置默认值为-1,也就是没有传递参数会传-1
        if (ID >= 0) {//如果id大于或等于0,就说明用户是点击item进入EditActivity,是修改或查看笔记,否则是新增笔记
            var bean = nm.queryNote(ID)//查询这条ID的内容
            ettitle.setText(bean.title)//显示标题
            etcontent.setText(bean.content)//显示内容
        }
        //为save按钮绑定事件
        toolbar.setOnMenuItemClickListener {
            if (ettitle.text.length < 0) {//判断标题是否为空
                Toast.makeText(this@EditActivity, "标题不可为空", Toast.LENGTH_LONG).show()
                return@setOnMenuItemClickListener false
            }
            if (etcontent.text.length < 0) {//判断内容是否为空
                Toast.makeText(this@EditActivity, "内容不可为空", Toast.LENGTH_LONG).show()
                return@setOnMenuItemClickListener false
            }
            save()
            finish()//关闭当前页面
            false
        }
        back.setOnClickListener {
            back()
        }
        //监听标题改变事件
        ettitle.addTextChangedListener(object : TextWatcher {
            override fun afterTextChanged(p0: Editable?) {
            }

            override fun beforeTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {
            }

            override fun onTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {
                ischage = true //将笔记改变状态设置成true
            }

        })
        //监听内容改变事件
        etcontent.addTextChangedListener(object : TextWatcher {
            override fun afterTextChanged(p0: Editable?) {
            }

            override fun beforeTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {
            }

            override fun onTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {
                ischage = true //将笔记改变状态设置成true
            }

        })
    }
    //保存笔记函数
    fun save(){
        if (ID >= 0) {//修改
            nm.chageNote(ID, ettitle.text.toString(), etcontent.text.toString())//修改这条笔记
            Toast.makeText(this@EditActivity, "修改成功", Toast.LENGTH_LONG)
        } else {//新增
            nm.addNote(ettitle.text.toString(), etcontent.text.toString())//数据库新增一条笔记
            Toast.makeText(this@EditActivity, "保存成功", Toast.LENGTH_LONG).show()
        }
    }
    //返回函数
    fun back(){
        //如果笔记被修改就弹出窗口提示用户笔记被修改,询问用户是否要保存/修改笔记
        if (ischage){
            AlertDialog.Builder(this).setTitle("骚气的提示").setMessage("您的笔记尚未保存,是否保存?").setPositiveButton("保存",object :DialogInterface.OnClickListener{
                override fun onClick(p0: DialogInterface?, p1: Int) {
                    save()
                    finish()
                }
            }).setNegativeButton("不保存",object :DialogInterface.OnClickListener{
                override fun onClick(p0: DialogInterface?, p1: Int) {
                    finish()
                }
            }).setNeutralButton("取消",null).show()
        }else{
            finish()
        }
    }
    // 为toolbar创建Menu
    override fun onCreateOptionsMenu(menu: Menu?): Boolean {
        getMenuInflater().inflate(R.menu.menu, menu);
        return true;
    }
    //拦截返回键
    override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean {
        if (keyCode==KeyEvent.KEYCODE_BACK){
            back()
            return true
        }
        return super.onKeyDown(keyCode, event)
    }
}

xml相对比前一篇笔记有一些小的调整,就不贴出来了
源码下载地址我会放在猫客技术论坛同名贴子下面,需要的可以下载下来看看

你可能感兴趣的:(安卓,Kotlin)