前言:在App开发中,如果想让应用中的某些数据能够被提供给其他应用访问,可以使用ContentProvider。
ContentProvider是Android的四大组件之一,是Android应用中的基础模块。它的作用是使应用中的数据能够被提供给其他应用访问。当你需要对外共享数据时,你可以使用ContentProvider,它会将数据封装并通过ContentResolver接口使其他应用能够访问共享的数据。ContentProvider实际上是对SQLiteOpenHelper的进一步封装,通过Uri映射来判断所要操作的数据库中的表,并进行增、删、改、查等操作。
URI是Uniform Resource Identifier(统一资源标识符)的缩写,是一个用于标识某一网络中资源名称的字符串。它允许用户对任何本地或互联网的资源通过特定的协议进行交互操作。
Android中ContentResolver中的URI,主要包括了两部分信息:一个是需要操作的ContentProvider,另一个是对ContentProvider中的哪个表进行操作。其主要格式如下:
schema:格式为content://,这是由Android固定设置的。
authority:用于唯一标识某个ContentProvider,外部调用者通过这个标识来找到所需的ContentProvider。
path:所要操作的表
id:查询数据是指定的查询条件,可选字段。
例如,当我们要查询手机系统中的音频文件时,我们会使用到Android系统定义好的“MediaStore.Audio.Media.EXTERNAL_CONTENT_URI”,查询源码可以得知,这个Uri的实际值是"content://media/external/audio/media"
要创建一个ContentProvider,只需创建一个类继承ContentProvider,然后覆写onCreate()、getType()、insert()、delete()、update()、query()几个方法。接下来,再使用ContentResolver调用对应的方法来对数据进行操作。下面我们通过实践来创建一个ContentProvider保存一些信息,然后通过ContentResolver来处理。
步骤一:首先,我们需要准备一个数据库。代码如下:
package com.test.myapplication; import android.content.Context; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteOpenHelper; public class MyDatabaseHelper extends SQLiteOpenHelper { public MyDatabaseHelper(Context context) { super(context, "mydb", null, 1); } @Override public void onCreate(SQLiteDatabase db) { String sql = "CREATE TABLE userinfo (name VARCHAR(20),tel VARCHAR(20))"; db.execSQL(sql); } @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { } }
步骤二:接下来,创建一个类继承ContentProvider,并且在对应的方法中执行数据库操作。代码如下(这里只做插入数据和查询数据):
package com.test.myapplication; import android.content.ContentProvider; import android.content.ContentValues; import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; import android.net.Uri; public class MyContentProvider extends ContentProvider { private MyDatabaseHelper myDatabaseHelper; public MyContentProvider() { } @Override public boolean onCreate() { myDatabaseHelper = new MyDatabaseHelper(getContext()); return true; } @Override public String getType(Uri uri) { // TODO: Implement this to handle requests for the MIME type of the data // at the given URI. throw new UnsupportedOperationException("Not yet implemented"); } @Override public Uri insert(Uri uri, ContentValues values) { SQLiteDatabase db = myDatabaseHelper.getWritableDatabase(); db.insert("userinfo", null, values); return uri; } @Override public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { SQLiteDatabase db = myDatabaseHelper.getWritableDatabase(); Cursor cursor = db.query("userinfo", projection, selection, selectionArgs, null, null, sortOrder); return cursor; } @Override public int delete(Uri uri, String selection, String[] selectionArgs) { throw new UnsupportedOperationException("Not yet implemented"); } @Override public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { throw new UnsupportedOperationException("Not yet implemented"); } }
步骤三:接下来,要在AndroidManifest.xml文件中注册上述ContentProvider。代码如下:
android:name=".MyContentProvider"
android:authorities="myprovider"
android:enabled="true"
android:exported="true">
步骤四:最后,在Activity中,用两个按钮测试插入数据和查询数据操作。代码如下:
package com.test.myapplication; import android.content.ContentResolver; import android.content.ContentValues; import android.database.Cursor; import android.net.Uri; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.util.Log; import android.view.View; import android.widget.Button; public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Button btnSave = (Button) findViewById(R.id.main_button); btnSave.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { ContentValues contentValues = new ContentValues(); contentValues.put("name", "test1"); contentValues.put("tel", "123456"); Uri uri = Uri.parse("content://myprovider/userinfo"); ContentResolver contentResolver = getContentResolver(); contentResolver.insert(uri, contentValues); } }); Button btnQuery = (Button) findViewById(R.id.main_button1); btnQuery.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Uri uri = Uri.parse("content://myprovider/userinfo"); ContentResolver contentResolver = getContentResolver(); Cursor cursor = contentResolver.query(uri, null, null, null, null); if (cursor.moveToFirst()) { Log.e("btnQuery", "onClick: name======" + cursor.getString(cursor.getColumnIndex("name"))); Log.e("btnQuery", "onClick: tel=======" + cursor.getString(cursor.getColumnIndex("tel"))); } } }); } }
实例:使用ContentResolver查询手机中本地图片文件
package com.test.myapplication; import android.content.ContentResolver; import android.database.Cursor; import android.provider.MediaStore; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.util.Log; import android.view.View; import android.widget.Button; public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Button btnOpenWifi = (Button) findViewById(R.id.main_button); btnOpenWifi.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { //获取ContentResolver实例 ContentResolver contentResolver = getContentResolver(); //设置查询条件 String selection = MediaStore.Images.Media.DATA + " like ?"; //设置查询条件参数,这里指定了要查询的目录 String path = "%/mnt/sdcard/myapp/images"; String[] selectionArgs = {path + "%"}; //使用指定的查询条件查询图片,如果不指定则selection和selectionArgs都为null。 //如果没有指定,将会查询外存储中"/mnt/sdcard"中所有可查询的图片 Cursor cursor = contentResolver.query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, null, selection, selectionArgs, null); String[] columnNames = cursor.getColumnNames(); //使用cursor.moveToNext()判断查询的结果集中是否有下一条数据 //如果有继续循环,否则终止循环 while (cursor.moveToNext()) { //循环遍历所查询表的所有字段, //使用cursor.getColumnIndex()根据字段名取得对应的下标index //再使用cursor.getXXX()方法根据下标取得对应的数据。 //其中getXXX()的XXX表示数据类型,如getString()、getInt()等 for (int i = 0; i < columnNames.length; i++) { String columnName = columnNames[i]; String string = cursor.getString(cursor.getColumnIndex(columnName)); Log.e("MainActivity", "onClick: " + columnName + "=====" + string); } } } }); } }