【第一部分】历史文章:
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(增删改查)操作。

  • SQLite是一款轻量级的关系数据库,它的运算是非常快的,并且占用资源少,通常只需要占用几百KB的内存就足够了,因而特别适合在移动设备上使用。
  • SQLite不仅支持标准的SQL语法,还遵循数据库的ACID事务,所以只要你以前使用过其他的关系数据库,就可以很快的上手SQLite。
  • SQLite比一般的数据库简单,甚至不用设置用户名及密码就可以使用。
    1、数据库的创建。
    Android为了让我们能够更加方便的管理数据库,专门提供了一个SQLiteOpenHelper帮助类。借助这个类可以非常简单的对数据库进行创建与升级。
    SQLiteOpenHelper的基本用法:
    SQLiteOpenHelper是一个抽象类,使用的时候必须自己创建一个类,去继承SQLiteOpenHelper。SQLiteOpenHelper有两个抽象方法,如下所示:
public void onCreate(SQLiteDatabase db) {}public void onUpgrade(SQLiteDatabase sqLiteDatabase, int i, int i1) {}  

我们必须在自己定义的类中重写以上的方法。然后分别在这两个方法中去实现创建、升级数据库的逻辑。

SQLiteOpenHelper中有两个重要的实例方法:

  • getReadableDatabase()
    getReadableDatabase()方法先读写方式打开数据库,如果数据库的磁盘空间满了,就会打开失败,当打开失败后会继续尝试以只读方式打开数据库。
  • getWritableDatabase()
    getWritableDatabase()方法以读写方式打开数据库,一旦数据库的磁盘空间满了,数据库就只能读而不能写,倘若使用getWritableDatabase()打开数据库就会出错。
    以上两个实例方法都可以创建或者打开一个现有的数据库,如果数据库已经存在,则直接打开,否则,创建一个新的数据库。

SQLiteOpenHelper中的两个构造方法:

一般情况下,我们使用参数少的那个构造函数(上图中第一个),这个构造函数里面有四个参数:

  • 第一个参数Context类型:表示上下文对象。
  • 第二个参数String类型:表示数据库的名字。
  • 第三个参数CursorFactory类型:一般我们填入null。
  • 第四个参数int类型:表示数据库版本,用于对数据库进行升级操作。
    注:构建完成SQLiteOpenHelper的实例之后,再调用getReadableDatabase()或者getWritableDatabase()方法就可以创建数据库了。
    创建完成的数据库存放的地址:/data/data/ /databases/目录。

2、使用SQl操作数据库。
在上面我们已经知道调用getReadableDatabase()或者getWritableDatabase()可以用于创建和升级数据库,不仅如此,这两个方法可以返回一个SQLiteDatabase对象,我们可以用这个对象完成数据库的CRUD操作。
(1)通过使用原生的SQL语句操作数据库:

  • execSQL(String sql , Object[] args) 执行带占位符的sql语句(update,insert,delete语句)。
 String sql_insert="insert into user(account,password) values(?,?)";db.execSQL(sql_insert,new String[]{account,password});
  • rawQuery( String sql , String[] args ) 执行带占位符的sql查询(select语句)。
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对象。因此,要获取查询结果的话,要根据游标的指示一条一条的遍历结果集合即可。

  • insert():插入数据
 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); // 插入第二条数据            }        });
  • update():更新数据
 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" });            }        });
  • delete():删除数据
 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" });            }        });
  • query():查询数据
 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();            }        });

下面是一个具体的简单的案例项目:使用了上篇文章中自定义适配器的相关知识点。

关键词:SQLite的CRUD操作、自定义数据适配器、ListView、对话框、监听器、各种控件的应用。

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控件,主要显示,学生的学号、姓名、分数。
  • 三个ImageView控件,显示,向上、向下箭头图标及删除图标。

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操作数据库的相关知识。

若文章中有错误的地方欢迎大家反馈或者留言,十分感谢!!!

更多相关文章

  1. Android中的EditText默认时不弹出软键盘的方法
  2. Android中文API(127) ―― MessageQueue
  3. android的sqlite数据库中单引号的诡异作用
  4. Android(安卓)失去焦点,关闭弹出的软键盘
  5. Android(安卓)Studio 如何快速添加override或者implements方法
  6. Android(安卓)studio虚拟机adb环境配置
  7. Android(安卓)Mms专题之:Android短彩信收发流程(Framework)
  8. android实现异步加载图片
  9. Android(安卓)Studio 常见问题集锦

随机推荐

  1. Android(安卓)UI - 右侧滑动实现A-Z的快
  2. [翻译]Android单手指缩放-第三部分(Androi
  3. Android(安卓)5.0学习之使用Material主题
  4. tools:text和android:text
  5. 安居客Android项目架构演进
  6. Android(安卓)View分区域点击实现方案—
  7. Android(安卓)二维码扫描源码下载
  8. Android中TextView文字镂空效果的实现
  9. Proguard混淆器Android
  10. Android多进程保活