Android开发教程之ContentProvider数据存储
一、contentprovider保存数据介绍
一个程序可以通过实现一个contentprovider的抽象接口将自己的数据完全暴露出去,而且contentprovider是以类似数据库中表的方式将数据暴露的。那么外界获取其提供的数据,也就应该与从数据库中获取数据的操作基本一样,只不过是采用url来表示外界需要访问的“数据库”。
contentprovider提供了一种多应用间数据共享的方式。
contentprovider是个实现了一组用于提供其他应用程序存取数据的标准方法的类。应用程序可以在contentprovider中执行如下操作:查询数据、修改数据、添加数据、删除数据。
标准的contentprovider:android提供了一些已经在系统中实现的标准contentprovider,比如联系人信息,图片库等等,可以用这些contentprovider来访问设备上存储的联系人信息、图片等等。
在contentprovider中使用的查询字符串有别于标准的sql查询,很多诸如select、add、delete、modify等操作都使用一种特殊的url进行,这种url由3部分组成,“content://”,代表数据的路径和一个可选的表示数据的id。
content://media/internal/images 这个url将返回设备上存储的所有图片
content://contacts/people/ 这个url将返回设备上的所有联系人信息
content://contacts/people/45 这个url返回单个结果(联系人信息中id为45的联系人记录)
如果想要存储字节型数据,比如位图文件等,那保存该数据的数据列其实是一个表示实际保存保存文件的url字符串,客户端通过它来读取对应的文件数据,处理这种数据类型的contentprovider需要实现一个名为_data的字段,_data字段列出了该文件在android文件系统上的精确路径。这个字段不仅是供客户端使用,而且也可以供contentresolver使用。客户端可以调用contentresolver.openoutputstream()方法来处理该url指向的文件资源,如果是contentresolver本身的话,由于其持有的权限比客户端要高,所以它能直接访问该数据文件。
二、使用方法
大多数contentprovider使用android文件系统或者sqlite数据库来保持数据,但是也可以以任何方式来存储。本例用sqlite数据库来保持数据。
1.创建一个接口,定义了一个名为content_url,并且是public static final的uri类型的类变量,必须为其指定一个唯一的字符串值,最好的方案是类的全称,和数据列的名称。
public interface iproivdermetadata { public static final string authority = "com.zhangmiao.datastoragedemo"; public static final string db_name = "book.db"; public static final int version = 1; public interface booktablemetadata extends basecolumns { public static final string table_name = "book"; public static final uri content_uri = uri.parse("content://" + authority + "/" + table_name); public static final string book_id = "_id"; public static final string book_name = "name"; public static final string book_publisher = "publisher"; public static final string sort_order = "_id desc"; public static final string content_list = "vnd.android.cursor.dir/vnd.bookprovider.book"; public static final string content_item = "vnd.android.cursor.item/vnd.bookprovider.book"; } }
2.实现sqliteopenhelper
public class contentproviderdbhelper extends sqliteopenhelper implements iproivdermetadata { private static final string tag = "contentproviderdbhelper"; public contentproviderdbhelper(context context) { super(context, db_name, null, version); } @override public void oncreate(sqlitedatabase db) { ... } @override public void onupgrade(sqlitedatabase db, int oldversion, int newversion) { ... } }
3.创建一个继承了contentprovider父类的类
public class contentproviderdbhelper extends sqliteopenhelper implements iproivdermetadata { public contentproviderdbhelper(context context) { super(context, db_name, null, version); } @override public void oncreate(sqlitedatabase db) { ... } @override public void onupgrade(sqlitedatabase db, int oldversion, int newversion) { ... } }
4.在androidmanifest.xml中使用标签来设置调用contentprovider。
<provider android:authorities="com.zhangmiao.datastoragedemo" android:name=".bookcontentprovider"/>
5.增加数据
mcontentresolver = getcontentresolver(); string[] booknames = new string[]{"chinese", "math", "english", "sports"}; string[] bookpublishers = new string[]{"xinhua", "gongxin", "dianzi", "youdian"}; for (int i = 0; i < booknames.length; i++) { contentvalues values = new contentvalues(); values.put(iproivdermetadata.booktablemetadata.book_name, booknames[i]); values.put(iproivdermetadata.booktablemetadata.book_publisher, bookpublishers[i]); mcontentresolver.insert(iproivdermetadata.booktablemetadata.content_uri, values); }
6.删除数据
string bookid = "1"; if (!"".equals(bookid)) { contentvalues values1 = new contentvalues(); values1.put(iproivdermetadata.booktablemetadata.book_id,bookid); mcontentresolver.delete(uri.withappendedpath( iproivdermetadata.booktablemetadata.content_uri, bookid), "_id = ?", new string[]{bookid} ); } else { mcontentresolver.delete( iproivdermetadata.booktablemetadata.content_uri, null, null ); }
7.查询数据
cursor cursor = mcontentresolver.query(iproivdermetadata.booktablemetadata.content_uri, null, null, null, null); string text = ""; if (cursor != null) { while (cursor.movetonext()) { string bookidtext = cursor.getstring(cursor.getcolumnindex(iproivdermetadata.booktablemetadata.book_id)); string booknametext = cursor.getstring(cursor.getcolumnindex(iproivdermetadata.booktablemetadata.book_name)); string bookpublishertext = cursor.getstring(cursor.getcolumnindex(iproivdermetadata.booktablemetadata.book_publisher)); text += "id = " + bookidtext + ",name = " + booknametext + ",publisher = " + bookpublishertext + "\n"; } cursor.close(); mtableinfo.settext(text); }
8.更新数据
string bookid1 = "2"; string bookname = "art"; string bookpublisher = "tiedao"; contentvalues values2 = new contentvalues(); values2.put(iproivdermetadata.booktablemetadata.book_name,bookname); values2.put(iproivdermetadata.booktablemetadata.book_publisher,bookpublisher); if ("".equals(bookid1)) { mcontentresolver.update(iproivdermetadata.booktablemetadata.content_uri, values2, null, null); } else { mcontentresolver.update(uri.withappendedpath(iproivdermetadata.booktablemetadata.content_uri, bookid1), values2, "_id = ? ", new string[]{bookid1} ); }
三、小案例
1.添加strings.xml文件
<string name="content_provider">contentprovider</string> <string name="add_data">增加数据</string> <string name="delete_data">删除数据</string> <string name="update_data">更改数据</string> <string name="query_data">查询数据</string>
2.修改activity_main.xml文件
<?xml version="1.0" encoding="utf-8"?> <android.support.design.widget.coordinatorlayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:fitssystemwindows="true" tools:context="com.zhangmiao.datastoragedemo.mainactivity"> <linearlayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <textview android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_horizontal" android:text="@string/content_provider" /> <linearlayout android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginbottom="@dimen/fab_margin" android:layout_margintop="@dimen/fab_margin" android:orientation="horizontal"> <button android:id="@+id/provider_add" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:text="@string/add_data" /> <button android:id="@+id/provider_delete" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:text="@string/delete_data" /> <button android:id="@+id/provider_update" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:text="@string/update_data" /> <button android:id="@+id/provider_query" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:text="@string/query_data" /> </linearlayout> <textview android:id="@+id/table_info" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="@string/app_name" /> </linearlayout> </android.support.design.widget.coordinatorlayout>
3.添加iprovidermetadata接口
package com.zhangmiao.datastoragedemo; import android.net.uri; import android.provider.basecolumns; /** * created by zhangmiao on 2016/12/20. */ public interface iprovidermetadata { public static final string authority = "com.zhangmiao.datastoragedemo"; public static final string db_name = "book.db"; public static final int version = 1; public interface booktablemetadata extends basecolumns { public static final string table_name = "book"; public static final uri content_uri = uri.parse("content://" + authority + "/" + table_name); public static final string book_id = "_id"; public static final string book_name = "name"; public static final string book_publisher = "publisher"; public static final string sort_order = "_id desc"; public static final string content_list = "vnd.android.cursor.dir/vnd.bookprovider.book"; public static final string content_item = "vnd.android.cursor.item/vnd.bookprovider.book"; } }
4.添加contentproviderdbhelper类
package com.zhangmiao.datastoragedemo; import android.content.context; import android.database.sqlite.sqlitedatabase; import android.database.sqlite.sqliteopenhelper; import android.util.log; /** * created by zhangmiao on 2016/12/20. */ public class contentproviderdbhelper extends sqliteopenhelper implements iprovidermetadata { private static final string tag = "contentproviderdbhelper"; public contentproviderdbhelper(context context) { super(context, db_name, null, version); } @override public void oncreate(sqlitedatabase db) { string tablesql = "create table if not exists " + booktablemetadata.table_name + " (" + booktablemetadata.book_id + " integer primary key autoincrement," + booktablemetadata.book_name + " varchar," + booktablemetadata.book_publisher + " varchar)"; db.execsql(tablesql); } @override public void onupgrade(sqlitedatabase db, int oldversion, int newversion) { log.w(tag, "upgrading database from version " + oldversion + "to" + newversion + ", which will destroy all old data"); db.execsql("drop table if exists " + db_name); oncreate(db); } }
5.添加bookcontentprovider类
package com.zhangmiao.datastoragedemo; import android.content.contentprovider; import android.content.contenturis; import android.content.contentvalues; import android.content.urimatcher; import android.database.cursor; import android.database.sqlite.sqlitedatabase; import android.net.uri; import android.support.annotation.nullable; import android.util.log; /** * created by zhangmiao on 2016/12/21. */ public class bookcontentprovider extends contentprovider { private static final string tag = "bookcontentprovider"; private static urimatcher urimatcher = null; private static final int books = 1; private static final int book = 2; private contentproviderdbhelper dbhelper; private sqlitedatabase db; static { urimatcher = new urimatcher(urimatcher.no_match); urimatcher.adduri(iprovidermetadata.authority, iprovidermetadata.booktablemetadata.table_name, books); urimatcher.adduri(iprovidermetadata.authority, iprovidermetadata.booktablemetadata.table_name + "/#", book); } @override public boolean oncreate() { dbhelper = new contentproviderdbhelper(getcontext()); return (dbhelper == null) ? false : true; } @nullable @override public string gettype(uri uri) { switch (urimatcher.match(uri)) { case books: return iprovidermetadata.booktablemetadata.content_list; case book: return iprovidermetadata.booktablemetadata.content_item; default: throw new illegalargumentexception("this is a unknow uri" + uri.tostring()); } } @nullable @override public uri insert(uri uri, contentvalues values) { switch (urimatcher.match(uri)) { case books: db = dbhelper.getwritabledatabase(); long rowid = db.insert( iprovidermetadata.booktablemetadata.table_name, iprovidermetadata.booktablemetadata.book_id, values); uri inserturi = uri.withappendedpath(uri, "/" + rowid); log.i(tag, "inserturi:" + inserturi.tostring()); getcontext().getcontentresolver().notifychange(uri, null); return inserturi; case book: default: throw new illegalargumentexception("this is a unknow uri" + uri.tostring()); } } @nullable @override public cursor query(uri uri, string[] projection, string selection, string[] selectionargs, string sortorder) { db = dbhelper.getreadabledatabase(); switch (urimatcher.match(uri)) { case books: return db.query(iprovidermetadata.booktablemetadata.table_name, projection, selection, selectionargs, null, null, sortorder); case book: long id = contenturis.parseid(uri); string where = "_id=" + id; if (selection != null && !"".equals(selection)) { where = selection + " and " + where; } return db.query(iprovidermetadata.booktablemetadata.table_name, projection, where, selectionargs, null, null, sortorder); default: throw new illegalargumentexception("this is a unknow uri" + uri.tostring()); } } @override public int delete(uri uri, string selection, string[] selectionargs) { db = dbhelper.getwritabledatabase(); switch (urimatcher.match(uri)) { case books: return db.delete(iprovidermetadata.booktablemetadata.table_name, selection, selectionargs); case book: long id = contenturis.parseid(uri); string where = "_id=" + id; if (selection != null && !"".equals(selection)) { where = selection + " and " + where; } return db.delete(iprovidermetadata.booktablemetadata.table_name, selection, selectionargs); default: throw new illegalargumentexception("this is a unknow uri" + uri.tostring()); } } @override public int update(uri uri, contentvalues values, string selection, string[] selectionargs) { db = dbhelper.getwritabledatabase(); switch (urimatcher.match(uri)) { case books: return db.update(iprovidermetadata.booktablemetadata.table_name, values, null, null); case book: long id = contenturis.parseid(uri); string where = "_id=" + id; if (selection != null && !"".equals(selection)) { where = selection + " and " + where; } return db.update(iprovidermetadata.booktablemetadata.table_name, values, selection, selectionargs); default: throw new illegalargumentexception("this is a unknow uri" + uri.tostring()); } } }
6.修改androidmanifest.xml文件
<provider android:authorities="com.zhangmiao.datastoragedemo" android:name=".bookcontentprovider"/>
7.修改mainactivity
package com.zhangmiao.datastoragedemo; import android.content.contentresolver; import android.content.contentvalues; import android.database.cursor; import android.net.*; import android.os.bundle; import android.support.v7.app.appcompatactivity; import android.util.log; import android.view.view; import android.widget.button; import android.widget.textview;import java.util.arraylist; import java.util.list; public class mainactivity extends appcompatactivity implements view.onclicklistener {private contentresolver mcontentresolver; private bookcontentprovider mbookcontentprovider;private textview mtableinfo; @override protected void oncreate(bundle savedinstancestate) { log.v("mainactivity", "oncreate"); super.oncreate(savedinstancestate); setcontentview(r.layout.activity_main); button cpadd = (button) findviewbyid(r.id.provider_add); button cpdelete = (button) findviewbyid(r.id.provider_delete); button cpupdate = (button) findviewbyid(r.id.provider_update); button cpquery = (button) findviewbyid(r.id.provider_query); mtableinfo = (textview) findviewbyid(r.id.table_info); cpadd.setonclicklistener(this); cpdelete.setonclicklistener(this); cpquery.setonclicklistener(this); cpupdate.setonclicklistener(this); } @override public void onclick(view v) { switch (v.getid()) {case r.id.provider_add: mcontentresolver = getcontentresolver(); string[] booknames = new string[]{"chinese", "math", "english", "sports"}; string[] bookpublishers = new string[]{"xinhua", "gongxin", "dianzi", "youdian"}; for (int i = 0; i < booknames.length; i++) { contentvalues values = new contentvalues(); values.put(iprovidermetadata.booktablemetadata.book_name, booknames[i]); values.put(iprovidermetadata.booktablemetadata.book_publisher, bookpublishers[i]); mcontentresolver.insert(iprovidermetadata.booktablemetadata.content_uri, values); } break; case r.id.provider_delete: string bookid = "1"; if (!"".equals(bookid)) { contentvalues values1 = new contentvalues(); values1.put(iprovidermetadata.booktablemetadata.book_id, bookid); mcontentresolver.delete( uri.withappendedpath( iprovidermetadata.booktablemetadata.content_uri, bookid ), "_id = ?", new string[]{bookid} ); } else { mcontentresolver.delete( iprovidermetadata.booktablemetadata.content_uri, null, null ); } break; case r.id.provider_query: cursor cursor = mcontentresolver.query(iprovidermetadata.booktablemetadata.content_uri, null, null, null, null); string text = ""; if (cursor != null) { while (cursor.movetonext()) { string bookidtext = cursor.getstring(cursor.getcolumnindex(iprovidermetadata.booktablemetadata.book_id)); string booknametext = cursor.getstring(cursor.getcolumnindex(iprovidermetadata.booktablemetadata.book_name)); string bookpublishertext = cursor.getstring(cursor.getcolumnindex(iprovidermetadata.booktablemetadata.book_publisher)); text += "id = " + bookidtext + ",name = " + booknametext + ",publisher = " + bookpublishertext + "\n"; } cursor.close(); mtableinfo.settext(text); } break; case r.id.provider_update: string bookid1 = "2"; string bookname = "art"; string bookpublisher = "tiedao"; contentvalues values2 = new contentvalues(); values2.put(iprovidermetadata.booktablemetadata.book_name, bookname); values2.put(iprovidermetadata.booktablemetadata.book_publisher, bookpublisher); if ("".equals(bookid1)) { mcontentresolver.update( iprovidermetadata.booktablemetadata.content_uri, values2, null, null); } else { mcontentresolver.update( uri.withappendedpath( iprovidermetadata.booktablemetadata.content_uri, bookid1), values2, "_id = ? ", new string[]{bookid1}); } break;default: log.v("mainactivity", "default"); break; } } }
推荐阅读
-
Android开发教程之ContentProvider数据存储
-
Android开发教程之ContentProvider数据存储
-
Android开发笔记之Android中数据的存储方式(一)
-
Android开发笔记之Android中数据的存储方式(二)
-
Android数据存储操作⑥ContentProvider、ContentResolver
-
Android开发笔记之Android中数据的存储方式(一)
-
Android开发笔记之Android中数据的存储方式(二)
-
详解Android开发数据持久化之文件存储(附源码)
-
Android应用开发SharedPreferences存储数据的使用方法
-
详解Android开发数据持久化之文件存储(附源码)