博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Android Sqite数据库 <7>
阅读量:4504 次
发布时间:2019-06-08

本文共 16584 字,大约阅读时间需要 55 分钟。

转换成xml可以看看网上的大神的杰作.

下面要解决一个问题,就是自己APP里面创建的数据和数据如何提供给其他APP使用,需要靠一个什么工具盒介质呢?

Android里面有四大组件,其中一种ContentProvider组件就能够做到,要ContentProvider组件提供的数据,那么就需要将ContentProvider在配置文件(AndroidManifest.xml)显示暴露出来.当然,Android的四大组件都需要在AndroidManifest.xml中注册,但是不一定暴露,要提供给其他APP使用,四大组件都需要设置暴露出来.

这里要开发两个APP,一个APP提供ContentProvider,另外一个使用共享的数据库,开发步骤如下:

<1> :根据前面的数据库基本使用,这里仍然需要使用SqliteOpenHelper来进行数据库操作,ContentProvider虽然重载了update(...).delete(...)等方法,但是在具体实现这些方法时,还是需要借助SqliteOpenHelper来操作数据库.,所以综述上面的,首先还是需要新建一个继承SqliteOpenHelper的类,另外为了方便管理数据库字段,一般先定义一个单独类专门管理数据库名,table名,字段名,Uri,等等:

package hx.android.test;import android.net.Uri;import android.provider.BaseColumns;public class Mytable{    public static class MyColumns implements BaseColumns {
/* * BaseColumns 是一个接口,里边有两个变量,一个是_ID=“_id”,一个是_COUNT="_ count" 。 * 在Android当中,每一个数据库表至少有一个字段,而且这个字段是_id。 * 所以当我们构造列名的辅助类时,直接实现BaseColumns ,这样我们便默认地拥有了_id字段。 * 如果没有继承BaseColum类,就要自己定义变量_id */ private MyColumns() {} public static final String AUTHORITY = "hx.android.test.mycontentprovider"; public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/mytable"); public static final String CONTENT_TYPE = "vnd.Android.cursor.dir/vnd.hx.mytable"; public static final String CONTENT_ITEM_TYPE = "vnd.Android.cursor.item/vnd.hx.mytable"; public static final String DEFAULT_SORT_ORDER = "created DESC"; public static final String TABLE_NAME = "mytable"; public static final int VERSION = 1; public static final String TITLE = "title"; public static final String BODY = "body"; public static final String NAME = "name";} }
View Code

然后新建一个继承SqliteOpenHelper的类:

package hx.android.test;import hx.android.test.Mytable.MyColumns;import android.content.Context;import android.database.sqlite.SQLiteDatabase;import android.database.sqlite.SQLiteOpenHelper;public class DatabaseHelper extends SQLiteOpenHelper {    public static String DATABASE_NAME = "mydatabase2.db";    public static int version = 1;    public DatabaseHelper(Context context) {        super(context, DATABASE_NAME, null, version);        // TODO Auto-generated constructor stub    }        @Override      public void onOpen(SQLiteDatabase db) {          super.onOpen(db);          //这是当打开数据库时的回调函数,一般也不会用到。    }    @Override    public void onCreate(SQLiteDatabase db) {        // 在数据库第一次生成的时候会调用这个方法,一般我们在这个方法里边生成数据库表        // SQL语句//        String sql = "CREATE TABLE " + MyColumns.TABLE_NAME + " (" +MyColumns._ID +"int not null,"+ MyColumns.TITLE//        + " text not null, " + MyColumns.BODY + " text not null," +MyColumns.NAME+"text not null"+ ");";        String s = "CREATE TABLE \"mytable\"( [_id] int PRIMARY KEY ,[title] varchar(100) ,[body] varchar(10) ,[name] varchar(100) ) ";        //执行这条SQL语句        db.execSQL(s);            }    @Override    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {        // 当数据库需要升级的时候,Android系统会主动的调用这个方法。一般我们在这个方法里边删除数据表,并建立新的数据表,        db.execSQL("DROP TABLE IF EXISTS notes");        onCreate(db);    }  }
View Code

<2> 新建一个继承ContentProvider的类,然后在这个类中的各个重载方法中操作前面继承SqliteOpenHelper来操作数据库:

package hx.android.test;import java.util.HashMap;import android.content.ContentProvider;import android.content.ContentUris;import android.content.ContentValues;import android.content.UriMatcher;import android.database.Cursor;import android.database.SQLException;import android.database.sqlite.SQLiteDatabase;import android.database.sqlite.SQLiteQueryBuilder;import android.net.Uri;import android.text.TextUtils;import android.util.Log;/** * ContentProvider是什么时候创建的,是谁创建的?访问某个应用程序共享的数据,是否需要启动这个应用程序? * 这个问题在 Android SDK中没有明确说明,但是从数据共享的角度出发,ContentProvider应该是Android在系统启动时就创建了,否则就谈不上数据共享了。  * 这就要求在AndroidManifest.XML中使用元素明确定义。 *  可能会有多个程序同时通过ContentResolver访问一个ContentProvider,会不会导致像数据库那样的“脏数 据”? *  这个问题一方面需要数据库访问的同步,尤其是数据写入的同步,在AndroidManifest.XML中定义ContentProvider的时 候,需要考虑是元素multiprocess属性的值; *  另外一方面Android在ContentResolver中提供了notifyChange() 接口,在数据改变时会通知其他ContentObserver,这个地方应该使用了观察者模式, *  在ContentResolver中应该有一些类似 register,unregister的接口。  *  至此,已经对ContentProvider提供了比较全面的分析,至于如何创建ContentProvider, *  可通过2种方法:创建一个属于你自己的 ContentProvider或者将你的数据添加到一个已经存在的ContentProvider中,当然前提是有相同数据类型并且有写入 Content provider的权限。 *  * */public class MyContentProvider extends ContentProvider {        private static final String TABLE_NAME = "mytable";    private static final int TABLES = 1;    private static final int TABLE_ID = 2;    private static final UriMatcher sUriMatcher ;    static{
//注册需要匹配的Uri /** * 什么是URI? 将其分为A,B,C,D 4个部分: A:标准前缀,用来说明一个Content Provider控制这些数据,无法改变的;"content://" B:URI的标识,它定义了是哪个Content Provider提供这些数据。对于第三方应用程序,为了保证URI标识的唯一性,它必须是一个完整的、小写的 类名。这个标识在 元素的 authorities属性中说明:一般是定义该ContentProvider的包.类的名称 ;"content://hx.android.text.myprovider" C:路径,不知道是不是路径,通俗的讲就是你要操作的数据库中表的名字,或者你也可以自己定义,记得在使用的时候保持一致就ok了;"content://hx.android.text.myprovider/tablename" D:如果URI中包含表示需要获取的记录的ID;则就返回该id对应的数据,如果没有ID,就表示返回全部; "content://hx.android.text.myprovider/tablename/#" #表示数据id * * * * UriMatcher:用于匹配Uri,它的用法如下: 1.首先把你需要匹配Uri路径全部给注册上,如下: //常量UriMatcher.NO_MATCH表示不匹配任何路径的返回码(-1)。 * UriMatcher uriMatcher = new UriMatcher(UriMatcher.NO_MATCH); //如果match()方法匹配 * content://com.changcheng.sqlite.provider.contactprovider/contact路径,返回匹配码为1 * uriMatcher.addURI(“com.changcheng.sqlite.provider.contactprovider”, “contact”, 1); //添加需要匹配uri,如果匹配就会返回匹配码 //如果match()方法匹配 * content://com.changcheng.sqlite.provider.contactprovider/contact/230路径,返回匹配码为2 * uriMatcher.addURI(“com.changcheng.sqlite.provider.contactprovider”, “contact/#”, 2);//#号为通配符 2.注册完需要匹配的Uri后,就可以使用uriMatcher.match(uri)方法对输入的Uri进行匹配,如果匹配就返回匹配码,匹配码是调用addURI()方法传入的第三个参数,假设匹配content://com.changcheng.sqlite.provider.contactprovider/contact路径,返回的匹配码为1。 * * * */ sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH); sUriMatcher.addURI(Mytable.MyColumns.AUTHORITY, TABLE_NAME, TABLES); sUriMatcher.addURI(Mytable.MyColumns.AUTHORITY, TABLE_NAME+"/#", TABLE_ID); }; @Override public int delete(Uri uri, String arg1, String[] arg2) { SQLiteDatabase db = mOpenHelper.getWritableDatabase(); return db.delete(TABLE_NAME, arg1, arg2); } @Override public String getType(Uri uri) { switch (sUriMatcher.match(uri)) { case TABLES: return Mytable.MyColumns.CONTENT_TYPE; case TABLE_ID: return Mytable.MyColumns.CONTENT_ITEM_TYPE; default: throw new IllegalArgumentException("Unknown URI " + uri); } } int i = 1; @Override public Uri insert(Uri uri, ContentValues initialValues) { // TODO Auto-generated method stub if (sUriMatcher.match(uri) != TABLES) { throw new IllegalArgumentException("Unknown URI " + uri); } ContentValues values; if (initialValues != null) { Log.i("##not null", "initialValues"); values = new ContentValues(initialValues); } else { Log.i("##null", "initialValues"); values = new ContentValues(); } if (values.containsKey(Mytable.MyColumns._ID) == false) { values.put(Mytable.MyColumns._ID, i); i++; } if (values.containsKey(Mytable.MyColumns.TITLE) == false) { values.put(Mytable.MyColumns.TITLE, "title"+i); } if (values.containsKey(Mytable.MyColumns.BODY) == false) { values.put(Mytable.MyColumns.BODY,"body"+i); } if (values.containsKey(Mytable.MyColumns.NAME) == false) { values.put(Mytable.MyColumns.NAME, "name"+i); } SQLiteDatabase db = mOpenHelper.getWritableDatabase(); long rowId = db.insert(TABLE_NAME, Mytable.MyColumns.BODY, values); if (rowId > 0) { /** * 下面会用到辅助类ContentUris 的两个实用方法 * withAppendedId(uri, id)用于为路径加上ID部分 * parseId(uri)方法用于从路径中获取ID部分 */ Uri myUri= ContentUris.withAppendedId(Mytable.MyColumns.CONTENT_URI, rowId); return myUri;//返回值为一个uri } throw new SQLException("Failed to insert row into " + uri); } DatabaseHelper mOpenHelper ; @Override public boolean onCreate() { // TODO Auto-generated method stub mOpenHelper = new DatabaseHelper(getContext()); return true; } @Override public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { SQLiteQueryBuilder qb = new SQLiteQueryBuilder();//是一个构造SQL查询语句的辅助类 switch (sUriMatcher.match(uri)) { case TABLES: qb.setTables(TABLE_NAME); break; case TABLE_ID: qb.setTables(TABLE_NAME); qb.appendWhere(Mytable.MyColumns._ID + "=" + uri.getPathSegments().get(1)); break; default: throw new IllegalArgumentException("Unknown URI " + uri); } SQLiteDatabase db = mOpenHelper.getReadableDatabase(); Cursor c = qb.query(db, projection, selection, selectionArgs, null, null, sortOrder); return c; } @Override public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { SQLiteDatabase db = mOpenHelper.getWritableDatabase(); String rowId = uri.getPathSegments().get(1); return db.update(TABLE_NAME, values, Mytable.MyColumns._ID + "=" + rowId, null); }}
View Code

<3> 自己APP使用ContentProvider提供的共享数据:

所有ContentProvider提供的数据,在被自己APP还是其他APP使用时,都要用到ContentResolver,相当于进行数据库连接,然后使用它的update(...)等方法进行操作.

package hx.android.test;import hx.android.test.Mytable.MyColumns;import android.content.Context;import android.database.sqlite.SQLiteDatabase;import android.database.sqlite.SQLiteOpenHelper;public class DatabaseHelper extends SQLiteOpenHelper {    public static String DATABASE_NAME = "mydatabase2.db";    public static int version = 1;    public DatabaseHelper(Context context) {        super(context, DATABASE_NAME, null, version);        // TODO Auto-generated constructor stub    }        @Override      public void onOpen(SQLiteDatabase db) {          super.onOpen(db);          //这是当打开数据库时的回调函数,一般也不会用到。    }    @Override    public void onCreate(SQLiteDatabase db) {        // 在数据库第一次生成的时候会调用这个方法,一般我们在这个方法里边生成数据库表        // SQL语句//        String sql = "CREATE TABLE " + MyColumns.TABLE_NAME + " (" +MyColumns._ID +"int not null,"+ MyColumns.TITLE//        + " text not null, " + MyColumns.BODY + " text not null," +MyColumns.NAME+"text not null"+ ");";        String s = "CREATE TABLE \"mytable\"( [_id] int PRIMARY KEY ,[title] varchar(100) ,[body] varchar(10) ,[name] varchar(100) ) ";        //执行这条SQL语句        db.execSQL(s);            }    @Override    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {        // 当数据库需要升级的时候,Android系统会主动的调用这个方法。一般我们在这个方法里边删除数据表,并建立新的数据表,        db.execSQL("DROP TABLE IF EXISTS notes");        onCreate(db);    }  }
View Code

<4> 在使用数据之前,需要现在AndroidManifest.xml先注册这个组件并且暴露:

其中 : android:authorities="hx.android.test.mycontentprovider"是对外暴露的.

<5> 现在自己的APP可以使用了,那么在新建一个Android工程,再做另外一个APP来使用这个共享数据:

package com.example.providerutest;import java.net.URI;import android.net.Uri;import android.os.Bundle;import android.app.Activity;import android.content.ContentResolver;import android.content.ContentValues;import android.content.UriMatcher;import android.database.Cursor;import android.util.Log;import android.view.Menu;import android.view.View;import android.view.View.OnClickListener;import android.widget.Button;import android.widget.TextView;import android.widget.Toast;public class MainActivity extends Activity {    private static final String TAG = "MainActivity";    private Uri mUri;    private Button mQueryBtn;    private Button mQueryIdBtn;    private Button mQuerySelBtn;    private TextView mDataView;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        mQueryBtn = (Button) findViewById(R.id.query);        mQueryBtn.setOnClickListener(new OnClickListener() {            @Override            public void onClick(View v) {                // TODO Auto-generated method stub                // content://+packagename+database tablename                mUri = Uri                        .parse("content://hx.android.test.mycontentprovider/mytable");                String datalist = "";                // 读取数据是用ContentResover                ContentResolver cr = MainActivity.this.getContentResolver();                Cursor cor = cr.query(mUri, null, null, null, null);                cor.moveToFirst();                while (!cor.isAfterLast()) {                    Log.i(TAG,                            "_id:" + cor.getInt(0) + " //title:"                                    + cor.getString(1));                    datalist = datalist + '\n' + "_id:" + cor.getInt(0)                            + " //title:" + cor.getString(1);                    cor.moveToNext();                }                mDataView.setText(datalist);            }        });        mQueryIdBtn = (Button) findViewById(R.id.queryid);        mQueryIdBtn.setOnClickListener(new OnClickListener() {            @Override            public void onClick(View v) {                // TODO Auto-generated method stub                // content://+packagename+database tablename                // get the second data lists(only one list will be return)                String datalist = "";                mUri = Uri                        .parse("content://hx.android.test.mycontentprovider/mytable/2");                ContentResolver cr = MainActivity.this.getContentResolver();                Cursor cor = cr.query(mUri, null, null, null, null);                cor.moveToFirst();                Log.i(TAG,                        "_id:" + cor.getInt(0) + " //title:" + cor.getString(1));                datalist = datalist + '\n' + "_id:" + cor.getInt(0)                        + " //title:" + cor.getString(1);                mDataView.setText(datalist);            }        });        mQuerySelBtn = (Button) findViewById(R.id.querysel);        mQuerySelBtn.setOnClickListener(new OnClickListener() {            @Override            public void onClick(View v) {                // TODO Auto-generated method stub                String datalist = "";                String selections = "_id=?";                String[] conditions = new String[] { "" + 3 };                mUri = Uri                        .parse("content://hx.android.test.mycontentprovider/mytable");                ContentResolver cr = MainActivity.this.getContentResolver();                Cursor cor = cr.query(mUri, null, selections, conditions, null);                cor.moveToFirst();                // only one data list will be return                Log.i(TAG,                        "_id : " + cor.getInt(0) + " //title : "                                + cor.getString(1));                Toast.makeText(                        MainActivity.this,                        "_id : " + cor.getInt(0) + " //title : "                                + cor.getString(1), Toast.LENGTH_SHORT).show();                datalist = datalist + '\n' + "_id:" + cor.getInt(0)                        + " //title:" + cor.getString(1);                mDataView.setText(datalist);            }        });        mDataView = (TextView) findViewById(R.id.dataview);    }    @Override    public boolean onCreateOptionsMenu(Menu menu) {        // Inflate the menu; this adds items to the action bar if it is present.        getMenuInflater().inflate(R.menu.main, menu);        return true;    }}
View Code

操作方法和上面第一个APP的操作方式差不多,只要知道Uri("content://packagename/tablename/#"),在利用ContentResolver就可以使用了.

另外在查询时经常需要到根据ID查询的条件,这个uri是如何产生呢,有两种方法:

<1> : 根据下面的uri去查询或者删除记录,将会操作数据库中id=ID的那条记录.

Uri uri=Uri.parse("content://packagename/tablename"+"/"+ID)

<2> : 下面可以再提供一个一般在程序中实时操作的,用的应该比上面的要多:

记住tablename后面没有"/",这个和第一种有区别.

Uri uri= ContentUris.withAppendedId("content://packagename/tablename", rowId);

好了,根据上面两个uri可以随便操作数据库任何一条记录了.

 

 

 

 

 

 

 

 

 

 

 

转载于:https://www.cnblogs.com/MMLoveMeMM/articles/3628894.html

你可能感兴趣的文章
easyloader [easyui_1.4.2] 分析源码,妙手偶得之
查看>>
动态规划
查看>>
[ 订单查询 ] 性能 高并发 : 分表 与 用户id%1024 存放表
查看>>
表格隔行变色_jQuery控制实现鼠标悬停高亮
查看>>
对于BFS的理解和部分例题(
查看>>
es5语法下,javascript如何判断函数是new还是()调用
查看>>
kaggle kernel使用指南
查看>>
数据不平衡问题的处理
查看>>
Django学习之天气调查实例(3):部署静态文件CSS、JS、images等(部署环境基于Ubuntu)...
查看>>
Pro Git阅读笔记--part1
查看>>
Python os 获取目录地址
查看>>
Oracle误删数据文件后出现oracle initialization or shutdown in progress解决
查看>>
叉乘(一)——左边还是右边
查看>>
Css Html 大风车
查看>>
Oracle数据库连接时“The Network Adapter could not establish the connection”“网络适配器无法建立连接问题”...
查看>>
awk用法
查看>>
关于近似装箱问题的思考。
查看>>
Java父类对象调用子类实体:方法重写与动态调用
查看>>
Prime 算法的简述
查看>>
开发工具 快捷键
查看>>