SQLite
什麼是SQLite數據庫?
特色:
輕量級、獨立、隔離、跨平臺、多語言接口、安全性。
如何和數據庫打交道
1、設計數據庫與表
創建數據庫
DatabaseHelper類
public class DatabaseHelper extends SQLiteOpenHelper {
public DatabaseHelper(Context context, String name, SQLiteDatabase.CursorFactory factory, int version) {
super(context, name, factory, version);
}
MainActivity類
Android提供了一個名爲SQLiteDatabase的類,該類封裝了一些操作數據庫的API,使用該類可以完成對數據進行添加(Create)、查詢(Retrieve)、更新(Update)和刪除(Delete)操作(這些操作簡稱爲CRUD)。對SQLiteDatabase的學習,我們應該重點掌握execSQL()和rawQuery()方法。 execSQL()方法可以執行insert、delete、update和CREATE TABLE之類有更改行爲的SQL語句; rawQuery()方法用於執行select語句。
DatabaseHelper databaseHelper = new DatabaseHelper(this,"test.db",null,1);
SQLiteDatabase sqLiteDatabase = databaseHelper.getReadableDatabase();
創建表
DatabaseHelper類
@Override
public void onCreate(SQLiteDatabase sqLiteDatabase) {
sqLiteDatabase.execSQL("create table user(username varchar(20) not null,password varchar(60) not null)");
}
2、對數據庫進行增刪改查
MainActivity類
package com.example.chenjinhua.sqlite;
import android.content.ContentValues;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
private SQLiteDatabase sqLiteDatabase;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button add_button = (Button) findViewById(R.id.add_button);
Button query_button = (Button) findViewById(R.id.query_button);
Button delete_button = (Button) findViewById(R.id.delete_button);
Button update_button = (Button) findViewById(R.id.update_button);
add_button.setOnClickListener(this);
query_button.setOnClickListener(this);
delete_button.setOnClickListener(this);
update_button.setOnClickListener(this);
DatabaseHelper databaseHelper = new DatabaseHelper(this,"test1.db",null,1);
sqLiteDatabase = databaseHelper.getReadableDatabase();
Log.i("MainActivity","create db");
}
@Override
public void onClick(View view) {
switch (view.getId()){
//insert:
case R.id.add_button:
ContentValues contentValues = new ContentValues();
contentValues.put(DatabaseHelper.USERNAME,"jinhua");
contentValues.put(DatabaseHelper.PASSWORD, "zxcv");
long rowNumber = sqLiteDatabase.insert(DatabaseHelper.USER_TABLE,null,contentValues);
if ( rowNumber != -1){
Toast.makeText(MainActivity.this, "插入成功", Toast.LENGTH_SHORT).show();
}
break;
//query
case R.id.query_button:
// 遊標,是要查找的數據的集合
Cursor cursor = sqLiteDatabase.query(DatabaseHelper.USER_TABLE,null,null,null,null,null,null);
if (cursor.moveToFirst()){
int count = cursor.getCount();//1、count是數據庫的所有數目;2、快捷鍵command+option+v
for (int i = 0; i < count; i++) {
String userName = cursor.getString(cursor.getColumnIndexOrThrow(DatabaseHelper.USERNAME));
String password = cursor.getString(cursor.getColumnIndexOrThrow(DatabaseHelper.PASSWORD));
Log.i("MainActivity",i + ":" + userName + "|" + password);
}
}
break;
//delete
case R.id.delete_button:
String whereClauseString = "userName = ?";
String[] whereArgsString = {"jinhua"};
sqLiteDatabase.delete(DatabaseHelper.USER_TABLE,whereClauseString,whereArgsString);
break;
//update
case R.id.update_button:
ContentValues contentValues1 = new ContentValues();
contentValues1.put(DatabaseHelper.PASSWORD,"100歲");
whereClauseString = "userName = ?";
String[] whereArgsString1 = {"jinhua"};
sqLiteDatabase.update(DatabaseHelper.USER_TABLE,contentValues1,whereClauseString,whereArgsString1);
}
}
}
除了上述方法,還可以使用原始方法,即用SQL語句。
sqLiteDatabase.execSQL("insert into user(username,age) values('張三','5歲')");
3、優化
(1) 如何設計數據庫與表
上萬條數據如何建表,比如300個城市,每個城市600條信息;
爲什麼不用文件存儲?
文件存儲弊端:文件存儲沒有規則;
數據庫優勢:a、有規則,用SQL語句即可查找;b、數據庫更新很方便,比如onUpgrade方法。
在手機端拆表,300個城市排序1個表,用二分法查表等。
(2)對數據庫進行增刪改查
a、原始SQL語句執行效率更高rawQuery execSQL;
b、只檢索有用的列、有用的行,越少越好;
c、是否排序;
d、是否創建索引。//當數據很多時需要創建索引,方便查找。
執行增刪改操作方法 :db.execSQL(sql); 或者db.insert()、db.delete()、db.update(),並且包括數據表的創建和刪除等等也可以通過execSQL實現
(3)、事務
需要操作很多數據時,用SQL很耗費性能,用事務。
//開始事務,此時db會被鎖定,其他線程需要操作數據庫的話會失敗
sqLiteDatabase.beginTransaction();
try {
//做操作
for (int i = 0; i <1000 ; i++) {
sqLiteDatabase.execSQL("insert into user(username,age) values('張三','5歲')");
}
//一定要設置成功,不設置的話會自動回滾提交
sqLiteDatabase.setTransactionSuccessful();
} catch (Exception e) {
e.printStackTrace();
} finally {
//關閉事務,同時纔會向數據庫裏進行批量的提交,endTransaction即提交的意思
sqLiteDatabase.endTransaction();
}
(4)對象關係映射 ORM
將一個對象和關係型數據庫的一張表對應起來,這樣不需要和複雜的SQL語句打交道,只需要簡單的操作對象的屬性和方法就行。
練習:
a) 做一個登錄界面,數據庫字段包含用戶名、密碼以及是否登錄中的狀態
b) 模擬登錄成功後,將登錄的用戶名及登錄狀態(登錄中)寫入數據庫,並跳轉新頁面,有退出按鈕
c) 當點擊退出時,將當前用戶登錄中的狀態清除
d) 下一次登錄時,顯示上一次登錄的用戶名
e) 保存所有用戶登錄的歷史,但一個用戶名只保留一條記錄。
遇到報錯:
sqLiteDatabase.execSQL(“create table ” + LOGIN_TABLE + “(” +
USER_NAME + ” varchar(20) not null,” + PASSWORD + ” varchar(60) not
null,” + LOGIN_STATE + ” varchar(20) not null);”);
error: no such table。
stackoverflow查了:
simply Change Your Databse name in Data base class which you implemented Using SQliteDatabase
然後我修改了數據庫名字,然後問題就解決了。可是我還沒明白爲什麼。。
ContentProvider
一、什麼是ContentProvider?
- 應用程序 間 共享數據的一種方式
- 爲存儲和獲取數據提供了統一的接口
- Android爲常見的一些數據提供了默認的ContentProvider
- 四大組件之一
系統提供的封裝好的ContentProvider,如:sdk- samples- notePad。
ContentProvider //提供者
1、提供query(uri)、delete(uri)、insert(uri)、update(uri)方法;
2、這些方法都要傳入uri;
3、根據不同的uri做不同的db操作。
sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
sUriMatcher.addURI(NotePad.AUTHORITY, "notes", NOTES);
sUriMatcher.addURI(NotePad.AUTHORITY, "notes/#", NOTE_ID);
sUriMatcher.addURI(NotePad.AUTHORITY, "live_folders/notes", LIVE_FOLDER_NOTES);
switch (sUriMatcher.match(uri)) {
case NOTES:
qb.setProjectionMap(sNotesProjectionMap);
break;
case NOTE_ID:
qb.setProjectionMap(sNotesProjectionMap);
qb.appendWhere(
NotePad.Notes._ID + // the name of the ID column;
"=" + uri.getPathSegments().get(NotePad.Notes.NOTE_ID_PATH_POSITION));
break;
case LIVE_FOLDER_NOTES:
qb.setProjectionMap(sLiveFolderProjectionMap);
break;
default:
throw new IllegalArgumentException("Unknown URI " + uri);
}
如何使用ContentProvider?
/*
1、ContentProvider就是一系列封裝的接口,把數據封裝起來,對外提供一系列增刪改查接口給別人;uri就是獲取數據的路徑。
2、通過ContentProvider提供的query這個接口,把通訊錄裏所有聯繫人查詢出來,操作數據;
3、ContentProvider可以用封裝的,也可以自己封裝ContentProvider,給自己應用用,也可以給其他應用程序用。
* */
//ContentResolver內容解析器
ContentResolver contentResolver = getContentResolver();
//通用資源標識符,表示資源(圖像、視頻、音頻)路徑,有3個字段表示:scheme(content://)、host(包名)、path;
Uri uri = Uri.parse("content://com.android.contacts/contacts");
//把這個xxx包裏面xxx這個表裏id爲10的username字段的值
Uri uri1 = Uri.parse("content://com.example.chenjinhua.testcontentprovider/table_name/10/username");
Cursor cursor = contentResolver.query(uri,null,null,null,null);
if ( cursor != null && cursor.moveToFirst()){}
二、ContentProvider的實現過程
- Database
- Uri
- UriMatcher
- ContentProvider
- query/insert/update/delete
- AndroidManifest.xml
1、Database
DatabaseHelper類建立db以及兩張表
package com.example.chenjinhua.sqlite;
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.util.Log;
/**
* Created by chenjinhua on 16/4/3.
*/
public class DatabaseHelper extends SQLiteOpenHelper {
public static final String USER_TABLE = "user";
public static final String USERNAME = "username";
public static final String PASSWORD = "password";
public static final String BOOK_TABLE = "book_table";
public static final String BOOK_NAME = "book_name";
public static final String BOOK_PRICE = "book_price";
public DatabaseHelper(Context context, String name, SQLiteDatabase.CursorFactory factory, int version) {
super(context, name, factory, version);
}
@Override
public void onCreate(SQLiteDatabase sqLiteDatabase) {
sqLiteDatabase.execSQL("create table " + USER_TABLE + "(" + USERNAME + " varchar(20) not null," + PASSWORD + " varchar(60) not null)");
sqLiteDatabase.execSQL("create table " + BOOK_TABLE + "(" + BOOK_NAME + " varchar(20) not null," + BOOK_PRICE + " varchar(60) not null)");
}
@Override
public void onUpgrade(SQLiteDatabase sqLiteDatabase, int i, int i1) {
}
}
2、Uri
新建package包、包內新建TestContentProvider類和URIList類
6、AndroidManifest.xml註冊
<provider
android:authorities="com.example.chenjinhua.sqlite"
android:name=".provider.TestContentProvider"/>