自定义ContentProvide

[Vue][面试]谈谈你对MVC、MVP和MVVM的理解 谈谈你对MVC、MVP和MVVM的理解 答题思路:此题涉及知识点很多,很难说清楚,说透彻,因为MVC,MVP这些我们前端程序员自己甚至都没用过。但是恰恰反映了前端这些年从无到有, 从有到优的变迁过程,因此沿此思路回答将十分清除。 Web1.0时代 在web1.0时代,并没有前端的概念。开发一个web应用多数采用ASP.NET/Java/PHP编写,项目通常由多个aspx/jsp/php文件构成,每个文件中同时包含了HTML、CSS、JavaScript、C#/Java/PHP代码, 系统整体架构可能如下图所 阅读详情
我们大家都知道让自己的数据和其它应用程序共享有两种方式:创建自己的Content Provider (即继承自Content Provider的子类) 或者是将自己的数据添加到已有的Content Provider中去,后者需要保证现有的Content Provider和自己的数据类型相同并且具有该 Content Provider的写入的权限。

如果需要创建一个Content Provider,则需要进行的工作主要分为以下3个步骤。

(1) 建立数据的存储系统

数据的存储系统可以由开发人员任意决定,一般来讲,大多数的Content Provider都通过Android的文件存储系统或SQLite 数据库建立自己的数据存储系统。

(2)扩展 ContentProvider类

开发一个继承自ContentProvider类的 子类代码来扩展 ContentProvider类,在这个步骤主要的工作是将要共享的数据包装并以ContentResolver 和 Cursor对象能够访问到的形式对外展示。具体来说需要实现ContentProvider 类中的6个抽象方法。

Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder):将查询的数据以Cursor 对象的形式返回。

Uri insert(Uri uri, ContentValues values):向 Content Provider中插入新数据记录,ContentValues 为数据记录的列名和列值映射。

int update(Uri uri, ContentValues values, String selection, String[] selectionArgs):更新Content Provider中已存在的数据记录。

int delete(Uri uri, String selection, String[] selectionArgs):从Content Provider中删除数据记录。

String getType(Uri uri):返回Content Provider中的数据( MIME )类型。

boolean onCreate():当 Content Provider 启动时被调用。

以上方法将会在ContentResolver 对象中调用,所以很好地实现这些抽象方法会为ContentResolver提供一个完善的外部接口。除了实现抽象方法外,还可以做一些提高可用性的工作。

定义一个 URI 类型的静态常量,命名为CONTENT_URI。 必须为该常量对象定义一个唯一的URI字符串,一般的做法是将 ContentProvider子类的全称类名作为URI字符串,如:
"content://wyf.wpf.MyProvider"。

定义每个字段的列名,如果采用的数据库存储系统为SQLite 数据库,数据表列名可以采用数据库中表的列名。不管数据表中有没有其他的唯一标识一个记录的字段,都应该定义一个"_id"字段 来唯一标识一个记录。模式使用 "INTEGER PRIMARY KEY AUTOINCREMENT" 自动更新 一般将这些列名字符串定义为静态常量, 如"_id"字段名定义为一个名为"_ID" 值为 "_id" 的静态字符串对象。

(3)在应用程序的AdnroidManifest.xml 文件中声明Content Provider组件。

创建好一个Content Provider必须要在应用程序的AndroidManifest.xml 中进行声明,否则该Content Provider对于 Android系统将是不可见的。如果有一个名为MyProvider的类扩展了 ContentProvider类,声明该组件的代码如下:
Xml代码 复制代码 收藏代码
  1. <provider name="wyf.wpf.MyProvider"
  2. authorities="wyf.wpf.myprovider"
  3. ...../> <!-- 为<provider>标记添加name、authorities属性-->

其中name属性为ContentProvider 子类的全称类名,authorities 属性唯一标识了一个ContentProvider。还可以通过 setReadPermission() 和 setWritePermission() 来设置其操作权限。当然也可以再上面的 xml中加入 android:readPermission 或者 android: writePermission属性来控制其权限。

注意:因为ContentProvider可能被不同的进程和线程调用,所以这些方法必须是线程安全的。


下边是一个例子修改了 SDK 中的 Notes例子。首先创建 ContentProvider 的 CONTENT_URI 和 一些字段数据,字段类可以继承自BaseColumns类,它包括了一些基本的字段,比如:_id等 代码如下:

NotePad类
Java代码 复制代码 收藏代码
  1. package xiaohang.zhimeng;
  2. import android.net.Uri;
  3. import android.provider.BaseColumns;
  4. public class NotePad {
  5. //ContentProvider的uri
  6. public static final String AUTHORITY = "com.xh.google.provider.NotePad";
  7. private NotePad(){}
  8. //定义基本字段 实现BaseColumns 这个接口里边已经定义了"_id"字段所以这里不用定义了
  9. public static final class Notes implements BaseColumns{
  10. private Notes(){}
  11. //Uri.parse 方法根据指定字符串创建一个 Uri 对象
  12. public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/notes");
  13. //新的MIME类型-多个
  14. public static final String CONTENT_TYPE = "vnd.android.cursor.dir/vnd.google.note";
  15. //新的MIME类型-单个
  16. public static final String CONTENT_ITME_TYPE = "vnd.android.cursor.item/vnd.google.note";
  17. public static final String DEFAULT_SORT_ORDER = "modified DESC";
  18. //字段
  19. public static final String TITLE = "title";
  20. public static final String NOTE = "note";
  21. public static final String CREATEDDATE = "created";
  22. public static final String MODIFIEDDATE = "modified";
  23. }
  24. }
package xiaohang.zhimeng;

import android.net.Uri;
import android.provider.BaseColumns;

public class NotePad {
	//ContentProvider的uri
	public static final String AUTHORITY = "com.xh.google.provider.NotePad";
	
	private NotePad(){}
	
	//定义基本字段   实现BaseColumns 这个接口里边已经定义了"_id"字段所以这里不用定义了
	public static final class Notes implements BaseColumns{
		private Notes(){}
		   
		//Uri.parse 方法根据指定字符串创建一个 Uri 对象
		public static final Uri		CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/notes");
		
		//新的MIME类型-多个
		public static final String 	CONTENT_TYPE = "vnd.android.cursor.dir/vnd.google.note";
		
		//新的MIME类型-单个
		public static final String 	CONTENT_ITME_TYPE  = "vnd.android.cursor.item/vnd.google.note";
		
		public static final String  DEFAULT_SORT_ORDER = "modified DESC";
		
		//字段
		public static final String  TITLE 			   = "title";
		public static final String  NOTE      		   = "note";
		public static final String  CREATEDDATE 	   = "created";
		public static final String  MODIFIEDDATE 	   = "modified";
	}
}


然后我们需要来创建自己的 ContentProvider 类的 NotePadProvider,它包括了查询、添加、删除、更新等操作以及打开和创建数据库,代码如下:

NotePadProvider 类
Java代码 复制代码 收藏代码
  1. package xiaohang.zhimeng;
  2. import java.util.HashMap;
  3. import xiaohang.zhimeng.NotePad.Notes;
  4. import android.content.ContentProvider;
  5. import android.content.ContentUris;
  6. import android.content.ContentValues;
  7. import android.content.Context;
  8. import android.content.UriMatcher;
  9. import android.content.res.Resources;
  10. import android.database.Cursor;
  11. import android.database.SQLException;
  12. import android.database.sqlite.SQLiteDatabase;
  13. import android.database.sqlite.SQLiteOpenHelper;
  14. import android.database.sqlite.SQLiteQueryBuilder;
  15. import android.net.Uri;
  16. import android.text.TextUtils;
  17. public class NotePadProvider extends ContentProvider{
  18. private static final String TAG = "NotePadProvider";
  19. //数据库名
  20. private static final String DATABASE_NAME = "note_pad.db";
  21. private static final int DATABASE_VERSION = 2;
  22. //表名
  23. private static final String NOTES_TABLE_NAME = "notes";
  24. private static HashMap<String, String> sNotesProjectionMap;
  25. private static final int NOTES = 1;
  26. private static final int NOTE_ID = 2;
  27. private static final UriMatcher sUriMatcher;
  28. private DatabaseHelper mOpenHelper;
  29. //创建表SQL语句
  30. private static final String CREATE_TABLE="CREATE TABLE"
  31. + NOTES_TABLE_NAME
  32. + "(" + Notes._ID
  33. + "INTEGER PRIMARY KEY,"
  34. + Notes.TITLE
  35. + " TEXT,"
  36. + Notes.NOTE
  37. + " TEXT,"
  38. + Notes.CREATEDDATE
  39. + " INTEGER,"
  40. + Notes.MODIFIEDDATE
  41. + " INTEGER" + "); ";
  42. static{
  43. sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
  44. sUriMatcher.addURI(NotePad.AUTHORITY, "notes", NOTES);
  45. sUriMatcher.addURI(NotePad.AUTHORITY, "notes/#", NOTE_ID);
  46. sNotesProjectionMap = new HashMap<String, String>();
  47. sNotesProjectionMap.put(Notes._ID, Notes._ID);
  48. sNotesProjectionMap.put(Notes.TITLE, Notes.TITLE);
  49. sNotesProjectionMap.put(Notes.NOTE, Notes.NOTE);
  50. sNotesProjectionMap.put(Notes.CREATEDDATE, Notes.CREATEDDATE);
  51. sNotesProjectionMap.put(Notes.MODIFIEDDATE, Notes.MODIFIEDDATE);
  52. }
  53. private static class DatabaseHelper extends SQLiteOpenHelper{
  54. //构造函数-创建数据库
  55. DatabaseHelper(Context context){
  56. super(context, DATABASE_NAME, null, DATABASE_VERSION);
  57. }
  58. //创建表
  59. @Override
  60. public void onCreate(SQLiteDatabase db) {
  61. db.execSQL(CREATE_TABLE);
  62. }
  63. //更新数据库
  64. @Override
  65. public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
  66. db.execSQL("DROP TABLE IF EXISTS notes");
  67. onCreate(db);
  68. }
  69. }
  70. //删除数据
  71. @Override
  72. public int delete(Uri uri, String selection, String[] selectionArgs) {
  73. SQLiteDatabase db = mOpenHelper.getWritableDatabase();
  74. int count;
  75. switch (sUriMatcher.match(uri)) {
  76. case NOTES:
  77. count = db.delete(NOTES_TABLE_NAME, selection, selectionArgs);
  78. break;
  79. case NOTE_ID:
  80. String noteId = uri.getPathSegments().get(1);
  81. count = db.delete(NOTES_TABLE_NAME, Notes._ID + "=" + noteId + (!TextUtils.isEmpty(selection) ? " AND (" + selection + ')' : ""), selectionArgs);
  82. break;
  83. default:
  84. throw new IllegalArgumentException("Unnown URI" + uri);
  85. }
  86. getContext().getContentResolver().notifyChange(uri, null);
  87. return count;
  88. }
  89. //如果有自定类型,必须实现该方法
  90. @Override
  91. public String getType(Uri uri) {
  92. switch (sUriMatcher.match(uri)) {
  93. case NOTES:
  94. return Notes.CONTENT_TYPE;
  95. case NOTE_ID:
  96. return Notes.CONTENT_ITME_TYPE;
  97. default:
  98. throw new IllegalArgumentException("Unknown URI " + uri);
  99. }
  100. }
  101. //插入数据库
  102. @Override
  103. public Uri insert(Uri uri, ContentValues initialValues) {
  104. if (sUriMatcher.match(uri) != NOTES) {
  105. throw new IllegalArgumentException("Unknown URI " + uri);
  106. }
  107. ContentValues values;
  108. if (initialValues != null) {
  109. values = new ContentValues(initialValues);
  110. }else {
  111. values = new ContentValues();
  112. }
  113. //返回以毫秒为单位的系统当前时间
  114. Long now = Long.valueOf(java.lang.System.currentTimeMillis());
  115. /**
  116. * contaisKey()我的理解就是判断传进来的那个ContentValues有没有相应的列值
  117. * 因为我们的一个ContentValues对象 对应一条数据库的记录
  118. * */
  119. if (values.containsKey(NotePad.Notes.CREATEDDATE) == false) {
  120. values.put(NotePad.Notes.CREATEDDATE, now);
  121. }
  122. if (values.containsKey(NotePad.Notes.MODIFIEDDATE) == false) {
  123. values.put(NotePad.Notes.MODIFIEDDATE, now);
  124. }
  125. if (values.containsKey(NotePad.Notes.TITLE) == false) {
  126. //返回一个全局共享的资源对象
  127. Resources r = Resources.getSystem();
  128. values.put(NotePad.Notes.TITLE, r.getString(android.R.string.unknownName));
  129. }
  130. if (values.containsKey(NotePad.Notes.NOTE) == false) {
  131. values.put(NotePad.Notes.NOTE, "");
  132. }
  133. SQLiteDatabase db = mOpenHelper.getWritableDatabase();
  134. long rowId = db.insert(NOTES_TABLE_NAME, Notes.NOTE, values);
  135. if (rowId > 0) {
  136. Uri noteUri = ContentUris.withAppendedId(NotePad.Notes.CONTENT_URI, rowId);
  137. getContext().getContentResolver().notifyChange(noteUri, null);
  138. return noteUri;
  139. }
  140. throw new SQLException("Failed to insert row into" + uri);
  141. }
  142. //当Content Provider启动时被调用
  143. @Override
  144. public boolean onCreate() {
  145. mOpenHelper = new DatabaseHelper(getContext());
  146. return true;
  147. }
  148. //查询操作 将查询的数据以 Cursor 对象的形式返回
  149. @Override
  150. public Cursor query(Uri uri, String[] projection, String selection,
  151. String[] selectionArgs, String sortOrder) {
  152. SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
  153. switch (sUriMatcher.match(uri)) {
  154. case NOTES:
  155. qb.setTables(NOTES_TABLE_NAME);
  156. qb.setProjectionMap(sNotesProjectionMap);
  157. break;
  158. case NOTE_ID:
  159. qb.setTables(NOTES_TABLE_NAME);
  160. qb.setProjectionMap(sNotesProjectionMap);
  161. qb.appendWhere(Notes._ID + "=" + uri.getPathSegments().get(1));
  162. break;
  163. default:
  164. throw new IllegalArgumentException("Unknown URI " + uri);
  165. }
  166. String orderBy;
  167. //返回true,如果字符串为空或0长度
  168. if (TextUtils.isEmpty(sortOrder)) {
  169. orderBy = NotePad.Notes.DEFAULT_SORT_ORDER;
  170. }else {
  171. orderBy = sortOrder;
  172. }
  173. SQLiteDatabase db = mOpenHelper.getReadableDatabase();
  174. Cursor c = qb.query(db, projection, selection, selectionArgs, null, null, orderBy);
  175. //用来为Cursor对象注册一个观察数据变化的URI
  176. c.setNotificationUri(getContext().getContentResolver(), uri);
  177. return c;
  178. }
  179. //更新数据
  180. @Override
  181. public int update(Uri uri, ContentValues values, String selection,
  182. String[] selectionArgs) {
  183. SQLiteDatabase db = mOpenHelper.getWritableDatabase();
  184. int count;
  185. switch (sUriMatcher.match(uri)) {
  186. case NOTES:
  187. count = db.update(NOTES_TABLE_NAME, values, selection, selectionArgs);
  188. break;
  189. case NOTE_ID:
  190. String noteId = uri.getPathSegments().get(1);
  191. count = db.update(NOTES_TABLE_NAME, values, Notes._ID + "=" + noteId + (!TextUtils.isEmpty(selection) ? " AND (" + selection + ')' : ""), selectionArgs);
  192. break;
  193. default:
  194. throw new IllegalArgumentException("Unknow URI " + uri);
  195. }
  196. return count;
  197. }
  198. }
package xiaohang.zhimeng;

import java.util.HashMap;
import xiaohang.zhimeng.NotePad.Notes;
import android.content.ContentProvider;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.Context;
import android.content.UriMatcher;
import android.content.res.Resources;
import android.database.Cursor;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.database.sqlite.SQLiteQueryBuilder;
import android.net.Uri;
import android.text.TextUtils;

public class NotePadProvider extends ContentProvider{
	
	private static final String 		   TAG = "NotePadProvider";
	//数据库名
	private static final String 		   DATABASE_NAME = "note_pad.db";
	private static final int 			   DATABASE_VERSION = 2;
	//表名
	private static final String 		   NOTES_TABLE_NAME = "notes";
	private static HashMap<String, String> sNotesProjectionMap;
	private static final int 			   NOTES = 1;
	private static final int 			   NOTE_ID = 2;
	private static final UriMatcher		   sUriMatcher;
	private DatabaseHelper mOpenHelper;
	//创建表SQL语句
	private static final String 		   CREATE_TABLE="CREATE TABLE"
														+ NOTES_TABLE_NAME
														+ "(" + Notes._ID
														+ "INTEGER PRIMARY KEY,"
														+ Notes.TITLE
														+ " TEXT,"
														+ Notes.NOTE
														+ " TEXT,"
														+ Notes.CREATEDDATE
														+ " INTEGER,"
														+ Notes.MODIFIEDDATE
														+ " INTEGER" + "); ";
	
	static{
		sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
		sUriMatcher.addURI(NotePad.AUTHORITY, "notes", NOTES);
		sUriMatcher.addURI(NotePad.AUTHORITY, "notes/#", NOTE_ID);
		
		sNotesProjectionMap = new HashMap<String, String>();
		sNotesProjectionMap.put(Notes._ID, Notes._ID);
		sNotesProjectionMap.put(Notes.TITLE, Notes.TITLE);
		sNotesProjectionMap.put(Notes.NOTE, Notes.NOTE);
		sNotesProjectionMap.put(Notes.CREATEDDATE, Notes.CREATEDDATE);
		sNotesProjectionMap.put(Notes.MODIFIEDDATE, Notes.MODIFIEDDATE);

	}
	
	private static class DatabaseHelper extends SQLiteOpenHelper{
		//构造函数-创建数据库
		DatabaseHelper(Context context){
			super(context, DATABASE_NAME, null, DATABASE_VERSION);
		}
		
		//创建表
		@Override
		public void onCreate(SQLiteDatabase db) {
			db.execSQL(CREATE_TABLE);
		}
		
		//更新数据库
		@Override
		public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
			db.execSQL("DROP TABLE IF EXISTS notes");
			onCreate(db);
		}
	}

	//删除数据
	@Override
	public int delete(Uri uri, String selection, String[] selectionArgs) {
		SQLiteDatabase db = mOpenHelper.getWritableDatabase();
		int count;
		switch (sUriMatcher.match(uri)) {
		case NOTES:
			count = db.delete(NOTES_TABLE_NAME, selection, selectionArgs);
			break;
			
		case NOTE_ID:
			String noteId = uri.getPathSegments().get(1);
			count = db.delete(NOTES_TABLE_NAME, Notes._ID + "=" + noteId + (!TextUtils.isEmpty(selection) ? " AND (" + selection + ')' : ""), selectionArgs);
			break;
			
		default:
			throw new IllegalArgumentException("Unnown URI" + uri);
		}
		getContext().getContentResolver().notifyChange(uri, null);
		return count;
	}
	//如果有自定类型,必须实现该方法
	@Override
	public String getType(Uri uri) {
		switch (sUriMatcher.match(uri)) {
		case NOTES:
			return Notes.CONTENT_TYPE;

		case NOTE_ID:
			return Notes.CONTENT_ITME_TYPE;
			
		default:
			throw new IllegalArgumentException("Unknown URI " + uri);
		}
	}

	//插入数据库
	@Override
	public Uri insert(Uri uri, ContentValues initialValues) {
		if (sUriMatcher.match(uri) != NOTES) {
			throw new IllegalArgumentException("Unknown URI " + uri);
		}
		ContentValues values;
		if (initialValues != null) {
			values = new ContentValues(initialValues);
		}else {
			values = new ContentValues();
		}
		//返回以毫秒为单位的系统当前时间
		Long now = Long.valueOf(java.lang.System.currentTimeMillis());
		/**
		 * contaisKey()我的理解就是判断传进来的那个ContentValues有没有相应的列值
		 * 因为我们的一个ContentValues对象 对应一条数据库的记录
		 * */
		if (values.containsKey(NotePad.Notes.CREATEDDATE) == false) {
			values.put(NotePad.Notes.CREATEDDATE, now);
		}
		if (values.containsKey(NotePad.Notes.MODIFIEDDATE) == false) {
			values.put(NotePad.Notes.MODIFIEDDATE, now);
		}
		if (values.containsKey(NotePad.Notes.TITLE) == false) {
			//返回一个全局共享的资源对象
			Resources r = Resources.getSystem();
			values.put(NotePad.Notes.TITLE, r.getString(android.R.string.unknownName));
		}
		if (values.containsKey(NotePad.Notes.NOTE) == false) {
			values.put(NotePad.Notes.NOTE, "");
		}
		SQLiteDatabase db = mOpenHelper.getWritableDatabase();
		long rowId = db.insert(NOTES_TABLE_NAME, Notes.NOTE, values);
		if (rowId > 0) {
			Uri noteUri = ContentUris.withAppendedId(NotePad.Notes.CONTENT_URI, rowId);
			getContext().getContentResolver().notifyChange(noteUri, null);
			return noteUri;
		}
		throw new SQLException("Failed to insert row into" + uri);
	}
	
	//当Content Provider启动时被调用
	@Override
	public boolean onCreate() {
		mOpenHelper = new DatabaseHelper(getContext());
		return true;
	}
	
	//查询操作  将查询的数据以 Cursor 对象的形式返回
	@Override
	public Cursor query(Uri uri, String[] projection, String selection,
			String[] selectionArgs, String sortOrder) {
		SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
		switch (sUriMatcher.match(uri)) {
		case NOTES:
			qb.setTables(NOTES_TABLE_NAME);
			qb.setProjectionMap(sNotesProjectionMap);
			break;
			
		case NOTE_ID:
			qb.setTables(NOTES_TABLE_NAME);
			qb.setProjectionMap(sNotesProjectionMap);
			qb.appendWhere(Notes._ID + "=" + uri.getPathSegments().get(1));
			break;
			
		default:
			throw new IllegalArgumentException("Unknown URI " + uri);
		}
		String orderBy;
		//返回true,如果字符串为空或0长度
		if (TextUtils.isEmpty(sortOrder)) {
			orderBy = NotePad.Notes.DEFAULT_SORT_ORDER;
		}else {
			orderBy = sortOrder;
		}
		SQLiteDatabase db = mOpenHelper.getReadableDatabase();
		Cursor c = qb.query(db, projection, selection, selectionArgs, null, null, orderBy);
		//用来为Cursor对象注册一个观察数据变化的URI
		c.setNotificationUri(getContext().getContentResolver(), uri);
		return c;
	}

	//更新数据
	@Override
	public int update(Uri uri, ContentValues values, String selection,
			String[] selectionArgs) {
		SQLiteDatabase db = mOpenHelper.getWritableDatabase();
		int count;
		switch (sUriMatcher.match(uri)) {
		case NOTES:
			count = db.update(NOTES_TABLE_NAME, values, selection, selectionArgs);
			break;
		
		case NOTE_ID:
			String noteId = uri.getPathSegments().get(1);
			count = db.update(NOTES_TABLE_NAME, values, Notes._ID + "=" + noteId + (!TextUtils.isEmpty(selection) ? " AND (" + selection + ')' : ""), selectionArgs);
			break;
			
		default:
			throw new IllegalArgumentException("Unknow URI " + uri);
		}
		
		return count;
	}
}


下面我们要来创建一个Activity类,首先向其中插入两个数据,然后通过Toast来显示数据库中的数据。 运行效果如下:





代码 Activity01 类
Java代码 复制代码 收藏代码
  1. package xiaohang.zhimeng;
  2. import android.app.Activity;
  3. import android.content.ContentValues;
  4. import android.database.Cursor;
  5. import android.net.Uri;
  6. import android.os.Bundle;
  7. import android.view.Gravity;
  8. import android.widget.Toast;
  9. public class Activity01 extends Activity {
  10. @Override
  11. public void onCreate(Bundle savedInstanceState) {
  12. super.onCreate(savedInstanceState);
  13. setContentView(R.layout.main);
  14. /*插入数据*/
  15. ContentValues values = new ContentValues();
  16. values.put(NotePad.Notes.TITLE, "title1");
  17. values.put(NotePad.Notes.NOTE, "NOTENOTE1");
  18. getContentResolver().insert(NotePad.Notes.CONTENT_URI, values);
  19. values.clear();
  20. values.put(NotePad.Notes.TITLE, "title2");
  21. values.put(NotePad.Notes.NOTE, "NOTENOTE2");
  22. getContentResolver().insert(NotePad.Notes.CONTENT_URI, values);
  23. //显示
  24. displayNote();
  25. }
  26. private void displayNote(){
  27. String columns[] = new String[] { NotePad.Notes._ID,
  28. NotePad.Notes.TITLE,
  29. NotePad.Notes.NOTE,
  30. NotePad.Notes.CREATEDDATE,
  31. NotePad.Notes.MODIFIEDDATE};
  32. Uri myUri = NotePad.Notes.CONTENT_URI;
  33. Cursor cur = managedQuery(myUri, columns, null, null, null);
  34. if (cur.moveToFirst()) {
  35. String id = null;
  36. String titile = null;
  37. do {
  38. id = cur.getString(cur.getColumnIndex(NotePad.Notes._ID));
  39. titile = cur.getString(cur.getColumnIndex(NotePad.Notes.TITLE));
  40. Toast toast = Toast.makeText(this, "TITILE:"+id + "\t" + "NOTE:" + titile, Toast.LENGTH_LONG);
  41. toast.setGravity(Gravity.TOP|Gravity.CENTER, 0, 40);
  42. toast.show();
  43. } while (cur.moveToNext());
  44. }
  45. }
  46. }
package xiaohang.zhimeng;

import android.app.Activity;
import android.content.ContentValues;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.view.Gravity;
import android.widget.Toast;

public class Activity01 extends Activity {
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        
        /*插入数据*/
        ContentValues values = new ContentValues();
        values.put(NotePad.Notes.TITLE, "title1");
        values.put(NotePad.Notes.NOTE, "NOTENOTE1");
        getContentResolver().insert(NotePad.Notes.CONTENT_URI, values);
        
        values.clear();
        values.put(NotePad.Notes.TITLE, "title2");
        values.put(NotePad.Notes.NOTE, "NOTENOTE2");
        getContentResolver().insert(NotePad.Notes.CONTENT_URI, values);
        //显示
        displayNote();
    }
    
    private void displayNote(){
    	String columns[] = new String[] { NotePad.Notes._ID,
    									  NotePad.Notes.TITLE,
    									  NotePad.Notes.NOTE,
    									  NotePad.Notes.CREATEDDATE,
    									  NotePad.Notes.MODIFIEDDATE};
    	
    	Uri myUri = NotePad.Notes.CONTENT_URI;
    	Cursor cur = managedQuery(myUri, columns, null, null, null);
    	if (cur.moveToFirst()) {
			String id = null;
			String titile = null;
			do {
				id = cur.getString(cur.getColumnIndex(NotePad.Notes._ID));
				titile = cur.getString(cur.getColumnIndex(NotePad.Notes.TITLE));
				Toast toast = Toast.makeText(this, "TITILE:"+id + "\t" + "NOTE:" + titile, Toast.LENGTH_LONG);
				toast.setGravity(Gravity.TOP|Gravity.CENTER, 0, 40);
				toast.show();
			} while (cur.moveToNext());
		}
    }
}


最后不要忘记在AndroidManifest.xml文件中声明我们使用的ContentProvider,下面是我的
AndroidManifest.xml文件
Xml代码 复制代码 收藏代码
  1. <?xml version="1.0" encoding="utf-8"?>
  2. <manifest xmlns:android="http://schemas.android.com/apk/res/android"
  3. package="xiaohang.zhimeng" android:versionCode="1"
  4. android:versionName="1.0">
  5. <application android:icon="@drawable/icon"
  6. android:label="@string/app_name">
  7. <provider android:name="NotePadProvider"
  8. android:authorities="com.xh.google.provider.NotePad" />
  9. <activity android:name=".Activity01"
  10. android:label="@string/app_name">
  11. <intent-filter>
  12. <action android:name="android.intent.action.MAIN" />
  13. <category
  14. android:name="android.intent.category.LAUNCHER" />
  15. </intent-filter>
  16. <intent-filter>
  17. <data
  18. android:mimeType="vnd.android.cursor.dir/vnd.google.note" />
  19. </intent-filter>
  20. <intent-filter>
  21. <data
  22. android:mimeType="vnd.android.cursor.item/vnd.google.note" />
  23. </intent-filter>
  24. </activity>
  25. </application>
  26. <uses-sdk android:minSdkVersion="5" />
  27. </manifest>
【PCB专题】Allegro导出3D文件 Allegro中如何导出3D文件,有没有一键导出操作? 阅读详情

相关推荐

【Cadence】Virtuoso@LayoutXL 差分电路版图镜像同步技巧详解

本文详细介绍了在Cadence Virtuoso LayoutXL中实现差分电路版图镜像同步的技巧,包括核心需求、环境配置、分步操作指南及高级技巧。通过使用LayoutXL的Group功能,工程师可以高效保持差分电路的对称性,提升版图迭代效率,确保高速信号处理的稳定性。特别适用于深亚微米工艺下的差分放大器设计。

weixin_29215391的博客 323

安卓Content Provide(内容提供者)

安卓四大组件之内容提供者Content ProvideContentProvide是什么使用Content Provide读取和操作相应程序中的数据获取ContentResolver类实例使用ContentResolver中的一系列方法进行增删改查程序中创建自己的Content Provide,给其他程序提供外部访问接口 ContentProvide是什么 ContentProvide用于实现程序之间的数据共享,提供一整套完整的机制,允许访问其他程序的数据(前提是目标程序提供外部访问的接口),同时保证被访问

qq_44356236的博客 714

使用 Wireshark 进行计算机网络协议分析

文章目录实验前准备一、Wireshark抓包示例二、Wireshark实作1、数据链路层实作一 熟悉Ethernet帧结构实作二 了解子网内/外通信时的 MAC 地址实作三 掌握 ARP 解析过程2、网络层实作一 熟悉 IP 包结构实作二 IP 包的分段与重组实作三 考察 TTL 事件3、传输层实作一 熟悉 TCP 和 UDP 段结构实作二 分析 TCP 建立和释放连接4、应用层实作一 了解 DNS 解析实作二 了解 HTTP 的请求和应答 实验前准备 本部分实验用到的是抓包和协议分析软件——Wiresha

weixin_51087836的博客 8199

Android studio学习笔记一

1.        在新建项目向导中: Application Name是App未来会显示在手机应用程序管理中的程序名称,默认也是应用程序图标下显示的文字。此外,默认也会以此作为项目名称。 Package Name(程序包名称)好比是Android App的“身份证ID”,因此Goole Play上众多的Android App其程序包名称是不能重复的。 Minimum Required

qq_27381193的博客 824

Linux 使用rm -rf /*命令后,恢复系统方法

Linux 使用rm -rf /*命令后,恢复系统方法 个人学习记录 这里实验环境采用的是radhel7.1的版本: 个人认为核心就是缺失什么组件,就从别的地方复制什么组件过来,先把系统拉起来,再慢慢恢复配置 进入救援模式 1、将/dev/sda两个分区分别挂载看看,里面的内容,有内容的就是根存在的分区 2、ifconfig eno16777777 192.168.8.2 3、从另外一台一样系统的根 。用 tar打包,一个个文件夹拷贝过来 4、到坏系统,scp另外一个系统的etc.tar.gz 5

weixin_43603476的博客 1万+

TPS563201DDCR电路翻车实录:从原理图到PCB,我踩过的5个坑及补救方法

本文详细记录了使用TPS563201DDCR电源芯片设计电路时遇到的5个常见问题及解决方案,包括EN引脚配置、BST电容选型、反馈网络设计、PCB布局优化以及散热处理。通过实际案例和数据分析,帮助工程师避免类似错误,提升电源模块的可靠性和效率。

weixin_42532938的博客 530

android 自定义 Content Provider示例

我们大家都知道让自己的数据和其它应用程序共享有两种方式:创建自己的Content Provider (即继承自Content Provider的子类) 或者是将自己的数据添加到已有的Content Provider中去,后者需要保证现有的Content Provider和自己的数据类型相同并且具有该 Content Provider的写入的权限。 如果需要创建一个Cont...

低级写手 我自由了 225

Upwork入门指南:如何创建吸引人的个人资料

本文详细介绍了如何在Upwork上创建并优化个人资料,帮助自由职业者吸引更多客户。内容包括: 注册与验证:从注册账号到邮箱验证的完整步骤。 个人资料填写:如何撰写吸引人的标题、简介,选择技能标签,以及设置专业头像和费率。 作品集与优化:上传高质量作品集,提升搜索排名和客户信任度。 常见问题解答:解决新手常见问题,如无工作经验或审核不通过。 通过本文的指导,你将学会打造一个专业且高效的个人资料,为在Upwork上获得更多机会奠定基础。

qq_61813593的博客 3518

android四大组件之-Broadcast的使用、Content Provider的使用

一、Broadcast的使用     在Android系统中,广播(Broadcast)是在组件之间传播数据(Intent)的一种机制;这些组件甚至是可以位于不同的进程中。由于广播的发送者和接收者事先不需要知道对方的存在,从而系统的各个组件可以松耦合地组织在一起,这样系统就具有高度的可扩展性,容易与其它系统进行集成。     Broadcast是广播,Android中用于接收广播的组件是Bro

wlb_blog的博客 672

【数据集】全球陆地表面反照率Albedo

【数据集】全球陆地表面反照率Albedo

WW、forever的博客 1453

[Dify 案例实战] 构建一个基于 Dify 的个人写作助理工具-带绑定资源

想要一个懂你风格、能帮你写文章、润色文字、生成大纲的 AI 写作助手? 本文将带你从 0 到 1,完整实现一个 基于 Dify 工作流的个人写作助理工具。 我们会利用 Dify 的 LLM 节点、变量传递、文本处理、知识库与多轮对话能力.

技术小甜甜:传播可落地技术,帮助个人和企业降低解决真实场景问题的成本 276

android存储方式ContentProvider

ContentProvider Android数据的四种存储方式SharedPreferences、SQLite、Content Provider和File   ContentProvider是安卓平台中,在不同应用程序之间实现数据共享的一种机制。一个应用程序如果需要让别的程序可以操作自己的数据,即可采用这种机制。并且此种方式忽略了底层的数据存储实现,ContentProvide...

linuxstuding 242

第一节:Vben Admin介绍和初次运行

本文是【实战Vben Admin + Python】的第一节,本文内容主要是介绍Vben Admin框架和我们后端使用的技术,开发环境和工具的准备本节文章的目的是Vben Admin的简单介绍,通过配置可以让项目前端运行起来,由于项目默认开启了mock,展示的都是静态模拟数据,我们在此基础上,下一节将研究分析下Vben Admin的目录。为我们后端搭建准备。

cuiwin的专栏 7415

自定义ContentProvide访问私有数据

通过自定义的ContentProvide可以访问私有数据,系统中也有许多ContentProvide,例如短信,联系人等 创建步骤: 1)先得创建数据库,通过SQLiteOpenHelper创建数据库,在onCreate方法中创建表 public class MySqlit extends SQLiteOpenHelper {     public MySqlit(Context co

smilepointwho的博客 365

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

温度PID控制PLC程序

温度PID稳定控制程序,适用于欧姆龙PLC,对其他PLC也具有很大参考价值

Android心得5.2--对ContentProvide分解介绍

1. Uri介绍 Uri代表了要操作的数据,Uri主要包含了两部分信息:1>.需要操作的ContentProvider。  2>.对ContentProvider中的什么数据进行操作,一个Uri由以下几部分组成:                                  ContentProvider(内容提供者)的scheme(计划;组合;体制;诡计)已经由Android所规定,

ykblog.github.io 1167

android 蓝牙通讯demo

android 下蓝牙通讯demo,实现了发现蓝牙,使能蓝牙,通过蓝牙发送消息。

Andriod第七课----ContentProvide

ContentProvide

u010243305的博客 321

汉书HE8,好用的汇编代码编写工具

汉书HE8,好用的汇编代码编写工具早期编写汇编代码所用功能强大

Android-ContentProvide

Android-ContentProvide概述一般应用的数据库是不允许其他应用访问的,可是在某些情况下我们又是必须要访问的,比如一些联系人云备份应用。 Android为了解决这个问题,提供了ContentProvide。它作为android的四大组件之一。 内容提供者的作用:把私有数据暴露给其他应用,通常,是把私有数据库的数据暴露给其他应用。通过single ContentResolver i

motionEnabled 707

ContentProvide 应用之间的通信

清单文件配置 exported 设置true 被的应用才可以访问  新建自定义内容提供者 extend ContendProvide package com.example.contentprovide; import android.content.ContentProvider; import android.content.ContentValues; import and

u013598111的专栏 663

四大组件之ContentProvide

应用的数据库是不允许其他应用访问的;内容提供者的作用就是让别的应用访问到你的私有数据。 内容提供者:把私有数据共享给其他应用访问;使用内容提供器可以自己定义访问规则,选择私有数据中哪些共享出去,哪些不共享;

郭可可博客 710

ContentProvide的生命周期

ContentProvide的生命周期 https://blog.youkuaiyun.com/carson_ho/article/details/76101093 定义 & 作用 定义:即内容提供者,是 Android 四大组件之一 作用:进程间 进行数据交互 & 共享,即跨进程通信 原理 ContentProvider的底层是采用 Android中的Binder机制 具体使用 关于ContentProvider的使用主要介绍以下内容: 统一资源标识符(URI) 定义:Uniform Reso

zhanlan5211的博客 941

ContentProvide

: 是android的四大组件之一。 *、新建类,继承contentProvider类,注册contentProvider *、在onCreate方法中获得SQLiteDatabase的对象,关联数据库。 *、在对应方法里实现数据库的相关操作。

路漫漫其修远兮 1337

Android四大组件之一 ContentProvide

四大组件之一 content provide

fry3309的博客 3845

ContentProvide之手机联系人

1.系统联系人主要表的构成 mimetype表:主要存储数据的mime类型 data表:主要存储联系人的数据 raw_contacts表:主要存储联系人的ID、姓名、删除标记 contacts表:ID以及一些辅助信息 2.使用ContentResolve访问系统联系人使用的帮助类--ContactsContract、ContentProviderOperation 使用Contacts

Simple_Man_Just的博客 1083

adb命令查看contentprovide

场景:自己写了一个contentprovide不知道是否生效,需要验证,当然也可以写一个demo apk验证,但是写demo还是太麻烦了,更便捷的方式就是adb命令查看contentprovide内容 直接给出adb命令查看contentprovide的命令: adb shell ontent query --uri content://com.android.partnerbrowsercustomizations/homepage 其中:com.android.partnerbrowsercu

wangxianlin2008的博客 2184

浅析ContentProvide

一、作用。     提供私有数据供别的APP使用。 二、主要步骤。    1、定义ContentProvider的子类继承ContentProvider类。     2、重写相关方法。 其方法有           1)booleanonCreate():一般在里面获得SQLiteDatabase实例,              SQLiteDatabase db=newDBHelp(

merbn的博客 1526

android四大组件之ContentProvide

在应用程序中很多内容是共享的(可以被多个程序访问),如系统的电话本程序,短信,媒体库等程序都实现了数据的共享,当然其使用的就是内容提供器 ContentProvider :主要用于在不同的应用程序之间实现数据共享的功能,允许一个程序访问另一个程序中的数据,同时还能保证数据的安全性,其可以选择对那一部分数据进行共共享,从而保证隐私数据不会泄露。 内容提供器一般有两种用法: 1:使用现有的内容提

WannerWang的博客 1918
上一篇: Android进程与线程基本知识
下一篇: ContentProvider简介
Jymot
博客等级 码龄14年 6粉丝 15原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值