//继承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" />