Android实验5---通讯录(解决ListView刷新问题及一些编码规范的总结)
实验要求
基于SQlite,ListView实现一个通信录,设计UI的同时实现以下功能:
1)录入用户姓名、电话;
2)通过姓名查找用户信息;
3)查看全部用户信息;
4)实现删除指定用户的信息;
4)实现更新指定用户的信息;
关于ListView刷新
在本实验中使用的适配器是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()!
通过id删除数据,更新数据
点击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();//适配器数据如果发生变化就刷新 }
UI布局设计
main.xml
<?xml version="1.0" encoding="utf-8"?><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
<?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"> <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; }}
更多相关文章
- Android实现登录功能,Android与服务器数据交互,使用tomcat、mysql
- Android(安卓)RecyclerView和ListView多布局实现
- 可左右两侧挤压傍边布局的Android抽屉
- 老罗的Android视频教程整理之常用布局
- android开发动态页面时常用的LayoutInflater实例化的三种方式
- Android中的布局方式(一)
- Android绘图机制(三) ViewGroup类的延伸
- Android(安卓)数据库SQLite更新升级问题
- Android数据加密之异或加密算法