数据存储ContentProvider

一个应用实现ContentProvider来提供内容给别的应用来操作,
一个应用通过ContentResolver来操作别的应用数据,当然在自己的应用中也可以。

1.ContentPrevider:

什么是?
    五大数据存储方式之一
    ContentProvider为存储和获取数据提供统一的接口。可以在不同的应用程序之间共享数据。统一了数据访问方式。
引入的原因:
    数据库在android中是私有的,不能跨进程访问
    ContentProvider统一了数据访问方式,外界无需关心数据是怎么存储的,我们可以通过一套接口,或者标准和程序中的数据
        打交道,对数据进行修改

ContentResolver(操作应用暴露的数据,及可使用此类对象进行增删查改)       
    通过ContentResolver resolver = getContentResolver();获得对象进行操作
查询方法:
        /**
         * 参数1 uri:访问地址uri
         * 参数2 projection:返回查询的列,当null的时候是所有的列
         * 参数3 selection:筛选条件
         * 参数4 selectionArgs: 筛选条件的值
         * 参数5 sortOrder:按某个字段排序
         * 返回值为Cursor
         */
        Cursor cursor = resolver.query(uri, null, null, null, null);

2.知识点:

SimpleCursorAdapter:游标适配器
        /**
         * 参数1:上下文对象
         * 参数2:列表item的布局视图
         * 参数3:查询结果的返回值,是一个集合Cursor
         * 参数4:字符串数组,值为Cursor集合中的列名,
         *          把列名对应的值绑定到UI上(系统实现了)
         * 参数5:整形数组,其中值为Cursor列名值多对应的控件
         * 
         */
        SimpleCursorAdapter adapter = new SimpleCursorAdapter(this, R.layout.item, cursor, new String[]{"number"}, new int[]{R.id.textView1});

Uri:统一资源定位符,根Uri操作相关的类必须借助ContentResolver
    每个ContentProvider都有一个公共的Uri(表示此contentProvider代表的数据)
    Android所提供的ContentProvider都存放在android.provider包当中
    所有URI都以“content://”开头,其中“content:”是用来标识数据是由Content Provider管理的schema.
        主要Uri有:
            content://sms/               所有短信
            content://sms/inbox        收件箱
            content://sms/sent          已发送
            content://sms/draft         草稿
            content://sms/outbox     发件箱
            content://sms/failed       发送失败
            content://sms/queued    待发送列表
    UriMatcher:用于匹配Uri
    ContentUris:可对contentUri后追加id,也可直接取出contentUri中的id
        ContentUris.appendId() 方法
        ContentUris.withAppendedId(contentUri, id) 在原有uri上追加id,自定义ContentProvider的时候,增删改的时候,追加目标id

ContentResolver:(操作应用暴露的数据,及可使用此类对象进行增删查改)ContentProvider的所有操作都通过ContentResolver 实现 
    ContentResolver resolver = getContentResolver();

Bitmap中compress()方法:通过流写图片
        OutputStream os = resolver.openOutputStream(uri);
        Bitmap bmp = BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher);
        /**
        * 参数1 format:图片格式(固定为CompressFormat.JPEG)
        * 参数2 quality:图片质量 0-100
        * 参数3 stream:输出流
        */
        bmp.compress(CompressFormat.JPEG, 100, os);
  1. 访问通讯录:

    1)联系人的数据库文件的位置 /data/data/com.android.providers.contacts/databases/contacts2.db
    
    contacts表:保存了ContactID。区分不同的人,无具体信息。该表不能进行增删改查
        该表保存了联系人的id和名称以及是否有电话号码(has_phone_number),是否被添加?到收藏夹等信息。
        Rows代表不同的人,这些人基于raw contact 的行的集合(无法直接向此表插入数据)(区分不同的人,无具体信息)
    
    raw_contacts表:保存了RawContactID和ContactID
        Rows包含一个人的简要数据,特指用户账户和类型(在此表中进行联系人的增删查改)
    
    mimetypes表:该表定义了所有的  MimeTypeID,即联系人的各个字段的唯一标志。
        Rows包含raw contact的具体数据信息,例如电子邮件或者电话号码(通过raw_contact或者contact任意一个表都能取出任何一个人的具体信息,其中mime_type区别数据类型) 
    
    data表:保存了两个ID:MimeTypeID和RawContactID
        联系人的所有信息保存在列data1至data15中,各列中保存的内容根据MimeTypeID的不同而不同。如保存号码(MimeTypeID=5)的那行数据中,
            data1列保存号码,data2列保存号码类型(手机号码/家庭号码/工作号码等)。
    
    注:一个contacts表对应多个   raw_contacts表 ,一个raw_contacts表又对应多个data表
    

    3)操作:这里只写了查询通讯录操作:

    方法一:a:从contacts表去查联系人id 
            b:根据id,去data表中匹配联系人,找详细数据
    Demo:
        public static List queryAllContacts(Context ctx) {
    
            // 查询联系人:Contacts:区别不同的人(没有个人具体信息),通过id和昵称。
            // URi地址
            Uri uri = Contacts.CONTENT_URI;
            ContentResolver resolver = ctx.getContentResolver();
            Cursor cursor = resolver.query(uri, null, null, null, null);
            List persons = new ArrayList();
            Person p = new Person();
            // 取contact表的id
            while (cursor.moveToNext()) {
                // 方式1,获得
                int _id = cursor.getInt(cursor.getColumnIndex("_id"));
                // 方式2,获得
                String name = cursor.getString(cursor.getColumnIndex(Contacts.DISPLAY_NAME));
                Log.e("-----", "---id---" + _id);
                Log.e("-----", "---name---" + name);
                p.setId(_id);
                p.setName(name);
                // 在data表查询具体信息,根据contact_id匹配查询具体人的信息
                // String字符串地址:content://com.android.contacts/data
                Cursor c = resolver.query(Data.CONTENT_URI, null, "contact_id = ?", new String[] { String.valueOf(_id) },
                        null);
                // 取data表详细内容,cursor代表一个结果集,用集合来存储
                List infos = new ArrayList();
                Info info = new Info();
                while (c.moveToNext()) {
                    // 此字段标识取出的值是电话还是邮箱等其他内容
                    String type = c.getString(c.getColumnIndex("mimetype"));
                    // 匹配电话与email
                    if (type.equals("vnd.android.cursor.item/phone_v2")) {
                        // data1放的是值
                        Log.e("-----", "匹配电话" + c.getString(c.getColumnIndex(Data.DATA1)));
                        info.setNumber(c.getString(c.getColumnIndex(Data.DATA1)));
                    } else if (type.equals("vnd.android.cursor.item/email_v2")) {
                        Log.e("-----", "匹配邮件" + c.getString(c.getColumnIndex(Data.DATA1)));
                        info.setEmail(c.getString(c.getColumnIndex(Data.DATA1)));
                    }
                }
                p.setList(infos);
                persons.add(p);
            }
            return persons;
        }       
    
    方法二:a:从raw_contact表去查id
            b:根据id,去data表中匹配联系人,找详细数据   
    Demo:   
        public static List queryAllContacts(Context ctx) {
    
            Uri uri = RawContacts.CONTENT_URI;
            ContentResolver resolver = ctx.getContentResolver();
            Cursor cursor = resolver.query(uri, null, null, null, null);
            List persons = new ArrayList();
            Person p = new Person();
            // 取contact表的id
            while (cursor.moveToNext()) {
                // 方式1,获得id
                int _id = cursor.getInt(cursor.getColumnIndex("_id"));
                // 方式2,获得name
                String name = cursor.getString(cursor.getColumnIndex(RawContacts.DISPLAY_NAME_ALTERNATIVE));
                Log.e("-----", "---id---" + _id);
                Log.e("-----", "---name---" + name);
                p.setId(_id);
                p.setName(name);
                // 在data表查询具体信息,根据raw_contact_id匹配查询具体人的信息
                Cursor c = resolver.query(Data.CONTENT_URI, null, "raw_contact_id = ?", new String[] { String.valueOf(_id) },
                        null);
                // 取data表详细内容,cursor代表一个结果集,用集合来存储
                List infos = new ArrayList();
                Info info = new Info();
                while (c.moveToNext()) {
                    // 此字段标识取出的值是电话还是邮箱等其他内容
                    String type = c.getString(c.getColumnIndex("mimetype"));
                    // 匹配电话与email
                    if (type.equals("vnd.android.cursor.item/phone_v2")) {
                        // data1放的是值
                        Log.e("-----", "匹配电话" + c.getString(c.getColumnIndex(Data.DATA1)));
                        info.setNumber(c.getString(c.getColumnIndex(Data.DATA1)));
                    } else if (type.equals("vnd.android.cursor.item/email_v2")) {
                        Log.e("-----", "匹配邮件" + c.getString(c.getColumnIndex(Data.DATA1)));
                        info.setEmail(c.getString(c.getColumnIndex(Data.DATA1)));
                    }
                }
                p.setList(infos);
                persons.add(p);
            }
            return persons;
    
        }           
    
  2. 访问图库
    权限
    1)查询图片库步骤:Uri地址:MediaStore.Images.Media.EXTERNAL_CONTENT_URI
    a: 获取Contentresolver对象
    ContentResolver resolver = getContentResolver();
    b: 调用query()方法,返回Cursor对象
    Cursor c = r.query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, null, null, null, null);
    c: 根据cursor对象获取图库的常中图片的常用字段:
    图片id: _id (MediaStore.Images.Media._ID),
    图片名称: _display_name (MediaStore.Images.Media.DISPLAY_NAME),
    图片类型: mime_type (MediaStore.Images.Media.MIME_TYPE),
    图片地址: _data (MediaStore.Images.Media.DATA)
    例子:获得图片地址的两种方式:
    //方式一:
    String date = c.getString(c.getColumnIndex(Images.Media.DATA));
    //方式二:
    String data = c.getString(c.getColumnIndex(“_data”));

    2)插入图片库步骤:插入图库的Uri地址:MediaStore.Images.Media.EXTERNAL_CONTENT_URI
    a: 获取Contentresolver对象
    ContentResolver resolver = getContentResolver();
    b:通过ContentValues对图片进行配置
    ContentValues values = new ContentValues();
    values.put(MediaStore.Images.Media.DISPLAY_NAME, “gg.png”);
    values.put(MediaStore.Images.Media.MIME_TYPE, “image/jpeg”);//注意类型,固定
    c:调用insert()方法插入,并返回Uri对象为插入图片的具体地址
    Uri uri = resolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
    d: 根据Uri对象获取图片的输出流(getContentResolver().openOutputStream(uri)),将图片写入到输出流中并刷新输出流且关闭输出流
    OutputStream os = resolver.openOutputStream(uri);
    Bitmap bmp = BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher);
    /** 将图片写入到输出流
    * 参数1 format:图片格式
    * 参数2 quality:图片质量 0-100
    * 参数3 stream:输出流
    */
    bmp.compress(CompressFormat.JPEG, 100, os);
    os.flush();
    os.close();

    图库中图片属性的所有信息:
    _id
    _data
    _size
    _display_name
    mime_type
    title
    date_added
    date_modified
    description
    picasa_id
    isprivate
    latitude
    longitude
    datetaken
    orientation
    mini_thumb_magic
    bucket_id
    bucket_display_name
    width
    height

5.SearchView:

属性:android:iconifiedByDefault=""
        值为true,表示初始搜索框是关闭的,仅显示一个放大镜;
        值为false搜索框是打开的
    android:imeOptions=""
        软键盘右下角的行为操作,值可以是搜索、下一个、发送、完成等等  
    android:queryHint输入框默认文本
监听:.setOnQueryTextListener  实现两个抽象方法
        onQueryTextSubmit(String query):开始搜索
        onQueryTextChange(String newText):输入框内容变化的监听器

6.AutoCompleteTextView:自动匹配

属性:可以在java文件中设置也可以在XNL中设置
    .setDropDownHeight方法 ,用来设置提示下拉框的高度,注意,这只是限制了提示下拉框的高度,提示数据集的个数并没有变化
    .setThreshold方法,设置从输入第几个字符起出现提示 
    .setCompletionHint方法,设置提示框最下面显示的文字
    .showdropdown方法,让下拉框弹出来
Demo:
    //下拉框的高度
    auto.setDropDownHeight(500);
    //从第几个字母开始匹配
    auto.setThreshold(1);
    //提示信息
    auto.setCompletionHint("最近搜索历史");

监听:.setOnFocusChangeListener(new OnFocusChangeListener() {
        //焦点改变
        @Override
        public void onFocusChange(View v, boolean hasFocus) {
            if(hasFocus){
                //展示提示框
                auto.showDropDown();
            }               
        }
    });     
  1. 访问短信:

    Uri地址:Telephony.Sms.CONTENT_URI
    字符串:content://sms

    方式1:通过字符串类型访问,content://sms
    步骤:
        a:声明一个字符串,内容为content://sms
            String sms = "content://sms";
        b:用Uri(统一资源定位符进行转码)
            Uri uri = Uri.parser(sms);
        c:获取ContentResolver对象
            ContentResolver resolver = getContentResolver();
        d:调用query()方法,返回Cursor对象
            Cursor cursor = resolver.query(uri, null, null, null, null);
        e: 根据cursor对象进行操作:
            与ListView的一起使用
                SimpleCursorAdapter adapter = new SimpleCursorAdapter(MainActivity.this, R.layout.item, cursor, new String[]{"address","body","date"}, 
                        new int[]{R.id.tel,R.id.body,R.id.date},SimpleCursorAdapter.FLAG_REGISTER_CONTENT_OBSERVER);
                listView.setAdapter(adapter);
    
    方式二:Uri类型,Telephony.Sms.CONTENT_URI
    步骤:
        a: 获取Contentresolver对象
            ContentResolver resolver = getContentResolver();
        b:  调用query()方法,返回Cursor对象
            Cursor cursor1 = resolver.query(Telephony.Sms.CONTENT_URI, null, null, null, null);
        c:根据cursor对象获取短信的常用字段:_id,address,person,body,type,date,read    
    

    短信库中所有的类型:

    _id                 短消息序号
    thread_id   
    address             发件人地址,手机号
    person              发件人,返回一个数字就是联系人表里的序号,陌生人为null,
    date                日期,long型
    date_sent
    protocol
    read                是否阅读,0未读,1已读
    status
    type
    reply_path_present
    subject
    body                消息内容
    service_center
    locked
    error_code
    seen
    
  2. 访问通话记录: Uri地址:CallLog.Calls.CONTENT_URI
    字符串:content://call_log/calls
    权限:
    步骤:
    a: 获取Contentresolver对象
    ContentResolver resolver = getContentResolver();
    b: 调用query()方法,返回Cursor对象
    Cursor cursor = resolver.query(CallLog.Calls.CONTENT_URI, null, null, null, null);

    c:根据cursor对象进行操作 
        与listView的一起使用
        /**
         * 参数1:上下文对象
         * 参数2:列表item的布局视图
         * 参数3:查询结果的返回值,是一个集合Cursor
         * 参数4:字符串数组,值为Cursor集合中的列名,
         *          把列名对应的值绑定到UI上(系统实现了)
         * 参数5:整形数组,其中值为Cursor列名值多对应的控件
         * 
         */
        SimpleCursorAdapter adapter = new SimpleCursorAdapter(this, R.layout.item, cursor, new String[]{"number"}, new int[]{R.id.textView1});
        listView.setAdapter(adapter);
        //监听
        listView.setOnItemClickListener(new OnItemClickListener() 
    

    Android通话记录数据库的字段介绍
    formatted_number
    numbertype 电话号码类型(家庭,工作等)
    duration 通话时长
    presentation
    geocoded_location
    lookup_uri
    countryiso
    transcription
    subscription
    subscription_id
    photo_id
    mark_content
    _id 主键
    type 电话类型(来电1,打出去2,未接3,语音邮件4)
    is_read
    number 电话号码
    voicemail_uri
    features
    new
    date 通话日期
    data_usage
    numberlabel
    mark_type
    subscription_component_name
    mark_count
    name
    is_cloud_mark
    matched_number
    normalized_number
    is_private
    ring_times

你可能感兴趣的:(Android)