温故而知新-Android四大组件之ContentProvider

ContentProvider简介

ContentProvider(内容提供者)是android中的四大组件之一,是为不同的app之间数据共享,提供统一的接口。当前应用使用ContentProvider将数据库数据操作暴露给其它应用,其它应用需要使用ContentResolver来调用ContentProvider的方法从而获取暴露的数据。它们之间的调用是通过Uri来进行交流的。我们平时开发中很少自己定义ContentProvider接口,但是用到系统开放的数据还是挺多的,比如联系人信息、短信信息、图片库、音频库等,这些都是谷歌为我们封装好的,我们只需要通过Uri就可以访问这些数据了。

为什么要有ContentProvider?
  • 功能需求:一个应用需要访问另一个应用的数据库表数据,比如 dada/dada/应用的包名/databases/xxx.db
  • 实际情况:一个应用的数据库文件时应用私有的,其它应用不能直接访问
相关API
  • ContentProvider 内容提供者类

    • //provider对象创建后调用(应用安装成功或手机启动完成)
      public boolean onCreate()
    • //查询表数据
      public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String s)
    • //插入表数据
      public Uri insert(@NonNull Uri uri, @Nullable ContentValues contentValues)
    • //删除表数据
      public int delete(@NonNull Uri uri, @Nullable String s, @Nullable String[] strings)
    • //更新表数据
      public int update(@NonNull Uri uri, @Nullable ContentValues contentValues, @Nullable String s, @Nullable String[] strings)
  • ContentResolver 内容提供者的解析类

    • //得到它的对象
      context.getContentResolver()
    • //调用provider进行数据库CRUD操作
      insert()、delete()、update()、query()
    • //注册uri的监听
      registerContentObserver(Uri uri,boolean notify,ContentObserver observer)
    • 解注册uri的监听
      unregisterContentObserver(ContentObserver observer)
    • //通知监听器
      notifyChange(Uri uri,ContentObserver observer)
  • UriMatcher:用于匹配Uri的容器

    • //添加一个合法的URI
      void addUri(String authority,String path,int code)
    • //匹配指定的uri,返回匹配码
      int match(Uri uri)
  • ContentUris:解析uri的工具类

    • 解析uri,得到其中的id
      long parseld(Uri contentUri)
    • //添加id到指定的uri中
      Uri withAppendedid(Uri contentUri,long id)
  • 基本步骤

    • 编写ContentProvider子类
      public class MyContentProvider extends ContentProvider {
      //实现insert 、delete、update、query等方法
      }
    • 在manifest.xml中注册
      <provider
      android:authorities="pjs.com.myapplication.mycontentprovider"
      android:name=".MyContentProvider"
      android:exported="true"
      />
  • Uri对象

    • 图片.png

案例一:获取linkman信息

  • 功能描述:
    • 通过系统自带的内容提供者类获取手机联系人信息,以列表展示。
  • 相关常量:
    • 联系人URI:Phone.CONTENT_URI
    • 姓名字段:Phone.DISPLAY_NAME
    • 号码字段: Phone.NUMBER
  • 读取联系人权限:
    • android.permission.READ_CONTACTS
  • 实例:


    点击按钮.png
展示通讯录联系人.png
返回点击的联系人.png
  • MainActivity代码,内容有一个点击进入自定义联系人的按钮是一个带回调的跳转startActivityForResult,requestCode设置101,有一个onActivityResult函数接收回调信息。
public class MainActivity extends AppCompatActivity {

    @BindView(R.id.content)
    TextView content;
    @BindView(R.id.button)
    Button button;

    Context context;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        ButterKnife.bind(this);
        context = this;

    }

    @OnClick(R.id.button)
    public void onViewClicked() {
        startActivityForResult(new Intent(context,LinkManActivity.class),101);
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);

        if(resultCode==RESULT_OK && requestCode==101) {
            String number = data.getStringExtra("number");
            content.setVisibility(View.VISIBLE);
            if(!TextUtils.isEmpty(number)) {
                content.setText("联系方式:"+number);
            }else {
                content.setText("获取失败");
            }

        }
    }
}
  • 自定义联系人LinkManActivity代码:此处只列出步骤详情请看代码
    1、获取系统自带的联系人uri
    2、用一个数组来装要获取的信息
    3、获取内容提供者解析类,ContentResolver
    4、调用provider提供的方法进行数据库CRUD操作
    5、通过游标遍历获取数据
public class LinkManActivity extends AppCompatActivity {

    Context context;
    @BindView(R.id.recyclerView)
    RecyclerView recyclerView;
    private PersonAdapter adapter;
    private List<Map<String, String>> mapList = new ArrayList<>();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_link_man);
        ButterKnife.bind(this);

        context = this;
        //1.获取系统自带的联系人uri
        Uri uri = ContactsContract.CommonDataKinds.Phone.CONTENT_URI;

        //2.用一个数组来装要获取的信息
        String[] contentArr = {ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME, ContactsContract.CommonDataKinds.Phone.NUMBER};

        //3.获取内容提供者解析类,ContentResolver
        ContentResolver resolver = this.getContentResolver();

        //4.调用provider提供的方法进行数据库CRUD操作
        Cursor cursor = resolver.query(uri, contentArr, null, null, null);

        //5.通过游标遍历获取数据,并添加到集合中
        Map<String,String> map = null;
        while (cursor.moveToNext()){
            String name = cursor.getString(0);
            String number = cursor.getString(1);
            map = new HashMap<>();
            map.put("phoneName",name);
            map.put("phoneNumber",number);
            mapList.add(map);
        }
        cursor.close();

        if(mapList!=null&&mapList.size()>0) {
            adapter = new PersonAdapter(context,mapList);
            recyclerView.setLayoutManager(new LinearLayoutManager(context,LinearLayoutManager.VERTICAL,false));
            recyclerView.addItemDecoration(new DividerItemDecoration(this,
                    DividerItemDecoration.VERTICAL_LIST));
            recyclerView.setAdapter(adapter);

            /**
             * 此处点击回调给MainActivity
             */
            adapter.setOnClickItemPosion(new PersonAdapter.OnClickItemPosion() {
                @Override
                public void onClickItem(String number) {
                    Intent intent = new Intent();
                    intent.putExtra("number",number);
                    setResult(RESULT_OK,intent);
                    finish();
                }
            });
        }
    }
}

  • 一并把PersonAdapter代码也粘出来吧
/**
 * 创建: PengJunShan on 2018-06-23  16:06
 * 描述:
 */

public class PersonAdapter extends RecyclerView.Adapter<PersonAdapter.MyViewHolder>{

    private Context context;
    private List<Map<String, String>> mapList;

    public PersonAdapter(Context context, List<Map<String, String>> mapList) {
        this.context = context;
        this.mapList = mapList;
    }

    @Override
    public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {

        View view = LayoutInflater.from(context).inflate(R.layout.item_person,parent,false);
        return new MyViewHolder(view);

    }

    @Override
    public void onBindViewHolder(MyViewHolder holder, int position) {
        Map<String, String> map = mapList.get(position);
        holder.name.setText(map.get("phoneName"));
        holder.number.setText(map.get("phoneNumber"));
    }

    @Override
    public int getItemCount() {
        if(mapList!=null&&mapList.size()>0) {
            return mapList.size();
        }
        return 0;
    }

    class MyViewHolder extends RecyclerView.ViewHolder{

        private TextView name,number;

        public MyViewHolder(View itemView) {
            super(itemView);
            name = itemView.findViewById(R.id.name);
            number = itemView.findViewById(R.id.number);

            itemView.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    if(onClickItemPosion!=null) {
                        onClickItemPosion.onClickItem(mapList.get(getLayoutPosition()).get("phoneNumber"));
                    }
                }
            });

        }
    }


    private OnClickItemPosion onClickItemPosion;

    public void setOnClickItemPosion(OnClickItemPosion onClickItemPosion) {
        this.onClickItemPosion = onClickItemPosion;
    }

    public interface OnClickItemPosion{
        void onClickItem(String number);
    }
}

【案例地址】(https://github.com/pengjunshan/LinkMan

推荐阅读更多精彩内容