zoukankan      html  css  js  c++  java
  • Android ContentProvider

    一 ContentProvider简介

    ContentProvider是四大组件之一 用来暴露应用里面的数据给其它应用访问

    Uri: 代表了要操作的数据 Uri主要包含了 需要操作的内容提供者 和 内容提供者中需要操作的指定数据

    UriMatcher: 用于匹配Uri

    ContentUris: 用于操作Uri路径后面的参数部分

    ContentProvider: 内容提供者 用于对外共享数据

    ContentResolver: 内容解决者 用于外部应用中 操作指定Uri内容提供者里面数据

    ContentObserver: 内容观察者 用于外部应用中 监听指定Uri内容提供者里面数据变化

    AsyncQueryHandler: 用于执行内容解决者的耗时操作 多用于查询

    二 举个例子

    ContentProvider作为一个应用程序名叫Provider

    ContentResolver作为一个应用程序名叫Resolver

    ContentObserver作为一个应用程序名叫Observer

    Provider端

    1. 新建一个SQLiteOpenHelper

    public class SQLiteUtils extends SQLiteOpenHelper {
    
        private static final String DB_NAME = "test.db";
        private static final int DB_VERSION = 1;
        private static SQLiteOpenHelper mInstance;
    
        private SQLiteUtils(Context context, String name, SQLiteDatabase.CursorFactory factory, int version) {
            super(context, name, factory, version);
        }
    
        public static synchronized SQLiteOpenHelper newInstance(Context context) {
            if (null == mInstance) {
                mInstance = new SQLiteUtils(context,
                        DB_NAME,
                        null,
                        DB_VERSION); //数据库的版本号 如果版本号不同 执行onUpgrade()方法
            }
            return mInstance;
        }
    
        @Override
        public void onCreate(SQLiteDatabase db) {
            // 创建表
            String sql = "CREATE TABLE android_account (" +
                    "id INTEGER PRIMARY KEY AUTOINCREMENT, " +
                    "name TEXT NOT NULL, " +
                    "money INTEGER NOT NULL)";
            db.execSQL(sql);
        }
    
        @Override
        public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
            // 数据库升级(在数据库版本发生变化时会被调用 一般在软件升级时才需改变版本号)
            String sql = "ALTER TABLE android_account ADD age INTEGER";
            db.execSQL(sql);
        }
    
    }

    2. 新建一个ContentProvider

    public class MyContentProvider extends ContentProvider {
    
        private static final String AUTHORITY = "com.hy.provider.provider.MyContentProvider";
        private static final int ANDROID_ACCOUNT = 10010;
        private static UriMatcher sMatcher = new UriMatcher(UriMatcher.NO_MATCH);
        static{
            // authority(授权) + path(一般是表名) = uri = code(唯一标识)
            sMatcher.addURI(AUTHORITY, "android_account", ANDROID_ACCOUNT); //content://authority/android_account
        }
        private SQLiteOpenHelper mHelper; //数据库帮助类
    
        @Override
        public boolean onCreate() {
            mHelper = SQLiteUtils.newInstance(getContext());
            return false;
        }
    
        @Nullable @Override
        public String getType(@NonNull Uri uri) {
            return null;
        }
    
        @Nullable @Override
        public Uri insert(@NonNull Uri uri, @Nullable ContentValues values) {
            SQLiteDatabase database = mHelper.getWritableDatabase();
            switch (sMatcher.match(uri)) {
                case ANDROID_ACCOUNT:
                    database.insert("android_account", null, values);
                    break;
    
                default:
                    // 如果匹配不上 对外抛出异常
                    throw new IllegalArgumentException("uri do not exist -> " + uri);
            }
            // SQLiteDatabase不需要手动关闭 内容提供者会自行维护
            getContext().getContentResolver().notifyChange(uri, null); //发出改变通知
            return null;
        }
    
        @Override
        public int delete(@NonNull Uri uri, @Nullable String selection, @Nullable String[] selectionArgs) {
            SQLiteDatabase database = mHelper.getWritableDatabase();
            switch (sMatcher.match(uri)) {
                case ANDROID_ACCOUNT:
                    database.delete("android_account", selection, selectionArgs);
                    break;
    
                default:
                    // 如果匹配不上 对外抛出异常
                    throw new IllegalArgumentException("uri do not exist -> " + uri);
            }
            // SQLiteDatabase不需要手动关闭 内容提供者会自行维护
            getContext().getContentResolver().notifyChange(uri, null); //发出改变通知
            return 0;
        }
    
        @Override
        public int update(@NonNull Uri uri, @Nullable ContentValues values, @Nullable String selection, @Nullable String[] selectionArgs) {
            SQLiteDatabase database = mHelper.getWritableDatabase();
            switch (sMatcher.match(uri)) {
                case ANDROID_ACCOUNT:
                    database.update("android_account", values, selection, selectionArgs);
                    break;
    
                default:
                    // 如果匹配不上 对外抛出异常
                    throw new IllegalArgumentException("uri do not exist -> " + uri);
            }
            // SQLiteDatabase不需要手动关闭 内容提供者会自行维护
            getContext().getContentResolver().notifyChange(uri, null); //发出改变通知
            return 0;
        }
    
        @Nullable @Override
        public Cursor query(@NonNull Uri uri, @Nullable String[] projection, @Nullable String selection, @Nullable String[] selectionArgs, @Nullable String sortOrder) {
            SQLiteDatabase database = mHelper.getReadableDatabase();
            Cursor cursor;
            switch (sMatcher.match(uri)) {
                case ANDROID_ACCOUNT:
                    cursor = database.query("android_account", //表名 如果是多表联合查询 可以用逗号将两个表名分开
                            projection, //要查询出来的列名
                            selection, //查询条件子句 在条件子句允许使用占位符"?"
                            selectionArgs, //selection语句中占位符的值
                            null,
                            null,
                            sortOrder);
                    break;
    
                default:
                    // 如果匹配不上 对外抛出异常
                    throw new IllegalArgumentException("uri do not exist -> " + uri);
            }
            // Cursor和SQLiteDatabase不需要手动关闭 内容提供者会自行维护
            return cursor;
        }
    
    }

    3. AndroidManifest.xml application节点里面配置provider

    <!-- authorities: 只是一个唯一标识 如果手机里面已经存在这样的授权安装应用就会失败
        exported: 是否允许其它应用访问 -->
    <provider android:name=".provider.MyContentProvider"
        android:authorities="com.hy.provider.provider.MyContentProvider"
        android:exported="true" />

    Resolver端

    public class MainActivity extends AppCompatActivity implements View.OnClickListener {
    
        // android:authorities="com.hy.provider.provider.MyContentProvider"
        Uri mUri = Uri.parse("content://com.hy.provider.provider.MyContentProvider/android_account");
        ContentResolver mResolver;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            findViewById(R.id.insert).setOnClickListener(this);
            findViewById(R.id.delete).setOnClickListener(this);
            findViewById(R.id.update).setOnClickListener(this);
            findViewById(R.id.select).setOnClickListener(this);
            findViewById(R.id.async).setOnClickListener(this);
            mResolver = getContentResolver();
        }
    
        @Override
        public void onClick(View view) {
            switch (view.getId()) {
                case R.id.insert:
                    try {
                        ContentValues values = new ContentValues();
                        values.put("name", "黄祎");
                        values.put("money", 222);
                        mResolver.insert(mUri, values);
    
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                    break;
    
                case R.id.delete:
                    try {
                        mResolver.delete(mUri, "id > ?", new String[]{"0"});
    
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                    break;
    
                case R.id.update:
                    try {
                        ContentValues values = new ContentValues();
                        values.put("money", 1100);
                        mResolver.update(mUri, values, "id > ?", new String[]{"0"});
    
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                    break;
    
                case R.id.select:
                    try {
                        Cursor cursor = mResolver.query(mUri, new String[]{"id", "name", "money"},
                                null, null, null);
                        while (cursor.moveToNext()) {
                            int id = cursor.getInt(cursor.getColumnIndex("id"));
                            String name = cursor.getString(cursor.getColumnIndex("name"));
                            int money = cursor.getInt(cursor.getColumnIndex("money"));
                            Log.i("HUANG", "id=" + id + ", name=" + name + ", money=" + money);
                        }
                        cursor.close();
    
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                    break;
    
                case R.id.async:
                    // 查询的数据如果超级多 直接查询就可能导致ANR 这是一个耗时的操作
                    // Android专门设计了一个类 用于执行内容解决者的耗时操作 多用于查询
                    new QueryHandler(mResolver).startQuery(0, //查询的唯一标识 该参数会传递给onQueryComplete()
                            null, //用来传递数据 该参数会传递给onQueryComplete()
                            mUri, new String[]{"id", "name", "money"}, null, null, null);
                    break;
            }
        }
    
        private class QueryHandler extends AsyncQueryHandler {
    
            public QueryHandler(ContentResolver cr) {
                super(cr);
            }
    
            @Override
            protected void onQueryComplete(int token, Object cookie, Cursor cursor) {
                super.onQueryComplete(token, cookie, cursor);
                while (cursor.moveToNext()) {
                    int id = cursor.getInt(cursor.getColumnIndex("id"));
                    String name = cursor.getString(cursor.getColumnIndex("name"));
                    int money = cursor.getInt(cursor.getColumnIndex("money"));
                    Log.i("HUANG", "id=" + id + ", name=" + name + ", money=" + money);
                }
            }
    
        }
    
    }

    Observer端

    public class MainActivity extends AppCompatActivity {
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            // 注册内容观察者监听
            getContentResolver().registerContentObserver(Uri.parse("content://com.hy.provider.provider.MyContentProvider/android_account"),
                    true, //true = 监听指定Uri和指定Uri的子路径
                    new MyContentObserver(new Handler()));
        }
    
        private class MyContentObserver extends ContentObserver {
    
            public MyContentObserver(Handler handler) {
                super(handler);
            }
    
            @Override
            public void onChange(boolean selfChange) {
                super.onChange(selfChange);
                // 当内容提供者发出改变通知 该方法就会调用
                Log.i("HUANG", "数据发生改变");
            }
    
        }
    
    }
  • 相关阅读:
    Python匿名函数详解
    python开发 -- 经常浏览的网站
    Python -- 变量指向
    我的Python开发之路---微信网页授权(扫码登陆)
    信息收集篇:玩转信息收集(一)
    TodoList:适合初学者的vue+node小项目
    节流和防抖的实现
    javascript的this问题
    bind、call、apply的区别与实现
    杜教筛
  • 原文地址:https://www.cnblogs.com/huangyi-427/p/9605211.html
Copyright © 2011-2022 走看看