第七章 数据存储
-
文件存储
-
将数据存储到文件中
fun save(view: View) { try { // 保存到/data/data/<package_name>/files/data文件中 val openFileOutput = openFileOutput("data", Context.MODE_PRIVATE) val bufferedWriter = BufferedWriter(OutputStreamWriter(openFileOutput)) bufferedWriter.use { it.write(fileContentEdit.text.toString()) } } catch (e: Exception) { } }
Context.MODE_PRIVATE
写入的内容将覆盖原内容Context.MODE_APPEND
追加内容use()
函数保证Lambda表达式中代码全部执行完之后自动将外层流关闭 -
从文件中获取内容
fun read(view: View) { try { val openFileInput = openFileInput("data") val bufferedReader = BufferedReader(InputStreamReader(openFileInput)) bufferedReader.use { it.forEachLine { fileContentEdit.setText(it) } } } catch (e:Exception) { } }
-
-
SharedPreferences
-
保存内容
fun save(view: View) { // 保存到/data/data/<package_name>/shared_prefs/data.xml文件中 val sharedPreferences = getSharedPreferences("data", Context.MODE_PRIVATE) val edit = sharedPreferences.edit() edit.putString("text", fileContentEdit.text.toString()) edit.apply() }
-
获取内容
fun read(view: View) { val sharedPreferences = getSharedPreferences("data", Context.MODE_PRIVATE) val string = sharedPreferences.getString("text", "") fileContentEdit.setText(string) }
-
-
SQLite数据库存储
-
创建数据库
class MyDatabaseHelper(val context: Context, name: String, version: Int) : SQLiteOpenHelper(context, name, null, version) { private val createBook = "create table Book(id integer primary key autoincrement, author text, price real, pages integer, name text)" override fun onCreate(db: SQLiteDatabase) { db.execSQL(createBook) Toast.makeText(context, "Create success", Toast.LENGTH_SHORT).show() } override fun onUpgrade(db: SQLiteDatabase?, oldVersion: Int, newVersion: Int) { TODO("Not yet implemented") } }
class DatabaseActivity : BaseActivity() { private lateinit var myDatabaseHelper: MyDatabaseHelper override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_database) myDatabaseHelper = MyDatabaseHelper(this, "Bookstore.db", 1) } fun create(view: View) { myDatabaseHelper.writableDatabase } }
-
升级数据库
class MyDatabaseHelper(val context: Context, name: String, version: Int) : SQLiteOpenHelper(context, name, null, version) { private val createBook = "create table Book(id integer primary key autoincrement, author text, price real, pages integer, name text)" private val createCategory = "create table Category(id integer primary key autoincrement, category_name text, category_code integer)" override fun onCreate(db: SQLiteDatabase) { db.execSQL(createBook) db.execSQL(createCategory) Toast.makeText(context, "Create success", Toast.LENGTH_SHORT).show() } override fun onUpgrade(db: SQLiteDatabase, oldVersion: Int, newVersion: Int) { TODO("Not yet implemented") db.execSQL("drop table if exists Book") db.execSQL("drop table if exists Category") onCreate(db) } }
class DatabaseActivity : BaseActivity() { private lateinit var myDatabaseHelper: MyDatabaseHelper override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_database) // 此处升级数据库版本号 myDatabaseHelper = MyDatabaseHelper(this, "Bookstore.db", 2) } fun create(view: View) { myDatabaseHelper.writableDatabase } fun upgrade(view: View) { myDatabaseHelper.writableDatabase } }
-
增
fun insert(view: View) { val writableDatabase = myDatabaseHelper.writableDatabase val va = ContentValues().apply { put("name", "The Da Vinci Code") put("author", "Dan Brown") put("pages", 454) put("price", 18.8) } writableDatabase.insert("Book", null, va) val apply = ContentValues().apply { put("name", "The Lost Symbol") put("author", "Dan Brown") put("pages", 510) put("price", 50) } writableDatabase.insert("Book", null, apply) // SQL语句 writableDatabase.execSQL("insert into Book(name, author, pages, price) values(?, ?, ?, ?)", arrayOf("Tha Da Vinci Code", "Dan Brown", "454", "15.55"))}
-
改
fun update(view: View) { val apply = ContentValues().apply { put("price", 0.9) } myDatabaseHelper.writableDatabase.update( "Book", apply, "name = ?", arrayOf("The Da Vinci Code") ) myDatabaseHelper.writableDatabase.execSQL("update Book set price = ? where name = ?", arrayOf(1.1, "The Lost Symbol")) }
-
删
fun delete(view: View) { myDatabaseHelper.writableDatabase.delete("Book", "pages > ?", arrayOf("500")) myDatabaseHelper.writableDatabase.execSQL("delete from Book where name = ?", arrayOf("The Da Vinci Code")) }
-
查
fun query(view: View) { val query = myDatabaseHelper.writableDatabase.query("Book", null, null, null, null, null, null, null ) if (query.moveToFirst()) { do { Toast.makeText(this, "Book name is ${query.getString(query.getColumnIndex("name"))}, author is ${ query.getString(query.getColumnIndex("author"))}", Toast.LENGTH_SHORT).show() } while (query.moveToNext()) } query.close() val cursor = myDatabaseHelper.writableDatabase.rawQuery("select * from Book", null) cursor.close() }
-
-
使用事务
在操作之前先开启事务,在数据库操作执行完成之后设置标记,最后结束事务
fun transaction() { val db = myDatabaseHelper.writableDatabase db.beginTransaction() try { db.delete("Book", null, null) val apply = ContentValues().apply { put("price", 0.9) } db.update("Book", apply, "name = ?", arrayOf("The Da Vinci Code")) db.setTransactionSuccessful() } catch (e: Exception) { e.printStackTrace() } finally { db.endTransaction() } }
-
升级数据库最佳写法
class MyDatabaseHelper(val context: Context, name: String, version: Int): SQLiteOpenHelper(context, name, null, version) { private val createBook = "create table Book (id integer primary key autoincrement, author text, price real, pages integer, name text)" override fun onCreate(db: SQLiteDatabase) { db.execSQL(createBook) } override fun onUpgrade(db: SQLiteDatabase, oldVersion: Int, newVersion: Int) { } }
升级第二版:
class MyDatabaseHelper(val context: Context, name: String, version: Int): SQLiteOpenHelper(context, name, null, version) { private val createBook = "create table Book (id integer primary key autoincrement, author text, price real, pages integer, name text)" private val createCategory = "create table Category (id integer primary key autoincrement, category_name text, category_code integer)" override fun onCreate(db: SQLiteDatabase) { db.execSQL(createBook) db.execSQL(createCategory) } override fun onUpgrade(db: SQLiteDatabase, oldVersion: Int, newVersion: Int) { if (oldVersion <= 1) { db.execSQL(createCategory) } } }
升级第三版
class MyDatabaseHelper(val context: Context, name: String, version: Int): SQLiteOpenHelper(context, name, null, version) { private val createBook = "create table Book (id integer primary key autoincrement, author text, price real, pages integer, text, category_id integer)" private val createCategory = "create table Category (id integer primary key autoincrement, category_name text, category_code integer)" override fun onCreate(db: SQLiteDatabase) { db.execSQL(createBook) db.execSQL(createCategory) } override fun onUpgrade(db: SQLiteDatabase, oldVersion: Int, newVersion: Int) { if (oldVersion <= 1) { db.execSQL(createCategory) } if (oldVersion <= 2) { db.execSQL("alter table Book add column category_id integer") } } }
-
Kotlin课堂:高阶函数应用
-
简化SharedPreferences的用法
fun SharedPreferences.open(block: SharedPreferences.Editor.() -> Unit) { val edit = edit() edit.block() // 或者这样 block(edit) edit.apply() }
转化Java的实现,这里直接new Activity了,可以放到Activity中
public class SharedPreferencesUtil { public static void main(String[] args) { SharedPreferences sharedPreferences = new Activity().getSharedPreferences("", 0); open(sharedPreferences, new Function1<SharedPreferences.Editor, Void>() { @Override public Void invoke(SharedPreferences.Editor editor) { // 这里添加具体业务逻辑 editor.putInt("", 1); return null; } }); } public static void open(SharedPreferences sp, Function1<SharedPreferences.Editor, Void> function1) { SharedPreferences.Editor edit = sp.edit(); function1.invoke(edit); } }
Kotlin中open函数接收的是一个SharedPreferences.Editor的函数类型参数,具体是什么函数不清楚。所以我们可以通过Editor的对象调用block()函数。
除了内联函数中引用的Lambda,Kotlin中一切Lambda本质都是对象(Java实现)。
优化前:
val sharedPreferences = getSharedPreferences("data", Context.MODE_PRIVATE) val edit = sharedPreferences.edit() edit.putString("text", fileContentEdit.text.toString()) edit.apply()
优化后:
getSharedPreferences("data", Context.MODE_PRIVATE).open { edit.putString("text", fileContentEdit.text.toString()) }
-
简化ContentValues用法
优化前:
ContentValues().apply { put("name", "The Lost Symbol") put("author", "Dan Brown") put("pages", 510) put("price", 50) }
先回顾下之前创建map:
mapOf("1" to "One", "2" to "Two")
fun ContentValues.cvOf(vararg pairs:Pair<String, Any?>) :ContentValues { val cv = ContentValues() for (pair in pairs) { val key = pair.first val value = pair.second when (value) { null -> putNull(key) is String -> put(key, value) is Int -> put(key, value) is Long -> put(key, value) is Boolean -> put(key, value) is Float -> put(key, value) is Double -> put(key, value) is ByteArray -> put(key, value) is Byte -> put(key, value) is Short -> put(key, value) else -> { val valueType = value.javaClass.canonicalName throw IllegalArgumentException("Illegal value type $valueType for key \"$key\"") } } } return cv }
vararg
可变参数列表Any?
泛型,Any是Kotlin中所有类的共同基类,而Any?
表示可以传入空值使用
apply
后的优化效果// 此处传入pair.size在创建ContentValues时就指定了大小,避免扩容时的性能损耗 fun contentValuesOf(vararg pairs: Pair<String, Any?>) = ContentValues(pairs.size).apply { for ((key, value) in pairs) { when (value) { null -> putNull(key) is String -> put(key, value) is Int -> put(key, value) is Long -> put(key, value) is Boolean -> put(key, value) is Float -> put(key, value) is Double -> put(key, value) is ByteArray -> put(key, value) is Byte -> put(key, value) is Short -> put(key, value) else -> { val valueType = value.javaClass.canonicalName throw IllegalArgumentException("Illegal value type $valueType for key \"$key\"") } } } }
优化前:
val apply = ContentValues().apply { put("name", "The Lost Symbol") put("author", "Dan Brown") put("pages", 510) put("price", 50) }
优化后:
val book = cvOf( "name" to "The Lost Symbol", "author" to "Dan Brown", "pages" to 510, "price" to 50 )
-