Content Provider 内容提供者

珍惜作者劳动成果 转载请注明出处

内容提供者的使用

1. 内容提供者的使用

    1) ContentResolver 类似于Socket的客户端部分
    2) 需要提供 Uri 对象,可以看作网址 , Android 内部提供了很多常量类来访问
    3) 访问Android内部的提供者,需要声明权限

    4) 在Android API 23 以上,所有的内部的提供者都需要动态权限检查,否则执行不了

    5) 总结:只要使用ContentResolver就可以直接调用 ContentProvider的内容


2. 联系人获取

    1) 联系人使用 ContactsContract 常量类来获取地址和列字段
    2) 使用SimpleCursorAdapter 时,最后一个参数是 代表Adapter可以自动
        收到联系人的变化,当联系人发生任何变化的时候,能够自动刷新ListView
    3) ContentProvider + Loader 就会自动刷新数据:仅限于Android自带的内容提供者

    4) 获取联系人详情,需要使用 Data表,通过联系人的ID,来查找指定的信息

3. Adapter 支持Button 点击事件

    1. getView(...)

            复用:

                CursorAdapter 没有复用,调用    newView()  加载布局 Button

                Button.setOnClickListener(listener)

            ViewHolder:

                bindView() 直接设置内容


    2. Adapter 内部需要一个成员变量,就是 OnClickListener的类型,只要Adapter增加一个set方法就好了

    3. Activity 调用 Adapter 的setOnClickListener(l) -> Adapter -> Button

通过清单文件添加权限

<!-- 获取通话记录的权限 -->
    <uses-permission android:name="android.permission.READ_CALL_LOG"/>
public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        ContentResolver resolver = this.getContentResolver();

        // 动态权限检查
        if (Build.VERSION.SDK_INT >= 16) {
            // state 代表是否允许
            int state = ActivityCompat.checkSelfPermission(this, Manifest.permission.READ_CALL_LOG);

            if (state == PackageManager.PERMISSION_GRANTED) {
                // 允许的情况

                // 所有常量类中的 CONTENT_URI 就可以用于内容提供者的访问
                getCallLogs();

            } else {

                // 需要申请, 会回调当前Activity的方法
                ActivityCompat.requestPermissions(
                        this,
                        new String[]{Manifest.permission.READ_CALL_LOG},
                        998
                );
            }
        }
    }

    @Override
    public void onRequestPermissionsResult(
            int requestCode,
            @NonNull String[] permissions,
            @NonNull int[] grantResults) {

        if (requestCode == 998) {
            // 参数2 每一个元素代表一个权限,对应参数3中的权限设置,是否允许
            if (permissions[0].equals(Manifest.permission.READ_CALL_LOG)) {
                if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {

                    getCallLogs();

                }
            }
        }

    }

    private void getCallLogs() {
        int state = ActivityCompat.checkSelfPermission(this, Manifest.permission.READ_CALL_LOG);
        // TODO: 获取通话记录
        ContentResolver resolver = getContentResolver();
        // 所有常量类中的 CONTENT_URI 就可以用于内容提供者的访问
        Cursor cursor = resolver.query(
                CallLog.Calls.CONTENT_URI,
                null, // 需要返回的列
                null, // where 语句
                null, // where 条件参数
                null  // orderby
        );

        if (cursor != null) {

            while (cursor.moveToNext()) {
                int index = cursor.getColumnIndex(CallLog.Calls.NUMBER);
                if (index != -1) {
                    String number = cursor.getString(index);
                    Log.d("MainActivity", "number = " + number);
                }
            }

            cursor.close();
        }
    }
}

自定义的内容提供者

自定义的内容提供者

1. 继承 ContentProvider

2. 实现 增 删 改 查 方法 以及 onCreate 方法

3. 制定 Uri 的网址规则,形成特定的功能

4. 四大组件都需要在清单文件注册,来确认内容提供者是否可以被 其他程序访问

5. 内部需要进行数据的操作,增 删 改 查

    5.1 确认使用哪种数据类型:SQLite, File, SharedPreferences

    5.2 onCreate 方法,需要初始化 通常 DbHelper

    5.3 每一个操作的方法,第一个参数都代表了 需要操作的哪一张表。通过Uri来标示;

    5.4 使用  UriMatcher 类对象,来进行网址匹配,判断访问那个表


关于 Uri 与 authorities 说明

Uri 就是一个网址

    规则:  content://<authority>/path

    authority 代表的就是 Android 系统中内容提供者的唯一标示,就像服务器的IP地址

    清单文件里面声明内容提供者的authority

    http://www.baidu.com/images
    http://www.baidu.com/news

MainActivity.java

public class DbHelper extends SQLiteOpenHelper {

    private static final String CREATE_TABLE_COST =
            "create table cost(" +
                    "_id integer primary key autoincrement," +
                    "money double not null default 0" +
                    ")";

    public DbHelper(Context context) {
        super(context, "myapp", null, 1);
    }

    @Override
    public void onCreate(SQLiteDatabase db) {
        db.execSQL(CREATE_TABLE_COST);
    }

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

    }
}

public class MoneyProvider extends ContentProvider {

    private static final UriMatcher uriMatcher;

    public static final int CODE_COST = 1;
    public static final int CODE_INCOME = 2;

    static{
        uriMatcher = new UriMatcher(0);

        // 添加 Uri的匹配规则,实现 uri 对应判断是哪个表的操作
        uriMatcher.addURI("*", "/cost", CODE_COST);
        uriMatcher.addURI("*", "/income", CODE_INCOME);
    }

    private DbHelper mDbHelper;

    public MoneyProvider() {
    }

    @Override
    public boolean onCreate() {

        // 数据库的初始化
        mDbHelper = new DbHelper(getContext());

        // 必须返回true
        return true;
    }

    /**
     * 添加方法,对外提供接口,可以让其他应用程序向当前程序的数据库添加数据内容
     * @param uri
     * @param values
     * @return
     */
    @Override
    public Uri insert(Uri uri, ContentValues values) {
        Uri ret = null;

        // content://xxxxx/cost 支出表
        // content://xxxxx/income 收入表

        int code = uriMatcher.match(uri);

        // 所有的数据库打开操作,都应该在 增删改查中完成,不允许在onCreate中。
        SQLiteDatabase database = mDbHelper.getWritableDatabase();

        switch (code) {
            case CODE_COST:

                long id = database.insert("cost", null, values);
                // 数据库添加完成之后返回的 ID,必须和 Uri参数拼接在一起,再返回
                ret = ContentUris.withAppendedId(uri, id);
                break;
            case CODE_INCOME:
                break;
        }

        database.close();

        return ret;
    }


    @Override
    public int delete(Uri uri, String selection, String[] selectionArgs) {
        int ret = 0;

        // content://xxxxx/cost 支出表
        // content://xxxxx/income 收入表

        int code = uriMatcher.match(uri);

        // 所有的数据库打开操作,都应该在 增删改查中完成,不允许在onCreate中。
        SQLiteDatabase database = mDbHelper.getWritableDatabase();

        switch (code) {
            case CODE_COST:

                ret = database.delete("cost", selection, selectionArgs);

                break;
            case CODE_INCOME:
                break;
        }

        database.close();

        return ret;
    }

    @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 Cursor query(Uri uri, String[] projection, String selection,
                        String[] selectionArgs, String sortOrder) {

        Cursor ret = null;

        SQLiteDatabase database = mDbHelper.getReadableDatabase();

        int code = uriMatcher.match(uri);

        switch (code) {
            case CODE_COST:
                ret = database.query("cost", projection, selection, selectionArgs, null, null, sortOrder);
                break;
            case CODE_INCOME:
                break;
        }

        return ret;
    }

    @Override
    public int update(Uri uri, ContentValues values, String selection,
                      String[] selectionArgs) {
        // TODO: Implement this to handle requests to update one or more rows.
        throw new UnsupportedOperationException("Not yet implemented");
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值