目錄
將數據存儲到文件中
創建文件和保存數據
讀取文件
Activity類中的getPreferences()方法
SQLite數據庫存儲
創建數據庫
調用數據庫
操作數據庫
增
刪
改
查
升級數據庫
將數據存儲到文件中
創建文件和保存數據
Context
類中提供了一個openFileOutput()
方法,可以用于將數據存儲到指定的文件中。這個方法接收兩個參數:第一個參數是文件名,在文件創建的時候使用,注意這里指定的文件名不可以包含路徑,因為所有的文件都默認存儲到/data/data/<package name>/files/目錄下;第二個參數是文件的操作模式,主要有MODE_PRIVATE
和MODE_APPEND
兩種模式可選,默認是MODE_PRIVATE
,表示當指定相同文件名的時候,所寫入的內容將會覆蓋原文件中的內容,而MODE_APPEND
則表示如果該文件已存在,就往文件里面追加內容,不存在就創建新文件。其實文件的操作模式本來還有另外兩種:MODE_WORLD_READABLE
和MODE_WORLD_WRITEABLE
。這兩種模式表示允許其他應用程序對我們程序中的文件進行讀寫操作,不過由于這兩種模式過于危險,很容易引起應用的安全漏洞,已在Android 4.2版本中被廢棄。
openFileOutput()
方法返回的是一個FileOutputStream
對象,得到這個對象之后就可以使用Java流的方式將數據寫入文件中了。以下是一段簡單的代碼示例,展示了如何將一段文本內容保存到文件中:
fun saveFile(saveString: String) {val output = openFileOutput("fileName", Context.MODE_PRIVATE)val writer = BufferedWriter(OutputStreamWriter(output))writer.use {it.write(saveString)}}
這里通過openFileOutput()
方法能夠得到一個FileOutputStream
對象,然后借助它構建出一個OutputStreamWriter
對象,接著再使用OutputStreamWriter
構建出一個BufferedWriter
對象,這樣你就可以通過BufferedWriter
將文本內容寫入文件中了。
注意,這里還使用了一個use
函數,這是Kotlin提供的一個內置擴展函數。它會保證在Lambda表達式中的代碼全部執行完之后自動將外層的流關閉,這樣就不需要我們再編寫一個finally
語句,手動去關閉流了,是一個非常好用的擴展函數。
另外,Kotlin是沒有異常檢查機制(checked exception)的。這意味著使用Kotlin編寫的所有代碼都不會強制要求你進行異常捕獲或異常拋出。即使你不寫try catch
代碼塊,在Kotlin中依然可以編譯通過。
讀取文件
類似于將數據存儲到文件中,Context
類中還提供了一個openFileInput()
方法,用于從文件中讀取數據。這個方法要比openFileOutput()
簡單一些,它只接收一個參數,即要讀取的文件名,然后系統會自動到/data/data/<package name>/files/目錄下加載這個文件,并返回一個FileInputStream
對象,得到這個對象之后,再通過流的方式就可以將數據讀取出來了。
以下是一段簡單的代碼示例,展示了如何從文件中讀取文本數據:
fun loadFile(): String {val stringBuilder = StringBuilder()val input = openFileInput("fileName")val reader = BufferedReader(InputStreamReader(input))reader.use {reader.forEachLine {stringBuilder.append(it)}}return stringBuilder.toString()}
在這段代碼中,首先通過openFileInput()
方法獲取了一個FileInputStream
對象,然后借助它又構建出了一個InputStreamReader
對象,接著再使用InputStreamReader
構建出一個BufferedReader
對象,這樣我們就可以通過BufferedReader
將文件中的數據一行行讀取出來,并拼接到StringBuilder
對象當中,最后將讀取的內容返回就可以了。
注意,這里從文件中讀取數據使用了一個forEachLine
函數,這也是Kotlin提供的一個內置擴展函數,它會將讀到的每行內容都回調到Lambda表達式中,我們在Lambda表達式中完成拼接邏輯即可。
SharedPreferences存儲
存儲數據到SharedPreferences中
要想使用SharedPreferences存儲數據,首先需要獲取SharedPreferences
對象。Android中主要提供了以下兩種方法用于得到SharedPreferences
對象。
-
Context
類中的getSharedPreferences()
方法此方法接收兩個參數:第一個參數用于指定SharedPreferences文件的名稱,如果指定的文件不存在則會創建一個,SharedPreferences文件都是存放在/data/data/<package name>/shared_prefs/目錄下的;第二個參數用于指定操作模式,目前只有默認的
MODE_PRIVATE
這一種模式可選,它和直接傳入0的效果是相同的,表示只有當前的應用程序才可以對這個SharedPreferences文件進行讀寫。其他幾種操作模式均已被廢棄,MODE_WORLD_READABLE
和MODE_WORLD_WRITEABLE
這兩種模式是在Android 4.2版本中被廢棄的,MODE_MULTI_PROCESS
模式是在Android 6.0版本中被廢棄的。 -
Activity
類中的getPreferences()
方法這個方法和Context中的
getSharedPreferences()
方法很相似,不過它只接收一個操作模式參數,因為使用這個方法時會自動將當前Activity
的類名作為SharedPreferences的文件名。得到了
SharedPreferences
對象之后,就可以開始向SharedPreferences文件中存儲數據了,主要可以分為3步實現。(1) 調用
SharedPreferences
對象的edit()
方法獲取一個SharedPreferences.Editor
對象。(2) 向
SharedPreferences.Editor
對象中添加數據,比如添加一個布爾型數據就使用putBoolean()
方法,添加一個字符串則使用putString()
方法,以此類推。(3) 調用
apply()
方法將添加的數據提交,從而完成數據存儲操作。
?代碼示例如下
fun saveSharedPreferences(saveString: String){val edit = getSharedPreferences("fileName",Context.MODE_PRIVATE).edit()edit.putString("editName","editValue")edit.apply()}
從SharedPreferences中讀取數據
SharedPreferences
對象中提供了一系列的get
方法,用于讀取存儲的數據,每種get
方法都對應了SharedPreferences.Editor
中的一種put
方法,比如讀取一個布爾型數據就使用getBoolean()
方法,讀取一個字符串就使用getString()
方法。這些get
方法都接收兩個參數:第一個參數是鍵,傳入存儲數據時使用的鍵就可以得到相應的值了;第二個參數是默認值,即表示當傳入的鍵找不到對應的值時會以什么樣的默認值進行返回。
代碼示例如下
fun loadSharedPreferences(): String {val sharedPreferences = getSharedPreferences("fileName", Context.MODE_PRIVATE)return sharedPreferences.getString("editName", "defValue")!!}
SQLite數據庫存儲
創建數據庫
Android為了讓我們能夠更加方便地管理數據庫,專門提供了一個SQLiteOpenHelper
幫助類,借助這個類可以非常簡單地對數據庫進行創建和升級。既然有好東西可以直接使用,那我們自然要嘗試一下了,下面我就對SQLiteOpenHelper
的基本用法進行介紹。
首先,你要知道SQLiteOpenHelper
是一個抽象類,這意味著如果我們想要使用它,就需要創建一個自己的幫助類去繼承它。SQLiteOpenHelper
中有兩個抽象方法:onCreate()
和onUpgrade()
。我們必須在自己的幫助類里重寫這兩個方法,然后分別在這兩個方法中實現創建和升級數據庫的邏輯。
SQLiteOpenHelper
中還有兩個非常重要的實例方法:getReadableDatabase()
和getWritableDatabase()
。這兩個方法都可以創建或打開一個現有的數據庫(如果數據庫已存在則直接打開,否則要創建一個新的數據庫),并返回一個可對數據庫進行讀寫操作的對象。不同的是,當數據庫不可寫入的時候(如磁盤空間已滿),getReadableDatabase()
方法返回的對象將以只讀的方式打開數據庫,而getWritableDatabase()
方法則將出現異常。
SQLiteOpenHelper
中有兩個構造方法可供重寫,一般使用參數少一點的那個構造方法即可。這個構造方法中接收4個參數:第一個參數是Context
,這個沒什么好說的,必須有它才能對數據庫進行操作;第二個參數是數據庫名,創建數據庫時使用的就是這里指定的名稱;第三個參數允許我們在查詢數據的時候返回一個自定義的Cursor,一般傳入null
即可;第四個參數表示當前數據庫的版本號,可用于對數據庫進行升級操作。構建出SQLiteOpenHelper
的實例之后,再調用它的getReadableDatabase()
或getWritableDatabase()
方法就能夠創建數據庫了,數據庫文件會存放在/data/data/<package name>/databases/目錄下。此時,重寫的onCreate()
方法也會得到執行,所以通常會在這里處理一些創建表的邏輯。
我們建立一個代碼示例如下:
class MyDatabaseHelper(private val context: Context,private val databaseName: String,val version: Int
) : SQLiteOpenHelper(context, databaseName, null, version) {private val createTable = "create table tableName(id integer primary key autoincrement, " +"key1 text," +"key2 real," +"key3 integer)"override fun onCreate(db: SQLiteDatabase?) {db?.execSQL(createTable)}override fun onUpgrade(db: SQLiteDatabase?, oldVersion: Int, newVersion: Int) {}
}
調用數據庫
val myDatabaseHelper =MyDatabaseHelper(this,"databaseName",1)
myDatabaseHelper.writableDatabase
操作數據庫
增
val myDatabaseHelper = MyDatabaseHelper(this, "databaseName", 1)
val db = myDatabaseHelper.writableDatabase
val value1 = ContentValues().apply {put("key1", "111")put("key2", 1.1)put("key3", 1)
}
db.insert("tableName", null, value1)val value2 = ContentValues().apply {put("key1", "222")put("key2", 2.2)put("key3", 2)
}
db.insert("tableName", null, value2)
刪
db.delete(tableName, "key2 = ? and key3 = ? ", arrayOf("2.2","2"))
改
val value3 = ContentValues().apply {put("key1", "444")}
db.update(tableName, value3, "key2 = ?", arrayOf("1.1"))
查
val course = db.query(tableName, null, null, null, null, null, null)if (course.moveToFirst()) {do {println(course.getString(course3.getColumnIndex("key1")))println(course.getString(course.getColumnIndex("key2")))println(course.getString(course.getColumnIndex("key3")))} while (course.moveToNext())}course.close()
升級數據庫
在MyDatabaseHelper類中,我們還有一個onUpgrade的方法沒有使用,這個方法就是用來升級數據庫的,當我們需要升級數據庫時,改寫MyDatabaseHelper的version,讓它大于我們直接傳入的數,這樣就會自動調用onUpgrade,示例代碼如下:
val myDatabaseHelper = MyDatabaseHelper(this, databaseName, 2)
然后我們在onUpgrade方法中編寫升級邏輯,代碼如下:
class MyDatabaseHelper(private val context: Context,private val databaseName: String,val version: Int
) : SQLiteOpenHelper(context, databaseName, null, version) {private val createTable = "create table tableName(id integer primary key autoincrement, " +"key1 text," +"key2 real," +"key3 integer)"private val createTable2 = "create table tableName2(id integer primary key autoincrement, " +"key1 text," +"key2 real," +"key3 integer)"override fun onCreate(db: SQLiteDatabase?) {db?.execSQL(createTable)db?.execSQL(createTable2)}override fun onUpgrade(db: SQLiteDatabase?, oldVersion: Int, newVersion: Int) {if (oldVersion<=1){db?.execSQL(createTable2)}}
}
當原來的版本是1時,我們就創建表2,不然就執行onCreate方法,創建表1表2。如果后續我們需要再表1中增加一個字段? tableName_id,那么我們將傳入的version改成3,再在onUpgrade方法中編寫如下代碼:
override fun onUpgrade(db: SQLiteDatabase?, oldVersion: Int, newVersion: Int) {if (oldVersion<=1){db?.execSQL(createTable2)}if (oldVersion<=2){db?.execSQL("alter table tableName add column tableName_id integer")}}
這樣我們就能在表1中新增一個tableName_id字段了