一、前言
在Android系统中,每个应用程序的SQLite数据库被保存在各自的/data/data/<package name>/databases
目录下
缺省情况下,所有数据库都是私有的,仅允许创建数据库的应用程序访问,如果需要共享数据库则可以使用ContentProvider
二、adb shell(对数据库和表的创建情况进行检查的工具,非必须)
adb是Android SDK中自带的一个调试工具,使用这个工具可以直接对连接在电脑上的手机或模拟器进行调试操作。
1.环境配置
它存放在sdk的platform-tools目录下,如果想要在命令行中使用这个工具,就需要先把它的路径配置到环境变量里。
Windows系统,可以右击计算机→属性→高级系统设置→环境变量,然后在系统变量(注意不是用户变量)里找到Path并点击编辑,将platform-tools目录配置进去
2.简单使用
① win+r打开cmd 输入adb shell(前提手机连了电脑或者虚拟机开了,不然会报error没有找到设备)
② 输入su切换到超级管理员
③ cd /data/data/com.example.databasetest(完整包名.类名)/databases/目录下,并使用ls命令查看到该目录里的文件 可以看到自己的数据库
④ sqlite3 dbname(数据库名)
可以看到版本号
以及最后一行是sqlite>,可以输入。
⑤ 输入.table 可以看到建的表
通过.schema命令来查看它们的建表语句。
键入.exit或.quit命令可以退出数据库的编辑,再键入exit命令就可以退出设备控制台了。
三、代码编写,以课程查询为例
1.编写类继承SQLiteOpenHelper,覆写onCreate方法和onUpgrade方法
package com.example.yogi.courseapp;
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
public class CourseData extends SQLiteOpenHelper {
private static final String db_name = "CourseDatas";//自定义的数据库名;
private static final int version = 2;//版本号,增加则会执行onUpgrade方法?
public CourseData(Context context) {
super(context, db_name, null, version);
}
// 该方法会自动调用,首先系统会检查该程序中是否存在数据库名为‘CoursDatas’的数据库
// 如果存在则不会执行该方法,如果不存在则会执行该方法。
@Override
public void onCreate(SQLiteDatabase db) {
String sql ="create table courses(" +
"id Integer primary key autoincrement," + //id自增,只支持integer不支持int
"coursename varchar(30)," +
"teacher varchar(20)," +
"time varchar(50)," +
"classroom varchar(30)" +
")";
db.execSQL(sql);
}
//数据库版本更新时执行该方法,如果表已存在则先删除再调用onCreate重新创建
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
db.execSQL("drop table if exists courses");
onCreate(db);
}
}
2.随便写一个布局
使用的是LinearLayout(线性布局)
嵌套了一下,外面这层要求垂直不重叠,里面那层要求水平不重叠。
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity"
tools:layout_editor_absoluteY="81dp">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal">
<Button
android:id="@+id/button"
android:layout_width="361dp"
android:layout_height="52dp"
android:layout_marginStart="16dp"
android:layout_marginLeft="16dp"
android:layout_marginTop="16dp"
android:text="课程表"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal"
android:layout_marginLeft="20dp">
<Button
android:id="@+id/name_btn"
android:layout_width="96dp"
android:layout_height="43dp"
android:text="课程名称:"
tools:layout_editor_absoluteX="16dp"
tools:layout_editor_absoluteY="77dp" />
<EditText
android:id="@+id/text_name"
android:layout_width="190dp"
android:layout_height="41dp"
tools:layout_editor_absoluteX="137dp"
tools:layout_editor_absoluteY="77dp" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal"
android:layout_marginLeft="20dp">
<Button
android:id="@+id/teacher_btn"
android:layout_width="96dp"
android:layout_height="43dp"
android:text="老师:"
tools:layout_editor_absoluteX="16dp"
tools:layout_editor_absoluteY="118dp" />
<EditText
android:id="@+id/text_teacher"
android:layout_width="190dp"
android:layout_height="41dp"
tools:layout_editor_absoluteX="137dp"
tools:layout_editor_absoluteY="120dp" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal"
android:layout_marginLeft="20dp">
<Button
android:id="@+id/time_btn"
android:layout_width="96dp"
android:layout_height="43dp"
android:text="时间:"
tools:layout_editor_absoluteX="16dp"
tools:layout_editor_absoluteY="161dp" />
<EditText
android:id="@+id/text_time"
android:layout_width="190dp"
android:layout_height="41dp"
tools:layout_editor_absoluteX="137dp"
tools:layout_editor_absoluteY="161dp" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal"
android:layout_marginLeft="20dp">
<Button
android:id="@+id/classroom_btn"
android:layout_width="96dp"
android:layout_height="43dp"
android:text="教室:"
tools:layout_editor_absoluteX="16dp"
tools:layout_editor_absoluteY="204dp" />
<EditText
android:id="@+id/text_classroom"
android:layout_width="190dp"
android:layout_height="41dp"
tools:layout_editor_absoluteX="137dp"
tools:layout_editor_absoluteY="209dp" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal"
android:layout_marginLeft="20dp">
<Button
android:id="@+id/id_delete"
android:layout_width="68dp"
android:layout_height="37dp"
android:text="ID删除"
tools:layout_editor_absoluteX="152dp"
tools:layout_editor_absoluteY="299dp" />
<Button
android:id="@+id/id_update"
android:layout_width="68dp"
android:layout_height="37dp"
android:text="ID更新"
tools:layout_editor_absoluteX="292dp"
tools:layout_editor_absoluteY="299dp" />
<Button
android:id="@+id/id_query"
android:layout_width="68dp"
android:layout_height="37dp"
android:text="ID查询"
tools:layout_editor_absoluteX="220dp"
tools:layout_editor_absoluteY="299dp" />
<Button
android:id="@+id/id_btn"
android:layout_width="57dp"
android:layout_height="37dp"
android:text="ID:"
tools:layout_editor_absoluteX="16dp"
tools:layout_editor_absoluteY="299dp" />
<EditText
android:id="@+id/input_id"
android:layout_width="58dp"
android:layout_height="41dp"
tools:layout_editor_absoluteX="79dp"
tools:layout_editor_absoluteY="304dp" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal"
android:layout_marginLeft="20dp">
<Button
android:id="@+id/clear_all"
android:layout_width="81dp"
android:layout_height="39dp"
android:text="清除显示"
tools:layout_editor_absoluteY="260dp" />
<Button
android:id="@+id/delete_all"
android:layout_width="81dp"
android:layout_height="39dp"
android:text="全部删除"
app:layout_constraintStart_toStartOf="parent"
tools:layout_editor_absoluteY="260dp" />
<Button
android:id="@+id/query_all"
android:layout_width="81dp"
android:layout_height="39dp"
android:text="全部显示"
app:layout_constraintStart_toStartOf="parent"
tools:layout_editor_absoluteY="260dp" />
<Button
android:id="@+id/add_btn"
android:layout_width="81dp"
android:layout_height="39dp"
android:text="添加数据"
app:layout_constraintStart_toStartOf="parent"
tools:layout_editor_absoluteY="260dp" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal"
android:layout_marginLeft="20dp">
<TextView
android:id="@+id/queryResult"
android:layout_width="346dp"
android:layout_height="145dp"
tools:layout_editor_absoluteX="16dp"
tools:layout_editor_absoluteY="350dp" />
</LinearLayout>
</LinearLayout>
</android.support.constraint.ConstraintLayout>
它长这样:
3.MainActivity,注册各控件并写点击事件
①得到一个SQLiteDatabase对象
SQLiteOpenHelper的getReadableDatabase()或getWritableDatabase()方法返回一个SQLiteDatabase对象,借助这个对象就可以对数据进行操作:
private CourseData courseDB;
private SQLiteDatabase mDatabase;
……
//onCreate函数中
courseDB = new CourseData(this);
mDatabase = courseDB.getWritableDatabase();
②SQLiteDatabase提供的insert()方法
用于添加数据,三个参数:
第一个参数是表名。
第二个参数用于在未指定添加数据的情况下给某些可为空的列自动赋值NULL,一般我们用不到这个功能,直接传入null即可。
第三个参数是一个ContentValues对象(即需要插入的数据),它提供了一系列的put()方法重载,用于向ContentValues中添加数据,只需要将表中的每个列名以及相应的待添加数据传入即可。
示例:
ContentValues values = new ContentValues();
//第一个参数应该是表中的列名吧
values.put("coursename",inputName.getText().toString());
values.put("teacher",inputTeacher.getText().toString());
values.put("time",inputTime.getText().toString());
values.put("classroom",inputRoom.getText().toString());
mDatabase.insert("courses",null,values);
③SQLiteDatabase提供的update()方法
用于对数据进行更新,这个方法接收4个参数:
第一个参数和insert()方法一样,也是表名,在这里指定去更新哪张表里的数据。
第二个参数是ContentValues对象,要把更新数据在这里组装进去。
第三、第四个参数用于约束更新某一行或某几行中的数据,不指定的话默认就是更新所有行。
示例:通过输入的id找记录,更新这条记录。
ContentValues values = new ContentValues();
String upd_id = inputId.getText().toString();
//更新使用了values.put的列,如果有列没有被values.put,则会保持原样不更新
values.put("coursename",inputName.getText().toString());
values.put("teacher",inputTeacher.getText().toString());
values.put("time",inputTime.getText().toString());
values.put("classroom",inputRoom.getText().toString());
mDatabase.update("courses",values,"id=?",new String[]{upd_id});
④SQLiteDatabase提供的delete()方法
用于删除数据,这个方法接收3个参数:
第一个参数仍然是表名,
第二、第三个参数又是用于约束删除某一行或某几行的数据,不指定的话默认就是删除所有行。
示例1:删除指定id的记录
String del_id = inputId.getText().toString();
mDatabase.delete("courses","id=?",new String[]{del_id});
示例2:删除该表所有记录
mDatabase.delete("courses",null,null);
⑤SQLiteDatabase提供的query()方法
用于对数据进行查询。这个方法的参数较多,最短的一个方法重载也需要传入7个参数。
第一个参数,当然还是表名。
第二个参数用于指定去查询哪几列,如果不指定则默认查询所有列。
第三、第四个参数用于约束查询某一行或某几行的数据,不指定则默认查询所有行的数据。
第五个参数用于指定需要去group by的列,不指定则表示不对查询结果进行group by操作。
第六个参数用于对group by之后的数据进行进一步的过滤,不指定则表示不进行过滤。
第七个参数用于指定查询结果的排序方式,不指定则表示使用默认的排序方式。
若只使用了第一个参数指明去查询哪张表,后面的参数全部为null。这就表示希望查询这张表中的所有数据。
查询完之后得到一个Cursor对象,我们通过对这个对象的遍历来取出数据。
示例:根据id查询
String query_id = inputId.getText().toString();
//columns为null 查询所有列
Cursor cursor = mDatabase.query("courses",null,"id=?",new String[]{query_id},null,null,null);
if(cursor.moveToFirst()){
//清空显示的地方,不然下一次查询的时候上一次的内容还在
queryResult.setText("");
do{
String courseId = String.valueOf(cursor.getInt(cursor.getColumnIndex("id")));
String courseName = cursor.getString(cursor.getColumnIndex("coursename"));
String classR = cursor.getString(cursor.getColumnIndex("classroom"));
String courseTime = cursor.getString(cursor.getColumnIndex("time"));
String cTeacher = cursor.getString(cursor.getColumnIndex("teacher"));
//保存 不然循环一次set一次,前面的就会被覆盖
String q = queryResult.getText().toString();
queryResult.setText(q+"\n"+"ID:"+courseId+",课程名称:"+courseName+",老师:"+cTeacher+",时间:"+courseTime+",教室:"+classR+"\n");
}while (cursor.moveToNext());
}
cursor.close();
⑥ MainActivity.java完整代码
package com.example.yogi.courseapp;
import android.content.ContentValues;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
private CourseData courseDB;
private SQLiteDatabase mDatabase;
private Button id_delete,id_update,id_search,delete_all,clear_all,add_btn,query_all;
private TextView queryResult;
private EditText inputName,inputId,inputTeacher,inputTime,inputRoom;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
courseDB = new CourseData(this);
mDatabase = courseDB.getWritableDatabase();
id_delete = findViewById(R.id.id_delete);
id_delete.setOnClickListener(this);
id_update = findViewById(R.id.id_update);
id_update.setOnClickListener(this);
id_search = findViewById(R.id.id_query);
id_search.setOnClickListener(this);
delete_all = findViewById(R.id.delete_all);
delete_all.setOnClickListener(this);
clear_all = findViewById(R.id.clear_all);
clear_all.setOnClickListener(this);
add_btn = findViewById(R.id.add_btn);
add_btn.setOnClickListener(this);
query_all = findViewById(R.id.query_all);
query_all.setOnClickListener(this);
queryResult = findViewById(R.id.queryResult);
queryResult.setOnClickListener(this);
inputId = findViewById(R.id.input_id);
inputId.setOnClickListener(this);
inputName = findViewById(R.id.text_name);
inputName.setOnClickListener(this);
inputRoom = findViewById(R.id.text_classroom);
inputRoom.setOnClickListener(this);
inputTeacher = findViewById(R.id.text_teacher);
inputTeacher.setOnClickListener(this);
inputTime = findViewById(R.id.text_time);
inputTime.setOnClickListener(this);
}
public void onClick(View view){
switch (view.getId()){
case R.id.query_all:
{
queryAllData();
break;
}
case R.id.add_btn:
{
addData();
break;
}
case R.id.clear_all:
{
inputTime.setText("");
inputTeacher.setText("");
inputRoom.setText("");
inputName.setText("");
queryResult.setText("");
inputId.setText("");
break;
}
case R.id.delete_all:
{
deleteAllData();
break;
}
case R.id.id_delete:
{
deleteId();
break;
}
case R.id.id_query:
{
queryId();
break;
}
case R.id.id_update:
{
updateId();
break;
}
}
}
private void updateId() {
ContentValues values = new ContentValues();
String upd_id = inputId.getText().toString();
//更新使用了values.put的列,如果有列没有被values.put,则会保持原样不更新
values.put("coursename",inputName.getText().toString());
values.put("teacher",inputTeacher.getText().toString());
values.put("time",inputTime.getText().toString());
values.put("classroom",inputRoom.getText().toString());
mDatabase.update("courses",values,"id=?",new String[]{upd_id});
}
//根据id查询
private void queryId() {
String query_id = inputId.getText().toString();
//columns为null 查询所有列
Cursor cursor = mDatabase.query("courses",null,"id=?",new String[]{query_id},null,null,null);
if(cursor.moveToFirst()){
queryResult.setText("");
do{
String courseId = String.valueOf(cursor.getInt(cursor.getColumnIndex("id")));
String courseName = cursor.getString(cursor.getColumnIndex("coursename"));
String classR = cursor.getString(cursor.getColumnIndex("classroom"));
String courseTime = cursor.getString(cursor.getColumnIndex("time"));
String cTeacher = cursor.getString(cursor.getColumnIndex("teacher"));
//保存 不然循环一次set一次,前面的就会被覆盖
String q = queryResult.getText().toString();
queryResult.setText(q+"\n"+"ID:"+courseId+",课程名称:"+courseName+",老师:"+cTeacher+",时间:"+courseTime+",教室:"+classR+"\n");
}while (cursor.moveToNext());
}
cursor.close();
}
private void deleteId() {
String del_id = inputId.getText().toString();
mDatabase.delete("courses","id=?",new String[]{del_id});
}
private void deleteAllData() {
mDatabase.delete("courses",null,null);
}
private void addData() {
ContentValues values = new ContentValues();
//第一个参数应该是表中的列名吧
values.put("coursename",inputName.getText().toString());
values.put("teacher",inputTeacher.getText().toString());
values.put("time",inputTime.getText().toString());
values.put("classroom",inputRoom.getText().toString());
mDatabase.insert("courses",null,values);
}
//查询所有
private void queryAllData(){
Cursor cursor = mDatabase.query("courses",null,null,null,null,null,null);
if(cursor.moveToFirst()){
queryResult.setText("");
do{
String courseId = String.valueOf(cursor.getInt(cursor.getColumnIndex("id")));
String courseName = cursor.getString(cursor.getColumnIndex("coursename"));
String classR = cursor.getString(cursor.getColumnIndex("classroom"));
String courseTime = cursor.getString(cursor.getColumnIndex("time"));
String cTeacher = cursor.getString(cursor.getColumnIndex("teacher"));
//保存 不然循环一次set一次,前面的就会被覆盖
String q = queryResult.getText().toString();
queryResult.setText(q+"\n"+"ID:"+courseId+",课程名称:"+courseName+",老师:"+cTeacher+",时间:"+courseTime+",教室:"+classR+"\n");
}while (cursor.moveToNext());
}
cursor.close();
}
}