Android入門之使用SQLite內(nèi)嵌式數(shù)據(jù)庫詳解
介紹
Android內(nèi)帶SQLite內(nèi)嵌式數(shù)據(jù)庫了。這對于我們存儲一些更復雜的結(jié)構(gòu)化數(shù)據(jù)帶來了極大的便利。比如說我們要存儲應用內(nèi)的常用聯(lián)系人,購物車暫存信息,常量。必竟從xml或者是json里取數(shù)據(jù)都沒有一條Select語句來得簡單。
SQLite常用有五種數(shù)據(jù)類型:
- NULL
- INTEGER
- REAL(浮點數(shù))
- TEXT(字符串文本)
- BLOB(二進制對象)
雖然只有五種,但是對于varchar,char等其他數(shù)據(jù)類型都是可以保存的,如下create table語句依然是可以生效的:
create table user(name varchar(20))
SQLite常用的三個類介紹
- SQLiteOpenHelper:抽象類,我們通過繼承該類,然后重寫數(shù)據(jù)庫創(chuàng)建以及更新的方法, 我們還可以通過該類的對象獲得數(shù)據(jù)庫實例,或者關(guān)閉數(shù)據(jù)庫;
- SQLiteDatabase:數(shù)據(jù)庫訪問類:我們可以通過該類的對象來對數(shù)據(jù)庫做一些增刪改查的操作;
- Cursor:游標,有點類似于JDBC里的resultset,結(jié)果集!可以簡單理解為指向數(shù)據(jù)庫中某 一個記錄的指針;
這三個類我們直接來看下面的Sample代碼各位就知道是什么樣的組合應用了。
private SQLiteDatabase db;
private Context context = null;
private DBOpenHelper dbOpenHelper;
private String DB_NAME="user.db";
private static final String DB_TABLE = "t_user_login";
dbOpenHelper = new DBOpenHelper(context, DB_NAME, null, DB_VERSION);
try {
db = dbOpenHelper.getWritableDatabase();
db.open();
StringBuilder sqlStr = new StringBuilder();
sqlStr.append("select loginId,password,user_name from ").append(DB_TABLE);
Cursor cur = db.rawQuery(sqlStr.toString(), null);
while (cur.moveToNext()) {
String loginId = cur.getString(cur.getColumnIndexOrThrow("loginId"));
String password = cur.getString(cur.getColumnIndexOrThrow("password"));
String userName = cur.getString(cur.getColumnIndexOrThrow("user_name"));
UserBean user = new UserBean();
user.setLoginId(loginId);
user.setPassword(password);
user.setUserName(userName);
userList.add(user);
}
} catch (SQLiteException ex) {
Log.e(TAG, ">>>>>>open db error: " + ex.getMessage(), ex);
}finally {
try{
db.close();
}catch(Exception e){}
}使用上和JDBC幾乎一樣,此處的Cursor相當于JDBC里的ResultSet。
敲黑板重要提醒-Android中如何正確使用db.open()/db.close()
在我們的例子里我們在每一個業(yè)務方法操作都會使用db.open一下,在finally塊里db.close一下。
同時要在Activity的onStop方法中去dbclose()掉它。
記得,它就和水龍頭一樣,用完就要關(guān)。
SQLiteOpenHelper類的使用
這個類通常我們都要新建一個其它的類來extends這個類才能使用,主要的是這個類里有這么兩個方法是很有用的。
public void onCreate
方法全簽名:public void onCreate(SQLiteDatabase db)
這個類的作用就是當SQLiteOpenHelper被實例化時,第一次用來做“初始化數(shù)據(jù)庫”用的。比如說我們有一個類如下
private static class DBOpenHelper extends SQLiteOpenHelper {
然后當你實例化這個類時
dbOpenHelper = new DBOpenHelper(context, DB_NAME, null, DB_VERSION);
它會自動觸發(fā)這個onCreate方法,在onCreate方法中我們可以做表創(chuàng)建以及數(shù)據(jù)初始化操作如:
private static final String DB_CREATE = "create table " +
DB_TABLE + " (" + KEY_ID + " VARCHAR(20) primary key , " +
KEY_PASSWORD + " text not null, " + KEY_NAME + " text not null);";
@Override
public void onCreate(SQLiteDatabase db) {
Log.i(TAG, ">>>>>>execute create table->" + DB_CREATE);
db.execSQL(DB_CREATE);
StringBuilder initDataSql = new StringBuilder();
initDataSql.append("INSERT INTO ").append(DB_TABLE).
append("(").append(KEY_ID).append(",").append(KEY_PASSWORD).
append(",").append(KEY_NAME).append(")").append("values(?,?,?)");
Log.i(TAG, ">>>>>>execute initDataSql->" + initDataSql.toString());
db.execSQL(initDataSql.toString(), new String[]{"root", "111111", "root"});
Log.i(TAG, ">>>>>>db init successfully");
}public void onUpgrade
方法全簽名:public void onUpgrade(SQLiteDatabase db, int _oldVersion, int _newVersion)
它有一個_newVersion這么一個參數(shù),這個參數(shù)也很有意思。當你在實例化SQLiteOpenHelper類傳入的DB_VERSION參數(shù)>就近一次實例化這個類傳入的DB_VERSION參數(shù)時,它就會觸發(fā)這個onUpgrade()方法,在這個方法里我們一般是根據(jù)業(yè)務場景的需要,沒有一概而論該怎么辦,通用的做法有:
- 重新執(zhí)行一遍onCreate();此時所有的數(shù)據(jù)會被清空并初始化;
- 有些Android發(fā)版時不需要做全數(shù)據(jù)庫清除,往往太過危險,而是會執(zhí)行alter更改表結(jié)構(gòu)、新建表、新插入-insert一些數(shù)據(jù)或者是稍帶著update一些數(shù)據(jù);
因此我才說,不一概而論而是需要依賴于你的實際業(yè)務場景來做操作。在我們的例子里我們會在onUpgrade里再執(zhí)行一下onCreate()。
使用SQLite操作數(shù)據(jù)庫方法介紹
這一塊在使用上分兩塊。它類似Hibernate一樣,也有API和原生SQL之分。
API的使用
即不需要書寫SQL,如下樣例:
public long addItem(UserBean user) throws Exception {
try {
ContentValues newValues = new ContentValues();
newValues.put(KEY_ID, user.getLoginId());
newValues.put(KEY_PASSWORD, user.getPassword());
newValues.put(KEY_NAME, user.getUserName());
Log.i(TAG, "addItem successfully with loginId->" + user.getLoginId() + " password->" + user.getPassword());
return db.insert(DB_TABLE, null, newValues);
} catch (Exception e) {
Log.e(TAG, "addItem error: " + e.getMessage(), e);
throw new Exception("addItem error: " + e.getMessage(), e);
}
}
我們可以看到全程沒有使用SQL。
原生SQL的使用
public List<UserBean> queryAll() {
List<UserBean> userList = new ArrayList<UserBean>();
try {
StringBuilder sqlStr = new StringBuilder();
sqlStr.append("select loginId,password,user_name from ").append(DB_TABLE);
Cursor cur = db.rawQuery(sqlStr.toString(), null);
while (cur.moveToNext()) {
String loginId = cur.getString(cur.getColumnIndexOrThrow("loginId"));
String password = cur.getString(cur.getColumnIndexOrThrow("password"));
String userName = cur.getString(cur.getColumnIndexOrThrow("user_name"));
UserBean user = new UserBean();
user.setLoginId(loginId);
user.setPassword(password);
user.setUserName(userName);
userList.add(user);
}
} catch (Exception e) {
Log.e(TAG, ">>>>>>queryAll error: " + e.getMessage(), e);
}
return userList;
}區(qū)分何時使用API何時使用原生SQL
如何區(qū)分呢?
答案很簡單,以下是最佳實踐 :
- 單表操作,就使用API好了;
- 跨表(>1個表)的操作或者是較復雜的邏輯如果使用API會產(chǎn)生循環(huán)套來套去不如寫一條長點的SQL那么請直接使用原生SQL;
在樣例前我們最后要了解一下,SQLite數(shù)據(jù)庫管理工具。
SQLite數(shù)據(jù)庫管理
Android里的SQLite一旦生成后它必須導出到AndroidStudio外部才能管理。按照如下步驟來導出SQLite數(shù)據(jù)庫
先使用Device File Explorer打開data->data->你的包全路徑下/databases,這里面有一個.db文件就是SQLite數(shù)據(jù)庫文件。另一個.db-journal是Transaction日志,我們后面講SQLite的Transaction時會講到。

選擇這個user.db右鍵選->save as,就可以導出到本地磁盤了。
然后你可以使用如下工具去管理SQLite數(shù)據(jù)庫文件。
Windows下的SQLite管理工具
請使用SQLite Expert Professional,我使用的是5.4.4。不過這個是收費的,它長這個樣但相當專業(yè)(收費的當然專業(yè))。

MAC下的SQLite管理工具
請使用SQLiteManager,完全免費并且和Windows的SQLite Expert Professional收費的一樣功能全。為什么呢?難道因為MAC貴。。。所以。。。有預收費之說:)?
好了,原理介紹完畢,我們要進入實踐課程了。
課程目標

1.該APP啟動會創(chuàng)建user.db數(shù)據(jù)庫,新建一張t_user_login表并初始化一條root/111111數(shù)據(jù)進入內(nèi)嵌SQLite數(shù)據(jù)庫;
2.用戶名密碼輸入root/111111點【登錄】按鈕可以得到登錄成功,如果輸入其它的不存在的帳戶信息會以Toast顯示“登錄失敗請校驗你的用戶名和密碼”;
3.用戶名密碼輸入任意值,點擊【增加一條記錄】按鈕,可以插入一條數(shù)據(jù)到內(nèi)嵌SQLite;
4.點擊【查詢所有記錄】會以Log和Toast顯示目前所有的相對應的表內(nèi)的數(shù)據(jù)即:select *操作;
5.例子中對于單表的插入操作我們使用的是Android自帶的SQLiteOpenHelper的原生API;
6.校驗登錄和查詢所有記錄我們用的是原生SQL+Cursor;
下面就進入代碼部分吧。
前端代碼
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="用戶登陸" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:text="請輸入用戶名" />
<EditText
android:id="@+id/editLoginid"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="用戶名" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="請輸入密碼" />
<EditText
android:id="@+id/editPassword"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="密碼"
android:inputType="textPassword" />
<Button
android:id="@+id/buttonLogin"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="登錄" />
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="#dfdfdf" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<Button
android:id="@+id/buttonAddItem"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="10dp"
android:text="增加一條記錄"/>
<Button
android:id="@+id/buttonQueryAll"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:text="查詢所有記錄"/>
</LinearLayout>
</LinearLayout>后端代碼
UserBean.java
package org.mk.android.demo.demosimplesqlite;
import java.io.Serializable;
public class UserBean implements Serializable {
public String getLoginId() {
return loginId;
}
public void setLoginId(String loginId) {
this.loginId = loginId;
}
private String loginId = "";
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
private String password = "";
private String userName = "";
}SQLite的核心操作-DBAdapter.java
package org.mk.android.demo.demosimplesqlite;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteException;
import android.database.sqlite.SQLiteOpenHelper;
import android.util.Log;
import java.util.ArrayList;
import java.util.List;
public class DBAdapter {
private static final String TAG = "DemoSQLite";
private static final String DB_NAME = "user.db";
private static final String DB_TABLE = "t_user_login";
private static final int DB_VERSION = 2;
public static final String KEY_ID = "loginId";
public static final String KEY_PASSWORD = "password";
public static final String KEY_NAME = "user_name";
private SQLiteDatabase db;
private Context context = null;
private DBOpenHelper dbOpenHelper;
public DBAdapter(Context ctx) {
context = ctx;
}
public void close() {
try {
if (db != null) {
db.close();
db = null;
}
} catch (Exception e) {
}
}
public void open() {
dbOpenHelper = new DBOpenHelper(context, DB_NAME, null, DB_VERSION);
try {
db = dbOpenHelper.getWritableDatabase();
} catch (SQLiteException ex) {
Log.e(TAG, ">>>>>>open db error: " + ex.getMessage(), ex);
}
}
public long addItem(UserBean user) throws Exception {
try {
ContentValues newValues = new ContentValues();
newValues.put(KEY_ID, user.getLoginId());
newValues.put(KEY_PASSWORD, user.getPassword());
newValues.put(KEY_NAME, user.getUserName());
Log.i(TAG, "addItem successfully with loginId->" + user.getLoginId() + " password->" + user.getPassword());
return db.insert(DB_TABLE, null, newValues);
} catch (Exception e) {
Log.e(TAG, "addItem error: " + e.getMessage(), e);
throw new Exception("addItem error: " + e.getMessage(), e);
}
}
public List<UserBean> queryAll() {
List<UserBean> userList = new ArrayList<UserBean>();
try {
StringBuilder sqlStr = new StringBuilder();
sqlStr.append("select loginId,password,user_name from ").append(DB_TABLE);
Cursor cur = db.rawQuery(sqlStr.toString(), null);
while (cur.moveToNext()) {
String loginId = cur.getString(cur.getColumnIndexOrThrow("loginId"));
String password = cur.getString(cur.getColumnIndexOrThrow("password"));
String userName = cur.getString(cur.getColumnIndexOrThrow("user_name"));
UserBean user = new UserBean();
user.setLoginId(loginId);
user.setPassword(password);
user.setUserName(userName);
userList.add(user);
}
} catch (Exception e) {
Log.e(TAG, ">>>>>>queryAll error: " + e.getMessage(), e);
}
return userList;
}
public int checkLogin(String loginId, String pwd) {
int result = 0;
StringBuilder sqlStr = new StringBuilder();
sqlStr.append("SELECT COUNT(*) FROM ").append(DB_TABLE).append(" WHERE ").append(KEY_ID).append("=? AND ").append(KEY_PASSWORD).append("=?");
Log.i(TAG, ">>>>>>execute checkLogin SQL: " + sqlStr.toString());
Log.i(TAG, ">>>>>>LoginId->" + loginId + " password->" + pwd);
try {
Cursor cur = db.rawQuery(sqlStr.toString(), new String[]{loginId, pwd});
if (cur != null) {
cur.moveToFirst();
result = cur.getInt(0);
}
} catch (Exception e) {
Log.e(TAG, "checkLogin dao error: " + e.getMessage(), e);
}
return result;
}
private static class DBOpenHelper extends SQLiteOpenHelper {
public DBOpenHelper(Context context, String name, SQLiteDatabase.CursorFactory factory, int version) {
super(context, name, factory, version);
}
private static final String DB_CREATE = "create table " +
DB_TABLE + " (" + KEY_ID + " VARCHAR(20) primary key , " +
KEY_PASSWORD + " text not null, " + KEY_NAME + " text not null);";
@Override
public void onCreate(SQLiteDatabase db) {
Log.i(TAG, ">>>>>>execute create table->" + DB_CREATE);
db.execSQL(DB_CREATE);
StringBuilder initDataSql = new StringBuilder();
initDataSql.append("INSERT INTO ").append(DB_TABLE).
append("(").append(KEY_ID).append(",").append(KEY_PASSWORD).
append(",").append(KEY_NAME).append(")").append("values(?,?,?)");
Log.i(TAG, ">>>>>>execute initDataSql->" + initDataSql.toString());
db.execSQL(initDataSql.toString(), new String[]{"root", "111111", "root"});
Log.i(TAG, ">>>>>>db init successfully");
}
@Override
public void onUpgrade(SQLiteDatabase db, int _oldVersion, int _newVersion) {
//db.execSQL("DROP TABLE IF EXISTS " + DB_TABLE);
//onCreate(_db);
db.execSQL("DROP TABLE IF EXISTS " + DB_TABLE);
onCreate(db);
}
}
}MainActivity.java
這個就來得相對簡單了。
package org.mk.android.demo.demosimplesqlite;
import androidx.appcompat.app.AppCompatActivity;
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;
import java.util.ArrayList;
import java.util.List;
public class MainActivity extends AppCompatActivity {
private static final String TAG = "DemoSQLite";
private SQLiteDatabase db;
private Context context;
private DBAdapter dbAdapter;
private EditText editLoginId;
private EditText editPassword;
private Button buttonLogin;
private Button buttonAddItem;
private Button buttonQueryAll;
private String strLoginId;
private String strPassword;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
context = getApplicationContext();
buttonLogin = (Button) findViewById(R.id.buttonLogin);
buttonAddItem = (Button) findViewById(R.id.buttonAddItem);
buttonQueryAll = (Button) findViewById(R.id.buttonQueryAll);
editLoginId = (EditText) findViewById(R.id.editLoginid);
editPassword = (EditText) findViewById(R.id.editPassword);
dbAdapter = new DBAdapter(context);
buttonLogin.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
try {
dbAdapter.open();
strLoginId = editLoginId.getText().toString();
strPassword = editPassword.getText().toString();
int answer = dbAdapter.checkLogin(strLoginId, strPassword);
Log.i(TAG, ">>>>>>checkLogin is->" + answer);
if (answer != 1) {
Toast.makeText(context, "登錄失敗請校驗你的用戶名和密碼", Toast.LENGTH_LONG).show();
} else {
Toast.makeText(context, "登錄成功", Toast.LENGTH_LONG).show();
}
} catch (Exception e) {
Log.e(TAG, ">>>>>>checkLogin error: " + e.getMessage(), e);
} finally {
dbAdapter.close();
}
}
});
buttonAddItem.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
try {
dbAdapter.open();
strLoginId = editLoginId.getText().toString();
strPassword = editPassword.getText().toString();
UserBean user = new UserBean();
user.setLoginId(strLoginId);
user.setPassword(strPassword);
user.setUserName(strLoginId);
long result = dbAdapter.addItem(user);
Toast.makeText(context, "增加一條數(shù)據(jù)成功", Toast.LENGTH_LONG).show();
} catch (Exception e) {
Log.e("TAG", ">>>>>>addItem error: " + e.getMessage(), e);
} finally {
dbAdapter.close();
}
}
});
buttonQueryAll.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
try {
dbAdapter.open();
StringBuilder sb = new StringBuilder();
List<UserBean> userList = new ArrayList<UserBean>();
userList = dbAdapter.queryAll();
if (userList != null && userList.size() > 0) {
userList.forEach(v -> {
sb.append("loginId->").append(v.getLoginId())
.append(" password->").append(v.getPassword())
.append(" userName->").append(v.getUserName())
.append("\n");
});
Log.i(TAG,sb.toString());
Toast.makeText(context, "查詢所有數(shù)據(jù)\n" + sb.toString(), Toast.LENGTH_LONG).show();
}
} catch (Exception e) {
Log.e(TAG, ">>>>>>queryAll error: " + e.getMessage(), e);
} finally {
dbAdapter.close();
}
}
});
}
@Override
protected void onStart(){
super.onStart();
dbAdapter.open();
}
@Override
protected void onStop() {
super.onStop();
dbAdapter.close();
}
}運行效果



自己動一下手試試吧。
以上就是Android入門之使用SQLite內(nèi)嵌式數(shù)據(jù)庫詳解的詳細內(nèi)容,更多關(guān)于Android SQLite內(nèi)嵌式數(shù)據(jù)庫的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Android 中ListView的Item點擊事件失效的快速解決方法
這篇文章主要介紹了Android 中ListView的Item點擊事件失效的快速解決方法的相關(guān)資料,需要的朋友可以參考下2016-09-09
ViewPager實現(xiàn)帶引導小圓點與自動跳轉(zhuǎn)的引導界面
這篇文章主要為大家詳細介紹了ViewPager實現(xiàn)帶引導小圓點與自動跳轉(zhuǎn)的引導界面,具有一定的參考價值,感興趣的小伙伴們可以參考一下2017-11-11
Android中自定義view實現(xiàn)側(cè)滑效果
這篇文章主要介紹了Android中自定義view實現(xiàn)側(cè)滑效果的相關(guān)資料,非常不錯,具有參考借鑒價值,需要的朋友可以參考下2016-11-11
Android中Activity跳轉(zhuǎn)的創(chuàng)建步驟總結(jié)
這篇文章主要介紹了Android中Activity跳轉(zhuǎn)的創(chuàng)建步驟總結(jié),本文詳細的講解了從工程創(chuàng)建到跳轉(zhuǎn)Activity的實現(xiàn)完整過程,需要的朋友可以參考下2014-10-10

