Android开发(3):数据存储之二:SQlite数据库和ContentProvider数据分享(伪)

一、SQlite数据库

1. 简介

  • Android SDK包含了若干有用的SQLite数据库管理类

  • 大多都存在于android.database.sqlite包中

  • 包中含有许多功能包类:管理数据库的创建和版本信息、 数据库管理以及查询生成类等

  • 利用这些包能帮助你生成正确的SQL表达式和查询

  • 支持储存数据类型:NULL(空值),INTEGER(int),REAL(8byte浮点数),TEXT(String),BLOB(byte[],可以存储图像信息)

2. 数据库使用

(1)创建数据库

  • 使用上下文创建数据库,即构造函数参数需要有Context。

  • 创建的类需要继承SQLiteOpenHelper类。

  • 需要声明定义数据库名字DB_NAME,版本DB_VRESION。

  • 必须重写onCreate,onUpgrade函数,必须声明定义构造函数并super。

  • 在onCreate函数中创建数据表,onUpgrade为更新数据库版本。

  • 创建数据库访问对象时(即new一个对象),实际上没有创建数据库。 只有调用 getWritableDatabase()或getReadableDatabase() 时才会创建数据库 。

下面的类在数据库中创建了三张表,即“users”,“comments”,“likes”。

public class Mydata extends SQLiteOpenHelper {

    private static final String DB_NAME = "mydb.db";
    private static final int DB_VRESION = 1;
    private static final String UserTable = "users";
    private static final String CommentTable = "comments";
    private static final String LikesTable = "likes";
    
    //在这个数据库中创建三张表
    static final String SQL_CREATE_TABLE1 = "create table " + UserTable + " (username text primary key,"
            + " password text not null, image BLOB);";
    static final String SQL_CREATE_TABLE2 = "create table " + CommentTable + " (_id integer primary key autoincrement,"
            + " name text, message text, date text, likes integer);";
    static final String SQL_CREATE_TABLE3 = "create table " + LikesTable + " (_id integer primary key autoincrement,"
            + "liker text, date text);";


    public Mydata(Context c){
        super(c, DB_NAME, null, DB_VRESION);
    }

    @Override
    public void onCreate(SQLiteDatabase db) {
        db.execSQL(SQL_CREATE_TABLE1);
        db.execSQL(SQL_CREATE_TABLE2);
        db.execSQL(SQL_CREATE_TABLE3);
    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
		// db.execSQL("DROP TABLE IF EXISTS " + TABLE_NAME); 
        // onCreate(db);
    }

    public String getUserTable() {
        return UserTable;
    }

    public String getCommentTable() {
        return CommentTable;
    }

    public String getLikesTable() {
        return LikesTable;
    }
}

(2)创建实体类

创建实体类并不是必须的,但是没有实体类并不能很好地对数据库进行操作,比如使用listview来展示数据库中的数据,得先把数据读(查询)到本地来,而创建相关的类来临时保存数据库的数据就很有必要。

比如我们在上面创建了三张表,我们相应地就可以创建三个类,当然要是觉得数据表很简单不一定需要类来保存数据也可以。类需要有以下元素:属性、构造函数、属性Get函数、属性Set函数

例如:我们创建用来保存用户信息的类,当然现实中不可能将密码就这样直接赋值。

public class Users implements Serializable {
    byte[] image;
    String password;
    String name;

    public Users(){
        password = "";
    }

    public Users(byte[] image, String password, String name){
        this.image = image;
        this.password = password;
        this.name = name;
    }



    public void setImage(byte[]  image) {
        this.image = image;
    }

    public void setName(String name) {
        this.name = name;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public byte[] getImage() {
        return image;
    }

    public String getName() {
        return name;
    }

    public String getPassword() {
        return password;
    }
}

(3)数据操作(增删改查)

  • 可以通过execsql函数直接执行SQL命令来完成数据操作,就像我们上面建表一样,但如果嫌麻烦,也可以通过调用SQLiteDatabase类的公共函数insert()、delete()、update()和 query()这四个函数,封装了执行的添加、删除、更新和查询功能的 SQL命令 。具体函数解释可以查看官方文档或者查看实现代码。

  • 创建数据库对象

    mydata = new Mydata(this);//其实还没创建
    
  • insert()函数

    SQLiteDatabase db = mydata.getWritableDatabase();//真正创建了数据库对象
    ContentValues values = new ContentValues();//使用ContentValues声明表中数据
    values.put("username", name);
    values.put("password", password);
    values.put("image", image);
    //插入“users”表中,必须保证 values 至少一个字段不为null ,否则出错
    db.insert("users", null, values); 
    db.close(); //使用完记得调用close()
    
  • delete()函数

    //比较简单,将数据名称替换掉即可
    SQLiteDatabase db = getWritableDatabase();
    String whereClause = "_id = ?";
    String[] whereArgs = { id.toString() };
    //如果后两个参数均为null,则删除所有数据,delete返回一个int,代表删除掉数据量。
    db.delete(TABLE_NAME, whereClause, whereArgs); 
    db.close();
    
  • update()函数

    SQLiteDatabase db = getWritableDatabase();
    String whereClause = "_id = ?";
    String[] whereArgs = { entity.getId().toString() };
    ContentValues values = new ContentValues();
    values.put("name", entity.getName());
    values.put("info", entity.getInfo());
    //返回更新的数据量
    int rows = db.update(TABLE_NAME, values, whereClause, whereArgs); 
    db.close();
    
  • query()函数

    在Android系统中,数据库查询结果的返回值并不是数据集合的完整拷贝,而是返回数据集的指针,这个指针就是Cursor类;

    //注意使用的是getReadableDatabase函数,而不是前面三个的getWritableDatabase。
    SQLiteDatabase db = getReadableDatabase();
    String selection = "_id = ?";
    String[] selectionArgs = { id.toString() };
    //如果参数全为null,则返回所有数据
    Cursor c = db.query(TABLE_NAME, null, selection, selectionArgs, null,null, null); 
    //在从Cursor中提取数据之前,推荐先测试一下Cursor中的数据数量,避免 在数据获取的过程中产生异常情况。
    if (c.moveToFirst()){
    	User m = new User(c.getInt(0),c.getString(1),c.getString(2)); 
    }
    c.close();
    db.close();
    

    Cursor类支持在查询的数据集合中多种方式移动,并能够获取数据集合的属性名称和序号,Cursor类方法说明如下:

    函数 说明
    moveToFirst 将指针移动到第一条数据上
    moveToNext 将指针移动到下一条数据上
    moveToPrevious 将指针移动到上一条数据上
    getCount 获取集合的数据数量
    getColumnIndexOrThrow 返回指定属性名称的序号,如果属性不存在则产生异常
    getColumnName 返回指定序号的属性名称
    getColumnNames 返回属性名称的字符串数组
    getColumnIndex 根据属性名称返回序号
    moveToPosition 将指针移动到指定的数据上
    getPosition 返回当前指针的位置

3. 学习过程遇到的坑

  • 数据库中的表以及表之间关系设计要合理,如果有学过数据库应该就懂,好的表可以减少很多空间
  • 在使用上述四个函数如果表名或者values字段名字出错,是不会报错的,而且不会修改数据库的内容,所以要确保自己不会输入错误。
  • 需要修改数据时,要对本地数据以及数据库数据同时修改,如果既有用于listview的数据集合(开始时是从数据库读取出来的),又有数据库数据,千万不要先修改本地数据再修改数据库数据,因为当你修改完本地数据的时候,你再来修改数据库数据,可能会借助本地数据的下标来进行数据的条件限定,但因为已经先修改了本地数据,所以此时数据不是一一对应的。所以要先修改数据库再修改本地数据。

二、ContentProvider数据分享

不详讲,这个还没学会。

这里只举一个使用数据提供者的例子,你在某个App已经拥有一个用户名,如何获取通讯录(另一个App)中用户的电话号码。

  • 在AndroidManifest.xml文件添加权限,声明读取通讯录的权限

    <uses-permission android:name="android.permission.READ_CONTACTS"/>
    
  • 使用getContentResolver方法查询相应用户名

    Cursor cursor = getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI,null, ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME + " = \"" + username + "\"", null, null);
    
  • 读取查询到的号码(得确保不为空)

    cursor.moveToFirst();
    String number = "\nPhone: ";
    do {
        number += cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER)) + "         ";
    } while (cursor.moveToNext());
    

猜你喜欢

转载自blog.csdn.net/chenxz_/article/details/84332895