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() ,这样如果适配器中的变量变化时,这个方法就会被调用,然后进行刷新操作.

编码规范总结

  1. 边界问题

当能刷新ListView之后,出现一个边界问题: 当我删除了最后一条数据之后,listView还显示它.发现是清空List出现了问题:先前我是如果搜索到数据时才进行List的清空,殊不知当删除最后一条数据后,数据表已空,而这个条数据就没有被清空,留在ListView上.
改正: 当搜索数据时,先进行清空操作,然后再搜索数据,判断为空或者List.add().

  1. 条件判断

下面代码的第一个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;
    }
}

  • 1
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

涛歌依旧fly

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值