Android基础-09

Android基础-09 内容提供者

01_为什么需要内容提供者

内容提供者:提供了统一的访问数据库的方式,可以让其他应用程序来调用。

02_编写内容提供者

步骤:

1、在工程中添加一个内容提供者的类,继承了ContentProvider类型,实现了增删改查的方法;
2、在清单文件中配置一个provider节点,指定authorities(相当于网站的域名,用来唯一标示一个内容提供者)、exported为true(从4.1开始,exported没有指定为true,表示其他应用程序不能访问这个内容提供者);

代码:

package com.itheima.accountdb;

import android.content.ContentProvider;
import android.content.ContentValues;
import android.content.UriMatcher;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.net.Uri;

public class AccountContentProvider extends ContentProvider {

    private static final int INSERT = 0;
    private static final int DELETE = 1;
    private static final int QUERY = 2;
    private static final int UPDATE = 3;
    private AccountDBHelper helper;

    //mUriMatcher uri匹配,NO_MATCH 匹配uri时如果没有匹配成功返回NO_MATCH
    private static UriMatcher  mUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);

    //mUriMatcher的岗前培训 content://com.itheima.accountdb.AccountContentProvider/insert
    static{
        //添加可以匹配到的uri
        //authority 内容提供者的主机名
        //path 访问的路径
        //code 匹配,当匹配成功时会返回这个匹配码
        mUriMatcher.addURI("com.itheima.accountdb.AccountContentProvider", "insert", INSERT);
        mUriMatcher.addURI("com.itheima.accountdb.AccountContentProvider", "delete", DELETE);
        mUriMatcher.addURI("com.itheima.accountdb.AccountContentProvider", "query", QUERY);
        mUriMatcher.addURI("com.itheima.accountdb.AccountContentProvider", "update", UPDATE);
    }

    /**
     * 内容提供者一创建的时候会调用这个方法
     * 初始化实例对象
     */
    @Override
    public boolean onCreate() {
        helper = new AccountDBHelper(getContext());
        return false;
    }

    @Override
    public Uri insert(Uri uri, ContentValues values) {
        if(mUriMatcher.match(uri) == INSERT){

            SQLiteDatabase db = helper.getWritableDatabase();
            db.insert("account", null, values);
            db.close();
        }else{
            System.out.println("口令不正确,请走开...");
        }
        return null;
    }

    @Override
    public int delete(Uri arg0, String arg1, String[] arg2) {
        return 0;
    }

    @Override
    public String getType(Uri uri) {
        return null;
    }

    @Override
    public Cursor query(Uri uri, String[] projection, String selection,
            String[] selectionArgs, String sortOrder) {
        return null;
    }

    @Override
    public int update(Uri uri, ContentValues values, String selection,
            String[] selectionArgs) {
        return 0;
    }
}

配置文件:

<!-- authorities:主机名,唯一标示内容提供者;exported,从4.1开始,exported没有指定为true,表示其他应用程序不能访问这个内容提供者 -->
<provider
    android:name="com.itheima.accountdb.AccountContentProvider"
    android:authorities="com.itheima.accountdb.AccountContentProvider"
    android:exported="true" >
</provider>

03_内容提供者工作的原理

内容提供者解析器是通过uri匹配要访问的内容提供者和访问路径的;

04_内容提供者的增删改查的实现

代码:

package com.itheima.accountdb;

import android.content.ContentProvider;
import android.content.ContentValues;
import android.content.UriMatcher;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.net.Uri;

public class AccountContentProvider extends ContentProvider {

    private static final int INSERT = 0;
    private static final int DELETE = 1;
    private static final int QUERY = 2;
    private static final int UPDATE = 3;
    private AccountDBHelper helper;

    //mUriMatcher uri匹配,NO_MATCH 匹配uri时如果没有匹配成功返回NO_MATCH
    private static UriMatcher  mUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);

    //mUriMatcher的岗前培训 content://com.itheima.accountdb.AccountContentProvider/insert
    static{
        //添加可以匹配到的uri
        //authority 内容提供者的主机名
        //path 访问的路径
        //code 匹配,当匹配成功时会返回这个匹配码
        mUriMatcher.addURI("com.itheima.accountdb.AccountContentProvider", "insert", INSERT);
        mUriMatcher.addURI("com.itheima.accountdb.AccountContentProvider", "delete", DELETE);
        mUriMatcher.addURI("com.itheima.accountdb.AccountContentProvider", "query", QUERY);
        mUriMatcher.addURI("com.itheima.accountdb.AccountContentProvider", "update", UPDATE);
    }

    /**
     * 内容提供者一创建的时候会调用这个方法
     * 初始化实例对象
     */
    @Override
    public boolean onCreate() {
        helper = new AccountDBHelper(getContext());
        return false;
    }

    @Override
    public Uri insert(Uri uri, ContentValues values) {
        if(mUriMatcher.match(uri) == INSERT){

            SQLiteDatabase db = helper.getWritableDatabase();
            db.insert("account", null, values);
            db.close();
        }else{
            System.out.println("口令不正确,请走开...");
        }
        return null;
    }

    @Override
    public int delete(Uri uri, String selection, String[] selectionArgs) {
        int n = 0;
        if(mUriMatcher.match(uri) == DELETE){

            SQLiteDatabase db = helper.getWritableDatabase();
            n  = db.delete("account", selection, selectionArgs);
            db.close();
        }else{
            System.out.println("口令不正确,请走开...");
        }

        return n ;
    }

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

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

            SQLiteDatabase db = helper.getWritableDatabase();
            Cursor cursor  = db.query("account",projection,selection , selectionArgs, null, null, null);
            return  cursor;
        }else{
            System.out.println("口令不正确,请走开...");
            return null;
        }

    }

    @Override
    public int update(Uri uri, ContentValues values, String selection,
            String[] selectionArgs) {
        int n = 0;
        if(mUriMatcher.match(uri) == UPDATE){

            SQLiteDatabase db = helper.getWritableDatabase();
            n = db.update("account", values, selection, selectionArgs);
            db.close();

        }else{
            System.out.println("口令不正确,请走开...");
        }

        return n ;
    }

    @Override
    public String getType(Uri uri) {
        return null;
    }

}

05_内容提供者的使用场景

使用场景:
    当需要给其他应用程序提供访问数据的接口(内容提供者的增删改查的方法);
    当需要访问其他应用程序的数据库中的数据时,需要使用内容提供者解析器来访问内容提供者;

06_插入短信

uri:content://sms/

短信表中需要关系的几列:address、date、type、body

代码:

ContentResolver resolver = getContentResolver();
//调用短信内容提供者增删改查方法需要使用uri
Uri uri = Uri.parse("content://sms/");
ContentValues values = new ContentValues();

values.put("address", "18910903535");
values.put("date", System.currentTimeMillis());
values.put("type", 1);
values.put("body", "itheimasdfdsfdsfdsf");

resolver.insert(uri,values);

07_内容提供者uri的写法

content://com.itheima.accountdb.AccountContentProvider/insert
http://www.baidu.com/image/1.jpg
组成部分:
        scheme名称、主机名(唯一标示内容提供者的)、path路径(操作的类型)、访问的数据资源;

08_短信的备份

步骤:

1、知道查询短信数据库表的uri;
2、通过内容提供者解析器查询短信数据;
3、把查询出来的短信数据序列化到xml的文件上;

代码:

package com.itheima.copysms;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

import org.xmlpull.v1.XmlSerializer;

import android.app.Activity;
import android.content.ContentResolver;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.util.Xml;
import android.view.View;

public class MainActivity extends Activity {

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

    public void backup(View v) {

        try {

            //1、知道查询短信数据库表的uri
            ContentResolver resolver = getContentResolver();
            Uri uri = Uri.parse("content://sms/");
            //2、通过内容提供者解析器查询短信数据;
            Cursor cursor = resolver.query(uri, new String[]{"address","date","type","body"}, null, null, "date desc");

            XmlSerializer s = Xml.newSerializer();

            FileOutputStream fos = new FileOutputStream(new File(Environment.getExternalStorageDirectory()+"/sms_backup.xml"));
            s.setOutput(fos, "UTF-8");

            s.startDocument("UTF-8", true);
            s.startTag(null, "smss");

            while(cursor.moveToNext()){
                String address = cursor.getString(0);
                long date = cursor.getLong(1);
                int type = cursor.getInt(2);
                String body = cursor.getString(3);
                //3、把查询出来的短信数据序列化到xml的文件上;
                s.startTag(null, "sms");

                s.startTag(null, "address");
                s.text(address);
                s.endTag(null, "address");

                s.startTag(null, "date");
                s.text(date+"");
                s.endTag(null, "date");

                s.startTag(null, "type");
                s.text(type+"");
                s.endTag(null, "type");

                s.startTag(null, "body");
                s.text(body+"");
                s.endTag(null, "body");

                s.endTag(null, "sms");
            }

            s.endTag(null, "smss");
            s.endDocument();
            fos.close();
            cursor.close();

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}

09_短信的还原操作

步骤:

1、读取已经备份的短信数据文件,使用pull解析xml格式的数据,读到list集合里面;
2、还原数据数据之前,先删除原来的短信数据;
3、通过内容提供者解析往短信应用程序中插入短信数据;

代码:

package com.itheima.restoresms;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import android.app.Activity;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.util.Xml;
import android.view.View;

import com.itheima.restoresms.domain.SMSInfo;

public class MainActivity extends Activity {

    private SMSInfo sms;

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

    public void restoresms(View view) {
        try {
            // 1、读取已经备份的短信数据文件,使用pull解析xml格式的数据,读到list集合里面;
            File file = new File(Environment.getExternalStorageDirectory()
                    + "/sms_backup.xml");
            FileInputStream fis = new FileInputStream(file);

            List<SMSInfo> list = getSMSList(fis);
            // 2、还原数据数据之前,先删除原来的短信数据;
            ContentResolver resolver = getContentResolver();
            Uri uri = Uri.parse("content://sms/");
            resolver.delete(uri, null, null);
            System.out.println("=====删除了原来的短信=======");
            // 3、通过内容提供者解析往短信应用程序中插入短信数据;
            for(SMSInfo sms : list){
                ContentValues values = new ContentValues();

                values.put("address", sms.getAddress());
                values.put("date", sms.getDate());
                values.put("type", sms.getType());
                values.put("body", sms.getBody());
                resolver.insert(uri, values);
            }
            System.out.println("======还原短信成功=========");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private List<SMSInfo> getSMSList(FileInputStream fis) {

        try {
            XmlPullParser parser = Xml.newPullParser();
            parser.setInput(fis, "UTF-8");

            List<SMSInfo> list = new ArrayList<SMSInfo>();
            int type = parser.getEventType();
            while (type != XmlPullParser.END_DOCUMENT) {
                switch (type) {
                case XmlPullParser.START_TAG:// 标签的开始位置
                    if ("sms".equals(parser.getName())) {
                        sms = new SMSInfo();
                    } else if ("address".equals(parser.getName())) {
                        String address = parser.nextText();
                        sms.setAddress(address);
                    } else if ("date".equals(parser.getName())) {
                        String date = parser.nextText();
                        sms.setDate(date);
                    } else if ("type".equals(parser.getName())) {
                        String smsType = parser.nextText();
                        sms.setType(smsType);
                    } else if ("body".equals(parser.getName())) {
                        String body = parser.nextText();
                        sms.setBody(body);
                    }
                    break;

                case XmlPullParser.END_TAG:// 标签的结束位置
                    if ("sms".equals(parser.getName())) {
                        list.add(sms);
                        System.out.println("---sms------" + sms);
                        sms = null;
                    }
                    break;
                }
                //解析下一个事件类型
                type= parser.next();
            }
            return list;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
}

10_联系人数据库的表结构

raw_contacts:contact_id 联系人的ID;
data:联系人的信息;
mimetypes:联系人信息字段的名称;

步骤:

1、知道使用内容提供者读取以上三张表时它们的uri;
    data:content://com.android.contacts/data/
    raw_contacts:content://com.android.contacts/raw_contacts/
2、通过内容提供者关联查询这三张表;

权限:

<uses-permission android:name="android.permission.READ_CONTACTS"/>
<uses-permission android:name="android.permission.WRITE_CONTACTS"/>

代码:

MainActivity.java:

package com.itheima.readcontacts;

import android.app.Activity;
import android.content.ContentResolver;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.view.View;

public class MainActivity extends Activity {

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

    public void readContacts(View view) {

        ContentResolver resolver = getContentResolver();

        Uri uri = Uri.parse("content://com.android.contacts/raw_contacts/");

        Cursor cursor = resolver.query(uri, new String[]{"_id"}, null, null, null);

        while(cursor.moveToNext()){
            long contact_id = cursor.getLong(0);
            System.out.println("=========contact_id="+contact_id);

            Uri datauri = Uri.parse("content://com.android.contacts/data/");
            //mimetype 代表mimetypes表中一条记录,可以简单的理解为view_data视图
            Cursor dataCursor = resolver.query(datauri, new String[]{"mimetype","raw_contact_id","data1"}, "raw_contact_id=?", new String[]{contact_id+""}, null);

            while(dataCursor.moveToNext()){
                String mimetype = dataCursor.getString(0);
                long raw_contact_id = dataCursor.getLong(1);
                String data1 = dataCursor.getString(2);

                System.out.println("raw_contact_id="+raw_contact_id+"; mimetype="+mimetype+"; data1="+data1);
            }
        }
    }

}

11_联系人的还原

步骤:

1、在raw_contacts插入一条数据:contact_id=id=总记录数+1;
2、在data表中插入数据:mimetype_id,raw_contact_id,data1;

代码:

package com.itheima.insertcontact;

import android.app.Activity;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.view.View;

public class MainActivity extends Activity {

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

    public void insert(View view) {

        ContentResolver resolver = getContentResolver();

        Uri rawconturi = Uri
                .parse("content://com.android.contacts/raw_contacts/");
        Cursor rawcursor = resolver.query(rawconturi, null, null, null, null);
        int rows = rawcursor.getCount();

        ContentValues values = new ContentValues();
        values.put("contact_id", rows + 1);
        // 在raw_contacts表中插入一条数据
        resolver.insert(rawconturi, values);

        Uri datauri = Uri.parse("content://com.android.contacts/data/");

        ContentValues nameValues = new ContentValues();

        nameValues.put("mimetype", "vnd.android.cursor.item/name");
        nameValues.put("raw_contact_id", rows + 1);
        nameValues.put("data1", "wangwu");
        resolver.insert(datauri, nameValues);

        ContentValues phoneValues = new ContentValues();

        phoneValues.put("mimetype", "vnd.android.cursor.item/phone_v2");
        phoneValues.put("raw_contact_id", rows + 1);
        phoneValues.put("data1", "13900000099");
        resolver.insert(datauri, phoneValues);

        ContentValues emailValues = new ContentValues();

        emailValues.put("mimetype", "vnd.android.cursor.item/email_v2");
        emailValues.put("raw_contact_id", rows + 1);
        emailValues.put("data1", "[email protected]");
        resolver.insert(datauri, emailValues);

        rawcursor.close();

    }
}

12_内容观察者

内容观察者:主要是用来观察内容提供者里面数据的变化情况;

13_短信窃听器

代码:

package com.itheima.smslistener;

import android.app.Activity;
import android.content.ContentResolver;
import android.database.ContentObserver;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;

public class MainActivity extends Activity {

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

    //得到内容提供者的解析器
    ContentResolver resolver = getContentResolver();
    //指定目标提供者的uri
    Uri uri = Uri.parse("content://sms/");
    //给指定的内容提供者注册一个内容观察者
    resolver.registerContentObserver(uri, true, new SmsContentObserver(new Handler()));
}

private class SmsContentObserver extends ContentObserver{

    public SmsContentObserver(Handler handler) {
        super(handler);
    }

    /**
     * 内容提供者中的数据发生变化时调用这个方法
     */
    @Override
    public void onChange(boolean selfChange) {
        super.onChange(selfChange);

        ContentResolver resolver = getContentResolver();
        Uri uri = Uri.parse("content://sms/");

        Cursor cursor = resolver.query(uri, new String[]{"address","date","type","body"}, null, null, "date desc");
        cursor.moveToNext();
        String address = cursor.getString(0);
        long date = cursor.getLong(1);
        int type = cursor.getInt(2);
        String body = cursor.getString(3);
        System.out.println("address="+address+"; date="+date+"; type="+type+"; body="+body);
    }
}
时间: 2024-08-28 19:20:32

Android基础-09的相关文章

Android基础01 快速入门 &amp; 布局

Android基础01 快速入门 & 布局 01.01  手机制式 第一代模拟制式手机(1G):1G就是大哥大,手机类似于简单的无线电双工电台,通话是锁定在一定频率,所以使用可调频电台就可以窃听通话.   第二代GSM.CDMA等数字手机(2G):手机使用PHS,GSM或者CDMA这些十分成熟的标准,具有稳定的通话质量和合适的待机时间,支持彩信业务的GPRS和上网业务的WAP服务,以及各式各样的Java程序等. 第三代移动通信技术(3G):3G,是英文3rd Generation的缩写,指第三代

Android基础入门教程——10.12 传感器专题(3)——加速度-陀螺仪传感器

Android基础入门教程--10.12 传感器专题(3)--加速度/陀螺仪传感器 标签(空格分隔): Android基础入门教程 本节引言: 本节继续来扣Android中的传感器,本节带来的是加速度传感器(Accelerometer sensor)以及 陀螺仪传感器(Gyroscope sensor),和上一节的方向传感器一样有着x,y,z 三个轴, 还是要说一点:x,y轴的坐标要和绘图那里的x,y轴区分开来!传感器的是以左下角 为原点的!x向右,y向上!好的,带着我们的套路来学本节的传感器吧

Android基础入门教程——8.1.3 Android中的13种Drawable小结 Part 3

Android基础入门教程--8.1.3 Android中的13种Drawable小结 Part 3 标签(空格分隔): Android基础入门教程 本节引言: 本节我们来把剩下的四种Drawable也学完,他们分别是: LayerDrawable,TransitionDrawable,LevelListDrawable和StateListDrawable, 依旧贴下13种Drawable的导图: 1.LayerDrawable 层图形对象,包含一个Drawable数组,然后按照数组对应的顺序来

Android基础入门教程——8.1.2 Android中的13种Drawable小结 Part 2

Android基础入门教程--8.1.2 Android中的13种Drawable小结 Part 2 标签(空格分隔): Android基础入门教程 本节引言: 本节我们继续来学习Android中的Drawable资源,上一节我们学习了: ColorDrawable:NinePatchDrawable: ShapeDrawable:GradientDrawable!这四个Drawable~ 而本节我们继续来学习接下来的五个Drawable,他们分别是: BitmapDrawable:Insert

Android基础入门教程——2.3.12 Date &amp; Time组件(下)

Android基础入门教程--2.3.12 Date & Time组件(下) 标签(空格分隔): Android基础入门教程 本节引言: 本节我们来继续学习Android系统给我们提供的几个原生的Date & Time组件,他们分别是: DatePicker(日期选择器),TimePicker(时间选择器),CalendarView(日期视图),好吧, 其实一开始让我扣这几个玩意我是拒绝的,因为在我的印象里,他们是这样的: 简直把我丑哭了,有木有,终于知道为什么那么多人喜欢自定义这种类型的

Android基础入门教程——2.1 View与ViewGroup的概念

Android基础入门教程--2.1 View与ViewGroup的概念 标签(空格分隔): Android基础入门教程 本节引言: 告别了第一章,迎来第二章--Android中的UI(User Interface)组件的详解, 而本节我们要学习的是所有控件的父类View和ViewGroup类!突发奇想,直接翻译官方文档对 这两个东西的介绍吧,对了,天朝原因,google上不去,Android developer上不去,我们可以 改hosts或者用vpn代理,当然也可以像笔者一样使用国内的API

2015年最新Android基础入门教程目录(完结版)

2015年最新Android基础入门教程目录(完结版) 标签(空格分隔): Android基础入门教程 前言: 关于<2015年最新Android基础入门教程目录>终于在今天落下了帷幕,全套教程 共148节已编写完毕,附上目录,关于教程的由来,笔者的情况和自学心得,资源分享 以及一些疑问等可戳:<2015最新Android基础入门教程>完结散花~ 下面是本系列教程的完整目录: 第一章:环境搭建与开发相关(已完结 10/10) Android基础入门教程--1.1 背景相关与系统架构

《2015最新Android基础入门教程》完结散花~

<2015最新Android基础入门教程>完结散花~ 标签(空格分隔): 反思小结 引言: 从六月底就开始编写这套教程,历时将近五个多月,今天终于写完了,全套教程正文部分148篇, 十大章,从基本UI控件到四大组件,Intent,Fragment,事件处理,数据存储,网络编程,绘图与动画, 多媒体,系统服务等都进行了详细的讲解!代码都是都是在Android Studio上进行编写的,全文 采用Markdown,行文结构清晰,还结合了实际开发中一些常见的问题进行了剖析-由于个人能力的局限, 虽然

Android基础入门教程——10.10 传感器专题(1)——相关介绍

Android基础入门教程--10.10 传感器专题(1)--相关介绍 标签(空格分隔): Android基础入门教程 1.传感器相关介绍: 说到传感器,相信大家都不会陌生吧,比如微信的摇一摇就用到了加速度传感器: 传感器的定义:一种物理设备或者生物器官,能够探测.感受外界的信号,物理条件(如光,热, 适度)或化学组成(如烟雾),并将探知的信息传递给其他的设备或者器官! 传感器的种类:可以从不同的角度对传感器进行划分,转换原理(传感器工作的基本物理或化学 效应):用途:输出信号以及制作材料和工艺