一、SQLite数据库
1、操作步骤
①建立表结构,DBTable
②建立数据库连接,DBConnection
③命令对象执行SQL语句
④返回操作结果
⑤关闭连接
2、查询数据库表
在FileExplorer/data/data/包名/databases
3、数据库出错如何调试
①首先,检查数据库创建成功没有
②然后,再看数据库打开没有
③接着,检查数据操作代码有问题没
4、Cursor 空指针异常,以为没有初始化
初始化:Cursor cursor = SQLiteDatabase.query(table表名,newString[]{},null,—-);
二、代码演示
1、User.java
package com.guan.dbsignin.model;
/** * 用户对象类 * @author Guan * @file com.guan.store.sqlite * @date 2015/8/31 * @Version 1.0 */
public class User {
private String userName;
private String userAddress;
public String getUserAddress() {
return userAddress;
}
public void setUserAddress(String userAddress) {
this.userAddress = userAddress;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
}
2、DBOpenHelper.java 创建数据库中的表,并做适当的初始化工作
/** * DBOpenHelper创建数据库中的表,并做适当的初始化工作 * * SQLiteOpenHelper 中有两个抽象方法,分别是 onCreate()和 onUpgrade() * @author Guan * @file com.guan.store.sqlite * @date 2015/9/1 * @Version 1.0 */
public class DBOpenHelper extends SQLiteOpenHelper {
private final String DATABASE_NAME = "androidDBStorageSqlite";
public static final String TABLE_NAME = "users";
public static final String COLUMN_USERNAME = "userName";
public static final String COLUMN_USERADDRES = "userAddress";
public static final String DATABASE_CREATE = "Create TABLE if not exists MAIN.[" + TABLE_NAME + "](\n" +
"[_id] integer PRIMARY KEY NOT NULL\n" +
",[" + COLUMN_USERNAME + "] integer NOT NULL\n" +
",[" + COLUMN_USERADDRES + "] integer NOT NULL\n" +
" \n" +
");";
public DBOpenHelper(Context context, String name, SQLiteDatabase.CursorFactory factory, int version) {
super(context, name, factory, version);
}
@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL(DATABASE_CREATE);
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
if (newVersion == 2) {
db.execSQL(DATABASE_CREATE);
} else if (oldVersion == 2 && newVersion == 1) {
db.execSQL("drop table MAIN.[" + TABLE_NAME + "]");
}
}
}
3、DBOperation.java 数据库操作类
/** * DBOperation实现数据库的各项操作,包括:建立及打开数据库、增、删、改、查等 * * @author Guan * @file com.guan.store.sqlite * @date 2015/8/31 * @Version 1.0 */
public class DBOperation {
private Context mContext;
private String firstTabName = null;
private SQLiteDatabase mSqLiteDatabase;
private final String DATABASE_NAME = "androidDBStorageSqlite";
public static final String TABLE_NAME = "users";
public static final String COLUMN_ID = "id";
public static final String COLUMN_USERNAME = "userName";
public static final String COLUMN_USERADDRES = "userAddress";
public DBOperation(Context pContext) {
this.mContext = pContext;
}
/** * 建立及打开数据库 * * SQLiteOpenHelper 中 还 有 两 个 非 常 重 要 的 实 例 方 法 , getReadableDatabase() 和 getWritableDatabase()。这两个方法都可以创建或打开一个现有的数据库(如果数据库已存在 则直接打开,否则创建一个新的数据库),并返回一个可对数据库进行读写操作的对象。 * 不同的是,当数据库不可写入的时候(如磁盘空间已满)getReadableDatabase()方法返回的对象将以只读的方式去打开数据库,而 getWritableDatabase()方法则将出现异常。 */
public void openOrCreateDatabase() {
try {
DBOpenHelper _helper = new DBOpenHelper(mContext,DATABASE_NAME,null,2);
mSqLiteDatabase = _helper.getWritableDatabase();
} catch (Exception e) {
e.printStackTrace();
}
}
/** * 插入用户 * @param user */
public long insertUser(User user) {
if (mSqLiteDatabase != null && user != null) {
// 插入一条记录
ContentValues values = new ContentValues();
values.put(COLUMN_USERNAME, user.getUserName());
values.put(COLUMN_USERADDRES, user.getUserAddress());
return mSqLiteDatabase.insert(TABLE_NAME, "", values);
}
return -1;
}
/** * 查询所有记录 */
public Cursor selectAll() {
if (mSqLiteDatabase != null) {
return mSqLiteDatabase.query(TABLE_NAME, new String[]{"_id", COLUMN_USERNAME, COLUMN_USERADDRES}, null, null, null, null, null);
}
return null;
}
/** * 根据条件查询用户 * @param selection * @param selectionArgs * @param groupBy * @param having * @param orderBy * @return */
public Cursor selectUser(String selection,String[] selectionArgs,String groupBy,String having,String orderBy) {
return mSqLiteDatabase.query(TABLE_NAME,new String[]{"_id",COLUMN_USERNAME, COLUMN_USERADDRES},selection,selectionArgs
,groupBy,having,orderBy);
}
/** * 删除用户 * @param id * @return */
public int deleteUser(int id) {
if (mSqLiteDatabase != null && id > 0) {
return mSqLiteDatabase.delete(TABLE_NAME,"_id=?",new String[]{String.valueOf(id)});
}
return -1;
}
/** * 更新用户 * @param user * @param id * @return */
public int updateUser(User user,int id) {
if (mSqLiteDatabase != null && user != null) {
ContentValues _values = new ContentValues();
_values.put(COLUMN_USERNAME,user.getUserName());
_values.put(COLUMN_USERADDRES,user.getUserAddress());
return mSqLiteDatabase.update(TABLE_NAME, _values, "_id=?", new String[]{String.valueOf(id)});
}
return -1;
}
/** * 关闭数据库 */
public void closeDatabase() {
mSqLiteDatabase.close();
mSqLiteDatabase = null;
}
}
4、activity_main.xml
<RelativeLayout 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:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" tools:context=".MainActivity">
<RelativeLayout android:id="@+id/llyt_sign" android:layout_width="fill_parent" android:layout_height="wrap_content" android:orientation="horizontal">
<Button android:id="@+id/add" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentRight="true" android:text="添加" />
</RelativeLayout>
<ListView android:id="@+id/lv_text" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentLeft="true" android:layout_alignParentStart="true" android:layout_below="@id/llyt_sign" android:layout_marginTop="10dp" />
</RelativeLayout>
5、activity_submit.xml
<RelativeLayout 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:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" tools:context="com.guan.dbsignin.activity.SubmitActivity">
<RelativeLayout android:id="@+id/llyt_sign" android:layout_width="fill_parent" android:layout_height="wrap_content" android:orientation="horizontal">
<Button android:id="@+id/bt_back" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentLeft="true" android:text="返回" />
<Button android:id="@+id/bt_submit" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentRight="true" android:text="提交" />
</RelativeLayout>
<EditText android:id="@+id/et_name" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_alignParentLeft="true" android:layout_alignParentStart="true" android:layout_below="@+id/llyt_sign" android:layout_marginTop="50dp" android:inputType="text" />
</RelativeLayout>
6、adapter_line.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent">
<TextView android:id="@+id/tv_1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentLeft="true" android:layout_marginTop="16dp" android:layout_gravity="center_vertical" android:layout_marginLeft="8dp" android:text="TextView" />
<TextView android:id="@+id/tv_2" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="bottom" android:layout_alignParentRight="true" android:layout_marginRight="8dp" android:layout_marginTop="40dp" android:text="TextView" />
</RelativeLayout>
7、MainActivity.java
/** * 点击添加按钮跳转到第二个activity,输入的数据要存入到数据库里面 , * 第一个activity显示的内容是第二个activity输入的内容,数据从数据库里面提取。 * 我每次打开activity1界面的时候如果数据库有数据 都要显示出来 */
public class MainActivity extends Activity {
@Bind(R.id.add)
Button add;
@Bind(R.id.lv_text)
ListView lvText;
private Cursor mCursor;
/** * 存储数据的数组列表 */
private ArrayList<HashMap<String, Object>> mListData;
/** * 适配器 */
private SimpleAdapter mListItemAdapter;
public static DBOperation mDBOperation;
private static final String TAG = "TAG";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ButterKnife.bind(this);
initVariable();
getData();
bindData();
}
/** * 初始化变量 */
private void initVariable() {
mDBOperation = new DBOperation(MainActivity.this);
mListData = new ArrayList<HashMap<String, Object>>();
// 创建数据库
mDBOperation.openOrCreateDatabase();
}
/** * 查询所有数据,并添加到列表中 */
public void getData() {
// 获取数据源,查找所有用户
Cursor cursor = mDBOperation.selectAll();
if (cursor != null) {
int columnsSize = cursor.getColumnCount();
// 获取表的内容
while (cursor.moveToNext()) {
HashMap<String, Object> map = new HashMap<String, Object>();
for (int i = 0; i < columnsSize; i++) {
map.put(mDBOperation.COLUMN_ID, cursor.getString(0));
map.put(mDBOperation.COLUMN_USERNAME, cursor.getString(1));
map.put(mDBOperation.COLUMN_USERADDRES, cursor.getString(2));
}
mListData.add(map);
}
cursor.close();
}
}
/** * 绑定数据 */
private void bindData() {
mCursor = mDBOperation.selectAll();
mListItemAdapter = new SimpleAdapter(MainActivity.this,
// 数据源
mListData,
// ListItem的XML实现
R.layout.adapter_line,
// 动态数组与ImageItem对应的子项
new String[]{mDBOperation.COLUMN_USERNAME, mDBOperation.COLUMN_USERADDRES},
// XML文件里面的两个ID
new int[]{R.id.tv_1, R.id.tv_2});
lvText.setAdapter(mListItemAdapter);
lvText.setOnCreateContextMenuListener(listviewLongPress);
}
/** * 触发监听 */
@OnClick(R.id.add)
public void submit() {
Intent _intent = new Intent(MainActivity.this, SubmitActivity.class);
startActivity(_intent);
this.finish();
}
/** * 长按事件响应 */
View.OnCreateContextMenuListener listviewLongPress = new View.OnCreateContextMenuListener() {
@Override
public void onCreateContextMenu(ContextMenu menu, View v,
ContextMenu.ContextMenuInfo menuInfo) {
final AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) menuInfo;
new AlertDialog.Builder(MainActivity.this)
.setTitle("删除当前数据")
.setIcon(android.R.drawable.ic_dialog_info)
.setMessage("确定删除当前记录")
.setPositiveButton("是",
new DialogInterface.OnClickListener() {
public void onClick(
DialogInterface dialoginterface, int i) {
// 获取位置索引
int mListPos = info.position;
// 获取对应HashMap数据内容
HashMap<String, Object> map = mListData
.get(mListPos);
// 获取id
int id = Integer.valueOf((map.get(mDBOperation.COLUMN_ID)
.toString()));
// 获取数组具体值后,可以对数据进行相关的操作
if (mDBOperation.deleteUser(id) != -1) {
// 移除listData的数据
mListData.remove(mListPos);
mListItemAdapter.notifyDataSetChanged();
}
}
})
.setNegativeButton("否",
new DialogInterface.OnClickListener() {
public void onClick(
DialogInterface dialoginterface, int i) {
}
}).show();
}
};
// public class MainActivity extends ListActivity
// /**
// * 获取数据源
// */
// private void displayData() {
//
// // 获取数据源,查找所有用户
// Cursor cursor = mDBOperation.selectAll();
// if (cursor != null) {
// // 绑定数据源与adapter
// SimpleCursorAdapter adapter = new SimpleCursorAdapter(this, android.R.layout.simple_list_item_2, cursor,
// new String[]{mDBOperation.COLUMN_USERNAME, mDBOperation.COLUMN_USERADDRES}, new int[]{android.R.id.text1, android.R.id.text2});
//
// // 绑定adapter到界面
// setListAdapter(adapter);
// }
// }
}
8、SubmitActivity.java
public class SubmitActivity extends AppCompatActivity {
@Bind(R.id.bt_back)
Button btBack;
@Bind(R.id.bt_submit)
Button btSubmit;
@Bind(R.id.et_name)
EditText etName;
private Intent _intent;
private SimpleDateFormat sDateFormat;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_submit);
ButterKnife.bind(this);
sDateFormat = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
}
@OnClick({R.id.bt_back, R.id.bt_submit})
public void submit(View view) {
switch (view.getId()) {
case R.id.bt_back:
_intent = new Intent(SubmitActivity.this, MainActivity.class);
startActivity(_intent);
this.finish();
break;
case R.id.bt_submit:
User _user = new User();
_user.setUserName(etName.getText().toString());
_user.setUserAddress(sDateFormat.format(new java.util.Date()));
MainActivity.mDBOperation.insertUser(_user);
_intent = new Intent(SubmitActivity.this, MainActivity.class);
startActivity(_intent);
this.finish();
break;
default:
break;
}
}
}
9、效果图演示
三、数据存储的最佳实现
使用事务,SQLite数据库是支持事务的,事务的特性可以保证让某一系列的操 作要么全部完成,要么一个都不会完成。例如:保证银行转账扣钱和收款的操作要么一起成功,要么都不会成功。
1、activity_main.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical">
<Button android:id="@+id/replace_data" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Replace data" />
</LinearLayout>
2、MainActivity.java
public class MainActivity extends Activity {
private MyDatabaseHelper dbHelper;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
dbHelper = new MyDatabaseHelper(this, "BookStore.db", null, 2);
Button replaceData = (Button) findViewById(R.id.replace_data);
replaceData.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
SQLiteDatabase db = dbHelper.getWritableDatabase();
db.beginTransaction();
// 开启事务
try {
db.delete("Book", null, null);
if (true) {
// 在这里手动抛出一个异常,让事务失败
throw new NullPointerException();
}
ContentValues values = new ContentValues();
values.put("name", "Game of Thrones");
values.put("author", "George Martin");
values.put("pages", 720);
values.put("price", 20.85);
db.insert("Book", null, values);
db.setTransactionSuccessful();
// 事务已经执行成功
} catch (Exception e) {
e.printStackTrace();
} finally {
db.endTransaction();
// 结束事务
}
}
});
}
}