ContentProvider与sqlit的搭配使用
来源:互联网 发布:asp.net 进销存源码 编辑:程序博客网 时间:2024/05/10 03:20
上一篇文章Android持久化存储的几种方式已经讲诉了Android开发中文件存储、网络存储和SharedPreferences这三种持久化存储的方式,以及大致讲了什么是ContentProvider和它的使用场景。那么这篇文章我们就来具体讲诉一下如何使用ContentProvider与sqlit搭配,实现与一个APP对另一个APP的数据增删改查。
首先我们使用SQLiteOpenHelper这个类来创建一个数据库,并创建一个储存个人信息的People_Message的表。
public class MyDatabaseHelper extends SQLiteOpenHelper { //sql语句,用来创建表。 public static final String People_Message="create table people(" +"num integer primary key autoincrement," +"name text," +"sex text)"; Context mContext; public MyDatabaseHelper(Context context, String name, SQLiteDatabase.CursorFactory factory, int version) { //调用父类构造方法,创建数据库。第一个参数是context。第二个参数是数据库的名字,第三个参CursorFactory指定在执行查询时获得一个游标实例的工厂类,设置为null,代表使用系统默认的工厂类,第四个参数是数据库的版本号,不能小于一。 super(context, name, factory, version); mContext=context; } @Override public void onCreate(SQLiteDatabase db) { //创建表,执行sql语句 db.execSQL(People_Message); } @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { //如果需要升级数据库,会调用该方法。可以用来删除表或者添加表。 }}
上面是一个继承了SQLiteOpenHelper类的类。在构造方法中会调用父类构造方法,创建一个数据库。然后在onCreate中使用 db.execSQL()这个方法执行sql语句,进行表创建。
然后我们需要在主线程中创建一个MyDatabaseHelper对象,这样就创建好了数据库和表(如果数据库和表已经存在,将不会创建)。
mMyDatabaseHelper=new MyDatabaseHelper(getApplicationContext(),"people_message",null,1);
然后我们需要得到一个SQLiteDatabase 对象,这个对象可以用来操作数据库。
//得到可以读写数据库的SQLiteDatabasedb=mMyDatabaseHelper.getWritableDatabase();//得到只读数据库的SQLiteDatabase//db=mMyDatabaseHelper.getReadableDatabase();
上面代码可以,我们可以通过刚才创造的SQLiteOpenHelper对象来获取SQLiteDatabase。其中有两种获取方式,一个可以对数据库进行写入,另一个只读。
SQLiteDatabase这个对象中有几个方法,是对修改数据库的几种方式进行了包装。
从数据库中查询数据
db.query(String table,String[] columns,String selection,String[] selectionArgs,String groupBy,String having,String orderBy,String limit)
参数意义:
table:表名
columns:需要得到的列名数组
selection:条件字句,相当于where
selectionArgs:条件字句,条件的数组
groupBy:分组列名
having:分组条件
orderBy:排序列名
limit:查询限制
往数据库中插入数据
db.insert(String table,String nullColumnHack,ContentValues values)
参数意义:
table:表名
nullColumnHack:空列的默认值
values:插入的数据,key-value类型的集合
把数据库中指定的数据删除
db.delete(String table,String whereClause,String[] whereArgs)
参数意义:
table:表名
whereClause:删除条件
whereArgs:删除条件值数组
修改数据库中指定的数据
db.update(String table,ContentValues values,String whereClause, String[] whereArgs)
参数意义:
table:表名
values:修改的数据,key-value类型的集合
whereClause:修改条件
whereArgs:修改条件值数组
执行具体的sql语句
db.execSQL(“sql语句”)
db.XXXX的方法还有许多,如果上面的不能满足你的要求,你可以看看源码,选择自己需要的方法。
上述方法中都有很多参数,除了db.execSQL()中的参数是你需要执行的sql语句外,其他的参数都有很多,这里不细讲,使用的时候大家可以再学习。
上面我们已经建立了一个数据库并且创建了一个表。下面就是需要对表进行操作了。这里我们使用ContentProvider来对表进行操作。
我们创建一个类继承与ContentProvider,并在AndroidManifast中进行注册。
public class MyContentProvider extends ContentProvider{ public MyContentProvider() { } @Override public int delete(Uri uri, String selection, String[] selectionArgs) { // Implement this to handle requests to delete one or more rows. throw new UnsupportedOperationException("Not yet implemented"); } @Override public String getType(Uri uri) { // TODO: Implement this to handle requests for the MIME type of the data // at the given URI. throw new UnsupportedOperationException("Not yet implemented"); } @Override public Uri insert(Uri uri, ContentValues values) { // TODO: Implement this to handle requests to insert a new row. throw new UnsupportedOperationException("Not yet implemented"); } @Override public boolean onCreate() { // TODO: Implement this to initialize your content provider on startup. return false; } @Override public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { // TODO: Implement this to handle query requests from clients. throw new UnsupportedOperationException("Not yet implemented"); } @Override public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { // TODO: Implement this to handle requests to update one or more rows. throw new UnsupportedOperationException("Not yet implemented"); }}
上面代码可以看见,除了无参构造函数之外,还会自动生成几个重写方法,这几个方法就是上面我们所说的增删改查几个方法,我们可以在对应函数中就可以自己编写对数据库的操作了。
我们发现上面的几个方法中第一个参数类型都是Uri,这个参数代表要操作的数据。我们先来简单说一下Uri的构造,理解一下Uri具体的用法。
Uri 通用资源标志符(Universal Resource Identifier)
uri及基本结构是 [scheme:][//authority][path][?query][#fragment] 这个五个部分,但是除了[scheme:][//authority]必须有之外,其他的每一个部分都可以不需要。但是顺序不能改变。
拿一个例子来说
uri=http://www.java2s.com:8080/yourpath/fileName.htm?stove=10&path=32&id=4#harvic
对于这个uri来说,我们来解析一下它的各部分结构。
[scheme:]=http 在//之前都属于[scheme:]
[//authority]=www.java2s.com:8080 主机名 //之后[path]之前
[path]=yourpath/fileName.htm 具体的路径 主机名之后[?query]之前都属于[path]
[?query]=?stove=10&path=32&id=4 ?号之后 #之前
[#fragment]=#harvic #之后都属于[#fragment]
(上面只是对Uri结构的简单的介绍,如果详细了解可以点击Uri详解之——Uri结构与代码提取查看)
上面就是Uri的具体结构,我们通过具体的Uri就可以访问我们需要访问的数据了,对于ContentProvider来说,用来访问它的Uri有具体的格式。
[scheme:]=content
[//authority]=主机名,在AndroidManifest文件中可以对具体ContentProvider的authorities属性进行修改和查看,这里我们上面定义ContentProvider的authorities为”test_contentProvider”。
<provider android:name=".contentProvider.MyContentProvider" android:authorities="test_contentProvider" android:enabled="true" android:exported="true"></provider>
[path]就是我们表的名字,在这个事例程序中就是”people”。
所以这个ContentProvider的指定Uri就是
Uri PEO=Uri.parse("content://test_contentProvider/people");
那么我们来看看完整的MyContentProvider类应该是怎样的
public class MyContentProvider extends ContentProvider{ MyDatabaseHelper mMyDatabaseHelper; SQLiteDatabase db; UriMatcher sMatcher; Uri PEO=Uri.parse("content://test_contentProvider/people"); public MyContentProvider() { } //用于匹配传入的URI,如果不匹配返回-1 public int getUriMatcher(Uri uri){ return sMatcher.match(uri); } @Override public int delete(Uri uri, String selection, String[] selectionArgs) { //删除数据 if(getUriMatcher(uri)==1){ db.delete("people",selection,selectionArgs); getContext().getContentResolver().notifyChange(PEO,null); return 1; } return 0; } @Override public String getType(Uri uri) { // TODO: Implement this to handle requests for the MIME type of the data // at the given URI. throw new UnsupportedOperationException("Not yet implemented"); } @Override public Uri insert(Uri uri, ContentValues values) { //判断传入的URI是否匹配,匹配的话将数据插入数据库 if (getUriMatcher(uri)==1){ db.insert("people",null,values); getContext().getContentResolver().notifyChange(PEO,null); } return null; } @Override public boolean onCreate() { //打开数据库,得到db mMyDatabaseHelper=new MyDatabaseHelper(getContext(),"data",null,1); //得到可以读写数据库的SQLiteDatabase db=mMyDatabaseHelper.getWritableDatabase(); //UriMatcher.NO_MATCH表示不匹配任何Uri的返回码-1 sMatcher=new UriMatcher(UriMatcher.NO_MATCH); //添加一个匹配规则:第一个参数contentProvider的authority值,第二个参数数据表名,第三个参数 匹配后返回值 sMatcher.addURI("test_contentProvider","people",1); return false; } @Override public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { //查询数据 if (getUriMatcher(uri)==1){ Cursor cursor=db.query("people",null,selection,selectionArgs,null,null,sortOrder); return cursor; } return null; } @Override public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { //更新数据 if (getUriMatcher(uri)==1){ db.update("people",values,selection,selectionArgs); getContext().getContentResolver().notifyChange(PEO,null); return 1; } return 0; }
1.首先我们在onCreate构造函数中,创建或打开要操作的数据库,得到用来操作数据库的db。
2.接着我们为new出一个UriMatcher对象,给这个对象添加一个URi(可以同时添加多个,只要返回码不一样),这个Uri就是用来访问当前MyContentProvider的指定Uri,通过对ContentProvider时传入的URI进行校验,判断是否可以能够匹配,根据匹配的返回码,得知具体需要操作的数据。
3.在增删改查的四个方法中,进行具体的数据操作,这篇文章主要是对数据库的增删改查操作,所以直接使用db.xxxx()方法来进行操作。
4.在增删改完成之后,如果对数据进行了修改,使用getContext().getContentResolver().notifyChange(PEO,null)这段代码,对指定的URI添加一个通知,通知当前URI的数据有修改,便于ContentObserver进行监听。
上面就构造出了一个自定义的ContentProvider。它的指定Uri”content://test_contentProvider/people”。
我们初始化数据库,向数据库中插入十条数据,便于显示和查询。
public class PeopleActivity extends AppCompatActivity{ MyDatabaseHelper mMyDatabaseHelper; SQLiteDatabase db; MyContentProvider mMyContentProvider; ListView mListView; List<PeopleBeen> mPeopleBeens; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_people); mListView=(ListView)findViewById(R.id.list); mPeopleBeens=new ArrayList<>(); mMyDatabaseHelper=new MyDatabaseHelper(getApplicationContext(),"data",null,1); //得到可以读写数据库的SQLiteDatabase db=mMyDatabaseHelper.getWritableDatabase(); PeopleBeen p; for(int i=0;i<10;i++){ p=new PeopleBeen(); p.setNum(10+i); p.setName("王"+i); p.setSex(((i%3==0)?"女":"男")); ContentValues values = new ContentValues(); values.put("num", p.getNum()); values.put("name", p.getName()); values.put("sex",p.getSex()); db.insert("people",null, values); } Cursor cursor=db.query("people",null,null,null,null,null,null); while (cursor.moveToNext()){ PeopleBeen pp=new PeopleBeen(); pp.setNum(cursor.getInt(cursor.getColumnIndex("num"))); pp.setName(cursor.getString(cursor.getColumnIndex("name"))); pp.setSex(cursor.getString(cursor.getColumnIndex("sex"))); mPeopleBeens.add(pp); } //mMyContentProvider=new MyContentProvider(); mListView.setAdapter(new ArrayAdapter<String>(this, android.R.layout.simple_expandable_list_item_1, getData())); } private List<String> getData(){ List<String> data = new ArrayList<String>(); for(PeopleBeen p:mPeopleBeens){ data.add(p.getNum()+" 名字:"+p.getName()+" 性别:"+p.getSex()); } return data; } @Override protected void onDestroy() { super.onDestroy(); db.close();; }}
运行结果:
现在我们新建一个项目,在另一个项目中使用这个ContentProvider。
public class MainActivity extends AppCompatActivity implements View.OnClickListener{ EditText ed_num; EditText ed_name; EditText ed_sex; Button bt_cx; Button bt_cr; Button bt_xg; Button bt_sc; TextView tv_jg; ContentResolver mContentResolver; PersonOberserver personOberserver; Uri PEO=Uri.parse("content://test_contentProvider/people"); Handler mHandler=new Handler(){ @Override public void handleMessage(Message msg) { super.handleMessage(msg); Toast.makeText(getApplication(),"修改成功",Toast.LENGTH_LONG).show(); } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); ed_num=(EditText)findViewById(R.id.et_num); ed_name=(EditText)findViewById(R.id.et_name); ed_sex=(EditText)findViewById(R.id.et_sex); bt_cx=(Button)findViewById(R.id.bt_cx); bt_cr=(Button)findViewById(R.id.bt_cr); bt_xg=(Button)findViewById(R.id.bt_xg); bt_sc=(Button)findViewById(R.id.bt_sc); tv_jg=(TextView)findViewById(R.id.tv_jg); bt_cx.setOnClickListener(this); bt_cr.setOnClickListener(this); bt_xg.setOnClickListener(this); bt_sc.setOnClickListener(this); //初始化ContentResolver,用来与ContentProvider建立联系 mContentResolver=getContentResolver(); //初始化ContentOberserver,用来监听指定URI数据的改变。 personOberserver=new PersonOberserver(mHandler); //注册监听,当指定URI发生改变时,personOberserver中的onChange()会得到执行。 mContentResolver.registerContentObserver(PEO,true,personOberserver); } @Override public void onClick(View view) { switch (view.getId()){ case R.id.bt_cr: //插入数据 ContentValues values = new ContentValues(); values.put("num", Integer.parseInt(ed_num.getText().toString())); values.put("name", ed_name.getText().toString()); values.put("sex",ed_sex.getText().toString()); mContentResolver.insert(PEO,values); break; case R.id.bt_cx: //根据编号查询数据 tv_jg.setText(""); Cursor cursor = mContentResolver.query(PEO, null, "num=?", new String[]{ed_num.getText().toString()}, null); while (cursor.moveToNext()){ tv_jg.setText("编号:"+cursor.getInt(cursor.getColumnIndex("num"))+" 姓名:"+cursor.getString(cursor.getColumnIndex("name"))+" 性别:"+cursor.getString(cursor.getColumnIndex("sex"))); } break; case R.id.bt_sc: //根据编号删除数据 int result=mContentResolver.delete(PEO,"num=?",new String[]{ed_num.getText().toString()}); break; case R.id.bt_xg: //根据编号修改数据 ContentValues values_xg = new ContentValues(); values_xg.put("name", ed_name.getText().toString()); values_xg.put("sex", ed_sex.getText().toString()); mContentResolver.update(PEO,values_xg,"num=?",new String[]{ed_num.getText().toString()}); break; } } @Override protected void onDestroy() { super.onDestroy(); mContentResolver.unregisterContentObserver(personOberserver); }}public class PersonOberserver extends ContentObserver{ Handler mHandler; public PersonOberserver(Handler handler) { super(handler); mHandler=handler; } @Override public void onChange(boolean selfChange) { Log.e("dd","dd"); Message message=new Message(); mHandler.sendMessage(message); }}
我们看上面的代码,首先在onCreate周期函数中,初始化了ContentResolver,ContentResolver叫做内容解析者,当外部应用需要对ContentProvider中的数据进行添加、删除、修改和查询操作时,可以使用ContentResolver 类来完成。ContentResolver 中也拥有insert(),delete(),update(),query()这四种方法,里面的参数和数据库操作时使用的增删改查方法的参数差不多。这四种方法对应的就是ContentProvider的四种数据操作方法
接着初始化了PersonOberserver对象,这个对象是一个可以用来监听特定URI数据变化的对象。我们用registerContentObserver方法来给ContentResolver注册一个PersonOberserver,这样,当指定URI的数据发生改变时,PersonOberserver中的onChange方法就会得到调用。
我们为四个button绑定了各自的监听事件,在监听事件中,我们使用了mContentResolver.xxxxx()方法来进行增删改查,它们的参数中都有一个URI参数,而这个URI参数就是找到指定ContentProvider的标识。有了这个URI,我们才能通过ContentResolver去执行指定ContentProvider中的方法,并得到相应的数据。
另一个app的演示结果
查:
增:
- ContentProvider与sqlit的搭配使用
- python中sqlit的使用
- sqlit使用
- android sqlit数据库的使用经验
- sqlit中使用到的查询语句
- ContentProvider的理解与使用
- ContentProvider的理解与使用
- WinSCP和PuTTY的搭配与使用
- RadioGroup与RadioButton的搭配使用
- 初学 retrofit2与RXJava 的搭配使用
- boost::bind与find_if的搭配使用
- TypeScript的使用(与Angular2搭配)
- sqlit 使用like匹配
- android sqlit的模板
- sqlit的基本操作
- GridView的使用(一):与ArrayAdapter搭配使用
- GridView的使用(二):与BaseAdapter搭配使用
- GridView的使用(三):与SimpleCursorAdapter搭配使用
- 面向对象程序设计上机练习三(有默认参数的函数)
- docker批量删除none的image镜像
- Ubuntu一键安装LAMP环境
- C++ String类 详解
- [最小割]BZOJ 3175—— [Tjoi2013]攻击装置
- ContentProvider与sqlit的搭配使用
- mysql的boolean和tinyint(1)
- KB和kB,MB和mb,详细解释计算机存储单位
- Angular 4.3 HttpClient (Angular访问 REST Web 服务) 三、拦截器 Interceptors
- 推荐一个生成app应用图标的方法
- How Many Tables(并查集)
- Android View 系统 1
- uva 1586 分子量————C12H22O11读取数字12。。。
- Python-机器学习 入门及技巧总结