基于SQlite,ListView实现一个通信录,设计UI的同时实现以下功能:
1)录入用户姓名、电话;
2)通过姓名查找用户信息;
3)查看全部用户信息;
4)实现删除指定用户的信息;
4)实现更新指定用户的信息;
在本实验中使用的适配器是BaseAdapter,刚开始没有在适配器定义List变量类型,而是直接声明一个全局变量results,进行数据的增删查改:
class MyBaseAdapter extends BaseAdapter{
private List<Info> results;//这是Adapter的数据,一定要有,刷新也是看个类的数据是否改变
@Override
public int getCount() {
return results.size();
}
//得到Item代表的对象
@Override
public Object getItem(int position) {
return results.get(position);
}
//得到Item的id
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
//加载ListView的Item布局
View view = View.inflate(MainActivity.this, R.layout.list_item, null);
TextView textView = view.findViewById(R.id.item);
textView.setText("name : "+ results.get(position).getName() + " tel : "+ results.get(position).getTel());
return view;
}
}
结果数据不能刷新,解决方法是:需要在适配器中声明变量,然后调用适配器的方法:notifyDataSetChanged() ,这样如果适配器中的变量变化时,这个方法就会被调用,然后进行刷新操作.
当能刷新ListView之后,出现一个边界问题: 当我删除了最后一条数据之后,listView还显示它.发现是清空List出现了问题:先前我是如果搜索到数据时才进行List的清空,殊不知当删除最后一条数据后,数据表已空,而这个条数据就没有被清空,留在ListView上.
改正: 当搜索数据时,先进行清空操作,然后再搜索数据,判断为空或者List.add().
下面代码的第一个if语句中,我是想当没有数据时,就提示没有数据,然后没了…就是有数据的情况,然后光顾着有数据的情况了.
SQLiteDatabase db = helper.getReadableDatabase();
Cursor cursor = null ;
if( cursor == null || cursor.getCount() == 0 ){ //防止出现异常
Toast.makeText(this,"没有数据",Toast.LENGTH_SHORT).show();
}else{
cursor.moveToFirst();
Info info = new Info();
// newList.clear();// 每次查询结果前必须先清空之前的数据 ,边界情况没有考虑清楚----当最后一条数据删除之后,还会保留显示,应该在查询之前就清空
//baseAdapter.results.clear();
info.setName(cursor.getString(1));
info.setTel(cursor.getString(2));
newList.add(info);
}
while (cursor.moveToNext()){
newList.add(new Info(cursor.getString(1),cursor.getString(2)));
}
baseAdapter.results = newList; //保持同一片内存
baseAdapter.notifyDataSetChanged();//刷新
cursor.close();
db.close();
改正:
if( cursor == null || cursor.getCount() == 0 ){ //防止出现异常
Toast.makeText(this,"没有数据",Toast.LENGTH_SHORT).show();
if(cursor!=null) cursor.close();
db.close();
return;
}
return之前一定要记得关闭一些数据操作流.还有对初始值null也要进行判断:如果cursor为null,就不存在cursor.close()!
点击ListView获取点击对应sqlite那一行的id, 我们知道position是listview布局中的位置,我们可以用position来获得我们想要的id:点击listview, 调用下面的函数:
resultList.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
Info info = baseAdapter.results.get(position);
nameText.setText(info.getName());
telText.setText(info.getTel());
SQLiteDatabase db = helper.getReadableDatabase();
Cursor cursor = db.query("information",null,null,null,null,null,null);
cursor.moveToPosition(position);
Id = cursor.getString(0); //获得点击Item的id
//关闭流
cursor.close();
db.close();
}
});
我表的设计是这样的:db.execSQL("CREATE table information(id INTEGER PRIMARY KEY AUTOINCREMENT,name VARCHAR(20),tel VARCHAR(20))");
cursor获得第一个列的值是cursor.getString(0)
Id 已作为全局变量进行使用, 方便后面的delete函数和update函数使用:
public int update(String name,String tel){
if(Id == null || Id.length()==0){
Toast.makeText(this,"请选中数据行,再进行更新!",Toast.LENGTH_SHORT).show();
return 0;
}
SQLiteDatabase db = helper.getWritableDatabase();
ContentValues contentValues = new ContentValues();
contentValues.put("name",name);
contentValues.put("tel",tel);
int number = db.update("information",contentValues,"id=?",new String[]{Id}); //根据id更新数据
db.close();
updateUI(); //刷新布局
return number;
}
public int delete(){
if(Id == null || Id.length()==0){
Toast.makeText(this,"请选中数据行,再进行删除!",Toast.LENGTH_SHORT).show();
return 0;
}
SQLiteDatabase db = helper.getWritableDatabase();
int num = db.delete("information","id = ? ",new String[]{Id});
db.close();
updateUI();//刷新布局
return num;
}
前面谈到ListView的刷新: 通过Adapter的方法notifyDataSetChanged() :baseAdapter.notifyDataSetChanged();//适配器数据如果发生变化就刷新
但光有这个还不算完.前提是Adapter数据得有变化,这个方法才起作用. 当你删除/更新一条数据后, 直接使用notifyDataSetChanged()是不能够刷新的,因为list
没有变化,所以需要重新"查询数据, 将查询的结果再添加到list中,这样list数据就会发生变化,这时再调用notifyDataSetChanged就起作用了":
public void updateUI(){
nameText.setText("");
telText.setText("");
Id="";
search("",""); //每次必须重新将数据进行刷新,重新查询,然后布局根据数据来刷新
baseAdapter.notifyDataSetChanged();//适配器数据如果发生变化就刷新
}
main.xml
<RelativeLayout 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"
android:paddingLeft="20dp"
android:paddingBottom="20dp"
android:paddingRight="20dp"
android:paddingTop="20dp"
android:orientation="vertical"
tools:context=".MainActivity">
<LinearLayout
android:id="@+id/L1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_centerHorizontal="true"
android:layout_marginTop="30dp"
android:background="#ffffff">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="姓 名:"
android:textSize="30sp" />
<EditText
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/name"
android:maxLines="1"
android:hint="请输入姓名" />
LinearLayout>
<LinearLayout
android:id="@+id/L2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@+id/L1"
android:background="#ffffff"
android:layout_marginTop="10dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="电话:"
android:textSize="30sp"
/>
<EditText
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/tel"
android:maxLines="1"
android:hint="请输入电话"
/>
LinearLayout>
<LinearLayout
android:id="@+id/L3"
android:layout_below="@+id/L2"
android:layout_marginTop="10dp"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:id="@+id/add_b"
android:text="添加"
/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:id="@+id/search_b"
android:text="查询"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:id="@+id/delete_b"
android:text="删除"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:id="@+id/update_b"
android:text="更新"/>
LinearLayout>
<ListView
android:id="@+id/result_list"
android:layout_below="@id/L3"
android:layout_width="match_parent"
android:layout_height="wrap_content">
ListView>
RelativeLayout>
List_Item.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/item"
android:text="这是list_item"
android:textSize="30sp"/>
LinearLayout>
package jzt.com.shiyan5;
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.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.BaseAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;
import java.util.ArrayList;
import java.util.List;
public class MainActivity extends AppCompatActivity implements View.OnClickListener{
private EditText nameText;
private EditText telText;
private ListView resultList;
private Button search_b;
private Button delete_b;
private Button update_b;
private Button add_b;
private String Id ="";
MyHelper helper;
MyBaseAdapter baseAdapter;
private List<Info> newList;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//创建SQLite数据库
helper = new MyHelper(this);
init();
}
public void init(){
nameText = findViewById(R.id.name);
telText = findViewById(R.id.tel);
//初始化控件
resultList = findViewById(R.id.result_list);
//创建一个Adapter实例
baseAdapter = new MyBaseAdapter();
baseAdapter.results = new ArrayList<>();
//设置Adapter
resultList.setAdapter(baseAdapter);
search_b = findViewById(R.id.search_b);
delete_b = findViewById(R.id.delete_b);
update_b = findViewById(R.id.update_b);
add_b = findViewById(R.id.add_b);
search_b.setOnClickListener(this);
delete_b.setOnClickListener(this);
update_b.setOnClickListener(this);
add_b.setOnClickListener(this);
newList = new ArrayList<>();
resultList.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
Info info = baseAdapter.results.get(position);
nameText.setText(info.getName());
telText.setText(info.getTel());
SQLiteDatabase db = helper.getReadableDatabase();
Cursor cursor = db.query("information",null,null,null,null,null,null);
cursor.moveToPosition(position);
Id = cursor.getString(0); //获得点击Item的id
//关闭流
cursor.close();
db.close();
}
});
}
@Override
public void onClick(View v) {
switch (v.getId()){
case R.id.add_b:
insert(nameText.getText().toString().trim(),telText.getText().toString().trim());
break;
case R.id.search_b:
search(nameText.getText().toString().trim(),telText.getText().toString().trim());
break;
case R.id.delete_b:
int num1 = delete();
if (num1 == 1){
Toast.makeText(this,"删除信息成功",Toast.LENGTH_SHORT).show();
}else if(num1 == 0){
Toast.makeText(this,"删除信息失败",Toast.LENGTH_SHORT).show();
}
break;
case R.id.update_b:
int num = update(nameText.getText().toString().trim(),telText.getText().toString().trim());
if(num==0 || num==-1){
Toast.makeText(this,"修改信息失败",Toast.LENGTH_SHORT).show();
}else if(num==1){
Toast.makeText(this,"信息修改成功",Toast.LENGTH_SHORT).show();
}
break;
}
}
public void updateUI(){
nameText.setText("");
telText.setText("");
Id="";
search("",""); //每次必须重新将数据进行刷新,重新查询,然后布局根据数据来刷新
baseAdapter.notifyDataSetChanged();//适配器数据如果发生变化就刷新
}
public int update(String name,String tel){
if(Id == null || Id.length()==0){
Toast.makeText(this,"请选中数据行,再进行更新!",Toast.LENGTH_SHORT).show();
return 0;
}
SQLiteDatabase db = helper.getWritableDatabase();
ContentValues contentValues = new ContentValues();
contentValues.put("name",name);
contentValues.put("tel",tel);
int number = db.update("information",contentValues,"id=?",new String[]{Id}); //根据id更新数据
db.close();
updateUI(); //刷新布局
return number;
}
public void insert(String name,String tel){
if(name.trim().length()==0||tel.trim().length()==0){
Toast.makeText(this,"姓名或者电话号码不能为空!",Toast.LENGTH_SHORT).show();
return;
}
name = name.trim();
tel = tel.trim();
SQLiteDatabase writableDatabase = helper.getWritableDatabase();
ContentValues contentValues = new ContentValues();
contentValues.put("name",name);
contentValues.put("tel",tel);
//第一个参数是数据库的表 第二个是如果是将要插入的行为空行时,这个列名设为null,第三个参数为contentvalues
writableDatabase.insert("information",null,contentValues);
Toast.makeText(this,"数据添加成功",Toast.LENGTH_SHORT).show();
updateUI();//将所填数据置空
writableDatabase.close();
}
public int delete(){
if(Id == null || Id.length()==0){
Toast.makeText(this,"请选中数据行,再进行删除!",Toast.LENGTH_SHORT).show();
return 0;
}
SQLiteDatabase db = helper.getWritableDatabase();
int num = db.delete("information","id = ? ",new String[]{Id});
db.close();
updateUI();//刷新布局
return num;
}
//根据名字搜索
public void search(String name,String tel){
SQLiteDatabase db = helper.getReadableDatabase();
Cursor cursor = null ;
//在查询之前就先将 数据进行清空
newList.clear();
baseAdapter.results.clear();
name = name.trim();
tel = tel.trim();
if(name.length()==0 && tel.length()==0){
cursor = db.query("information",null,null,null,null,null,null);
}else if(name.length()!=0 && tel.length()==0){
cursor = db.query("information", null, "name=?", new String[]{name }, null, null, null);
}else if(name.length()==0&&tel.length()!=0){
cursor = db.query("information",null,"tel=?",new String[]{tel},null,null,null);
}else if(name.length()!=0 && tel.length()!=0){
cursor = db.query("information",null,"name=? and tel=?",new String[]{name , tel},null,null,null);
}else if(name.length()==0 && tel.length() ==0){
cursor = db.query("information",null,null,null,null,null,null) ;
}
if( cursor == null || cursor.getCount() == 0 ){ //防止出现异常
Toast.makeText(this,"没有数据",Toast.LENGTH_SHORT).show();
if(cursor!=null) cursor.close();
db.close();
return;
}else{
cursor.moveToFirst();
Info info = new Info();
// newList.clear();// 每次查询结果前必须先清空之前的数据 ,边界情况没有考虑清楚----当最后一条数据删除之后,还会保留显示,应该在查询之前就清空
//baseAdapter.results.clear();
info.setName(cursor.getString(1));
info.setTel(cursor.getString(2));
newList.add(info);
}
while (cursor.moveToNext()){
newList.add(new Info(cursor.getString(1),cursor.getString(2)));
}
baseAdapter.results = newList; //保持同一片内存
baseAdapter.notifyDataSetChanged();//刷新
Toast.makeText(this,"为您查询到"+newList.size()+"条数据",Toast.LENGTH_SHORT).show();
cursor.close();
db.close();
}
class MyBaseAdapter extends BaseAdapter{
private List<Info> results;//这是Adapter的数据,一定要有,刷新也是看个类的数据是否改变
@Override
public int getCount() {
return results.size();
}
//得到Item代表的对象
@Override
public Object getItem(int position) {
return results.get(position);
}
//得到Item的id
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
//加载ListView的Item布局
View view = View.inflate(MainActivity.this, R.layout.list_item, null);
TextView textView = view.findViewById(R.id.item);
textView.setText("name : "+ results.get(position).getName() + " tel : "+ results.get(position).getTel());
return view;
}
}
}
Info.java
package jzt.com.shiyan5;
public class Info {
private String name;
private String tel;
public Info(){
}
public Info(String name,String tel){
this.name = name;
this.tel = tel;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getTel() {
return tel;
}
public void setTel(String tel) {
this.tel = tel;
}
}