内容提供者 ContentResolver 数据库 示例 -1

MainActivity




public class MainActivity extends ListActivity {

    private TextView tv_info;

    private EditText editText;

    @Override

    protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        List<String> mData = new ArrayList<String>(Arrays.asList("获取所有数据", "插入", "删除", "查找", "更新"));

        ListAdapter mAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, mData);

        editText = new EditText(this);

        editText.setHint("请输入要增删改查数据的Name");

        editText.setTextSize(TypedValue.COMPLEX_UNIT_SP, 16);

        editText.setPadding(0, 30, 0, 30);

        editText.setGravity(Gravity.CENTER);

        getListView().addFooterView(editText);

        tv_info = new TextView(this);// 将内容显示在TextView中

        tv_info.setTextColor(Color.BLUE);

        tv_info.setTextSize(TypedValue.COMPLEX_UNIT_SP, 16);

        tv_info.setPadding(20, 10, 20, 10);

        getListView().addFooterView(tv_info);

        setListAdapter(mAdapter);

    }

    @Override

    protected void onListItemClick(ListView l, View v, int position, long id) {

        PersonDao2 dao = new PersonDao2(this);

        String content = editText.getText().toString().trim();

        switch (position) {

        case 0:

            ArrayList<Person> list = dao.findAll();

            tv_info.setText(list.toString());

            break;

        case 1:

            tv_info.setText(dao.add(content, new Random().nextInt(10) + "") + "");

            break;

        case 2:

            tv_info.setText(dao.delete(content) + "");

            break;

        case 3:

            tv_info.setText(dao.find(content) + "");

            break;

        case 4:

            tv_info.setText(dao.update(content, "呵呵") + "");

            break;

        }

    }

}

ContentProvider


/** 提供一些public的方法,让其他应用访问自己私有的文件。我们很少会自己来定义ContentProvider,因为我们很多时候都不希望自己应用的数据暴露给*/

public class MyContentProvider extends ContentProvider {

    private SQLiteDatabase db;

    private static final UriMatcher matcher = new UriMatcher(UriMatcher.NO_MATCH);// 参数表示匹配不成功时的返回值,这里为-1

    // 主机名称

    public static final String authority = "com.bqt.contentprovider.person";

    // 定义一些静态全局常量

    public static final int QUERY = 0;

    public static final int INSERT = 1;

    public static final int DELETE = 2;

    public static final int UPDATE = 3;

    // 给匹配器添加一些【匹配规则】,放在静态代码块中的作用:随类加载而优先加载,且只加载一次

    static {

        // 参数: authority 主机名 ,path 路径名, code 匹配码,匹配成功时的返回值

        matcher.addURI(authority, "query", QUERY);// 可以使用限定符*和#。* may be used as a wild card for any text, and # may be used as a wild card for numbers.

        matcher.addURI(authority, "insert", INSERT);//即Uri格式为【content://com.bqt.contentprovider.person/insert】

        matcher.addURI(authority, "delete", DELETE);

        matcher.addURI(authority, "update", UPDATE);

    }

    @Override

    public boolean onCreate() {

        MySQLiteOpenHelper helper = new MySQLiteOpenHelper(getContext());

        db = helper.getWritableDatabase();

        return true;//true if the provider was successfully loaded, false otherwise

    }

    @Override

    public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {

        if (matcher.match(uri) == QUERY) {

            //表名,要查询的列名数组,选择条件,选择条件对应的参数,分组,分组条件,排序

            Cursor cursor = db.query(MySQLiteOpenHelper.TABLE_NAME, projection, selection, selectionArgs, null, null, sortOrder);

            return cursor;//Returns:A Cursor object, which is positioned before the first entry.

        } else return null;

    }

    @Override

    public int delete(Uri uri, String selection, String[] selectionArgs) {

        if (matcher.match(uri) == DELETE) {

            return db.delete(MySQLiteOpenHelper.TABLE_NAME, selection, selectionArgs);

            //Returns:    the number of rows affected if a whereClause is passed in, 0 otherwise. To remove all rows and get a count pass "1" as the whereClause

        } else throw new IllegalArgumentException("非法uri");

    }

    @Override

    public Uri insert(Uri uri, ContentValues values) {

        if (matcher.match(uri) == INSERT) {

            long id = db.insert(MySQLiteOpenHelper.TABLE_NAME, null, values);//Returns:    the row ID of the newly inserted row, or -1 if an error occurred

            return ContentUris.withAppendedId(uri, id);//a new URI with the given ID appended to the end of the path

        } else throw new IllegalArgumentException("非法uri");

    }

    @Override

    public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {

        if (matcher.match(uri) == UPDATE) {

            return db.update(MySQLiteOpenHelper.TABLE_NAME, values, selection, selectionArgs);//Returns:the number of rows affected

        } else throw new IllegalArgumentException("非法uri");

    }

    @Override

    /**MIME类型*/

    public String getType(Uri uri) {

        return "";//a MIME type string, or null if there is no type.

    }

}

SQLiteOpenHelper


/** 数据库【创建】或【打开】辅助类 */

public class MySQLiteOpenHelper extends SQLiteOpenHelper {

    public static final String DB_NAME = "person.db";

    public static int DB_VERSION = 2;

    //所有的表名及SQL語句都放到一個單獨的類中,这里图方便放到了这里

    public static final String TABLE_NAME = "person";

    public static final String CREATE_TABLE = "create table if not exists " + TABLE_NAME + " (id integer primary key autoincrement," + "name varchar,"

            + "number varchar)";

    public MySQLiteOpenHelper(Context context) {

        super(context, DB_NAME, null, DB_VERSION);

    }

    @Override

    public void onCreate(SQLiteDatabase db) {

        db.execSQL(CREATE_TABLE);

        //        db.execSQL(DBConstants.CREATE_PHOTO_TABLE);

        //        db.execSQL(DBConstants.CREATE_DOWNLOAD_TABLE);

        //        db.execSQL(DBConstants.CREATE_USER_TABLE);

        //        db.execSQL(DBConstants.CREATE_GIFTS_TABLE);

        //        db.execSQL(DBConstants.CREATE_ZIP_TABLE);

    }

    @Override

    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {

        db.execSQL("drop table if exists " + TABLE_NAME);

        //        db.execSQL("drop table if exists " + DBConstants.DB_PHOTO_TABLE);

        //        db.execSQL("drop table if exists " + DBConstants.DB_DOWNLOAD_TABLE);

        //        db.execSQL("drop table if exists " + DBConstants.DB_USER_TABLE);

        //        db.execSQL("drop table if exists " + DBConstants.DB_GIFTS_TABLE);

        //        db.execSQL("drop table if exists " + DBConstants.DB_ZIP_TABLE);

        onCreate(db);

    }

}

DAO1


/** DAO(Data Access Object) 数据访问对象,是一个面向对象的数据库接口,夹在业务逻辑与数据库资源中间。相当于是数据库的【工具类】*/

public class PersonDao {

    private MySQLiteOpenHelper helper;

    public PersonDao(Context context) {

        helper = new MySQLiteOpenHelper(context);

    }

    public ArrayList<Person> findAll() {

        SQLiteDatabase db = helper.getWritableDatabase();

        ArrayList<Person> persons = new ArrayList<Person>();

        Cursor cursor = db.rawQuery("select * from person", null);

        //Returns:A Cursor object, which is positioned before the first entry.

        while (cursor.moveToNext()) {

            int id = cursor.getInt(cursor.getColumnIndex("id"));//获取指定列的值

            String name = cursor.getString(cursor.getColumnIndex("name"));

            String number = cursor.getString(cursor.getColumnIndex("number"));

            Person p = new Person(id, name, number);

            persons.add(p);

        }

        cursor.close();

        db.close();

        return persons;

    }

    public boolean find(String name) {

        SQLiteDatabase db = helper.getWritableDatabase();

        Cursor cursor = db.rawQuery("select * from person where name=?", new String[] { name });

        boolean result = cursor.moveToNext();//结果集最初始时是指向表的最前面的,moveToNext时指向的才是【第一条】数据

        cursor.close();

        db.close();

        return result;

    }

    public void add(String name, String number) {

        SQLiteDatabase db = helper.getWritableDatabase();

        db.execSQL("insert into person(name,number) values(?,?)", new Object[] { name, number });

        //Returns:    the row ID of the newly inserted row, or -1 if an error occurred

        db.close();

    }

    public void update(String name, String newNumber) {

        SQLiteDatabase db = helper.getWritableDatabase();

        db.execSQL("update person set number=? where name=?", new Object[] { newNumber, name });

        //Returns:the number of rows affected

        db.close();

    }

    public void delete(String name) {

        SQLiteDatabase db = helper.getWritableDatabase();

        db.execSQL("delete from person where name=?", new Object[] { name });

        //Returns:    the number of rows affected if a whereClause is passed in, 0 otherwise. To remove all rows and get a count pass "1" as the whereClause

        db.close();

    }

}

DAO2


public class PersonDao2 {

    private MySQLiteOpenHelper helper;

    public PersonDao2(Context context) {

        helper = new MySQLiteOpenHelper(context);

    }

    public ArrayList<Person> findAll() {

        SQLiteDatabase db = helper.getWritableDatabase();//数据库不作为成员变量的原因:1、使用完要及时关闭;2、关闭后必须重新通过helper打开。

        //java.lang.IllegalStateException: attempt to re-open an already-closed object: SQLiteDatabase: /data/data/com.bqt.contentprovider/databases/person.db

        ArrayList<Person> persons = new ArrayList<Person>();

        Cursor cursor = db.query("person", new String[] { "name", "number", "id" }, null, null, null, null, null);

        while (cursor.moveToNext()) {

            int id = cursor.getInt(cursor.getColumnIndex("id"));

            String name = cursor.getString(cursor.getColumnIndex("name"));

            String number = cursor.getString(cursor.getColumnIndex("number"));

            persons.add(new Person(id, name, number));

        }

        cursor.close();

        db.close();

        return persons;

    }

    public boolean find(String name) {

        SQLiteDatabase db = helper.getWritableDatabase();

        Cursor cursor = db.query("person", null, "name=?", new String[] { name }, null, null, null);

        //要查询的表名,要查询的列名的数组(null代表所有列),选择条件(即WHERE语句,可以使用占位符 String[])

        //选择条件中占位符的值(数组类型),分组语句(groupBy),having条件语句,排序语句(orderBy)

        boolean result = cursor.moveToNext();//Returns:whether the move succeeded.

        cursor.close();

        db.close();

        return result;

    }

    public long add(String name, String number) {

        SQLiteDatabase db = helper.getWritableDatabase();

        ContentValues values = new ContentValues();// 其实是一个map集合,里面保存的是每条记录的"键值对"信息

        values.put("name", name);

        values.put("number", number);

        long id = db.insert("person", null, values);//返回新添加行的行号

        db.close();

        return id;

    }

    public int update(String name, String newNumber) {

        SQLiteDatabase db = helper.getWritableDatabase();

        ContentValues values = new ContentValues();

        values.put("number", newNumber);

        int number = db.update("person", values, "name=?", new String[] { name });// 返回修改的行的【个数】

        db.close();

        return number;

    }

    public int delete(String name) {

        SQLiteDatabase db = helper.getWritableDatabase();

        int number = db.delete("person", "name=?", new String[] { name });//返回删除行的行号

        db.close();

        return number;

    }

}

Bean


public class Person {

    public int id;

    public String name;

    public String number;

    public Person(int id, String name, String number) {

        this.id = id;

        this.name = name;

        this.number = number;

    }

    @Override

    public String toString() {

        return "id=" + id + ", name=" + name + ", number=" + number + "\n";

    }

}

数据库表及SQL语句常量


/** 所有的数据库的表名及SQL語句都放到这個單獨的類中 */

public class DBConstants {

    /***************************************************

     * 

     * 上传图片表

     * 

     ***************************************************/

    public static final String DB_PHOTO_TABLE = "upload_photo";

    public static final String CREATE_PHOTO_TABLE = "create table if not exists "+

            DB_PHOTO_TABLE+

            " (id integer primary key autoincrement," +

            "phAlbtmId varchar,"+

            "photoUrl varchar," +

            "uploadState varchar)";

    public static final String INSERT_INTO_TAB_PHOTO = "INSERT INTO  "+ DB_PHOTO_TABLE +" VALUES(null,?,?,?)";

    /***************************************************

     * 

     * 下载表

     * 

     ***************************************************/

    public static final String DB_DOWNLOAD_TABLE = "download_table";

    public static final String CREATE_DOWNLOAD_TABLE = "create table " + DB_DOWNLOAD_TABLE + 

            " (_id integer primary key autoincrement, " +

            "gameId integer, " +

            "gameName text, " +

            "gamePackage text, " +

            "status integer, " +

            "totalSize integer, " +

            "hasRead integer, " +

            "downloadUrl text, " +

            "filePath text, " +

            "imgUrl text" +

            ")";

    public static final String INSERT_INTO_TAB_DOWNLOAD = "INSERT INTO  "+ DB_DOWNLOAD_TABLE +" VALUES(null,?,?,?,?,?,?,?,?,?)";

    /***************************************************

     * 

     * 用户账号表

     * 

     ***************************************************/

    public static final String DB_USER_TABLE = "user_table";

    public static final String CREATE_USER_TABLE = "CREATE TABLE IF NOT EXISTS " 

            + DB_USER_TABLE 

            + "(id INTEGER PRIMARY KEY AUTOINCREMENT,"

            + " userId text,"

            + " userAccount text,"

            + " userPwd text,"

            + " avatarUrl text,"

            + "chargeStatus INTEGER,"

            + "showDialogState INTEGER)";

    public static final String INSERT_INTO_TAB_USER = "INSERT INTO  "+ DB_USER_TABLE +" VALUES(null,?,?,?,?,?,?)";

    /************************************************************

     * 

     * 座驾信息记录表start

     * 

     ************************************************************/

    public static final String DB_CAR_DOWNLOAD_RECORD = "car_download_record";

    public static final String DB_CAR_TABLE = "user_car_table";

    public static final String CREATE_CAR_TABLE = "CREATE TABLE IF NOT EXISTS " 

            + DB_CAR_TABLE 

            + "(id INTEGER PRIMARY KEY AUTOINCREMENT,"

            + "carId varchar,"

            + "carType varchar,"

            + "carName varchar,"

            +"carSound,"

            + "carPrice varchar,"

            +"carUrl varchar,"

            +"carIsShock varchar)";

    public static final String INSERT_INTO_TAB_CAR = "INSERT INTO  "+ DB_CAR_TABLE +" VALUES(null,?,?,?,?,?,?,?)";

    /************************************************************

     * 

     * 座驾信息记录表end

     * 

     ************************************************************/

    /***************************************************

     * 

     * zip下载表

     * 

     ***************************************************/

    public static final String DB_ZIP_TABLE = "zip_downLoad_table";

    public static final String CREATE_ZIP_TABLE = "CREATE TABLE IF NOT EXISTS " 

            + DB_ZIP_TABLE 

            + "(id INTEGER PRIMARY KEY AUTOINCREMENT,"

            + " curSize INT8,"

            + " totalSize INT8,"

            + " downLoadUrl text,"

            + " zipName text,"

            + "versionCode INTEGER)";

    public static final String INSERT_INTO_TAB_ZIP = "INSERT INTO  "+ DB_ZIP_TABLE +" VALUES(null,?,?,?,?,?)";

    /***************************************************

     * 

     * 记录礼物信息表

     * 

     ***************************************************/

    public static final String DB_GIFTS_TABLE = "gifts_table";

    public static final String CREATE_GIFTS_TABLE = "CREATE TABLE IF NOT EXISTS " 

            + DB_GIFTS_TABLE 

            + "(id INTEGER PRIMARY KEY AUTOINCREMENT,"

            + "versionCode INTEGER,"

            + "giftType INTEGER,"

            + "giftId INTEGER,"

            + "giftName text,"

            + "giftPrice INTEGER,"

            + "giftImgUrl text,"

            + "giftAnimIntervals text,"

            + "giftAnimCount INTEGER,"

            + "animType INTEGER,"

            + "animValue INTEGER,"

            + "animAudio text)";

    public static final String INSERT_INTO_TAB_GIFTS = "INSERT INTO  "+ DB_GIFTS_TABLE +" VALUES(null,?,?,?,?,?,?,?,?,?,?,?)";

}

AndroidTestCase


/** 测试类。使用方法:在【outline】中对要测试的【方法右键】--> Run As --> Android JUnit Test */

public class MyAndroidTestCase extends AndroidTestCase {

    Context context = getContext();

    //不能把PersonSQLiteOpenHelper或PersonDao抽出为对象的成员

    public SQLiteDatabase testGetDB() {

        return new MySQLiteOpenHelper(getContext()).getWritableDatabase();

    }

    public void testAdd() {

        Log.i("bqt", "" + (context == null));//true。PersonDao2不作为成员,因为成员变量初始化时getContext返回的还是null。

        PersonDao2 dao2 = new PersonDao2(getContext());

        for (int i = 0; i < 10; i++) {

            dao2.add("包青天" + i, "" + i);

            dao2.add("白乾涛" + i, "" + i);

        }

    }

    public void testFind() {

        assertEquals(true, new PersonDao2(getContext()).find("包青天1"));

    }

    public void testUpdate() {

        new PersonDao2(getContext()).update("包青天4", "包青天44444");

    }

    public void testDelete() {

        new PersonDao2(getContext()).delete("包青天5");

    }

    public void testFindAll() {

        ArrayList<Person> persons = new PersonDao2(getContext()).findAll();

        for (Person person : persons) {

            System.out.println(person);

        }

    }

    // 测试事务。当版本号增加时,测试是否成功

    public void testTransaction() {

        MySQLiteOpenHelper helper = new MySQLiteOpenHelper(getContext());

        SQLiteDatabase db = helper.getWritableDatabase();

        db.beginTransaction();// 开启事务

        try {

            db.execSQL("update person set account = account + 1000 where name=?", new Object[] { "包青天6" });

            //    int i = 1 / 0;//执行到这里后抛出一个异常,后面的没有执行到,事务失败

            db.execSQL("update person set account = account - 1000 where name=?", new Object[] { "包青天7" });

            db.setTransactionSuccessful();//若执行到这里,证明已成功执行上面的SQL语句,所以"标记"事务已成功

        } catch (Exception e) {

            e.printStackTrace();

        } finally {

            db.endTransaction();// 结束事务

        }

    }

}

清单文件


<?xml version="1.0" encoding="utf-8"?>

<manifest xmlns:android="http://schemas.android.com/apk/res/android"

    package="com.bqt.contentprovider"

    android:versionCode="1"

    android:versionName="1.0" >

    <uses-sdk

        android:minSdkVersion="8"

        android:targetSdkVersion="21" />

    <!-- 增加instrumentation标签,并指定包名 -->

    <instrumentation

        android:name="android.test.InstrumentationTestRunner"

        android:targetPackage="com.bqt.contentprovider" />

    <!-- 内容提供者定义的权限。android:protectionLevel 代表了权限等级

    normal:低风险权限,只要申请了就可以使用(在AndroidManifest.xml中添加<uses-permission>标签),安装时不需要用户确认;

    dangerous:高风险权限,安装时需要用户的确认才可使用;

    signature:只有当申请权限的应用程序的数字签名与声明此权限的应用程序的数字签名相同时(如果是申请系统权限,则需要与系统签名相同),才能将权限授给它;

    signatureOrSystem:签名相同,或者申请权限的应用为系统应用(在system image中)。 -->

    <permission

        android:name="com.bqt.permission"

        android:protectionLevel="normal" />

    <application

        android:allowBackup="true"

        android:icon="@drawable/ic_launcher"

        android:label="@string/app_name"

        android:theme="@style/AppTheme" >

        <!-- 增加uses-library标签 -->

        <uses-library android:name="android.test.runner" />

        <activity

            android:name="com.bqt.contentprovider.MainActivity"

            android:label="@string/app_name" >

            <intent-filter>

                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />

            </intent-filter>

        </activity>

        <!-- 属性依次为:全限定类名,用于匹配的URI,是否共享数据,访问时需要具备的权限 -->

        <provider

            android:name=".MyContentProvider"

            android:authorities="com.bqt.contentprovider.person"

            android:exported="true"

            android:permission="com.bqt.permission" />

    </application>

</manifest>

来自为知笔记(Wiz)

附件列表

时间: 2024-11-13 04:39:42

内容提供者 ContentResolver 数据库 示例 -1的相关文章

内容提供者 ContentResolver 数据库 示例 -2

MainActivity public class MainActivity extends ListActivity {     // 访问内容提供者时需要的主机名称     public static final String authority = "com.bqt.contentprovider.person";     private TextView tv_info;     private ContentResolver resolver;     @Override  

第九天 内容提供者 ContentResolver

1. 内容提供者,提供 其他数据库的访问. 内容提供者需要在配置清单中 配置 1 <provider android:name="" 2 android:authorities="" 3 android:exported="true"></provider>

android100 自定义内容提供者

#ContentProvider,就是来操作数据的,增删改查, * 四大组件之一 * 应用的数据库是不允许其他应用访问的 * 内容提供者的作用就是让别的应用访问到你的数据库 * 内容提供者的作用:把私有数据暴露给其他应用,通常,是把私有数据库的数据暴露给其他应用 *短信联系人都是在数据库里面.mmssms是短信数据库, *短信数据库有短信数据库的内容提供者,联系人数据库有联系人数据库的内容提供者.拿到对应数据库的内容提供者就能够访问对应的数据库数据. ###短信数据库 * sms表 * body

Android10_内容提供者_内容观察者_标题栏

安卓四大组件Activity ,Service,BroadCastReceiver,ContentProvider(内容提供者) 1.1内容提供者的作用: 应用程序创建的数据库默认都是私有的,别的应用程序不可以访问里面的数据,如果有需求把自己应用程序私有的数据库暴露给别的用户增删改查,就需要使用内容提供者. 1.2 内容提供者的代码实现 在需要提供给它人数据的应用中 ①创建一个项目,并且创建数据库(数据库开启帮助类)(非必要) ②创建一个类,继承ContentProvider内容提供者, 内容提

【安卓】如何使用广播和内容提供者来叫醒小伙伴(控制你的朋友)

摘要:通过多种方法来获取最新短信(静态广播,动态广播,监测数据库变动),保证短信的稳定获取,为了保证应用正常运行,代码中使用开机启动 service的方法,并且能够保证程序不被用户意外关闭出现无法提醒的问题,收到命令后使用内容提供者删除命令短信 ============================================================================================================================= 正

内容提供者(内容提供者实现、使用场景、Uri、短信的备份与还原等等)

1.编写内容提供者 步骤: 1.在工程里创建一个类,继承ContentProvider,重写了onCreate和增删改查的方法: 2.在清单文件中配置一个provider,需要这个数据authorities,用来唯一标识内容者的,在android4.1版本之后需要exported="true"的属性,否则其他应用程序没有权限访问这个内容提供者: 3.在onCreate方法里得到数据库的帮助类: 2.内容提供者工作的原理 模版代码: //uri匹配正时返回的匹配码 int code =

Android 内容提供者(ContentProvider)的简单实用

Android 中的数据库是对应用私有的,自己是无法使用别的应用的数据库的.但是往往有需求要我们使用另外一个应用或者系统应用的数据,这时候就彰显了内容提供者,ContentPrivider的作用,他就是两个应用数据的桥梁,通过内容提供者和内容接受者我们可以在不同应用间传递数据. ContentPrivider也可以视为一种数据存储.它存储数据的方式和使用它的应用程序无关,重要的是应用如何以一致的编程接口,来访问存储其中的数据.内容提供者与数据库的使用差不多,也可以增删改查.而且数据可以存储于数据

内容提供者和内容观察者

1.创建一个内容提供者,继承contentProvider,作为四大组件之一,contentProvider需要在配置文件中进行配置 <provider android:name="cn.itcast.mobilesafe.provider.AppLockedProvider" android:authorities="cn.itcast.applockprovider"> </provider> 2. package cn.itcast.m

内容提供者ContentProvider和内容解析者ContentResolver

简介 ContentProvider 在android中的作用是对外共享数据,也就是说你可以通过ContentProvider把应用中的数据共享给其他应用访问,其他应用可以通过ContentProvider 对你应用中的数据进行添删改查.关于数据共享,以前我们学习过文件操作模式,知道通过指定文件的操作模式为Context.MODE_WORLD_READABLE 或Context.MODE_WORLD_WRITEABLE同样也可以对外共享数据.那么,这里为何要使用ContentProvider 对