Android开发学习之路--Content Provider之初体验
Posted 东月之神
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android开发学习之路--Content Provider之初体验相关的知识,希望对你有一定的参考价值。
天气说变就变,马上又变冷了,还好空气不错,阳光也不错,早起上班的车上的人也不多,公司来的同事和昨天一样一样的,可能明天会多一些吧,那就再来学习android吧。学了两个android的组件,这里学习下第三个android的组件,Content Provider内容提供器。
Content Provider向我们提供了在不同应用程序之间的数据共享,比如微信啊,支付宝啊,想要获取手机联系人的信息,而手机联系人是另一个应用程序,那么这时候就需要用到Content Provider了。Content Provider为存储和获取数据提供了统一的接口,对数据进行了封装,我们不用关心数据存储的细节,使用表的形式来组织数据。Android提供了一些默认的ContentProvider,比如音频,视频,图片和通讯录等。
类似于文件,SharedPreferences或者SQLiteDataBase都有一个路径,那么ContentProvider也是有路径的,它的路径由Uri表示,Uri主要包含了两部分的信息,一个是需要操作的ContentProvider,另一个就是对ContentProvider中的什么数据进行操作。一个简单的Uri:
content://com.example.contentprovidertest.provider/person/2
scheme:content://表示,这个是android定义好的,不能改变的
主机名或者authority:com.example.contentprovidertest.provider表示,唯一的,一般指的是包名,
路径:person,表示的是person这个表,2表示id为2。
如果要把上面的字符串转变为uri,那么就要使用Uri类中的parse()方法,如下:
Uri uri=Uri.parse("content://com.example.contentprovidertest.provider/person/2");这里先来写个例子,用来获取通讯录中的信息吧。新建ContentProviderTest工程,因为模拟器的联系人还没有创建,这里先添加几个好友:
接着我们继续编写代码,先在layout中添加listview,因为通讯录一般都是用listview来实现的。代码如下:
<?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:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" tools:context="com.example.jared.contentprovidertest.MainActivity"> <ListView android:id="@+id/contacts" android:layout_height="match_parent" android:layout_width="match_parent"/> </LinearLayout>
这里就简单地加了一个listview,接着修改MainAcitivity代码:
package com.example.jared.contentprovidertest; import android.database.Cursor; import android.os.Bundle; import android.provider.ContactsContract; import android.support.v7.app.AppCompatActivity; import android.widget.ArrayAdapter; import android.widget.ListView; import java.util.ArrayList; import java.util.List; public class MainActivity extends AppCompatActivity { private ListView contactViews; ArrayAdapter<String> adapter; List<String> contactList = new ArrayList<String>(); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); contactViews = (ListView)findViewById(R.id.contacts); adapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, contactList); contactViews.setAdapter(adapter); readContacts(); } public void readContacts() { Cursor cursor = null; try { cursor = getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null, null, null, null); while(cursor.moveToNext()) { String ContactName = cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME)); String ContactPhoneNum = cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER)); contactList.add(ContactName+'\n'+ContactPhoneNum); } } catch (Exception e) { e.printStackTrace(); } finally { if(cursor != null){ cursor.close(); } } } }
这里用了string类型的适配器,然后通过cursor来获取联系人名字和电话号码,其中的名字和电话的定义最终也是字符串。
String DISPLAY_NAME = "display_name";
String NUMBER = "number";这个和数据库的存取很类似,接着在AndroidManifest中添加权限:
<uses-permission android:name="android.permission.READ_CONTACTS"/>然后运行app,效果如下:
由上可知,获得了三个联系人的信息,也就是我们刚保存的信息。
接着学习自定义的ContentProvider,这里借用了dbtest中的MyDBHelper类,新建myContenProvider类,代码如下:
package com.example.jared.contentprovidertest; import android.content.ContentProvider; 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; /** * Created by jared on 16/2/15. */ public class myContentProvider extends ContentProvider { public static final int PERSON_DIR = 0; public static final int PERSON_ITEM = 1; public static final int TEACHER_DIR = 2; public static final int TEACHER_ITEM = 3; private static UriMatcher uriMatcher; private static final String AUTHORITY = "com.example.jared.contentprovidertest.provider"; private MyDBHelper myDBHelper; static { uriMatcher = new UriMatcher(UriMatcher.NO_MATCH); uriMatcher.addURI(AUTHORITY, "person", PERSON_DIR); uriMatcher.addURI(AUTHORITY, "person/#", PERSON_ITEM); uriMatcher.addURI(AUTHORITY, "teacher", TEACHER_DIR); uriMatcher.addURI(AUTHORITY, "teacher/#", TEACHER_DIR); } @Override public boolean onCreate() { myDBHelper = new MyDBHelper(getContext(), "PersonStore.db", null, 2); return true; } @Override public int update(Uri uri, ContentValues contentValues, String s, String[] strings) { SQLiteDatabase db = myDBHelper.getWritableDatabase(); int updateRows = 0; switch (uriMatcher.match(uri)) { case PERSON_DIR: updateRows = db.update("person", contentValues, s, strings); break; case PERSON_ITEM: String personId = uri.getPathSegments().get(1); updateRows = db.update("person", contentValues, "id = ?", new String[]{personId}); break; case TEACHER_DIR: updateRows = db.update("teacher", contentValues, s, strings); break; case TEACHER_ITEM: String teacherId = uri.getPathSegments().get(1); updateRows = db.update("teacher", contentValues, "id = ?", new String[]{teacherId}); break; default: break; } return updateRows; } @Override public int delete(Uri uri, String s, String[] strings) { SQLiteDatabase db = myDBHelper.getWritableDatabase(); int deleteRows = 0; switch (uriMatcher.match(uri)) { case PERSON_DIR: deleteRows = db.delete("person", s, strings); break; case PERSON_ITEM: String personId = uri.getPathSegments().get(1); deleteRows = db.delete("person", "id = ?", new String[]{personId}); break; case TEACHER_DIR: deleteRows = db.delete("teacher", s, strings); break; case TEACHER_ITEM: String teacherId = uri.getPathSegments().get(1); deleteRows = db.delete("teacher", "id = ?", new String[]{teacherId}); break; default: break; } return deleteRows; } @Nullable @Override public String getType(Uri uri) { switch (uriMatcher.match(uri)) { case PERSON_DIR: return "vnd.android.cursor.dir/vnd."+AUTHORITY+".person"; //break; case TEACHER_DIR: return "vnd.android.cursor.dir/vnd."+AUTHORITY+".teacher"; //break; case PERSON_ITEM: return "vnd.android.cursor.item/vnd."+AUTHORITY+".person"; //break; case TEACHER_ITEM: return "vnd.android.cursor.item/vnd."+AUTHORITY+".teacher"; //break; default: break; } return null; } @Nullable @Override public Cursor query(Uri uri, String[] strings, String s, String[] strings1, String s1) { SQLiteDatabase db = myDBHelper.getWritableDatabase(); Cursor cursor = null; switch (uriMatcher.match(uri)) { case PERSON_DIR: cursor = db.query("person", strings, s, strings1, null, null, s1); break; case PERSON_ITEM: String personId = uri.getPathSegments().get(1); cursor = db.query("person", strings, "id = ?", new String[]{personId}, null, null, s1); break; case TEACHER_DIR: cursor = db.query("teacher", strings, s, strings1, null, null, s1); break; case TEACHER_ITEM: String teacherId = uri.getPathSegments().get(1); cursor = db.query("teacher", strings, "id = ?", new String[]{teacherId}, null, null, s1); break; default: break; } return cursor; } @Nullable @Override public Uri insert(Uri uri, ContentValues contentValues) { SQLiteDatabase db = myDBHelper.getWritableDatabase(); Uri uriReturn = null; switch (uriMatcher.match(uri)) { case PERSON_DIR: case PERSON_ITEM: long newPersonId = db.insert("person", null, contentValues); uriReturn = Uri.parse("content://"+AUTHORITY+"/person/"+newPersonId); break; case TEACHER_DIR: case TEACHER_ITEM: long newTeacherId = db.insert("teacher", null, contentValues); uriReturn = Uri.parse("content://"+AUTHORITY+"teacher"+newTeacherId); break; default: break; } return uriReturn; } }
这里基本上和数据库的操作没什么不同,就是需要注意AUTHORITY需要在AndroidManifest中注册。
通过UriMatcher来匹配uri,然后通过Uri.parse解析uri。此外这里又重写了onCreate方法,update方法,delete方法。getType方法,query方法,insert方法。其中onCreate方法主要是创建数据库,update为更新数据,delete是删除数据,query是查询数据,insert为插入数据,基本和数据库的操作很类似。
getType方法主要是获取Uri对象的MIME类型
如果以路径结尾的话,那么就是:vnd.android.cursor.dir/vnd.+authoriry+.path;
如果以id结尾的话,那么就是:vnd.android.cursor.item/vnd.+authoriry+.path;
接着就是AndroidManifest了,代码如下:
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.jared.contentprovidertest" > <uses-permission android:name="android.permission.READ_CONTACTS"/> <application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:supportsRtl="true" android:theme="@style/AppTheme" > <activity android:name=".MainActivity" > <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <provider android:name=".myContentProvider" android:exported="true" android:authorities="com.example.jared.contentprovidertest.provider"> </provider> </application> </manifest>
这里需要添加provider,其中android:name属性是类名。android:exported属性表示对外暴露,所以需要为true。android:authorities属性表示的是authority,也就是上面代码的那个authority,必须一致。这样基本上就ok了。
接着我们创建一个ContentProviderTest2工程,用来获取,操作ContentProviderTest的内容。layout就参考了dbtest的工程的代码:
<?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="vertical"> <Button android:id="@+id/createDB" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="创建数据库" /> <LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content"> <Button android:id="@+id/addData" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="添加数据"/> <Button android:id="@+id/updateData" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="更新数据"/> <Button android:id="@+id/delData" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="删除数据"/> <Button android:id="@+id/queryData" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="查询数据"/> </LinearLayout> </LinearLayout>
接着编写代码实现各个按钮的功能:
package com.example.jared.contentprovidertest2; import android.content.ContentValues; import android.database.Cursor; import android.net.Uri; import android.os.Bundle; import android.support.v7.app.AppCompatActivity; import android.util.Log; import android.view.View; import android.widget.Button; public class MainActivity extends AppCompatActivity { private static final String TAB = "MainActivity"; private Button addDataBtn; private Button deleteDataBtn; private Button updateDataBtn; private Button queryDataBtn; public String id1, id2; private static final String PERSON_URI = "content://com.example.jared.contentprovidertest.provider/person"; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); addDataBtn = (Button)findViewById(R.id.addData); addDataBtn.setOnClickListener(new myOnClickListener()); deleteDataBtn = (Button)findViewById(R.id.delData); deleteDataBtn.setOnClickListener(new myOnClickListener()); updateDataBtn = (Button)findViewById(R.id.updateData); updateDataBtn.setOnClickListener(new myOnClickListener()); queryDataBtn = (Button)findViewById(R.id.queryData); queryDataBtn.setOnClickListener(new myOnClickListener()); } private class myOnClickListener implements View.OnClickListener { @Override public void onClick(View view) { switch (view.getId()) { case R.id.addData: id1 = setAddDataBtn("xiao ming", 20, 172.5, "man"); id2 = setAddDataBtn("xiao hong", 22, 162.5, "woman"); break; case R.id.delData: setDeleteDataBtn(id1); break; case R.id.updateData: setUpdateDataBtn(id1, 175.0); break; case R.id.queryData: setQueryDataBtn(); break; default: break; } } } public void setQueryDataBtn() { Uri uri = Uri.parse(PERSON_URI); Cursor cursor = getContentResolver().query(uri, null, null, null, null); if(cursor != null) { while (cursor.moveToNext()) { String personName = cursor.getString(cursor.getColumnIndex("name")); int personAge = cursor.getInt(cursor.getColumnIndex("age")); double personHeight = cursor.getDouble(cursor.getColumnIndex("height")); String personSex = cursor.getString(cursor.getColumnIndex("sex")); Log.d(TAB, "name:"+personName + " |age:"+personAge + " |height:" +personHeight + " |sex:"+personSex); } cursor.close(); } } public void setUpdateDataBtn(String id, double height) { Uri uri = Uri.parse(PERSON_URI+"/"+id); ContentValues values = new ContentValues(); values.put("height", height); getContentResolver().update(uri, values, null, null); } public void setDeleteDataBtn(String id) { Uri uri = Uri.parse(PERSON_URI+"/"+id); getContentResolver().delete(uri, null, null); } public String setAddDataBtn(String name, int age, double height, String sex) { Uri uri = Uri.parse(PERSON_URI); ContentValues values = new ContentValues(); values.put("name", name); values.put("age", age); values.put("height", height); values.put("sex", sex); Uri newUri = getContentResolver().insert(uri, values); return newUri.getPathSegments().get(1); } }
这里基本上都是先把字符串转换为Uri,然后通过getContentResolver()类的方法来实现各个功能,准备好代码后,我们继续运行看下效果:
首先是添加功能:按添加按钮再按查询,查看log信息如下:
02-15 03:47:53.730 17319-17319/com.example.jared.contentprovidertest2 D/MainActivity: name:xiao ming |age:20 |height:172.5 |sex:man 02-15 03:47:53.780 17319-17319/com.example.jared.contentprovidertest2 D/MainActivity: name:xiao hong |age:22 |height:162.5 |sex:woman已经添加了数据,然后是更新功能:按更新按钮再按查询,查看log信息如下:
02-15 03:49:33.210 17319-17319/com.example.jared.contentprovidertest2 D/MainActivity: name:xiao ming |age:20 |height:175.0 |sex:man 02-15 03:49:33.210 17319-17319/com.example.jared.contentprovidertest2 D/MainActivity: name:xiao hong |age:22 |height:162.5 |sex:woman已经更新身高为175.0了,然后是删除功能:按删除按钮再按查询,查看log信息如下:
02-15 03:50:46.650 17319-17319/com.example.jared.contentprovidertest2 D/MainActivity: name:xiao hong |age:22 |height:162.5 |sex:woman
查询功能已经在上面的多次操作中用过了,基本上访问另外一个app数据的功能也实现了。ContentProvider就先学到这里了,继续学习别的内容!
以上是关于Android开发学习之路--Content Provider之初体验的主要内容,如果未能解决你的问题,请参考以下文章