ContentProvider
ContentProvider是一种数据共享机制,它将同意其他应用程序对自身应用程序中的数据
运行增删改查操作;
ContentProvider是Android核心组件之中的一个,因此,开发者在创建它时,须要自己定义继承
ContentProvider,并且,它须要在项目清单文件里(AndroidMainfest.xml)中注冊。
ContentProvider须要定义用于訪问数据的URI,当其它应用程序知晓相应的URI时,就可以
运行数据的相关操作。
ContentProvider无需被激活,当配置了ContentProvider的应用程序被安装到设备上。
同一台设备上的其他应用程序随时都能够訪问它的数据。
ContentProvider的开发步骤:
自己定义类继承android,content.ContentProvider类。
重写android.content.ContentProvider类中声明的抽象方法;
在AndroidMainfest.xml文件里配置ContentProvider:
创建<application>节点下加入<provider>子节点。
配置android.name属性,指定ContentProvider类;
配置android.authorities属性,指定用于訪问数据的URI的host部分;
配置android:exported属性,指定值为true。
标准URI:scheme://host:port/path
比如:http://www.goole.com:80/android
注意:基于ContentProvider中数据增删改查的方法与使用SQLite数据库时使用的方法极为相似。因此,
大多数的ContentProvider共享的数据的方式都是通过操作SQLite数据库完毕的,可是,ContentProvider
与SQLite数据库没有必定的关联。
ContentProvider样例:
package com.example.lianxi; import android.content.ContentProvider; import android.content.ContentValues; import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; import android.net.Uri; public class StudentProvider extends ContentProvider{ private DBOpenHelper helper; @Override public int delete(Uri arg0, String selection, String[] selectionArgs) { SQLiteDatabase db = helper.getReadableDatabase(); db.delete("students", selection, selectionArgs); return 0; } @Override public String getType(Uri uri) { // TODO Auto-generated method stub return null; } @Override public Uri insert(Uri uri, ContentValues values) { //插入 SQLiteDatabase db = helper.getReadableDatabase(); db.insert("students", null, values); return null; } @Override public boolean onCreate() { // 完毕初始化的操作 helper = new DBOpenHelper(getContext()); return false; } @Override public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { // 查询 SQLiteDatabase db = helper.getReadableDatabase(); Cursor cursor = db.query("students", projection, selection, selectionArgs, null, null, sortOrder); return cursor; } @Override public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { SQLiteDatabase db = helper.getReadableDatabase(); db.update("students", values, selection, selectionArgs); return 0; } }
DBOpenHelper:
package com.example.lianxi; import android.content.Context; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteOpenHelper; public class DBOpenHelper extends SQLiteOpenHelper{ public DBOpenHelper(Context context){ super(context,"number2.db",null,1); } @Override public void onCreate(SQLiteDatabase db) { // TODO Auto-generated method stub String sql = "CREATE TABLE [students] (" +"[_id] INTEGER PRIMARY KEY AUTOINCREMENT," +"[_name] VARCHAR(50) UNIQUE NOT NULL," +"[_age] INT NOT NULL DEFAULT 16" +")"; db.execSQL(sql); } @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { // TODO Auto-generated method stub } }
MainActivity:
package com.example.lianxi; import android.app.Activity; import android.content.ContentValues; import android.content.SharedPreferences; import android.content.SharedPreferences.Editor; import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; import android.os.Bundle; import android.view.View; import android.widget.EditText; import android.widget.Toast; public class MainActivity extends Activity { private DBOpenHelper helper; private SQLiteDatabase db; private EditText name; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); helper = new DBOpenHelper(this); db = helper.getReadableDatabase(); name = (EditText) findViewById(R.id.name); } public void find_All(View view){ Cursor cursor = db.query("students", new String[]{"_id","_name","_age"}, null, null, null, null, "_id desc"); long id; String name; int age; for(cursor.moveToFirst(); !cursor.isAfterLast();cursor.moveToNext()){ id = cursor.getLong(cursor.getColumnIndex("_id")); name = cursor.getString(cursor.getColumnIndex("_name")); age = cursor.getInt(cursor.getColumnIndex("_age")); System.out.println("id = " + id + " ," + "name = " +name +" ," + "age = " + age); } cursor.close(); } public void findName(View view){ String findName = name.getText().toString(); Cursor cursor = db.query("students", null, "_name=?", new String[]{findName}, null, null, null); if(cursor.moveToFirst()){ long id1; String name1; int age1; id1 = cursor.getLong(cursor.getColumnIndex("_id")); name1 = cursor.getString(cursor.getColumnIndex("_name")); age1 = cursor.getInt(cursor.getColumnIndex("_age")); Toast.makeText(this, "学生记录为id = " + id1 + " ," + "name = " +name1 + " ," + "age = " + age1, Toast.LENGTH_LONG).show(); }else{ Toast.makeText(this, "没有匹配的记录!
", Toast.LENGTH_LONG).show(); } } }
布局设置:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical" > <Button android:id="@+id/find_all" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_marginTop="30dp" android:onClick="find_All" android:text="查询全部数据" /> <LinearLayout android:layout_width="fill_parent" android:layout_height="fill_parent" android:layout_marginTop="30dp" android:orientation="horizontal" > <EditText android:id="@+id/name" android:layout_width="wrap_content" android:layout_height="wrap_content" android:ems="10" > </EditText> <Button android:id="@+id/find" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginLeft="20dp" android:onClick="findName" android:text="查询" /> </LinearLayout> </LinearLayout>
要在AndroidMainfest.xml中注冊:
<provider android:name="com.example.lianxi.StudentProvider"
android:exported="true"
android:authorities="test"></provider>
訪问ContentProvider共享的数据
ContentResolver:ContentResolver:用于訪问其他应用程序通过ContentProvider共享的数据;
通过ContextWraper类定义的getContentResolver()方法就可以获取ContentResolver的对象。
通过使用ContentResolver訪问上一个应用程序内的数据。样例:
布局不需改动,MainActivity:
package com.example.lianxi; import android.app.Activity; import android.content.ContentValues; import android.content.SharedPreferences; import android.content.SharedPreferences.Editor; import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; import android.os.Bundle; import android.view.View; import android.widget.EditText; import android.widget.Toast; public class MainActivity extends Activity { private DBOpenHelper helper; private SQLiteDatabase db; private EditText name; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); helper = new DBOpenHelper(this); db = helper.getReadableDatabase(); name = (EditText) findViewById(R.id.name); } public void find_All(View view){ Cursor cursor = db.query("students", new String[]{"_id","_name","_age"}, null, null, null, null, "_id desc"); long id; String name; int age; for(cursor.moveToFirst(); !cursor.isAfterLast();cursor.moveToNext()){ id = cursor.getLong(cursor.getColumnIndex("_id")); name = cursor.getString(cursor.getColumnIndex("_name")); age = cursor.getInt(cursor.getColumnIndex("_age")); System.out.println("id = " + id + " ," + "name = " +name +" ," + "age = " + age); } cursor.close(); } public void findName(View view){ String findName = name.getText().toString(); Cursor cursor = db.query("students", null, "_name=?", new String[]{findName}, null, null, null); if(cursor.moveToFirst()){ long id1; String name1; int age1; id1 = cursor.getLong(cursor.getColumnIndex("_id")); name1 = cursor.getString(cursor.getColumnIndex("_name")); age1 = cursor.getInt(cursor.getColumnIndex("_age")); Toast.makeText(this, "学生记录为id = " + id1 + " ," + "name = " +name1 + " ," + "age = " + age1, Toast.LENGTH_LONG).show(); }else{ Toast.makeText(this, "没有匹配的记录!", Toast.LENGTH_LONG).show(); } } }
訪问到的结果为:
12-30 13:36:02.608: I/System.out(1305): id=1 12-30 13:36:02.616: I/System.out(1305): name=Mike 12-30 13:36:02.616: I/System.out(1305): age=28 12-30 13:36:02.616: I/System.out(1305): id=2 12-30 13:36:02.616: I/System.out(1305): name=fgusdfg 12-30 13:36:02.616: I/System.out(1305): age=21 12-30 13:36:02.616: I/System.out(1305): id=3 12-30 13:36:02.616: I/System.out(1305): name=huanghdf 12-30 13:36:02.616: I/System.out(1305): age=23 12-30 13:36:02.616: I/System.out(1305): id=4 12-30 13:36:02.616: I/System.out(1305): name=Macal 12-30 13:36:02.616: I/System.out(1305): age=45 12-30 13:36:02.616: I/System.out(1305): id=5 12-30 13:36:02.616: I/System.out(1305): name=jiaokong 12-30 13:36:02.616: I/System.out(1305): age=34 12-30 13:36:02.616: I/System.out(1305): id=6 12-30 13:36:02.620: I/System.out(1305): name=sdfff 12-30 13:36:02.620: I/System.out(1305): age=56
SimpleCursorAdapter:
SimpleCursorAdapter是一种使用Cursor对象作为数据源的Adapter。
使用SimpleCursorAdapter时,要求Cursor对象中必须存在名为_id的列。
使用实例,相同訪问的是上面应用的数据:
MainActivity:
package com.example.contentresolver; import android.app.Activity; import android.content.ContentResolver; import android.database.Cursor; import android.net.Uri; import android.os.Bundle; import android.support.v4.widget.SimpleCursorAdapter; import android.view.Menu; import android.view.MenuItem; import android.widget.ListView; public class MainActivity extends Activity { private ListView listView; private SimpleCursorAdapter adapter; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); ContentResolver cr = getContentResolver(); Uri uri = Uri.parse("content://test"); Cursor cursor = cr.query(uri, new String[] { "_id", "_name", "_age" }, null, null, null); listView = (ListView) findViewById(R.id.lv_student); String[] from = { "_id", "_name", "_age" }; int[] to = { R.id.item_id, R.id.item_name, R.id.item_age }; adapter = new SimpleCursorAdapter(this, R.layout.student_item, cursor, from, to, 0); listView.setAdapter(adapter); } }
布局:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:gravity="center_vertical" > <LinearLayout android:id="@+id/ll_head" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal" > <TextView android:id="@+id/tv_id" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="ID" android:gravity="center" android:layout_weight="1" android:padding="3dp" android:layout_margin="1dp" android:background="#aaaaaa" android:textColor="#ffffff"/> <TextView android:id="@+id/tv_name" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="NAME" android:gravity="center" android:layout_weight="1" android:padding="3dp" android:layout_margin="1dp" android:background="#aaaaaa" android:textColor="#ffffff"/> <TextView android:id="@+id/tv_age" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="AGE" android:gravity="center" android:layout_weight="1" android:padding="3dp" android:layout_margin="1dp" android:background="#aaaaaa" android:textColor="#ffffff"/> </LinearLayout> <ListView android:id="@+id/lv_student" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_marginTop="30dp"></ListView> </RelativeLayout>
item_student:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="horizontal" > <TextView android:id="@+id/item_id" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="ID" android:gravity="center" android:layout_weight="1" android:padding="3dp" android:layout_margin="1dp" /> <TextView android:id="@+id/item_name" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="NAME" android:gravity="center" android:layout_weight="1" android:padding="3dp" android:layout_margin="1dp" /> <TextView android:id="@+id/item_age" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="AGE" android:gravity="center" android:layout_weight="1" android:padding="3dp" android:layout_margin="1dp" /> </LinearLayout>
ContentProvider中的URI,自己定义ContentProvider。实例:
核心代码:
StudentProvider:
package com.example.lianxi; 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; public class StudentProvider extends ContentProvider { /* * 验证URI 1、是否合法 2、推断操作类型 */ /* * 合法的URI content://com.example.lianxi.providers/student 訪问所有的数据 * content://com.example.lianxi.providers/student/5 訪问ID为5的数据 */ private DBOpenHelper helper; private static UriMatcher MATCHER;// 用于验证URi的类 private static String AUTHORITY = "com.example.lianxi.providers"; private static String PATH = "student"; private static int MATCHER_ALL = 23; private static int MATCHER_ID = 34; static { MATCHER = new UriMatcher(UriMatcher.NO_MATCH); MATCHER.addURI(AUTHORITY, PATH, MATCHER_ALL); MATCHER.addURI(AUTHORITY, PATH + "/#", MATCHER_ID); } @Override public int delete(Uri uri, String selection, String[] selectionArgs) { if (MATCHER.match(uri) == MATCHER_ID) { SQLiteDatabase db = helper.getReadableDatabase(); long id = ContentUris.parseId(uri); String whereClause; if (selection == null || "".equals(selection)) { whereClause = "_id" + id; } else { whereClause = selection + " and _id=" + id; } int result = db.delete("students", whereClause, selectionArgs); return result; } else { throw new IllegalArgumentException("非法的URI:" + uri.toString()); } } @Override public String getType(Uri uri) { // TODO Auto-generated method stub return null; } @Override public Uri insert(Uri uri, ContentValues values) { // 插入 if (MATCHER.match(uri) == MATCHER_ALL) { SQLiteDatabase db = helper.getReadableDatabase(); long id = db.insert("students", null, values); return ContentUris.withAppendedId(uri, id);// 返回的为两者合成的 } else { throw new IllegalArgumentException("非法的URI:" + uri.toString()); } } @Override public boolean onCreate() { // 完毕初始化的操作 helper = new DBOpenHelper(getContext()); return false; } @Override public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { // 查询 if (MATCHER.match(uri) == MATCHER_ALL) { SQLiteDatabase db = helper.getReadableDatabase(); Cursor cursor = db.query("students", projection, selection, selectionArgs, null, null, sortOrder); return cursor; } else if (MATCHER.match(uri) == MATCHER_ID) { SQLiteDatabase db = helper.getReadableDatabase(); long id = ContentUris.parseId(uri); String whereClause; if (selection == null || "".equals(selection)) { whereClause = "_id=" + id; } else { whereClause = selection + " and _id=" + id; } Cursor cursor = db.query("students", projection, whereClause, selectionArgs, null, null, sortOrder); return cursor; } else { throw new IllegalArgumentException("非法的URI:" + uri.toString()); } } @Override public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { if (MATCHER.match(uri) == MATCHER_ID) { SQLiteDatabase db = helper.getReadableDatabase(); long id = ContentUris.parseId(uri); String whereClause; if (selection == null || "".equals(selection)) { whereClause = "_id=" + id; } else { whereClause = selection + " and _id=" + id; } int result = db .update("students", values, whereClause, selectionArgs); return result; } else { throw new IllegalArgumentException("非法的URI:" + uri.toString()); } } }
执行时须要先将上一个应用部署到虚拟机中。然后再将获取数据的应用执行,
通过一个应用获取还有一个应用中的数据:
其它代码同上:核心代码:
Uri uri = Uri.parse("content://com.example.lianxi.providers/student/5");//获取一个数值
Uri uri = Uri.parse("content://com.example.lianxi.providers/student");//获取全部数值
ContentObserver监听数据的变化
使用ContentObserver可监听数据变化,当注冊了ContentObserver的URI相应的数据发生变化时。该类中的onChange()
方法会被回调。
调用ContentResolver类定义的registerContentObserver()能够注冊ContentObserver。
注意:ContentObserver的工作原理并非每分每秒的监听相应的数据,仅仅有ContentProvider的增删改查方法必须通知
了数据发生变化以后。ContentObserver才干知晓数据的变化。
实例:
核心代码:
StudentProvider:
@Override public int delete(Uri uri, String selection, String[] selectionArgs) { if (MATCHER.match(uri) == MATCHER_ID) { SQLiteDatabase db = helper.getReadableDatabase(); long id = ContentUris.parseId(uri); String whereClause; if (selection == null || "".equals(selection)) { whereClause = "_id=" + id; } else { whereClause = selection + " and _id=" + id; } int result = db.delete("students", whereClause, selectionArgs); this.getContext().getContentResolver().notifyChange(uri, null); return result; } else { throw new IllegalArgumentException("非法的URI:" + uri.toString()); } }
MainActivity:
package com.example.contentresolver; import android.app.Activity; import android.content.ContentResolver; import android.content.ContentUris; import android.database.ContentObserver; import android.database.Cursor; import android.net.Uri; import android.os.Bundle; import android.os.Handler; import android.support.v4.widget.SimpleCursorAdapter; import android.view.ContextMenu; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.view.ContextMenu.ContextMenuInfo; import android.widget.AdapterView.AdapterContextMenuInfo; import android.widget.ListView; public class MainActivity extends Activity { private ListView listView; private SimpleCursorAdapter adapter; private Cursor cursor; private Uri uri; private ContentResolver cr; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); cr = getContentResolver(); uri = Uri.parse("content://com.example.lianxi.providers/student");//获取一个数值 // Uri uri = Uri.parse("content://com.example.lianxi.providers/student");//获取全部数值 cursor = cr.query(uri, new String[] { "_id", "_name", "_age" }, null, null, null); ContentObserver observer = new ContentObserver(new Handler()){ @Override public void onChange(boolean selfChange) { // TODO Auto-generated method stub cursor.requery(); adapter.notifyDataSetChanged(); super.onChange(selfChange); } }; cr.registerContentObserver(uri, true, observer); listView = (ListView) findViewById(R.id.lv_student); String[] from = { "_id", "_name", "_age" }; int[] to = { R.id.item_id, R.id.item_name, R.id.item_age }; adapter = new SimpleCursorAdapter(this, R.layout.student_item, cursor, from, to, 0); listView.setAdapter(adapter); registerForContextMenu(listView); } @Override public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) { // TODO Auto-generated method stub AdapterContextMenuInfo info = (AdapterContextMenuInfo)menuInfo; int position = info.position; cursor.moveToPosition(position); String studentName = cursor.getString(cursor.getColumnIndex("_name")); menu.add(Menu.NONE,1,1,"删除"+ studentName ); super.onCreateContextMenu(menu, v, menuInfo); } @Override public boolean onContextItemSelected(MenuItem item) { // TODO Auto-generated method stub AdapterContextMenuInfo info = (AdapterContextMenuInfo) item.getMenuInfo(); int position = info.position; cursor.moveToPosition(position); long id = cursor.getLong(cursor.getColumnIndex("_id")); Uri deleteUri = ContentUris.withAppendedId(uri, id); cr.delete(deleteUri,null,null); return super.onContextItemSelected(item); } }
今天今天2015年最后一天。
。
。。