实现功能:
1. 创建一个SQLiteOpenHelper子类
(1)实现数据库创建功能;
(2)实现升级管理功能;
2. 实现数据库的增删改查操作
(1)上方控件中输入数值,点击添加,则将数据存入数据库中,同时下方的ListView添加一行;
(2)点击下方的一行,则该行内容显示到上方的的控件中,修改其内容,然后点击修改按钮,则更新数据库和ListView;
(3)先用(2)中操作选择一行,然后点击删除按钮,则从数据库和界面中删除选中的数据;
(4)上方输入年龄值,点击查询按钮,则将大于等于该年龄值的查询结果(可能多行)用AlertDialog显示出来。例如:输入18,则显示:
4 ccc 18 1.78
5 ddd 19 1.8
1.activity_main.xml
2.items.xml
3.People.java
package com.example.sqlite;
public class People {
public int ID = -1;
public String Name;
public int Age;
public float Height;
public int getID() {
return ID;
}
public void setID(int ID) {
this.ID = ID;
}
public String getName() {
return Name;
}
public void setName(String name) {
Name = name;
}
public int getAge() {
return Age;
}
public void setAge(int age) {
Age = age;
}
public float getHeight() {
return Height;
}
public void setHeight(float height) {
Height = height;
}
}
4.MyDBOpenHelper.java
package com.example.sqlite;
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
public class MyDBOpenHelper extends SQLiteOpenHelper {
//必须重写的构造函数
public MyDBOpenHelper(Context context, String name, SQLiteDatabase.CursorFactory factory,
int version) {
super(context, name, factory, version);
}
//必须重写的创建数据库处理--传入的参数是框架中创建的SQLiteDatabase操作对象
@Override
public void onCreate(SQLiteDatabase db) {
String createSQL="create table "+DBAdapter.DB_TABLE+" ("+DBAdapter.KEY_ID+
" integer primary key autoincrement,"
+DBAdapter.KEY_NAME+" text not null,"+DBAdapter.KEY_AGE+" integer,"+
DBAdapter.KEY_HEIGHT+" float);";
db.execSQL(createSQL); //执行创建语句
}
/*必须重写的升级数据库处理--准确的说,应该是版本变化处理:
* 只要前面的构造函数中的版本不同于数据库文件的版本,就会调用此函数*/
//三个参数: 数据库对象,旧版本号,新版本号
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
db.execSQL("DROP TABLE IF EXISTS "+DBAdapter.DB_TABLE); //一般情况下不能直接删除数据,先保存...
onCreate(db);
System.out.println(oldVersion+"--"+newVersion);
}
//可选的方法---每次成功打开数据库后首先被执行
@Override
public void onOpen(SQLiteDatabase db) {
super.onOpen(db);
}
}
5.DBAdapter.java
package com.example.sqlite;
import android.annotation.SuppressLint;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class DBAdapter {
//数据库基本信息
private static final String DB_NAME="people.db"; //数据库名
public static final String DB_TABLE="info"; //表名
private static final int DB_VERSION=1; //数据库版本
//字段名称
public static final String KEY_ID="id";
public static final String KEY_NAME="name";
public static final String KEY_AGE="age";
public static final String KEY_HEIGHT="height";
private SQLiteDatabase db=null; //数据库对象
private Context context; //记住由构造函数传入的上下文对象
//数据库辅助操作对象
private MyDBOpenHelper helper;
public DBAdapter(Context context){
this.context=context; //记住由构造函数传入的上下文对象
//若此处的数据库版本不同于系统文件中实际的版本,则会触发升级动作
helper=new MyDBOpenHelper(context, DB_NAME, null, DB_VERSION);
}
//创建/打开数据库
public boolean createDB(){
try{
db=helper.getWritableDatabase();
}catch(Exception e){
return false;
}
return true;
}
//添加
public boolean insert(People people){
ContentValues cv=new ContentValues();
//设置插入的字段数值----对于自增的字段不需要设置
cv.put(KEY_NAME, people.Name);
cv.put(KEY_AGE, people.Age);
cv.put(KEY_HEIGHT, people.Height);
if (db.insert(DB_TABLE, null, cv)==-1)
return false;
return true;
}
//查询数据
public List
6.MainActivity.java
package com.example.sqlite;
import android.app.ListActivity;
import android.content.Context;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.Button;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class MainActivity extends ListActivity {
//数据库适配对象,用于操作数据库
DBAdapter db=null;
//Listview底层数据对象变量
private List> list;
//input输入框控件
private TextView Name;
private TextView Age;
private TextView Height;
//被点击的那行数据的id
int reop_id = -1;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//创建数据库适配对象
db=new DBAdapter(this);
//创建数据库
if (!db.createDB()){
Toast.makeText(MainActivity.this, "创建数据库失败!", Toast.LENGTH_SHORT).show();
return;
}
//获取数据
list=db.query();
//创建自定义的Adapter对象
MyAdapter adapter = new MyAdapter(this);
setListAdapter(adapter);
Button btnInsert = findViewById(R.id.insert);
Button btnUpdate = findViewById(R.id.update);
Button btnDelete = findViewById(R.id.delete);
Button btnQuery = findViewById(R.id.query);
Name = findViewById(R.id.name);
Age = findViewById(R.id.age);
Height = findViewById(R.id.height);
//定义一个People类型的变量,用于存放一组信息
People people = new People();
//添加
btnInsert.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
//将文本框控件中的信息赋值给people
people.setName(Name.getText().toString());
people.setAge(Integer.parseInt(Age.getText().toString()));
people.setHeight(Float.parseFloat(Height.getText().toString()));
db.insert(people);//将该组信息传参给insert函数-->将信息添加到数据库
list = db.query();//获取此时数据库的所有信息,赋值给list-->用于显示在界面上
//通知列表数据修改
adapter.notifyDataSetChanged();
//将上方控件中的内容清空
Name.setText("");
Age.setText("");
Height.setText("");
}
});
//修改
btnUpdate.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
people.setName(Name.getText().toString());
people.setAge(Integer.parseInt(Age.getText().toString()));
people.setHeight(Float.parseFloat(Height.getText().toString()));
db.updateData(reop_id,people);//更新被点击的那一行(指定id)的数据
list = db.query();//获取此时数据库的所有信息,赋值给list-->用于显示在界面上
//通知列表数据修改
adapter.notifyDataSetChanged();
//将上方控件中的内容清空
Name.setText("");
Age.setText("");
Height.setText("");
}
});
//删除
btnDelete.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View view) {
db.delete(reop_id);//删除被点击的那一行(指定id)的数据
list = db.query();//获取此时数据库的所有信息,赋值给list-->用于显示在界面上
//通知列表数据修改
adapter.notifyDataSetChanged();
//将上方控件中的内容清空
Name.setText("");
Age.setText("");
Height.setText("");
}
});
//条件查询
btnQuery.setOnClickListener(new View.OnClickListener() {
int age;
@Override
public void onClick(View view) {
//获取文本框中输入的年龄
age = Integer.parseInt(Age.getText().toString());
//获取条件查询得到的数据组
People[] queryList = db.getData(age);
if(queryList.length > 0){ //判断是否有符合条件的数据组
list.clear(); //如果有,则先清空此时显示在界面上的数据信息
//依次取出条件查询得到的数据组,并添加到list中-->用于显示在界面上
for(int i = 0; i < queryList.length; i++){
//用于获取一组数据的各字段信息,并存放在queryMap中
Map queryMap = new HashMap();
queryMap.put("id",queryList[i].ID);
queryMap.put("name",queryList[i].Name);
queryMap.put("age",queryList[i].Age);
queryMap.put("height",queryList[i].Height);
list.add(queryMap);
}
}
//通知列表数据修改
adapter.notifyDataSetChanged();
//将上方控件中的内容清空
Name.setText("");
Age.setText("");
Height.setText("");
}
});
}
//定义静态的viewHolder类
static class ViewHolder{
TextView idOut;
TextView nameOut;
TextView ageOut;
TextView heightOut;
}
public final class MyAdapter extends BaseAdapter{
//实例化布局对象-->用来实例化每行的布局(View对象)
private LayoutInflater mInflater;
public MyAdapter(Context context){
this.mInflater = LayoutInflater.from(context);
}
//获取List的总行数
@Override
public int getCount() {
return list.size();
}
@Override
public Object getItem(int arg0) {
return null;
}
@Override
public long getItemId(int position) {
return 0;
}
@Override
public View getView(int position, View convertview, ViewGroup parent) {
//定义viewHolder-->当listview滚动的时候快速设置值,而不必每次都重新创建很多对象,从而提升性能
ViewHolder viewHolder;
//当初始页面convertview缓存为空时,创建每一行的view
if(convertview == null){
viewHolder = new ViewHolder();
//实例化一行的布局
convertview = mInflater.inflate(R.layout.items,null);
//找到行内子控件
viewHolder.idOut=convertview.findViewById(R.id.idOutput);
viewHolder.nameOut= convertview.findViewById(R.id.nameOutput);
viewHolder.ageOut= convertview.findViewById(R.id.ageOutput);
viewHolder.heightOut= convertview.findViewById(R.id.heightOutput);
//将convertView的tag设置为viewHolder,
convertview.setTag(viewHolder);
}else{
//当convertview不为空时,重复使用其中已有的view
viewHolder = (ViewHolder) convertview.getTag();
}
//子控件赋值
viewHolder.idOut.setText(String.valueOf((Integer)list.get(position).get("id")));
viewHolder.nameOut.setText((String)list.get(position).get("name"));
viewHolder.ageOut.setText(String.valueOf((Integer) list.get(position).get("age")));
viewHolder.heightOut.setText(String.valueOf((Float)list.get(position).get("height")));
//返回此时新的convertview缓存
return convertview;
}
}
//重写此方法——点击某一行时回调函数
@Override
protected void onListItemClick(ListView l, View v, int position, long id){
super.onListItemClick(l,v,position,id);
reop_id = (Integer)list.get(position).get("id");
//将该行内容显示到上方的的控件中
Name.setText((String)list.get(position).get("name"));
Age.setText(String.valueOf((Integer) list.get(position).get("age")));
Height.setText(String.valueOf((Float)list.get(position).get("height")));
}
//退出界面,关闭数据库
protected void onDestroy() {
super.onDestroy();
db.close();
}
}
过程中遇到的问题及解决方法:
1)运行报错:android.content.res.Resources$NotFoundException: String resource ID #0x14
原因及解决方法:一般是指类型转换错误,比如不小心把int传给text.setText(),例子:text.setText(20);这是错误的,可以这样写text.setText(String.valueOf(20));
2)问题:在activity_main.xml中,ListView的布局失效
解决方法:因为ListView是相对父控件布局的,所以ListView要处在相对布局RelativeLayout下。
3)运行报错:Attempt to invoke virtual method 'android.view.View android.view.Window.findViewById(int)' on a null object reference
原因及解决方法:是因为想要获取的控件不在activity_main.xml里面,所以就会报空指针异常;应该先使用inflate获得另外的xml文件.再使用findViewById方法获取。
如:View account = View.inflate(this, R.layout.account, null);
navView = (NavigationView)account.findViewById(R.id.nav_view);
4)运行报错:java.lang.IllegalStateException: System services not available to Activities before onCreate()
原因及解决方法:此服务需要激活系统服务,所以要把此类变量的实例化工作放到MainActivity的OnCreate函数里面。
5)问题:每次查询时,之前在界面上的数据也还在
解决方法:查询前清空list列表
6)问题:查询时出现两条重复的数据,而其他符合条件的数据不显示(ArrayList.add后,前面数据被覆盖)
导致原因:
ArrayList集合里存的是同一个值,有可能是同一个引用或者就是同一个值。
错误代码:
ArrayList
如错误代码所示,每次add的都是同一个引用,一个指向不同对象的引用obj
结果就是集合里所有的值都是obj,obj指向哪,集合里的值就指向哪。
解决方法:
将 Objec new在循环的里面。
for (int i = 10; i > 0; i--) {
Object obj=new Object();
objt.set(i);
list.add(obj);
}