【第一部分】历史文章:
Android学习笔记(一)——创建第一个Android项目
Android学习笔记(二)android studio基本控件及布局(实现图片查看器)
Android学习笔记(三)android studio中CheckBox自定义样式(更换复选框左侧的勾选图像)
Android学习笔记(四)Android 中Activity页面的跳转及传值
Android学习笔记(五)——Toast提示、Dialog对话框、Menu菜单
Android学习笔记(六)——自定义ListView布局+AsyncTask异步任务
Android学习笔记(七)——数据存储(共享参数SharedPreferences)
Android学习笔记(八)——数据存储(SD卡文件操作)
Android学习笔记(九)——网络技术
Android学习笔记(十)——实现新闻列表案例
Android学习笔记(十一)——一些高级控件的使用
【第二部分】主要问题解决:
Android Studio(存)读取不了SD卡上的文件——【已解决】
本篇文章将介绍,Android的数据存储方式——SqLite的使用方法,包括创建数据库、创建表、进行相应表中数据的CRUD(增删改查)操作。
SQLiteOpenHelper
帮助类。借助这个类可以非常简单的对数据库进行创建与升级。SQLiteOpenHelper
是一个抽象类,使用的时候必须自己创建一个类,去继承SQLiteOpenHelper。SQLiteOpenHelper有两个抽象方法,如下所示:public void onCreate(SQLiteDatabase db) {}
public void onUpgrade(SQLiteDatabase sqLiteDatabase, int i, int i1) {}
我们必须在自己定义的类中重写以上的方法。然后分别在这两个方法中去实现创建、升级数据库的逻辑。
SQLiteOpenHelper中有两个重要的实例方法:
getReadableDatabase()
方法先读写方式打开数据库,如果数据库的磁盘空间满了,就会打开失败,当打开失败后会继续尝试以只读方式打开数据库。getWritableDatabase()
方法以读写方式打开数据库,一旦数据库的磁盘空间满了,数据库就只能读而不能写,倘若使用getWritableDatabase()打开数据库就会出错。SQLiteOpenHelper中的两个构造方法:
一般情况下,我们使用参数少的那个构造函数(上图中第一个),这个构造函数里面有四个参数:
getReadableDatabase()
或者getWritableDatabase()
方法就可以创建数据库了。/data/data/ /databases/
目录。2、使用SQl操作数据库。
在上面我们已经知道调用getReadableDatabase()
或者getWritableDatabase()
可以用于创建和升级数据库,不仅如此,这两个方法可以返回一个SQLiteDatabase
对象,我们可以用这个对象完成数据库的CRUD操作。
(1)通过使用原生的SQL语句操作数据库:
String sql_insert="insert into user(account,password) values(?,?)";
db.execSQL(sql_insert,new String[]{account,password});
String sql_query="select * from user where account=? and password=?";
Cursor cursor= db.rawQuery(sql_query,new String[]{account,password});
(2) 通过以下四个辅助方法来实现:
SQLite直接使用的数据结构是ContentValues类
,类似于映射Map
,提供了put和get
方法用来存取键值对。
注意:区别在于ContentValues的键只能是字符串;ContentValues主要用于记录增加和更新操作,即SQLiteDatabase的insert和update
方法。对于查询操作来说,使用的是另一个游标类Cursor
。调用SQLiteDatabase的query方法,返回Cursor对象。因此,要获取查询结果的话,要根据游标的指示一条一条的遍历结果集合即可。
Button addData = (Button) findViewById(R.id.add_data);
addData.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
SQLiteDatabase db = dbHelper.getWritableDatabase();
ContentValues values = new ContentValues();
// 开始组装第一条数据
values.put("name", "The Da Vinci Code");
values.put("author", "Dan Brown");
values.put("pages", 454);
values.put("price", 16.96);
db.insert("Book", null, values); // 插入第一条数据
values.clear();
// 开始组装第二条数据
values.put("name", "The Lost Symbol");
values.put("author", "Dan Brown");
values.put("pages", 510);
values.put("price", 19.95);
db.insert("Book", null, values); // 插入第二条数据
}
});
Button updateData = (Button) findViewById(R.id.update_data);
updateData.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
SQLiteDatabase db = dbHelper.getWritableDatabase();
ContentValues values = new ContentValues();
values.put("price", 10.99);
db.update("Book", values, "name = ?", new String[] { "The Da Vinci Code" });
}
});
Button deleteButton = (Button) findViewById(R.id.delete_data);
deleteButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
SQLiteDatabase db = dbHelper.getWritableDatabase();
db.delete("Book", "pages > ?", new String[] { "500" });
}
});
Button queryButton = (Button) findViewById(R.id.query_data);
queryButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
SQLiteDatabase db = dbHelper.getWritableDatabase();
// 查询Book表中所有的数据
Cursor cursor = db.query("Book", null, null, null, null, null, null);
if (cursor.moveToFirst()) {
do {
// 遍历Cursor对象,取出数据并打印
String name = cursor.getString(cursor.getColumnIndex("name"));
String author = cursor.getString(cursor.getColumnIndex("author"));
int pages = cursor.getInt(cursor.getColumnIndex("pages"));
double price = cursor.getDouble(cursor.getColumnIndex("price"));
} while (cursor.moveToNext());
}
cursor.close();
}
});
下面是一个具体的简单的案例项目:使用了上篇文章中自定义适配器的相关知识点。
1、编写主活动布局。
activity_main.xml
<?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:id="@+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
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="cn.edu.hznu.sqlist.MainActivity">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/addLL"
android:orientation="horizontal"
>
<EditText
android:id="@+id/nameET"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:hint="学生姓名"
android:inputType="textPersonName" />
<EditText
android:id="@+id/balanceET"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:hint="分数"
android:inputType="number" />
<ImageView
android:onClick="add"
android:id="@+id/addIV"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@android:drawable/ic_input_add"
/>
</LinearLayout>
<ListView
android:id="@+id/accountLV"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="@id/addLL">
</ListView>
</LinearLayout>
EditText
控件,主要完成输入学生的姓名、分数。ImageView
控件,主要完成显示+
图片,点击后向数据库添加数据。ListView
控件,用于展示数据。2、编写列表项的布局。
item_layout.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal"
android:padding="10dp">
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:id="@+id/idTV"
android:text="1"
android:textColor="#000000"
android:textSize="20sp"
/>
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="2"
android:id="@+id/nameTV"
android:text="PQ"
android:textColor="#000000"
android:textSize="20sp"
android:singleLine="true"
/>
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="2"
android:id="@+id/balanceTV"
android:text="12345"
android:singleLine="true"
android:textColor="#000000"
android:textSize="20sp"
/>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical">
<ImageView
android:id="@+id/upIV"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="2dp"
android:src="@android:drawable/arrow_up_float"
/>
<ImageView
android:id="@+id/downIV"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@android:drawable/arrow_down_float"
/>
</LinearLayout>
<ImageView
android:id="@+id/deleteIV"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@android:drawable/ic_menu_delete"
/>
</LinearLayout>
TextView
控件,主要显示,学生的学号、姓名、分数。3、编写对应的实体类。
Student.java
package cn.edu.hznu.sqlist.bean;
public class Student {
public Student(Long id, String name, Integer score) {
this.id = id;
this.name = name;
this.score = score;
}
public Student(String name,Integer score){
this.name=name;
this.score=score;
}
private Long id;
private String name;
private Integer score;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getScore() {
return score;
}
public void setScore(Integer score) {
this.score = score;
}
@Override
public String toString() {
return "[学号" + id + ", 姓名:" + name + " , 分数:" + score + "]";
}
}
4、编写SQLiteOpenHelper的工具帮助类。
注意:SQLiteOpenHelper
是一个抽象类,需要自己定义,继承SQLiteOpenHelper
类即可,同时,重写对应的方法。
MyHelper.java
package cn.edu.hznu.sqlist.utils;
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
public class MyHelper extends SQLiteOpenHelper {
public MyHelper(Context context, String name, SQLiteDatabase.CursorFactory factory, int version) {
super(context, name, factory, version);
}
@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL("CREATE TABLE student(id INTEGER PRIMARY KEY AUTOINCREMENT,name VARCHAR(20),score INTEGER)");
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
}
}
5、编写数据库操作类。(CRUD对应的方法)
StudentDao.java
package cn.edu.hznu.sqlist.dao;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import java.util.ArrayList;
import java.util.List;
import cn.edu.hznu.sqlist.bean.Student;
import cn.edu.hznu.sqlist.utils.MyHelper;
public class StudentDao {
private MyHelper helper;
public StudentDao(Context context) {
helper=new MyHelper(context,"student.db",null,1);
}
public void insert(Student account) {
//获取数据库对象
SQLiteDatabase db = helper.getWritableDatabase();
//用来装载要插入的数据的map<列名,列的值>
ContentValues values = new ContentValues();
values.put("name", account.getName());
values.put("score", account.getScore());
//向account表插入数据values
long id = db.insert("student", null, values);
account.setId(id);//的到id
db.close();//关闭数据库
}
//根据id 删除数据
public int delete(long id) {
SQLiteDatabase db = helper.getWritableDatabase();
//按条件删除指定表中的数据,返回受影响的行数
int count = db.delete("student", "id=?", new String[]{id + ""});
db.close();
return count;
}
//更新数据
public int update(Student account) {
SQLiteDatabase db = helper.getWritableDatabase();
ContentValues values = new ContentValues();//要修改的数据
values.put("name", account.getName());
values.put("score", account.getScore());
int count = db.update("student", values, "id=?", new String[]{account.getId() + ""});//更新并得到行数
db.close();
return count;
}
//查询所有数据倒序排列
public List<Student> queryAll() {
SQLiteDatabase db = helper.getReadableDatabase();
Cursor c = db.query("student", null, null, null, null, null, "score DESC");
List<Student> list = new ArrayList<Student>();
while (c.moveToNext()) {
//可以根据列名获取索引
long id = c.getLong(c.getColumnIndex("id"));
String name = c.getString(1);
int score = c.getInt(2);
list.add(new Student(id, name, score));
}
c.close();
db.close();
return list;
}
}
6、自定义数据适配器StudentAdapter。
StudentAdapter.java
package cn.edu.hznu.sqlist.adapter;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.support.annotation.NonNull;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;
import java.util.List;
import cn.edu.hznu.sqlist.R;
import cn.edu.hznu.sqlist.bean.Student;
import cn.edu.hznu.sqlist.dao.StudentDao;
public class StudentAdapter extends ArrayAdapter<Student> {
private Context c;
private int item_layout_id;
private EditText nameET; //学生姓名
private EditText balanceET; //学生分数
private ListView accountLV;
private List<Student> list;
private StudentDao dao;
public StudentAdapter(Context context, int resource, List objects) {
super(context, resource,objects);
item_layout_id=resource;
c=context;
list=objects;
dao=new StudentDao(context);
}
@NonNull
@Override
public View getView(int position, View convertView, ViewGroup parent) {
View view=null;
final ViewHolder holder;
if(convertView==null){//回收站为空\
/**
* LayoutInflater.from()得到布局填充器对象
* getContext()获取当前上下文
* inflate() 加载填充布局
*/
view= LayoutInflater.from(getContext())
.inflate(item_layout_id,parent,false);
holder=new ViewHolder(view);
view.setTag(holder);
}else {//显示后续的列表项
view=convertView;
holder= (ViewHolder) view.getTag();
}
final Student itemData=getItem(position);
holder.idTV.setText(itemData.getId()+"");
holder.nameTV.setText(itemData.getName()+"");
holder.balanceTV.setText(itemData.getScore()+"");
holder.upIV.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
itemData.setScore(itemData.getScore()+1);
notifyDataSetChanged();
dao.update(itemData);
}
});
holder.downIV.setOnClickListener(new View.OnClickListener(){
public void onClick(View v){
itemData.setScore(itemData.getScore()-1);
notifyDataSetChanged();
dao.update(itemData);
}
});
holder.deleteIV.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
android.content.DialogInterface.OnClickListener listener=new android.content.DialogInterface.OnClickListener(){
@Override
public void onClick(DialogInterface dialog, int which) {
list.remove(itemData);
dao.delete(itemData.getId());
notifyDataSetChanged();
}
};
AlertDialog.Builder builder=new AlertDialog.Builder(c); //
builder.setTitle("确定要删除吗?");
builder.setPositiveButton("确定",listener);
builder.setNegativeButton("取消",null);
builder.show();
}
});
return view;
}
class ViewHolder{
TextView idTV;
TextView nameTV;
TextView balanceTV;
ImageView upIV;
ImageView downIV;
ImageView deleteIV;
public ViewHolder(View view) {
idTV=(TextView)view.findViewById(R.id.idTV);
nameTV=(TextView)view.findViewById(R.id.nameTV);
balanceTV=(TextView)view.findViewById(R.id.balanceTV);
upIV=(ImageView)view.findViewById(R.id.upIV);
downIV=(ImageView)view.findViewById(R.id.downIV);
deleteIV=(ImageView)view.findViewById(R.id.deleteIV);
}
}
}
7、编写MainActivity.java。
MainActivity.java
package cn.edu.hznu.sqlist;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.text.TextUtils;
import android.view.View;
import android.widget.AdapterView;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.Toast;
import java.util.List;
import cn.edu.hznu.sqlist.adapter.StudentAdapter;
import cn.edu.hznu.sqlist.bean.Student;
import cn.edu.hznu.sqlist.dao.StudentDao;
public class MainActivity extends AppCompatActivity {
private EditText nameET; //学生姓名
private EditText balanceET; //学生分数
private ListView accountLV;
private List<Student> list;
private StudentDao dao;
private StudentAdapter adapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
accountLV=(ListView)findViewById(R.id.accountLV);
nameET=(EditText)findViewById(R.id.nameET);
balanceET=(EditText)findViewById(R.id.balanceET);
dao=new StudentDao(this);
list=dao.queryAll(); //查询数据库
adapter=new StudentAdapter(MainActivity.this, R.layout.item_layout,list);
accountLV.setAdapter(adapter);
//点击列表项的事件
accountLV.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
Student a=(Student) parent.getItemAtPosition(position);
Toast.makeText(getApplicationContext(),a.toString(),Toast.LENGTH_SHORT).show();
}
});
}
//增加操作
public void add(View v) {
String name = nameET.getText().toString().trim();
String score = balanceET.getText().toString().trim();
if(TextUtils.isEmpty(name)||TextUtils.isEmpty(score)){
Toast.makeText(MainActivity.this,"请填写信息!", Toast.LENGTH_SHORT).show();
return ;
}else{
Student a = new Student(name, score.equals("") ? 0 : Integer.parseInt(score));
dao.insert(a);
list.add(a);
adapter.notifyDataSetChanged(); //动态更新listview
}
}
}
总结:通过本次的小案例,对SQLite的四种操作,做了理解及使用,结合前几次的其他知识的学习,做了一次阶段性的小总结。但是,该案例还有需要改进的地方。比如,插入数据的有效性的检验,修改分数的区间范围限制等;在后期持续改进中。
在下接下来的一篇文章中将会介绍,使用LitePal操作数据库的相关知识。
若文章中有错误的地方欢迎大家反馈或者留言,十分感谢!!!