Geekband006第六周笔记分享

来源:互联网 发布:富士触摸屏编程软件 编辑:程序博客网 时间:2024/05/14 21:07

SQLite数据库简介

– 轻量级 : SQLite数据库是一个轻量级的数据库, 适用于少量数据的CURD;
– 文件本质 : SQLite数据库支持大部分SQL语法, 允许使用SQL语句操作数据库, 其本质是一个文件, 不需要安装启动;
– 数据读写 : SQLite数据库打开只是打开了一个文件的读写流, 如果有大数据量读写, 需要高并发存储, 那么就不应该使用SQLite;

创建和打开数据库的方法

使用openOrCreateDatabase()方法来创建,若数据库不存在,则会创建新数据库,若存在,则打开数据库。

打开数据库 : 根据数据库文件 对象打开数据库, 如果数据库不存在就创建数据库

public static SQLiteDatabase openOrCreateDatabase (File file, SQLiteDatabase.CursorFactory factory)  

打开数据库 : 根据数据库文件 路径打开数据库, 如果数据库不存在就创建数据库

public static SQLiteDatabase openOrCreateDatabase (String path, SQLiteDatabase.CursorFactory factory)  

使用insert方法插入记录

SQLiteDatabase的insert方法的签名为

long insert(String table,String nullColumnHack,ContentValues values)

这个插入方法的参数说明如下:
table:代表想插入数据的表名。
nullColumnHack:代表强行插入null值的数据列的列名。
values:代表一行记录的数据。
insert方法插入的一行记录使用ContentValues存放,ContentValues类似于Map,它提供了put(String key,Xxx value)(其中key为数据列的列名)方法用于存入数据、getAsXxx(String key)方法用于取出数据。
例如如下语句:

ContentValues values=new ContentValues();values.put("name","孙悟空"):values.put("age",500);//返回新添记录的行号,该行号是一个内部直,与主键id无关,发生错误返回-1long rowid=db.insert("person_inf",null,values);

使用update方法更新数据

SQLiteDatabase的update方法签名为

update(String table,ContentValues values,String whereClause,String[] whereArgs)

这个更新方法的参数说明如下:
table:代表想要更新数据的表名。
values:代表想要更新的数据。
whereClause:满足该whereClause子句的记录将会被更新。
whereArgs:用于为whereArgs子句传递参数。
例如我们想要更新person_inf表中所有主键大于20的人的人名,可调用如下方法:

ContentValues values=new ContentValues();//存放更新后的人名values.put("name","新人名");int result=db.update("person_inf",values,"_id>?",new Integer[]{20});

使用delete方法删除记录

SQLiteDatabase的delete方法签名为

delete(String table,String whereClause,String[] whereArgs)

这个删除的参数说明如下:
table:代表想删除数据的表名。
whereClause:满足该whereClause子句的记录将会被删除。
whereArgs:用于为whereArgs子句传入参数。
删除person_inf表中所有人名以孙开头的记录

int result=db.delete("person_inf","person_name like ?",new String[]{"孙_"});

使用query方法查询记录

SQLiteDatabase的query方法签名为

Cursor query(boolean distinct,String table,String[] columns,String selection,String[] selectionArgs,String groupBy,String having,String orderBy,String limit)

这个query方法的参数说明如下。
distinct:指定是否去除重复记录。
table:执行查询数据的表名。
columns:要查询出来的列名。
selection:查询条件子句。
selectionArgs:用于为selection子句中占位符传入参数值,值在数组中的位置与占位符在语句中的位置必须一致,否则就会有异常。
groupBy:用于控制分组。
having:用于对分组进行过滤。
orderBy:用于对记录进行排序。
limit:用于进行分页。

例如查询出person_inf表中人名以孙开头的数据

Cursor cursor=db.query("person_inf",new String[]{"_id,name,age"},"name like ?",new String []{"孙%"},null,null,"personid desc","5,10");cursor.close();

SQLiteOpenHelper

Android平台提供给我们一个数据库辅助类来创建或打开数据库,管理数据库的版本,这个辅助类继承自SQLiteOpenHelper类

创建一个新的class如下所示,onCreate(SQLiteDatabase db)和onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion)方法会被自动添加。

package android.geekband006;import android.content.ContentValues;import android.content.Context;import android.database.sqlite.SQLiteDatabase;import android.database.sqlite.SQLiteOpenHelper;/** * Created by cm on 16/3/31. */public class MyDatabaseHelper extends SQLiteOpenHelper {    public static final String DATABASE_NAME = "geekband.db";    public static final String USER_INFO_TABLE_NAME = "user_info";    public static final String USER_NAME = "user_name";    public static final String USER_PASSWORD = "user_password";    public static final String LOGIN_STATE = "login_state";    public static final String LAST_LOGIN_TIME = "last_login_time";    public static final int VERSION = 1;    public static final int NOT_ACTIVE = 0;    public static final int IS_ACTIVE = 1;    public static final long INIT_TIME = 0;//    String user1 = "'user1'," +    public MyDatabaseHelper(Context context) {        super(context, DATABASE_NAME, null, VERSION);    }    @Override    public void onCreate(SQLiteDatabase db) {        db.execSQL("create table " + USER_INFO_TABLE_NAME + " ("                        + USER_NAME + " varchar(20) NOT NULL PRIMARY KEY, "                        + USER_PASSWORD + " varchar(20) NOT NULL, "                        + LOGIN_STATE + " int NOT NULL, "                        + LAST_LOGIN_TIME + " int NOT NULL);");        long time = INIT_TIME;        insertInfo(db, "user1", "user1", NOT_ACTIVE, time);        insertInfo(db, "user2", "user2", IS_ACTIVE, time);    }    public void insertInfo(SQLiteDatabase db, String name, String password, int state, long time) {        ContentValues contentValues = new ContentValues();        contentValues.put(USER_NAME, name);        contentValues.put(USER_PASSWORD, password);        contentValues.put(LOGIN_STATE, state);        contentValues.put(LAST_LOGIN_TIME,time);        db.insert(USER_INFO_TABLE_NAME, null, contentValues);    }    @Override    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {    }}

SQLiteOpenHelper 的构造函数,当数据库不存在时,就会创建数据库,然后打开数据库(过程已经被封装起来了),再调用onCreate (SQLiteDatabase db)方法来执行创建表之类的操作。当数据库存在时,SQLiteOpenHelper 就不会调用onCreate (SQLiteDatabase db)方法了,它会检测版本号,若传入的版本号高于当前的,就会执行onUpgrade()方法来更新数据库和版本号。

创建完SQLiteOpenHelper 类之后,在主activity里面就可以通过SQLiteOpenHelper.getWritableDatabase()或者getReadableDatabase()方法来获取在SQLiteOpenHelper 类里面创建的数据库实例。(也就是说只有调用这两种方法才真正地实例化数据库)

getWritableDatabase() 方法——以读写方式打开数据库,如果数据库所在磁盘空间满了,而使用的又是getWritableDatabase() 方法就会出错。因为此时数据库就只能读而不能写.

getReadableDatabase()方法——则是先以读写方式打开数据库,如果数据库的磁盘空间满了,就会打开失败,但是当打开失败后会继续尝试以只读方式打开数据库不会报错

关于 Cursor

在你理解和使用 Android Cursor 的时候你必须先知道关于 Cursor 的几件事情:
Cursor 是每行的集合。
使用 moveToFirst() 定位第一行。
你必须知道每一列的名称。
你必须知道每一列的数据类型。
Cursor 是一个随机的数据源。
所有的数据都是通过下标取得。
Cursor 位于 android.database.Cursor类,可见出它的设计是基于数据库服务产生的。
在Android 查询数据是通过Cursor 类来实现的。当我们使用 SQLiteDatabase.query()方法时,就会得到Cursor对象, Cursor所指向的就是每一条数据。

关于 Cursor 的重要方法

close()
关闭游标,释放资源

copyStringToBuffer(int columnIndex, CharArrayBuffer buffer)
在缓冲区中检索请求的列的文本,将将其存储

getColumnCount()
返回所有列的总数

getColumnIndex(String columnName)
返回指定列的名称,如果不存在返回-1

getColumnIndexOrThrow(String columnName)
从零开始返回指定列名称,如果不存在将抛出IllegalArgumentException 异常。

getColumnName(int columnIndex)
从给定的索引返回列名

getColumnNames()
返回一个字符串数组的列名

getCount()
返回Cursor 中的行数

moveToFirst()
移动光标到第一行

moveToLast()
移动光标到最后一行

moveToNext()
移动光标到下一行

moveToPosition(int position)
移动光标到一个绝对的位置

moveToPrevious()
移动光标到上一行

小例子:
(1) 为空的Cursor的判断
if (cur.moveToFirst() == false)
{
//为空的Cursor
return;
}

(2) 访问 Cursor 的下标获得其中的数据

int nameColumnIndex = cur.getColumnIndex(People.NAME);
String name = cur.getString(nameColumnIndex);

(3)循环 Cursor 取出需要的数据

while(cur.moveToNext())
{
//光标移动成功
//把数据取出
}

当cur.moveToNext() 为假时将跳出循环,即Cursor数据循环完毕。

如果你喜欢用 for 循环而不想用While 循环可以使用Google 提供的几下方法:
isBeforeFirst()
返回游标是否指向之前第一行的位置

isAfterLast()
返回游标是否指向第最后一行的位置

isClosed()
如果返回 true 即表示该游戏标己关闭

有了以上的方法,可以如此取出数据:

AbstractCursorfor(cur.moveToFirst();!cur.isAfterLast();cur.moveToNext()){    int nameColumn = cur.getColumnIndex(People.NAME);    int phoneColumn = cur.getColumnIndex(People.NUMBER);    String name = cur.getString(nameColumn);    String phoneNumber = cur.getString(phoneColumn);}

使用ContentProvider(内容提供者)共享数据

ContentProvider在android中的作用是对外共享数据,也就是说你可以通过ContentProvider把应用中的数据共享给其他应用访问,其他应用可以通过ContentProvider对你应用中的数据进行添删改查。关于数据共享,以前我们学习过文件操作模式,知道通过指定文件的操作模式为Context.MODE_WORLD_READABLE或Context.MODE_WORLD_WRITEABLE同样也可以对外共享数据。那么,这里为何要使用ContentProvider对外共享数据呢?是这样的,如果采用文件操作模式对外共享数据,数据的访问方式会因数据存储的方式而不同,导致数据的访问方式无法统一,如:采用xml文件对外共享数据,需要进行xml解析才能读取数据;采用sharedpreferences共享数据,需要使用sharedpreferences API读取数据。
使用ContentProvider对外共享数据的好处是统一了数据的访问方式。
当应用需要通过ContentProvider对外共享数据时,第一步需要继承ContentProvider并重写下面方法:

public class PersonContentProvider extends ContentProvider{   public boolean onCreate()   public Uri insert(Uri uri, ContentValues values)   public int delete(Uri uri, String selection, String[] selectionArgs)   public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs)   public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder)   public String getType(Uri uri)}

第二步需要在AndroidManifest.xml使用对该ContentProvider进行配置,为了能让其他应用找到该ContentProvider ,ContentProvider采用了authorities(主机名/域名)对它进行唯一标识,你可以把ContentProvider看作是一个网站(想想,网站也是提供数据者),authorities 就是他的域名:

<manifest.... >   <application android:icon="@drawable/icon" android:label="@string/app_name">      <provider android:name=".PersonContentProvider"            android:authorities="com.ljq.providers.personprovider"/>   </application></manifest>

Uri介绍

Uri代表了要操作的数据,Uri主要包含了两部分信息:1》需要操作的ContentProvider ,2》对ContentProvider中的什么数据进行操作,一个Uri由以下几部分组成:
ContentProvider(内容提供者)的scheme已经由Android所规定, scheme为:content://
主机名(或叫Authority)用于唯一标识这个ContentProvider,外部调用者可以根据这个标识来找到它。
路径(path)可以用来表示我们要操作的数据,路径的构建应根据业务而定,如下:
要操作person表中id为10的记录,可以构建这样的路径:/person/10
要操作person表中id为10的记录的name字段, person/10/name
要操作person表中的所有记录,可以构建这样的路径:/person
要操作xxx表中的记录,可以构建这样的路径:/xxx
当然要操作的数据不一定来自数据库,也可以是文件、xml或网络等其他存储方式,如下:
要操作xml文件中person节点下的name节点,可以构建这样的路径:/person/name
如果要把一个字符串转换成Uri,可以使用Uri类中的parse()方法,如下:

Uri uri = Uri.parse("content://com.ljq.provider.personprovider/person")

UriMatcher类使用介绍

因为Uri代表了要操作的数据,所以我们经常需要解析Uri,并从Uri中获取数据。Android系统提供了两个用于操作Uri的工具类,分别为UriMatcher和ContentUris 。掌握它们的使用,会便于我们的开发工作。
UriMatcher类用于匹配Uri,它的用法如下:
首先第一步把你需要匹配Uri路径全部给注册上,如下:

//常量UriMatcher.NO_MATCH表示不匹配任何路径的返回码UriMatcher  sMatcher = new UriMatcher(UriMatcher.NO_MATCH);//如果match()方法匹配content://com.ljq.provider.personprovider/person路径,返回匹配码为1sMatcher.addURI("com.ljq.provider.personprovider", "person", 1);//添加需要匹配uri,如果匹配就会返回匹配码//如果match()方法匹配content://com.ljq.provider.personprovider/person/230路径,返回匹配码为2sMatcher.addURI("com.ljq.provider.personprovider", "person/#", 2);//#号为通配符switch (sMatcher.match(Uri.parse("content://com.ljq.provider.personprovider/person/10"))) {    case 1     break;   case 2     break;   default://不匹配     break;}

注册完需要匹配的Uri后,就可以使用sMatcher.match(uri)方法对输入的Uri进行匹配,如果匹配就返回匹配码,匹配码是调用addURI()方法传入的第三个参数,假设匹配content://com.ljq.provider.personprovider/person路径,返回的匹配码为1

ContentUris类使用介绍

ContentUris类用于操作Uri路径后面的ID部分,它有两个比较实用的方法:
withAppendedId(uri, id)用于为路径加上ID部分:

Uri uri = Uri.parse("content://com.ljq.provider.personprovider/person")Uri resultUri = ContentUris.withAppendedId(uri, 10); //生成后的Uri为:content://com.ljq.provider.personprovider/person/10

parseId(uri)方法用于从路径中获取ID部分:

Uri uri = Uri.parse("content://com.ljq.provider.personprovider/person/10")long personid = ContentUris.parseId(uri);//获取的结果为:10

使用ContentProvider共享数据

ContentProvider类主要方法的作用:
public boolean onCreate():该方法在ContentProvider创建后就会被调用,Android开机后,ContentProvider在其它应用第一次访问它时才会被创建。
public Uri insert(Uri uri, ContentValues values):该方法用于供外部应用往ContentProvider添加数据。
public int delete(Uri uri, String selection, String[] selectionArgs):该方法用于供外部应用从ContentProvider删除数据。
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs):该方法用于供外部应用更新ContentProvider中的数据。
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder):该方法用于供外部应用从ContentProvider中获取数据。
public String getType(Uri uri):该方法用于返回当前Url所代表数据的MIME类型。

如果操作的数据属于集合类型,那么MIME类型字符串应该以vnd.android.cursor.dir/开头,

例如:要得到所有person记录的Uri为content://com.ljq.provider.personprovider/person,那么返回的MIME类型字符串应该为:”vnd.android.cursor.dir/person”。

如果要操作的数据属于非集合类型数据,那么MIME类型字符串应该以vnd.android.cursor.item/开头,

例如:得到id为10的person记录,Uri为content://com.ljq.provider.personprovider/person/10,那么返回的MIME类型字符串为:”vnd.android.cursor.item/person”。

使用ContentResolver操作ContentProvider中的数据

当外部应用需要对ContentProvider中的数据进行添加、删除、修改和查询操作时,可以使用ContentResolver 类来完成,要获取ContentResolver 对象,可以使用Activity提供的getContentResolver()方法。 ContentResolver 类提供了与ContentProvider类相同签名的四个方法:
public Uri insert(Uri uri, ContentValues values):该方法用于往ContentProvider添加数据。
public int delete(Uri uri, String selection, String[] selectionArgs):该方法用于从ContentProvider删除数据。
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs):该方法用于更新ContentProvider中的数据。
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder):该方法用于从ContentProvider中获取数据。

这些方法的第一个参数为Uri,代表要操作的ContentProvider和对其中的什么数据进行操作,

假设给定的是:Uri.parse(“content://com.ljq.providers.personprovider/person/10”),那么将会对主机名为com.ljq.providers.personprovider的ContentProvider进行操作,操作的数据为person表中id为10的记录。

使用ContentResolver对ContentProvider中的数据进行添加、删除、修改和查询操作:

ContentResolver resolver =  getContentResolver();Uri uri = Uri.parse("content://com.ljq.provider.personprovider/person");//添加一条记录ContentValues values = new ContentValues();values.put("name", "linjiqin");values.put("age", 25);resolver.insert(uri, values);  //获取person表中所有记录Cursor cursor = resolver.query(uri, null, null, null, "personid desc");while(cursor.moveToNext()){   Log.i("ContentTest", "personid="+ cursor.getInt(0)+ ",name="+ cursor.getString(1));}//把id为1的记录的name字段值更改新为zhangsanContentValues updateValues = new ContentValues();updateValues.put("name", "zhangsan");Uri updateIdUri = ContentUris.withAppendedId(uri, 2);resolver.update(updateIdUri, updateValues, null, null);//删除id为2的记录Uri deleteIdUri = ContentUris.withAppendedId(uri, 2);resolver.delete(deleteIdUri, null, null);
0 0
原创粉丝点击