自定义ContentProvider

一、自定义ContentProvider:

(一)、操作步骤:

1、编写一个类,必须继承自ContentProvider类;

2、实现ContentProvider类中所有的抽象方法;

    需要实现:onCreate() 、getType() 、query() 、insert() 、update()、delete() 等方法。


【备注:】

ContentProvider暴露出来的数据和方法并不是给自身调用的,而是给其他应用程序来调用。其他应用程序通过其ContentResolver对象调用的query() 、insert() 、update()、delete() 等方法就是我们在这里暴露出来的ContentProvider类中的重写后的query() 、insert() 、update()、delete() 方法。

3、定义ContentProvider的Uri。这个Uri是ContentResolver对象执行CRUD操作时重要的参数;

4、使用UriMatcher对象映射Uri返回代码;

5、在AndroidMainfest.xml文件中使用<provider>标签注册ContentProvider。

2345,,3348

(二)、ContentProvider类中的六个抽象方法:

1、boolean onCreate() 初始化provider

2、Uri insert(Uri uri, ContentValues values)插入新数据到ContentProvider

3、int delete(Uri uri, String selection, String[] selectionArgs)从ContentProvider中删除数据

4、int update(Uri uri, ContentValues values, String selection, String[] selectionArgs)   更新ContentProvider已经存在的数据

5、Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder)  返回数据给调用者

        uri,查询字段,where条件,where条件字段,排序

6、String getType(Uri uri) 返回ContentProvider数据的Mime类型

(四)、在清单文件中声明注册ContentProvider:

<provider android:name=".MyWordsProvider"
android:authorities="com.steven.wordscontentprovider"
android:exported="true" />
//android:name属性的值是:ContentProvider类的子类的完整路径;
//android:authorities属性的值是:content:URI中authority部分。一般就是将name属性的值全小写。
//android:exported属性是否允许其他应用调用。如果是false,则该ContentProvider不允许其他应用调用。

(五)、UriMatcher:

        继承ContentProvider类后发现,ContentProvider类中只有一个onCreate()生命周期方法——当其他应用程序通过ContentResolver第一次访问该ContentProvider时,onCreate()会被回调。

        其他应用在通过ContentResolver对象执行CRUD操作时,都需要一个重要的参数Uri。为了能顺利提供这个Uri参数,Android系统提供了一个UriMatcher工具类。

UriMatcher工具类提供了两个方法:

1、void addURI(String authority , String path , int code)  :  该方法用于向UriMatcher对象注册Uri。其中authority和path是Uri中的重要部分。而code代表该Uri对应的标示符。

2、int match(Uri uri) : 根据注册的Uri来判断指定的Uri对应的标示符。如果找不到匹配的标示符,该方法返回-1。

private static UriMatcher matcher = null;
        static {
                // 定义一个Uri匹配器。将UriMatcher.NO_MATCH,即-1作为参数。
         matcher = new UriMatcher(UriMatcher.NO_MATCH);
                // 定义一组匹配规则
         matcher.addURI(AUTHORITY, "words", 1);
         matcher.addURI(AUTHORITY, "newwords", 2);
 }

三、UriMatcher对象的addURI方法的#和*问题:

(一)、#和*的含义:

1、UriMatcher.addURI(String authority, String path, int code)


*和#是两个通配符,它们用在uri地址中,*可以匹配任何文本,#匹配任何数字。


(二)、截取Uri地址和拼接Uri地址的方法:【重点

1、Uri对象的截取方法:

  • public abstract String getLastPathSegment () 
  • public abstract String getPath ()
  • public abstract List<String> getPathSegments ()


2、Uri对象的拼接方法:

  • public static Uri withAppendedPath (Uri baseUri, String pathSegment)


3、ContentUris对象的截取id的方法:

  • public static long parseId (Uri contentUri)


4、ContentUris对象的拼接id的方法:

  • public static Uri withAppendedId (Uri contentUri, long id)


【备注:】Content URIs 的语法规则:content://authority/path/id 

三、CotentResolver实现联系人的CRUD操作
(一)、实现步骤:
1、实例化ContentResolver:
resolver = getContentResolver();
【备注:】标准Uri的格式:
1)、标准前缀:content://
2)、Authority(授权):  相当于网址
3)、path : authority后面的所有部分

需要四个Uri对象或者Uri字符串:
1)、表示操作raw_contacts表   content://com.android.contacts/raw_contacts
2)、操作data表   content://com.android.contacts/data
3)、操作data表中的phones    content://com.android.contacts/data/phones
4)、操作data表中的emails    content://com.android.contacts/data/emails

2、实现查询方法:
1)、先从raw_contacts表中查询_id , displayname
2)、从data表中根据_id查询data1中phones
3)、从data表中根据_id查询data1中emails
【注意:】及时将查询产生的cursor进行关闭,要及时将查询数据放置到List<Map<String, String>>,适配器选择SimpleAdapter

四、自定义ContentProvider
(一)、ContentProvider的crud方法与SQLiteDatabase的Crud方法的异同
1、insert()方法:
        1)、Uri insert(Uri uri  , ContentValues values)
        2)、long  insert(String table , String  nullColumnHack ,  ContentValues values)
2、delete()
        1)、int delete(Uri uri  , String selection , String[] selectionArgs)
        2)、int delete(String tablename , String selection  , String[] selectionArgs)
3、update()
        1)、int update(Uri uri  , ContentValues values , String selection , String[] selectionArgs)
        2)、int update(String tablename  , ContentValues values , String selection , String[] selectionArgs)

4、query()方法:
        1)、Cursor query(Uri uri , String[] projection  , String selection , String[] selectionArgs , String sortOrder)
        2)、Cursor query(String tablename , String[] projection  , String selection , String[] selectionArgs , String groupby , String having , String orderby)
参数个数:
ResolVer、Provider:参数个数2345
SQLiteDatabase:参数个数3347

public class MainActivity extends Activity {
private ListView listView_main;
private TextView textView_empty;
private ContentResolver resolver = null;
private SimpleAdapter adapter = null;
private List<Map<String, String>> totalList = new ArrayList<Map<String, String>>();

private String uri_raw_contacts = "content://com.android.contacts/raw_contacts";
private String uri_phones = "content://com.android.contacts/data/phones";
private String uri_emails = "content://com.android.contacts/data/emails";
private String uri_data = "content://com.android.contacts/data";
/*
*1、多表联查步骤(查电话和email)
*  1、先getContentResolver得到resolver对象
*  2、使用query方法查询出raw_contacts表的_id和display_name,返回cursor对象
*   3、使用while循环参数为cursor.moveToNext()  ,将数据添加到map集合,然后将map添加到list(存放到哪里看适配器种类)
*   4、通过查询出来的_id,用query方法查询phones表中的电话和邮箱,然后存储
*   5、数据都存放到同一个list集合中
*   6、通过simpleadapter显示到listview中
*   7、listview的刷新方式是清空旧集合,添加新集合,然后适配器调用notifyDataSetChanged()
*2、添加联系人
*   1、必须先往raw_contacts表中添加一条空数据,返回值是uri,通过ContentUris.parseId方法将uri中得到id
*   2、得到空id后往这条空id中添加数据
*   3、添加数据用ContentValues创建对象,将值put进values
*   4、用resolver对象调用insert方法,添加数据      resolver.insert(dataUri, values);
* 3、删除数据
  * 1、删除直接调用resolver.delete(Uri.parse(uri_raw_contacts), "_id = ?", new String[] { _id });
*   2、删除时用的id可以从监听中获得
*         1、onCreateContextMenu上下文菜单创建时AdapterContextMenuInfo info = (AdapterContextMenuInfo) menuInfo;
*         2、onContextItemSelected(MenuItem item) {AdapterContextMenuInfo info = (AdapterContextMenuInfo) item.getMenuInfo();
            String _id = totalList.get(info.position).get("_id");
总之先得到AdapterContextMenuInfo,这样可以得到position
 4、更新数据
   resolver.update(Uri.parse(uri_call_log), values,"_id=?", new String[] { id });
   id获取方式同上

* */
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initData();
initView();
reloadListView();
}
private void initData() {
resolver = getContentResolver();
}

@SuppressLint("NewApi")
private void initView() {
listView_main = (ListView) findViewById(R.id.listView_main);
textView_empty = (TextView) findViewById(R.id.textView_empty);

adapter = new SimpleAdapter(this, totalList,//用这个加载两个cursor数据
R.layout.item_listview_main, new String[] { "_id",
"display_name", "phones", "emails" }, new int[] {
R.id.textView_item_id, R.id.textView_item_displayname,
R.id.textView_item_phones, R.id.textView_item_emails });
listView_main.setAdapter(adapter);
listView_main.setEmptyView(textView_empty);
registerForContextMenu(listView_main);
}
// 获取联系人的姓名、emails及phones的方法
private List<Map<String, String>> selectContactsList() {
List<Map<String, String>> list = new ArrayList<Map<String, String>>();
Cursor cursor_contacts = resolver.query(Uri.parse(uri_raw_contacts),
new String[] { "_id", "display_name" }, null, null, "_id desc");
while (cursor_contacts.moveToNext()) {
String raw_contact_id = cursor_contacts.getString(0);
String display_name = cursor_contacts.getString(1);
Map<String, String> map = new HashMap<String, String>();
map.put("_id", raw_contact_id);
map.put("display_name", display_name);
// 拿到了当前用户raw_contact_id的所有的电话号码
Cursor cursor_phones = resolver.query(Uri.parse(uri_phones),
new String[] { "raw_contact_id", "data1" },
"raw_contact_id=?", new String[] { raw_contact_id }, null);
StringBuilder sb_phones = new StringBuilder();
while (cursor_phones.moveToNext()) {
            sb_phones.append(cursor_phones.getString(1));
sb_phones.append("|");
}
         map.put("phones", sb_phones.toString());
cursor_phones.close();

// 拿到了当前用户raw_contact_id的所有的Emails
Cursor cursor_emails = resolver.query(Uri.parse(uri_emails),
new String[] { "raw_contact_id", "data1" },
"raw_contact_id=?", new String[] { raw_contact_id }, null);
StringBuilder sb_emails = new StringBuilder();
while (cursor_emails.moveToNext()) {
            sb_emails.append(cursor_emails.getString(1));
sb_emails.append("|");
}
         map.put("emails", sb_emails.toString());
cursor_emails.close();

list.add(map);
}
      cursor_contacts.close();
return list;
}
// 添加联系人
private void insertContacts(List<String> list) {
Uri dataUri = Uri.parse(uri_data);
// 第一步:往raw_contacts表中添加一条空数据,目的是先获取到联系人的id
ContentValues values = new ContentValues();
// content://com.android.contacts/raw_contacts/12
Uri uri_id = resolver.insert(Uri.parse(uri_raw_contacts), values);
long _id = ContentUris.parseId(uri_id);
// 往data表中添加联系人姓名
values.clear();
values.put("raw_contact_id", _id);
values.put("mimetype", "vnd.android.cursor.item/name");
values.put("data1", list.get(0));
values.put("data2", list.get(0));
resolver.insert(dataUri, values);
// 往data表中添加phones
values.clear();
values.put("raw_contact_id", _id);
values.put("mimetype", "vnd.android.cursor.item/phone_v2");
values.put("data1", list.get(1));
values.put("data2", 2);
resolver.insert(dataUri, values);
// 往data表中添加emails
values.clear();
values.put("raw_contact_id", _id);
values.put("mimetype", "vnd.android.cursor.item/email_v2");
values.put("data1", list.get(2));
values.put("data2", 2);
resolver.insert(dataUri, values);
}
private int deletedContacts(String _id) {
int count = resolver.delete(Uri.parse(uri_raw_contacts), "_id = ?", new String[] { _id });
return count;
}
private void reloadListView() {
totalList.clear();
totalList.addAll(selectContactsList());
adapter.notifyDataSetChanged();
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.action_insert:
// 自定义对话框
List<String> list = new ArrayList<String>();
list.add("Luyibin");
list.add("123456");
list.add("Luyibin@qq.com");
insertContacts(list);
break;
}
return super.onOptionsItemSelected(item);
}
@Override
public void onCreateContextMenu(ContextMenu menu, View v,
ContextMenuInfo menuInfo) {
// TODO Auto-generated method stub
super.onCreateContextMenu(menu, v, menuInfo);
AdapterContextMenuInfo info = (AdapterContextMenuInfo) menuInfo;
menu.setHeaderIcon(R.drawable.ic_launcher);
menu.setHeaderTitle(totalList.get(info.position).get("display_name"));
getMenuInflater().inflate(R.menu.contextmenu_exec, menu);
}
@Override
public boolean onContextItemSelected(MenuItem item) {
AdapterContextMenuInfo info = (AdapterContextMenuInfo) item
            .getMenuInfo();
String _id = totalList.get(info.position).get("_id");
switch (item.getItemId()) {
case R.id.action_delete:
int count = deletedContacts(_id);
if (count > 0) {
Toast.makeText(this, "delete ok!", 0).show();
} else {
Toast.makeText(this, "delete err!", 0).show();
}
break;
case R.id.action_update:
break;
}
return super.onContextItemSelected(item);
}
}