Android四大组件之ContentProvider(1)
ContentProvider 是 Android四大组件之一,Android提供了五种数据存储技术(其他的四种分别是:SharedPreferences、IO、SQLite、网络)。这五种技术都能由ContentProvider提供的方法按统一的代码格式存取。这种以一致性的方法操作多样性的数据源与面向对象的多态异曲同工。
Android中的Contentprovider机制可支持在多个应用中存储和读取数据。这也是跨应用共享数据的唯一方式。在android系统中,没有一个公共的内存区域,供多个应用共享存储数据。
Android提供了一些主要数据类型的Contentprovider,比如音频、视频、图片和私人通讯录等。可在android.provider包下面找到一些android提供的Contentprovider。可以获得这些Contentprovider,查询它们包含的数据,当然前提是已获得适当的读取权限。
ContentProvider是什么时候创建的,是谁创建的?访问某个应用程序共享的数据,是否需要启动这个应用程序?这个问题在Android SDK中没有明确说明,但是从数据共享的角度出发,ContentProvider应该是Android在系统启动时就创建了,否则就谈不上数据共享了。这就要求在AndroidManifest.XML中使用<provider>元素明确定义。
下面以一个简单的案例来介绍下如何通过ContentProvider来访问本APP中的数据。
ContentProvider类的使用步骤
1、自定义MyProvider extends ContentProvider子类,在该类中重写用于增删改查的操作。
2、在AndroidManifest.xml中注册该类
3、设定共享数据的uri地址。
4、在其它类或其他项目中调用ContentResolver对象中的增删改查方法,按uri提供的地址对数据进行操作。
MyProvider.java
package com.example.contentprovider_01; import com.example.util.MySQLiteOpenHelper; import com.example.util.Persons; import android.content.ContentProvider; import android.content.ContentUris; import android.content.ContentValues; import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; import android.net.Uri; public class MyProvider extends ContentProvider { MySQLiteOpenHelper mSQLiteHelper; int count = 1; @Override public int delete(Uri uri, String selection, String[] selectionArgs) { SQLiteDatabase db = mSQLiteHelper.getWritableDatabase(); int id = db.delete(Persons.TABLE_NAME, selection, selectionArgs); return id; } @Override public String getType(Uri uri) { return null; } @Override public Uri insert(Uri uri, ContentValues values) { SQLiteDatabase db = mSQLiteHelper.getWritableDatabase(); // 返回的是插入那条数据的id long id = db.insert(Persons.TABLE_NAME, null, values); return ContentUris.withAppendedId(uri, id); } @Override public boolean onCreate() { // 创建MySQLiteOpenHelper对象 mSQLiteHelper = new MySQLiteOpenHelper(getContext()); return false; // ? } @Override public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { SQLiteDatabase db = null; try { if (count == 1) { //用来控制初始化的数据只往数据库插一次 db = mSQLiteHelper.getWritableDatabase(); mSQLiteHelper.insert(); count++; } else { db = mSQLiteHelper.getReadableDatabase(); Cursor cursor = db.query(Persons.TABLE_NAME, projection, selection, selectionArgs, null, null, sortOrder); return cursor; } } catch (Exception e) { e.printStackTrace(); } return null; } @Override public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { SQLiteDatabase db = mSQLiteHelper.getWritableDatabase(); int id = db .update(Persons.TABLE_NAME, values, selection, selectionArgs); return id; } }
注册MyProvider类
<provider android:name=".MyProvider" android:authorities="com.example.myProvider" > <!--authorities属性设置提供其它项目调用MyProvider类中方法的地址。--> </provider>
ContentResolver类的使用
ContentResolver类用于操作ContentProvider共享的数据。该类提供了与ContentProvider类同名的方法,只要获得了ContentProvider类在AndroidManifest.xml中注册的authorities属性值,就能用ContentProvider类中的同名方法操作ContentProvider类所在的项目中的数据。
1,创建ContentResolver对象
ContentResolver mResolver = this.getContentResolver(); //this是当前组件,如Activity类的对象
2,对数据进行操作
Cursor cursor = query(Uri uri, String[] projection, String selection,String[] selectionArgs, String sortOrder)
SQLiteOpenHelper类的使用
SQliteOpenHelper是一个抽象类,来管理数据库的创建和版本的管理。要使用它必须实他的构造方法、onCreate(SQLiteDatabase),onUpgrade(SQLiteDatabase, int, int)方法。其详细讲解我会在SQLite的部分再详细说明。
本案例是要使用ContentProvider来访问SQLite数据库。因为SQLite数据库只能被本应用访问,我们可以通过使用ContentProvider来把SQLite中的数据公开给其它应用访问。
MySQLiteOpenHelper.java代码如下:
package com.example.util; import android.content.ContentValues; import android.content.Context; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteOpenHelper; /** * 该类继承自SQLiteOpenHelper,创建SQLite数据库、表、对表进行增删改查 * */ public class MySQLiteOpenHelper extends SQLiteOpenHelper { // 创建库名:provider.db的数据库 public MySQLiteOpenHelper(Context context) { super(context, "provider.db", null, 1); } // 创建t_person表 @Override public void onCreate(SQLiteDatabase db) { db.execSQL("DROP TABLE IF EXISTS t_person"); db.execSQL("CREATE TABLE IF NOT EXISTS t_person " + "(_id integer primary key autoincrement," + " name varchar(20), " + "phone varchar(12))"); } // 数据库版本更新时用 @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { } // 增加3条记录 public void insert() { ContentValues values = new ContentValues(); values.put(Persons.COLUMN_NAME, "悟空"); values.put(Persons.COLUMN_PHONE, "13554391999"); SQLiteDatabase db = this.getWritableDatabase(); db.insert(Persons.TABLE_NAME, null, values); values.put(Persons.COLUMN_PHONE, "13554391888"); db.execSQL("insert into t_person(name,phone) values ('唐僧','1383838338')"); db.execSQL("insert into t_person(name,phone) values ('八戒','8787887')"); } }
提供一个存储常量的工具类Persons.java
public class Persons { public static final String TABLE_NAME = "t_person"; public static final String COLUMN_NAME = "name"; public static final String COLUMN_PHONE = "phone"; }
界面如下:按钮下面是一个ListView,用来显示数据
MainActivity.java代码如下:
package com.example.contentprovider_01; import com.example.util.Persons; import android.net.Uri; import android.os.Bundle; import android.app.Activity; import android.content.ContentResolver; import android.content.ContentValues; import android.database.Cursor; import android.support.v4.widget.SimpleCursorAdapter; import android.view.Menu; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.ListView; import android.widget.TextView; public class MainActivity extends Activity implements OnClickListener { // 以下解析的字符串是AndroidManifest.xml中<Provider>标签authorities属性的值 private static final Uri URI_TEST = Uri .parse("content://com.example.myProvider"); // 声明成员变量 ContentResolver mResolver; SimpleCursorAdapter mAdapter; Button btnAdd, btnDelete, btnUpdate, btnQuery; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); setupView(); ListView listView = (ListView) findViewById(R.id.listview); // 创建MySQLiteOpenHelper对象 mResolver = getContentResolver(); // 创建Cursor对象,这里通过ContentResolver来进行查询操作,实际上就是调用ContentProvider对象中的方法。 Cursor cursor = mResolver.query(URI_TEST, null, null, null, null); // 创建CursorAdapter对象 mAdapter = new SimpleCursorAdapter(this, R.layout.listview_item, cursor, new String[] { Persons.COLUMN_NAME, Persons.COLUMN_PHONE }, new int[] { R.id.tv_name, R.id.tv_phone }); listView.setAdapter(mAdapter); } private void setupView() { btnAdd = (Button) findViewById(R.id.btn_add); btnDelete = (Button) findViewById(R.id.btn_delete); btnUpdate = (Button) findViewById(R.id.btn_update); btnQuery = (Button) findViewById(R.id.btn_query); btnAdd.setOnClickListener(this); btnDelete.setOnClickListener(this); btnUpdate.setOnClickListener(this); btnQuery.setOnClickListener(this); } @Override public void onClick(View v) { switch (v.getId()) { case R.id.btn_add: ContentValues values = new ContentValues(); values.put(Persons.COLUMN_NAME, "沙僧"); values.put(Persons.COLUMN_PHONE, "1414141414"); mResolver.insert(URI_TEST, values); break; case R.id.btn_delete: mResolver.delete(URI_TEST, "_id=?", new String[] { "1" }); break; case R.id.btn_update: ContentValues values2 = new ContentValues(); values2.put(Persons.COLUMN_NAME, "唐三藏"); values2.put(Persons.COLUMN_PHONE, "88888888"); mResolver.update(URI_TEST, values2, "_id=?", new String[] { "2" }); break; case R.id.btn_query: break; } // 查询表 queryAll(); } private void queryAll() { Cursor cursor = mResolver.query(URI_TEST, null, null, null, null); mAdapter.changeCursor(cursor);// 更新游标适配器对象 mAdapter.notifyDataSetChanged();// 通知垂直列表空间数据发生改变 } }
运行过程:
当运行程序是,首先调用MainActivity中的onCreate(),获取ContentResolver的对象,调用其query()。实际上通过ContentResolver对象调用了MyProvider中的query().在此之前,Android系统会先创建MyProvider对象,调用其onCreate(),在这里也就创建了SQLiteOpenHelper对象;在执行MyProvider的query()中,就是利用SQLiteOpenHelper的对象来访问数据库。
运行结果:
1)当程序运行后,显示如上图的界面。
2)当点击QUERY-->
3)当点击ADD
4) 当点击其他按钮都可以看到对应的改变。说明可以通过ContentProvider来访问本地数据库数据。