四大应用组件ContentProvider

   1. 认识

ContentProvider用于应用B数据库暴露接口, A应用通过ContentResolver访问B接口,读取数据库数据
   Uri格式:
   content: //  com.example.transupportprovider/trains/122
   前缀 :   //  唯一标识                       / 表  / 表id
   ContentProvider的前缀就是:content
   唯一标识 :  用包名一般


  2. 通过ContentResolver  实现 A应用  对 B应用 ContentResolver 暴露接口的访问

   A应用暴露接口


   2.1  DBHelper.java   提供内部数据库访问

package com.example.myapplication;

import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.util.Log;

/**
 * 数据库操作的帮助类
 * @author denganzhi
 *
 */
public class DBHelper extends SQLiteOpenHelper {


	public DBHelper(Context context,int version) {
		super(context, "atguigu.db", null, version);
	}

	/**
	 * 什么时候才会创建数据库文件?
	 * 	1). 数据库文件不存在
	 *  2). 连接数据库
	 * 
	 * 什么时候调用?
	 * 	当数据库文件创建时调用(1次)
	 * 在此方法中做什么?
	 * 	建表
	 * 	插入一些初始化数据
	 */
	@Override
	public void onCreate(SQLiteDatabase db) {
		Log.e("TAG", "DBHelper onCreate()");
		//建表
		String sql = "create table person(_id integer primary key autoincrement, name varchar,age int)";
		db.execSQL(sql);
		//插入一些初始化数据
		db.execSQL("insert into person (name, age) values ('Tom1', 11)");
		db.execSQL("insert into person (name, age) values ('Tom2', 12)");
		db.execSQL("insert into person (name, age) values ('Tom3', 13)");
	}

	//当传入的版本号大于数据库的版本号时调用
	// 用户版本升级
	@Override
	public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
		Log.e("TAG", "DBHelper onUpgrade()-->"+"oldVersion:"+oldVersion + "newVersion:"+newVersion);
	}
    // 还有版本下降的时候调用的方法onDowngrade
}

2.2 PersonProvider.java:  实现ContentProvider  接口暴露方法

package com.example.myapplication;

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

/**
 * 操作person表的provider类
 *
 */
public class PersonProvider extends ContentProvider {

	//用来存放所有合法的Uri的容器,这里的参数是如果url不能匹配返回的值:-1一般返回
	private static UriMatcher matcher = new UriMatcher(UriMatcher.NO_MATCH);
	//保存一些合法的uri
	// 前缀:// provider的唯一标识/表明/id
	// content://com.atguigu.l09_provider.personprovider/person 不根据id操作
	// content://com.atguigu.l09_provider.personprovider/person/3 根据id操作
	static {
		matcher.addURI("com.example.myapplication.PersonProvider", "/person", 1);
		matcher.addURI("com.example.myapplication.PersonProvider", "/person/#", 2);  //#匹配任意数字
	}
	private DBHelper dbHelper;
	public PersonProvider() {
		Log.e("TAG", "PersonProvider()");
	}
	// 当内容提供者被创建的时候调用,适合做数据初始化操作
	@Override
	public boolean onCreate() {
		Log.e("TAG", "PersonProvider onCreate()");
		dbHelper = new DBHelper(getContext(),1);

		return false;
	}

	/**
	 * content://com.atguigu.l09_provider.personprovider/person 不根据id查询
	 * content://com.atguigu.l09_provider.personprovider/person/3 根据id查询
	 * 查询表数据:
	 *  URI:地址
	 *  projection: 查询那些字段
	 *  String selection,
	 String[] selectionArgs 查询条件,条件中可能有?

	 */
	@Override
	public Cursor query(Uri uri, String[] projection, String selection,
						String[] selectionArgs, String sortOrder) {
		Log.e("TAG", "PersonProvider query()");

		//得到连接对象
		SQLiteDatabase database = dbHelper.getReadableDatabase();

		//1.匹配uri, 返回code
		int code = matcher.match(uri);
		//如果合法, 进行查询
		if(code==1) {//不根据id查询,配合1
			Cursor cursor = database.query("person", projection, selection, selectionArgs, null, null, null);
			return cursor;
		} else if(code==2) {//根据id查询,匹配2
			//得到id
			long id = ContentUris.parseId(uri);
			//查询
			Cursor cursor = database.query("person", projection, "_id=?", new String[]{id+""}, null, null, null);
			return cursor;
		} else {//如果不合法, 抛出异常
			throw new RuntimeException("查询的uri不合法");
		}
	}

	/**
	 * content://com.atguigu.l09_provider.personprovider/person 插入
	 * content://com.atguigu.l09_provider.personprovider/person/3 根据id插入(没有)
	 * values: map接口插入数据
	 */
	@Override
	public Uri insert(Uri uri, ContentValues values) {
		Log.e("TAG", "PersonProvider insert()");
		//得到连接对象
		SQLiteDatabase database = dbHelper.getReadableDatabase();
		//匹配uri, 返回code
		int code = matcher.match(uri);
		//如果合法, 进行插入
		if(code==1) {
			long id = database.insert("person", null, values);
			//将id添加到uri中
			uri = ContentUris.withAppendedId(uri, id);
			database.close();
			return uri;
		} else {
			//如果不合法, 抛出异常
			database.close();
			throw new RuntimeException("插入的uri不合法");
		}
	}

	/**
	 * content://com.atguigu.l09_provider.personprovider/person 不根据id删除
	 * content://com.atguigu.l09_provider.personprovider/person/3 根据id删除
	 *
	 * String selection, String[] selectionArgs: 删除条件
	 */
	@Override
	public int delete(Uri uri, String selection, String[] selectionArgs) {
		Log.e("TAG", "PersonProvider delete()");
		//得到连接对象
		SQLiteDatabase database = dbHelper.getReadableDatabase();
		//匹配uri, 返回code
		int code = matcher.match(uri);
		int deleteCount = -1;
		//如果合法, 进行删除
		if(code==1) {
			deleteCount = database.delete("person", selection, selectionArgs);
		} else if(code==2) {
			long id = ContentUris.parseId(uri);
			deleteCount = database.delete("person", "_id="+id, null);
		} else {
			//如果不合法, 抛出异常
			database.close();
			throw new RuntimeException("删除的uri不合法");
		}

		database.close();
		return deleteCount;
	}

	/**
	 * content://com.atguigu.l09_provider.personprovider/person 不根据id更新
	 * content://com.atguigu.l09_provider.personprovider/person/3 根据id更新
	 *
	 * values: map更新数据
	 *  String selection,
	 String[] selectionArgs 更新条件
	 */
	@Override
	public int update(Uri uri, ContentValues values, String selection,
					  String[] selectionArgs) {
		Log.e("TAG", "PersonProvider update()");
		//得到连接对象
		SQLiteDatabase database = dbHelper.getReadableDatabase();
		//匹配uri, 返回code
		int code = matcher.match(uri);
		int updateCount = -1;
		//如果合法, 进行更新
		if(code==1) {
			updateCount = database.update("person", values, selection, selectionArgs);
		} else if(code==2) {
			long id = ContentUris.parseId(uri);
			updateCount = database.update("person", values, "_id="+id, null);
		} else {
			//如果不合法, 抛出异常
			database.close();
			throw new RuntimeException("更新的uri不合法");
		}

		database.close();
		return updateCount;
	}
	// MIME:
	@Override
	public String getType(Uri uri) {
		// TODO Auto-generated method stub
		return null;
	}
}

   B应用使用 ContentResolver 访问暴露接口,协议 Uri 的格式

   通过ContentResolver 接口,访问ContentProvider  暴露的方法


    public static String prividerStr="content://com.example.myapplication.PersonProvider/person";
    /*
	 * 通过ContentResolver调用ContentProvider查询所有记录
	 */
    public void selectProvier(View v) {
        //1. 得到ContentResolver对象
        ContentResolver resolver = getContentResolver();
        //2. 调用其query, 得到cursor
        Uri uri = Uri.parse("content://com.example.myapplication.personprovider/person/1");
        uri = Uri.parse(prividerStr);
        Cursor cusor = resolver.query(uri, null, null, null, null);
        //3. 取出cursor中的数据, 并显示
        if(cusor!=null){
            while(cusor.moveToNext()) {
                int id = cusor.getInt(0);
                String name = cusor.getString(1);
                Toast.makeText(this, id+" : "+name, 1).show();
            }
            cusor.close();
        }

    }

    public void addFun(View view) {

        //1. 得到ContentResolver对象
        ContentResolver resolver = getContentResolver();
        //2. 调用其insert
        Uri uri = Uri.parse(prividerStr);
        //uri = Uri.parse("content://com.atguigu.l09_provider.personprovider/person/3");
        ContentValues values = new ContentValues();
        values.put("name", "JACK");
        uri = resolver.insert(uri, values);

        Toast.makeText(this, uri.toString(), 1).show();
    }

    public void updateFun(View view) {
        //1. 得到ContentResolver对象
        ContentResolver resolver = getContentResolver();
        //2. 执行update
        Uri uri = Uri.parse("content://com.example.myapplication.PersonProvider/person/10");
        ContentValues values = new ContentValues();
        values.put("name", "JACK2");
        // 返回更新成功个数
        int updateCount = resolver.update(uri, values, null, null);

        Toast.makeText(this, "updateCount="+updateCount, 1).show();
    }

    public void deleteFun(View view) {
        //1. 得到ContentResolver对象
        ContentResolver resolver = getContentResolver();
        //2. 执行delete
        Uri uri = Uri.parse("content://com.example.myapplication.PersonProvider/person/2");
        int deleteCount = resolver.delete(uri, null, null);
        Toast.makeText(this, "deleteCount="+deleteCount, 1).show();
    }

 3.  内容提供者使用案例

案例1: 读取联系人

AndroidManifest.xml

  <!-- 读取联系人记录的权限 -->
    <uses-permission android:name="android.permission.READ_CONTACTS"/>

 Java 代码:系统已经提供了现成的CONTENT_URI ,把数据库字段封装成了常量

  private static final int MY_PERMISSIONS_REQUEST_CALL_PHONE =10 ; 
public void selectContacts(View view) {

        if (ContextCompat.checkSelfPermission(this,
                Manifest.permission.READ_CONTACTS)
                != PackageManager.PERMISSION_GRANTED)
        {

            ActivityCompat.requestPermissions(this,
                    new String[]{Manifest.permission.READ_CONTACTS},
                    MY_PERMISSIONS_REQUEST_CALL_PHONE);
        } else
        {
            selectContacts();
        }
    }

    public void selectContacts() {
        ContentResolver resolver = getContentResolver();
        //执行查询得到cursor
        String[] projection = {ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME, ContactsContract.CommonDataKinds.Phone.NUMBER};
        Cursor cursor = resolver.query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, projection, null, null, null);
        //取出其中的数据保存到data
        while(cursor.moveToNext()) {
            String name = cursor.getString(0);
            String number = cursor.getString(1);
            Map<String, String> map = new HashMap<String, String>();
            map.put("name", name);
            map.put("number", number);
            Log.e("denganzhi","name:"+name   + "number:"+ number);
        }
    }


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

        if (requestCode == MY_PERMISSIONS_REQUEST_CALL_PHONE)
        {
            if (grantResults[0] == PackageManager.PERMISSION_GRANTED)
            {
                selectContacts();
            } else
            {
                // Permission Denied
                Toast.makeText(MainActivity.this, "Permission Denied", Toast.LENGTH_SHORT).show();
            }
            return;
        }
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    }

 案例2: 读取sd卡本地视频路径

  @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_local);
        /**
         * 读取sd卡中本地的所有的视频
         * Android系统本地的视频播放器,已经把SD卡上的视频扫描,
         * 把数据存储数据库中了,
         * 所以只是需要使用内容提供者读取系统播放器的数据即可
         */

        ContentResolver contentProvider= getContentResolver();
        // 系统封装 Uri
        Uri uri= MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
        String[] objs={
                MediaStore.Video.Media.DISPLAY_NAME, // 视频文件在sdcard上名称
                MediaStore.Video.Media.DURATION,     // 视频总时长
                MediaStore.Video.Media.SIZE,       // 视频大小
                MediaStore.Video.Media.DATA,    // 视频绝对地址
                MediaStore.Video.Media.ARTIST,     // 歌曲演唱者
        };
        Cursor  cursor= contentProvider.query(uri,objs,null,null,null);
        if(cursor!=null){
            while(cursor.moveToNext()){
                String name = cursor.getString(0);
                long  duration = cursor.getLong(1);
                long  size = cursor.getLong(2);
                String path = cursor.getString(3);
                String artist = cursor.getString(4);
                Log.e("denganzhi","name:"+name+ " duration:"+duration +" size:"+size +" path:"+path +" artist:"+artist);
            }
        }
        cursor.close();
    }

  案例3:获取本地所有的音频文件:

   ContentResolver contentProvider= getContentResolver();
        // 系统封装 Uri
        Uri uri= MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
        String[] objs={
                MediaStore.Audio.Media.DISPLAY_NAME, // 音频文件在sdcard上名称
                MediaStore.Audio.Media.DURATION,     // 音频总时长
                MediaStore.Audio.Media.SIZE,       // 音频大小
                MediaStore.Audio.Media.DATA,    // 音频绝对地址
                MediaStore.Audio.Media.ARTIST,     // 歌曲演唱者
        };
        Cursor cursor= contentProvider.query(uri,objs,null,null,null);
        if(cursor!=null){
            while(cursor.moveToNext()){
                String name = cursor.getString(0);
                long  duration = cursor.getLong(1);
                long  size = cursor.getLong(2);
                String path = cursor.getString(3);
                String artist = cursor.getString(4);
                Log.e("denganzhi","name:"+name+ " duration:"+duration +" size:"+size +" path:"+path +" artist:"+artist);
            }
        }
        cursor.close();

  源码路径:https://download.csdn.net/download/dreams_deng/12233364

 4.  内容观察者使用

 原理:C应用注册B应用的内容观察者,B应用在数据库操作crud的时候
 发布url[ getContentResolver().notifyChange(uri,null)],
 那么C应用就可以监听到   resolver.registerContentObserver(uri, true, new ContentObserver(new Handler()) {

案例: 监听收短信,可以实现读取验证码,获取用户短信上传服务器

1.  使用广播实现,短信窃听器

AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="ndkdemo.denganzhi.com.xmlversion">

    <!-- 权限配置 -->
    <uses-permission android:name="android.permission.SEND_SMS" />

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

    <!-- 接收短信,权限配置 -->
    <uses-permission android:name="android.permission.RECEIVE_SMS" />

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

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


        <!-- 接收短信广播,短信窃听器 -->
        <receiver android:name="ndkdemo.denganzhi.com.xmlversion.SmsReceiver"
            >
            <intent-filter android:priority="1000">
                <action android:name="android.provider.Telephony.SMS_RECEIVED" />
            </intent-filter>
        </receiver>




    </application>

</manifest>
权限申请
// 判断权限
            if (ContextCompat.checkSelfPermission(this,
                    Manifest.permission.RECEIVE_SMS)
                    != PackageManager.PERMISSION_GRANTED)
            {

                // 权限申请
                ActivityCompat.requestPermissions(this,
                        new String[]{Manifest.permission.RECEIVE_SMS},
                        MY_PERMISSIONS_REQUEST_CALL_PHONE);
            } else
            {
                //具备权限发短信、接收短信权限

            }
SmsReceiver 接收短信广播
package ndkdemo.denganzhi.com.xmlversion;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.telephony.SmsManager;
import android.telephony.SmsMessage;
import android.util.Log;

import java.text.SimpleDateFormat;
import java.util.Date;

public class SmsReceiver extends BroadcastReceiver {


    String Tag="denganzhi1";
    @Override
    public void onReceive(Context context, Intent intent) {

        Log.e("denganzhi", "短信到来了....... ");

        // 短信的格式是pub 格式 https://blog.csdn.net/zx249388847/article/details/52597990/
        //  谷歌考虑 Android 工程师比较难理解,直接

        Object[] pdus = (Object[]) intent.getExtras().get("pdus");
        if (pdus != null && pdus.length > 0) {
            SmsMessage[] messages = new SmsMessage[pdus.length];
            for (int i = 0; i < pdus.length; i++) {
                byte[] pdu = (byte[]) pdus[i];
                // 把pud 转化为短信 对象
                messages[i] = SmsMessage.createFromPdu(pdu);
            }
            for (SmsMessage message : messages) {
                String content = message.getMessageBody();// 得到短信内容
                String sender = message.getOriginatingAddress();// 得到发信息的号码
//                if (sender.equals("110")) {
//                    abortBroadcast();// 中止发送
//                    Log.e("TAG", "此号码为黑名单号码,已拦截!");
//                }
                Date date = new Date(message.getTimestampMillis());
                SimpleDateFormat format = new SimpleDateFormat(
                        "yyyy-MM-dd HH:mm:ss");
                String sendContent = format.format(date) + ":" + sender + "--"
                        + content;

//                SmsManager smsManager = SmsManager.getDefault();// 发信息时需要的
//                smsManager.sendTextMessage("", null, sendContent, null,
//                        null);// 转发给
                // 打印短信内容
                Log.e(Tag, sendContent);
            }

        }
    }
}

2. 内容观察者使用,监听短信变化,读取变化短信收到的,搜集用户信息

读写读取:

 public void readSmsContext(View view){
        Uri uri = Uri.parse("content://sms/");
        ContentResolver resolver = getContentResolver();
        Cursor cursor = resolver.query(uri, new String[] { "address", "date",
                "type", "body" }, null, null, null);
        while (cursor.moveToNext()) {
            String address = cursor.getString(0);
            String date = cursor.getString(1);
            String type = cursor.getString(2);
            String body = cursor.getString(3);
            Log.e(Tag,"address:" + address);
            Log.e(Tag,"date:" + date);
            Log.e(Tag,"type:" + type);
            Log.e(Tag,"body:" + body);
            Log.e(Tag,"--------------------");
        }
        cursor.close();
    }
MainActivity 功能实现:
  @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        if (ContextCompat.checkSelfPermission(this,
                Manifest.permission.READ_SMS)
                != PackageManager.PERMISSION_GRANTED)
        {

            // 权限申请
            ActivityCompat.requestPermissions(this,
                    new String[]{Manifest.permission.READ_SMS},
                    MY_PERMISSIONS_REQUEST_CALL_PHONE);
        } else
        {
            //具备权限发短信、接收短信权限

        }


            // 短信Uri, 注册短信 Uri
        Uri uri= Uri.parse("content://sms/");
        ContentResolver resolver = getContentResolver();
        resolver.registerContentObserver(uri, true, new ContentObserver(new Handler()) {
        @Override
        public boolean deliverSelfNotifications() {
            return super.deliverSelfNotifications();
        }

        @Override
        public void onChange(boolean selfChange) {
            super.onChange(selfChange);
       // 读取变化的短信
            //全部短信
         //   public static final String SMS_URI_ALL = "content://sms/";
            //收件箱短信
        //    public static final String SMS_URI_INBOX = "content://sms/inbox";
            //发件箱短信
         //   public static final String SMS_URI_SEND = "content://sms/sent";
            //草稿箱短信
         //   public static final String SMS_URI_DRAFT = "content://sms/draft";
            Uri uri = Uri.parse("content://sms/inbox");
            ContentResolver resolver = getContentResolver();
            Cursor cursor = resolver.query(uri, new String[] { "address", "date",
                    "type", "body" }, null, null, null);
            while (cursor.moveToNext()) {
                String address = cursor.getString(0);
                String date = cursor.getString(1);
                String type = cursor.getString(2);
                String body = cursor.getString(3);
                Log.e(Tag,"--------------------");
                Log.e(Tag,"address:" + address);
                Log.e(Tag,"date:" + date);
                Log.e(Tag,"type:" + type);
                Log.e(Tag,"body:" + body);
                Log.e(Tag,"--------------------");
                break;
            }
            cursor.close();

        }
    }); 
  }

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值