1.ContentProvider简单介绍

在Android中有些数据(如通讯录、音频、视频文件等)是要供非常多应用程序使用的。为了更好地对外提供数据。Android系统给我们提供了Content Provider使用。通过它能够訪问上面所说的数据,比如非常多音乐播放器中的扫描功能事实上就用到了Content Provider功能(当然。也有的播放器是自己去实现更底层的功能)。这种优点是统一管理。比方添加了某个音频文件,底层就会将这种变化通知Content Provider,从而当应用程序訪问时就能够获得当前最新的数据。

当然,Android也同意我们定义自己的Content Provider。仅仅要继承它的基类,而且实现以下的方法就可以。

public boolean onCreate()
在创建ContentProvider时调用

public Cursor query(Uri, String[],
String, String[], String):用于查询指定Uri的ContentProvider。返回一个Cursor

public Uri insert(Uri, ContentValues):依据指定的Uri加入数据到ContentProvider中

public int update(Uri, ContentValues,
String, String[]):用于更新指定Uri的ContentProvider中的数据

public int delete(Uri, String,
String[]):依据Uri删除指定的数据

public String getType(Uri):用于返回指定的Uri中的数据的MIME类型

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

比如:要得到全部p1记录的Uri为content://contacts/p1,那么返回的MIME类型字符串为"vnd.android.cursor.dir/p1"。

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

比如:要得到id为100的student记录的Uri为content://contacts/student/100。那么返回的MIME类型字符串应为"vnd.android.cursor.item/student"。

2.Uri简单介绍

一个标准的Uri为content://authority/path可分为下面三部分:

(1)content://:这个部分是ContentProvider规定的,就像http://代表Http这个协议一样。使用ContentProvider的协议是content://

(2)authorities:它在所在的Android系统必须是唯一的,由于系统就是通过它来决定操作或訪问哪个ContentProvider的。这与互联网上的网址必须唯一是一样的道理。

(3)path:资源路径。

显然,从上面的分析能够看出ContentProvider尽管也可实现跨进程通信。可是它适用的场景主要是与数据库相关。有时也可能是文本文件或XML等存储方式。

3.ContentResolver

假设仅仅是定义一个ContentProvider的话,没有不论什么意义,由于ContentProvider仅仅是内容提供者,它要被别的应用(进程)读取才有价值。

与实现ContentProvder的方法相相应,使用ContentResolver相关的方法例如以下所看到的:

getContentResolver():Context类提供的,用于获取ContentResolver对象;

insert(Uri uri,ContentValues values):向Uri相应的ContentProvider中插入values相应的数据;

update(Uri uri,ContentValues values,String where,String[]selectionArgs):更新Uri相应的ContentProvider中where处的数据。当中selectionArgs是筛选參数。

query(Uri uri,String[]projection,String selection,String[]selectionArgs,String sortOrder):查询Uri相应的ContentProvider中where处的数据,当中selectionArgs是筛选參数,sortOrder是排序方式。

delete(Uri uri,String where,String[]selectionArgs):删除Uri相应的ContentProvider中where处的数据。当中selectionArgs是筛选參数。

4.UriMatcher

为了确定一个ContentProvider实际能处理的Uri。以及确定每一个方法中Uri參数所操作的数据,Android系统提供了UriMatcher工具类。它主要有例如以下两个方法:

(1)void addURI(String authority,String path,String code):该方法用于向UriMatcher对象注冊Uri。

当中authority和path组合成一个Uri,而code则代表该Uri相应的标识码;

(2)int match(Uri uri):依据前面注冊的Uri来推断指定Uri相应的标识码。

假设找不到匹配的标识码。该方法将会返回-1。

以下通过两个实例来解说ContentProvider的使用方法,第一个实例是自定义了一个ContentProvider而且在还有一个应用中读取它;第二个实例是读取当前手机中的联系人。

首先是第一个样例,项目结构例如以下图所看到的:

以下是各个类的代码。首先是常量的定义:

package com.android.student.utils;

import android.net.Uri;

/**
* 这里定义了与ContentProvider相关的字符串以及Student相应的数据表中的字段
* @author Bettar
*
*/
public class StudentWords { //注意Manifest文件里的authorities属性要跟这里保持一致。
public static final String AUTHORITY="com.android.student.provider"; public static final Uri STUDENT_WITH_ID_URI=Uri.parse("content://"+AUTHORITY+"/student");
public static final Uri STUDENT_URI=Uri.parse("content://"+AUTHORITY+"/student"); public static final String TABLE_NAME="student";
public static final String ID="id";
public static final String NAME="name";
public static final String SCORE="score";
public static final String ADDR="address"; }

然后是数据库帮助类:

import com.android.student.utils.StudentWords;

import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.widget.Toast; public class StudentDbHelper extends SQLiteOpenHelper{ private Context context;
public StudentDbHelper(Context context,String name,int version)
{
super(context,name,null,version);
this.context=context;
} @Override
public void onCreate(SQLiteDatabase db)
{
String createSQL="create table "+StudentWords.TABLE_NAME+"("+StudentWords.ID
+" integer primary key autoincrement,"
+StudentWords.NAME+" varchar,"
+StudentWords.SCORE+" integer,"
+StudentWords.ADDR+" varchar)";
db.execSQL(createSQL);
}
@Override
public void onUpgrade(SQLiteDatabase db,int oldVersion,int newVersion)
{
//升级版本号时,可能要运行表结构的改动之类,此处临时不考虑升级问题。因而仅仅是用Toast提示
Toast.makeText(context,
"newVersion:"+newVersion+" will replace oldVersion:"+oldVersion,
Toast.LENGTH_LONG).show();
} }

最后是ContentProvider类的定义:

package com.android.student.provider;

import com.android.student.database.StudentDbHelper;

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.provider.UserDictionary.Words; import com.android.student.utils.StudentWords; public class StudentProvider extends ContentProvider{ private static final String TAG="StudentProvider";
private static UriMatcher matcher=new UriMatcher(UriMatcher.NO_MATCH);
private static final int STUDENT_WITH_ID=1;
private static final int STUDENT=2; private StudentDbHelper dbHelper; static
{
matcher.addURI(StudentWords.AUTHORITY,"student/#",STUDENT_WITH_ID);
//matcher.addURI(StudentWords.AUTHORITY, "student", SINGLE_STUDENT);
//注意当中的#为通配符
matcher.addURI(StudentWords.AUTHORITY, "student", STUDENT);
} @Override
public boolean onCreate()
{
dbHelper=new StudentDbHelper(this.getContext(),"student.db3",1);
return true;
} @Override
public String getType(Uri uri)
{
switch(matcher.match(uri))
{
case STUDENT_WITH_ID:
return "vnd.android.cursor.item/com.android.student";
case STUDENT:
return "vnd.android.cursor.dir/com.android.student";
default:
throw new IllegalArgumentException("Unknown Uri:"+uri);
}
} /**
* 由单一的selection这一个筛选条件组合成包括id的复杂筛选条件
* @param uri
* @param selection
* @return
*/
private String getComplexSelection(Uri uri,String selection)
{
long id=ContentUris.parseId(uri);
String complexSelection=StudentWords.ID+"="+id;
if(selection!=null&&!"".equals(selection))
{
complexSelection+=" and "+selection;
}
return complexSelection;
} @Override
public int delete(Uri uri,String selection,String[]selectionArgs) { SQLiteDatabase db=dbHelper.getReadableDatabase();
int num=0;
switch(matcher.match(uri))
{
case STUDENT_WITH_ID:
String complexSelection=getComplexSelection(uri,selection);
num=db.delete(StudentWords.TABLE_NAME, complexSelection, selectionArgs);
break;
case STUDENT:
num=db.delete(StudentWords.TABLE_NAME,selection,selectionArgs);
break;
default:
throw new IllegalArgumentException("Unknown Uri:"+uri);
}
//通知数据已经改变
getContext().getContentResolver().notifyChange(uri, null);
return num;
} @Override
public Uri insert(Uri uri, ContentValues values) {
SQLiteDatabase db=dbHelper.getReadableDatabase();
switch(matcher.match(uri))
{ case STUDENT_WITH_ID:
case STUDENT:
long rowId=db.insert(StudentWords.TABLE_NAME, StudentWords.ID,values);
if(rowId>0)
{
Uri studentUri=ContentUris.withAppendedId(uri, rowId);
//假设设置了观察者的话,要通知全部观察者
getContext().getContentResolver().notifyChange(studentUri, null);
return studentUri;
}
break;
default:
throw new IllegalArgumentException("Unknow Uri:"+uri);
}
return null;
} /**
* 注意当中的projection事实上是columns,即列名数组
*/
@Override
public Cursor query(Uri uri, String[] projection, String selection,
String[] selectionArgs, String sortOrder) {
SQLiteDatabase db=dbHelper.getReadableDatabase();
switch(matcher.match(uri))
{
//这事实上是包括id信息的情况
case STUDENT_WITH_ID:
String complexSelection=getComplexSelection(uri,selection);
return db.query(StudentWords.TABLE_NAME,projection,complexSelection,selectionArgs,null,null,sortOrder);
//这是不带数字的情况,可是也未必就是好多个,一个也能够。
case STUDENT:
return db.query(StudentWords.TABLE_NAME
,projection,selection,selectionArgs,null,null,sortOrder);
default:
throw new IllegalArgumentException("Unknow Uri"+uri);
} } @Override
public int update(Uri uri, ContentValues values, String selection,
String[] selectionArgs)
{
SQLiteDatabase db=dbHelper.getWritableDatabase();
int num=0;
switch(matcher.match(uri))
{
case STUDENT_WITH_ID:
String complexSelection=getComplexSelection(uri,selection);
num=db.update(StudentWords.TABLE_NAME, values, complexSelection, selectionArgs);
break;
case STUDENT:
num=db.update(StudentWords.TABLE_NAME, values, selection,selectionArgs);
break;
default:
throw new IllegalArgumentException("Unknow Uri:"+uri);
} getContext().getContentResolver().notifyChange(uri,null);
return num;
} }

当然,要记得在Manifest文件里增加ContentProvider的声明:

 <provider android:name="com.android.student.provider.StudentProvider"
android:authorities="com.android.student.provider"
android:exported="true"/>

以下是对ContentResolver的样例,首先项目中的文件结构例如以下:





然后是layout文件 :

 <ScrollView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
>
<LinearLayout
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
android:orientation="vertical"
tools:context=".MainActivity" > <TextView
android:id="@+id/tv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="下面为输入參数:"
/>
<EditText
android:id="@+id/nameET"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:hint="Name"
/>
<EditText
android:id="@+id/scoreET"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:hint="Score"
/>
<EditText
android:id="@+id/addrET"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:hint="Address"
/>
<Button
android:id="@+id/insertButton"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Insert"
/>
<TextView
android:id="@+id/searchTv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="下面为查询參数:"
/>
<EditText
android:id="@+id/inputNameET"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:hint="Input name"
/>
<Button
android:id="@+id/searchButton"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Search"
/>
<TextView
android:id="@+id/searchResultTv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="下面为Update參数"
/>
<EditText
android:id="@+id/inputIdET"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:hint="Input id"
/>
<Button
android:id="@+id/updateButton"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Update"
/>
<TextView
android:id="@+id/searchResultTv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="下面为删除參数"
/>
<EditText
android:id="@+id/inputIdForDeleteET"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:hint="Input id"
/>
<Button
android:id="@+id/deleteButton"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Delete"
/> </LinearLayout>
</ScrollView>

项目中也有StudentWords这个类,由于与上面的StudentWords全然同样,故此处不再列出,MainActivity的代码例如以下:

package com.android.student.studentcontentresolver;

import java.util.ArrayList;
import java.util.List;
import java.util.Map; import com.android.student.utils.StudentWords; import android.net.Uri;
import android.os.Bundle;
import android.app.Activity;
import android.content.ContentResolver;
import android.content.ContentUris;
import android.content.ContentValues;
import android.database.Cursor;
import android.view.Menu;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;
import android.view.View;
public class MainActivity extends Activity implements View.OnClickListener{ ContentResolver contentResolver; private EditText nameET,scoreET,addressET;
private Button insertButton;
private EditText inputNameET;
private Button searchButton; private EditText inputIdForUpdateET,inputIdForDeleteET;
private Button updateButton,deleteButton; private void initView()
{
nameET=(EditText)findViewById(R.id.nameET);
scoreET=(EditText)findViewById(R.id.scoreET);
addressET=(EditText)findViewById(R.id.addrET);
insertButton=(Button)findViewById(R.id.insertButton);
inputNameET=(EditText)findViewById(R.id.inputNameET);
searchButton=(Button)findViewById(R.id.searchButton); inputIdForUpdateET=(EditText)findViewById(R.id.inputIdET);
inputIdForDeleteET=(EditText)findViewById(R.id.inputIdForDeleteET); updateButton=(Button)findViewById(R.id.updateButton);
deleteButton=(Button)findViewById(R.id.deleteButton); insertButton.setOnClickListener(this);
searchButton.setOnClickListener(this);
updateButton.setOnClickListener(this);
deleteButton.setOnClickListener(this);
} @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
contentResolver=getContentResolver();
initView();
} @Override
public void onClick(View view)
{
switch(view.getId())
{
case R.id.insertButton:
insert();
break;
case R.id.searchButton:
query();
break;
case R.id.updateButton:
update();
break;
case R.id.deleteButton:
delete();
break;
default:
break;
}
} private void insert()
{
String name=nameET.getText().toString();
String score=scoreET.getText().toString();
String addr=addressET.getText().toString();
ContentValues values=new ContentValues();
values.put(StudentWords.NAME, name);
values.put(StudentWords.SCORE, new Integer(score));
values.put(StudentWords.ADDR, addr); //contentResolver.insert(StudentWords.SINGLE_STUDENT_URI, values);
//一个是多个的特例,所以此处用MANY_STUDENTS_URI就可以。
contentResolver.insert(StudentWords.STUDENT_URI, values); Toast.makeText(getBaseContext(), "加入学生信息成功", Toast.LENGTH_SHORT).show(); } private void query()
{
String name=inputNameET.getText().toString();
//Cursor cursor=contentResolver.query(uri, projection, selection, selectionArgs, sortOrder)
Cursor cursor=contentResolver.query(StudentWords.STUDENT_URI, null, "name like ? or address like ?", new String[]{"%"+name+"%","%"+name+"%"}, null);
Toast.makeText(getBaseContext(), getResult(cursor), Toast.LENGTH_LONG).show(); } private void update()
{
//Uri updateUri=StudentWords.SINGLE_STUDENT_URI
//更新id值为id的记录
Integer id=new Integer(inputIdForUpdateET.getText().toString());
Uri updateUri=ContentUris.withAppendedId(StudentWords.STUDENT_WITH_ID_URI,id);
ContentValues values=new ContentValues();
values.put(StudentWords.NAME,"VictorWang");
contentResolver.update(updateUri, values, null, null);
} private void delete()
{
//删除id值为id的记录
Integer id=new Integer(inputIdForDeleteET.getText().toString());
Uri deleteUri=ContentUris.withAppendedId(StudentWords.STUDENT_WITH_ID_URI, id);
contentResolver.delete(deleteUri, null, null);
} private List<String>convertCursor2List(Cursor cursor)
{
List<String>result=new ArrayList<String>();
while(cursor.moveToNext())
{
result.add(cursor.getString(1)+" ");
result.add(cursor.getString(2)+" ");
result.add(cursor.getString(3)+" ");
}
return result;
} private String getResult(Cursor cursor)
{
StringBuilder sb=new StringBuilder();
while(cursor.moveToNext())
{
sb.append(cursor.getString(1)+" ");
sb.append(cursor.getString(2)+" ");
sb.append(cursor.getString(3)+"\n");
}
return sb.toString();
} @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;
} }

执行结果例如以下:



今天先写到这里,联系人和ContentObserver的样例后面再加入。

Android中的跨进程通信方法实例及特点分析(二):ContentProvider的更多相关文章

  1. Android中的跨进程通信方法实例及特点分析(一):AIDL Service

    转载请注明出处:http://blog.csdn.net/bettarwang/article/details/40947481 近期有一个需求就是往程序中增加大数据的採集点,可是由于我们的Andro ...

  2. Android随笔之——跨进程通信(一) Activity篇

    在Android应用开发中,我们会碰到跨进程通信的情况,例如:你用QQ通讯录打电话的时候会调用系统的拨号应用.某些新闻客户端可以将新闻分享到QQ.微信等应用,这些都是跨进程通信的情况.简而言之,就是一 ...

  3. Android使用AIDL跨进程通信

    一.基本类型 1.AIDL是什么 AIDL是Android中IPC(Inter-Process Communication)方式中的一种,AIDL是Android Interface definiti ...

  4. Android中的跨进程调用技术AIDL

    什么是AIDL Android系统中的进程之间不能共享内存,因此,需要提供一些机制在不同进程之间进行数据通信. 为了使其他的应用程序也可以访问本应用程序提供的服务,Android系统采用了远程过程调用 ...

  5. Android四种跨进程通信

    由于android系统中应用程序之间不能共享内存.因此,在不同应用程序之间交互数据(跨进程通讯)就稍微麻烦一些.在android SDK中提供了4种用于跨进程通讯的方式.这4种方式正好对应于andro ...

  6. android自动化测试解决跨进程通信问题

    大概用这些吧: IPC  Handler    Messager   Bundle  service(binder)   messageconnection ,thead.getXXX.getId 注 ...

  7. 【朝花夕拾】Android性能篇之(七)Android跨进程通信篇

    前言 只要是面试高级工程师岗位,Android跨进程通信就是最受面试官青睐的知识点之一.Android系统的运行由大量相互独立的进程相互协助来完成的,所以Android进程间通信问题,是做好Andro ...

  8. 图文详解 Android Binder跨进程通信机制 原理

    图文详解 Android Binder跨进程通信机制 原理 目录 目录 1. Binder到底是什么? 中文即 粘合剂,意思为粘合了两个不同的进程 网上有很多对Binder的定义,但都说不清楚:Bin ...

  9. Android跨进程通信的四种方式

    由于android系统中应用程序之间不能共享内存.因此,在不同应用程序之间交互数据(跨进程通讯)就稍微麻烦一些.在android SDK中提供了4种用于跨进程通讯的方式.这4种方式正好对应于andro ...

随机推荐

  1. Java+7入门经典 -1 简介

    第一章 Java简介 1.1 Java概览 applet程序可嵌入网页; Java会通过隐式检测禁止Java applet的恶意代码; Java Server Pages-JSP 创建服务器应用程序, ...

  2. 浅谈PPM (Project Portfolio Management) - 1

    前言: 本文以纯理论性的PPM解说为主,不会涉及到具体怎样实施,我会在以后介绍具体的PPM实施方案介绍. PPM,可能非常多人并不清楚甚至可能没听说过,这是一个近些年才流行起来的概念,是Project ...

  3. 设置MAVEN_OPTS环境变量

    运行mvn命令实际上是执行了Java命令,既然是运行Java,那么运行Java命令可用的参数当然也应该在运行mvn命令时可用.这个时候,MAVEN_OPTS环境变量就能派上用场. 通常需要设置MAVE ...

  4. sudo service memcached start

    我安装后memcached后,并使用 ? 1 sudo service memcached start

  5. 如何使用NArrange进行代码优化

    Narrange是一个.NET代码管理工具.它可以对源代码自动进行美化和把类成员分成一个组.区域.目前支持C#.VB.NET,将来会支持更多.NET上的语言. 主要的作用是: ◆ 减少程序员的开发时间 ...

  6. SRM 223 Div II Level Two: BlackAndRed,O(N)复杂度

    题目来源:http://community.topcoder.com/stat?c=problem_statement&pm=3457&rd=5869 解答分析:http://comm ...

  7. Swift - String与NSString的区别,以及各自的使用场景

    String是Swift里新增加的类型,它与原来的NSString可以很方便地互相转换.但在实际开发中,我们该如何选择? 1,能使用String类型就尽量使用String类型,原因如下: (1)现在C ...

  8. linux学习之四---gdb调试

    在Linux应用程序开发中,最经常使用的调试器是gdb. 一.启动和退出gdb gdb调试的对象是可运行文件,而不是程序的源码.假设要使一个可运行文件能够被gdb调试,那么使用编译器gcc编译时须要增 ...

  9. shadow dom

    初识shadow dom 我们先看个input="range"的表现: what amazing ! 一个dom能表现出这么多样式嘛? 无论是初学者和老鸟都是不肯相信的,于是在好奇 ...

  10. 三篇IMO的文章

    http://column.iresearch.cn/b/201411/687499.shtml?from=singlemessage&isappinstalled=1 http://colu ...