ContentProvider:自定义的应用

//继承ContentProvider的自定义类
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 com.example.Sqlutil.MySqliteOpenHelper;

//以下代码是继承ContentProvider类用它里面的增删改查方法,其他应用操作时就是调用这里的方法
/*在清单文件中声明注册 ContentProvider ://在<activity>里面配置
 <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 不允许其他应用调用
 */
public class MyContentProvider extends ContentProvider {
	// authorties功能清单中您配置暴露给其他应用使用的属性名字
	private static String authorties = "com.example.providercustomUtils.mycontentprovider";
	private MySqliteOpenHelper openHelper;// 继承SQLiteOpenHelper的类
	private static UriMatcher matcher;// 匹配器/匹配类:当外部应用调用它内部的方法时,要匹配外部应用传进来的uri
	private static final int MATCH_STUDENT = 110;
	private static final int MATCH_NAME = 119;
	private static final int MATCH_SCORE = 120;
	static {// 静态代码块只执行一次
		matcher = new UriMatcher(UriMatcher.NO_MATCH);// 如果uri不匹配,即不正确时 ,返回-1;
		// 第一个参数:uri中authorties,第二个参数:path路径,建议写上表名;第三个:匹配正确的返回值(自定义的值)
		// matcher.addURI(authority, path, code),可以写多个matcher
		matcher.addURI(authorties, "studentinfo", MATCH_STUDENT);
		matcher.addURI(authorties, "studentinfo/*", MATCH_NAME);
		matcher.addURI(authorties, "studentinfo_id/#", MATCH_SCORE);
		// 注意:文本跟数字matcher都存在时,path所取的名字要不同,/*这个是文本标志,/#个是数字的标志
	}

	// 以下只用到一个Uri
	@Override
	// 首次访问执行一次,做初始化的操作,比如去继承SQLiteOpenHelper的类去执行建表或数据库操作等
	public boolean onCreate() {
		openHelper = new MySqliteOpenHelper(getContext());
		return false;
	}

	// openHelper.getReadableDatabase() : 如果空间不足,不能写,只能读
	// openHelper.getWritableDatabase(); 如果空间不足,既不能写,也不能读(报错)
	@Override
	public Cursor query(Uri uri, String[] projection, String selection,
			String[] selectionArgs, String sortOrder) {
		// 查询首先用一个Switch,因为有多个mathcer时有多个操作
		Cursor cursor = null;
		SQLiteDatabase db = openHelper.getReadableDatabase();
		switch (matcher.match(uri)) {
		// 路径正确时,返回匹配正确的值,就查询
		case MATCH_STUDENT:
			cursor = db.query("studentinfo", projection, selection,
					selectionArgs, null, null, sortOrder);
			break;

		case MATCH_NAME:
			String name = uri.getLastPathSegment();// 获取URI最后的文本,即传过来的文字,字符等
			cursor = db.query("studentinfo", projection, "sname like ?",
					new String[] { name + "%" }, null, null, null);// 模糊查询
			break;
		case MATCH_SCORE:
			long score = ContentUris.parseId(uri);
			// 数字跟uri获取id的方式一样获取,不能像上面uri.getLastPathSegment()那样操作了
			cursor = db.query("studentinfo", projection, "score=?",
					new String[] { score + "" }, null, null, null);
			break;
		}
		return cursor;
	}

	@Override
	public String getType(Uri uri) {
		return null;
	}

	@Override
	public Uri insert(Uri uri, ContentValues values) {
		SQLiteDatabase db = openHelper.getReadableDatabase();
		Uri insertUri = null;
		switch (matcher.match(uri)) {
		case MATCH_STUDENT:
			long rowid = db.insert("studentinfo", null, values);
			insertUri = ContentUris.withAppendedId(uri, rowid);
			// 原始URI生成,等价于上面的:long row=db.insert();
			// uri=String path="content://"+authorties+"/studentinfo"+"/"+row;
			break;
		// 返回值是URI,所以要用工具类构造(ContentUris)
		default:
			break;
		}
		return insertUri;
	}

	@Override
	public int delete(Uri uri, String selection, String[] selectionArgs) {

		SQLiteDatabase db = openHelper.getReadableDatabase();
		int row = 0;
		switch (matcher.match(uri)) {
		case MATCH_STUDENT:
			// 返回的是影响行数
			row = db.delete("studentinfo", selection, selectionArgs);
			break;

		default:
			break;
		}
		return row;
	}

	@Override
	public int update(Uri uri, ContentValues values, String selection,
			String[] selectionArgs) {
		SQLiteDatabase db = openHelper.getReadableDatabase();
		int row = 0;
		switch (matcher.match(uri)) {
		case MATCH_STUDENT:
			// 返回的是影响行数
			db.update("studentinfo", values, selection, selectionArgs);
			break;

		default:
			break;
		}
		return row;
	}

}


//继承SQLiteOpenHelper的数据库类
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteDatabase.CursorFactory;
import android.database.sqlite.SQLiteOpenHelper;

public class MySqliteOpenHelper extends SQLiteOpenHelper {
	// super(context, name, factory, version),要重写构造方法,父类参数意义
	// context上下文;name:dbName,数据库名;factory:游标工厂;version版本号,可以自己设置
	// 我们可以自己重写,让它传入的参数变少,只用传入上下文

	// 定义一些静态参数,让它传进的参数变少
	private static final String DBNAME = "student2.db";
	// 数据库会在第一次升级软件时创建,存放地址:data/data/项目.包名/datebase()
	private static final int VERSION = 1;// 版本可以自己取

	public MySqliteOpenHelper(Context context) {
		super(context, DBNAME, null, VERSION);
		/*
		 * public MySqliteOpenHelper(Context context, String name, CursorFactory
		 * factory, int version) { super(context, name, factory, version); }
		 */
	}

	@Override
	public void onCreate(SQLiteDatabase db) {
		// 创建数据库表,首次升级时调用,初始化一些数据
		String sql = "create table studentinfo "
				+ " (sid integer primary key autoincrement not null,"
				+ " sname varchar(30) not null," + " sex varchar(2) not null,"
				+ " score integer not null)";
		db.execSQL(sql);
	}

	@Override
	public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
		// 大于旧版本时,就升级
		if (newVersion > oldVersion) {
			db.execSQL("drop table if exists studentinfo ");
			// 实际操作是先备份数据,再进行删除升级
		}
	}

}

//清单文件配置
 <!-- provider配置提供给其他应用跟配置activity差不多,exported="true"true代表给外面调用 -->
        <provider
            android:name="com.example.providercustomUtils.MyContentProvider"
            android:authorities="com.example.providercustomUtils.mycontentprovider"
            android:exported="true" >
        </provider>

//以下是我新建一个项目进行跨应用的测试类

//用来测试自定义ContentProvider类,即跨应用的使用测试(测试的自定义项目名称是:AndDay16ContentProviderCustom)
public class StudnetProviderTest extends AndroidTestCase {
	// scheme://authority/path
	// authority为com.example.providercustomUtils.mycontentprovider
	// 要记得你在另外一个项目应用的配置的authorities,不能有错,后面加上路径、表名等构成Uri
	private String student_uri = "content://com.example.providercustomUtils.mycontentprovider/studentinfo";
	// student_name访问文本,被操作的应用那里要写一个匹配器 ,/*这个是文本标志
	private String student_name = "content://com.example.providercustomUtils.mycontentprovider/studentinfo/小";// 就想访问数据库字段,模糊查询
	// student_score访问的是数字,被操作的应用那里要写一个匹配器,/#个是数字的标志
	private String student_score = "content://com.example.providercustomUtils.mycontentprovider/studentinfo_id/90";
	private ContentResolver resolver;
	private Cursor cursor;

	public void queryTest() {
		resolver = getContext().getContentResolver();
		cursor = resolver.query(Uri.parse(student_score), new String[] { "sid",
				"sname", "sex", "score" }, null, null, null);
		while (cursor.moveToNext()) {
			String sname = cursor.getString(cursor.getColumnIndex("sname"));
			String sex = cursor.getString(cursor.getColumnIndex("sex"));
			String score = cursor.getString(cursor.getColumnIndex("score"));
			Log.i("MainActivity", sname + "-" + sex + "-" + score);
			// String sname = cursor.getString(1);
			// String sex = cursor.getString(2);
			// String score = cursor.getString(3);
		}
		cursor.close();
	}

	public void addTest() {
		resolver = getContext().getContentResolver();
		ContentValues values = new ContentValues();
		values.put("sname", "小小");
		values.put("sex", "女");
		values.put("score", 98);
		Uri insertUri = resolver.insert(Uri.parse(student_uri), values);
		Log.i("MainActivity", "row id" + ContentUris.parseId(insertUri));// 系统带的ContentUris.parseId,把uri放进去可以返回一个插入后的id
	}

}
//测试时在Mianifest.xml功能文件引入测试单元
 <!-- 引入Android单元测试框架  <application>外面加入-->
    <instrumentation
        android:name="android.test.InstrumentationTestRunner"
        android:targetPackage="com.example.andday16providercustomtest" >
    </instrumentation>
    <!-- 单元测试的依赖包 在 <application 的里面加入-->
        <uses-library android:name="android.test.runner" />


你可能感兴趣的:(ContentProvider:自定义的应用)