zoukankan      html  css  js  c++  java
  • AndroidのContentProvider之数据库更新UI

    ---恢复内容开始---

    快过年了,明年还要找工作。。。。。

    之前写过很多android各种知识点的demo,但是过了很久没用到就会忘掉。

    现在复习一下。

    这篇用到的知识点有几个:SQLiteOpenHelper,Cursor,CursorAdapter,ContentProvider,ContentObserver

    对于数据库的操控一般都是用SQLiteOpenHelper,创建该类实例,可以得到一个SQLiteDatabase,而实际上操作数据库用的还是这个。

    (一)我们先看下SQLiteOpenHelper这个类的实例

    package com.bvin.study.observer;
    
    import android.content.Context;
    import android.database.sqlite.SQLiteDatabase;
    import android.database.sqlite.SQLiteOpenHelper;
    
    public class DBHelper extends SQLiteOpenHelper{
        
        public DBHelper(Context context){
            super(context,"cache",null,Config.DATA_VERSION);
        }
    
        @Override
        public void onCreate(SQLiteDatabase db) {
            // TODO Auto-generated method stub
            db.execSQL("create table person(_id integer primary key autoincrement,name string,sex string,age integer)");
        }
    
        @Override
        public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
            // TODO Auto-generated method stub
            
        }
    
        
        
    }

    这个类主要负责数据库的创建和版本的更新管理。
    一般情况下,是可以过去这个类的实例也就是SQLiteDatabase实例去做增删查改的工作。SQLiteDatabase已经封装了对数据库的各种操作方法,而且还提供了一个db.execSQL(sql, bindArgs)方法来执行原生sql语句,有人说这种方式比它封装的方法更高效。但是execSQL()是不返回值的,下面看下那些个方法都返回些什么值。

    SQLiteDatabase

    1.public long insert (String table, String nullColumnHack, ContentValues values)

    这里是向一个表插入数据,values有把要插入的数据和表中的字段对应起来,返回的是插入到表中该行所在得行id。

    2.public int update (String table, ContentValues values, String whereClause, String[] whereArgs)

    这个方法后面的是按照什么样的条件去更新符合条件的记录,返回更新的记录所在行。

    3.public Cursor query (String table, String[] columns, String selection, String[] selectionArgs, String groupBy, String having, String orderBy, String limit)

    返回查询到的结果集

    4.public int delete (String table, String whereClause, String[] whereArgs)

    返回删除的哪行

    而查询可以 用异步查询AsyncQueryHandler ,其实这个类也可以执行增删查该,分别override每个方法来做出响应处理

    (二)ContentProvider

    这是android四大组件之一,不需要手动实例化,只要在Androidmanifest.xml里面把ContentProvider注册上去就行。

     <provider android:name=".MyProvide" android:authorities="com.bvin.study.observer.MyProvide"/>


    android:name即指定类名,android:authorities即绑定唯一的标识符,而这个一定要和URI的一样。

    ContentProvider的uri形式跟域名很像:content://authorities//path,这个uri是非常重要的东西。

    path可以表示某张表再后面可以指定某一行的某个字段,像/person/18/name就表示person表中第18个人的name

    ui叫统一资源定位符,这样就唯一标识了这个资源,别的应用程序就可以用你的数据了,android系统本身就提供了大量的provider如短信,联系人等

    好,uri讲完了就轮到ContentProvider了。

    ContentProvider一般不主动构造,它跟Activity一样提供了一个入口方法。光有ContentProvider不行啊,所谓巧妇难为无米之炊啊。所以米在哪里呢,米就用我们做好的DBHelper。DBHelper获取数据库SQLiteDatabase,这个才是真正的数据库。再ContentProvider里覆盖操作数据库的各种方法,然后用SQLiteDatabase去执行各个操作。

     看看ContentProvider内部的实现

    package com.bvin.study.observer;
    
    import android.content.ContentProvider;
    import android.content.ContentValues;
    import android.database.Cursor;
    import android.net.Uri;
    
    public class MyProvide extends ContentProvider{
        
        DBHelper dbHelper;
    
        @Override
        public int delete(Uri uri, String selection, String[] selectionArgs) {
            // TODO Auto-generated method stub
            return 0;
        }
    
        @Override
        public String getType(Uri uri) {
            // TODO Auto-generated method stub
            return null;
        }
    
        @Override
        public Uri insert(Uri uri, ContentValues values) {
            // TODO Auto-generated method stub
            
            long rowId = -1;
            rowId =dbHelper.getWritableDatabase().insert(Config.TABLE_NAME, null, values);
            Uri cururi = Uri.withAppendedPath(Config.CONTENT_URI, rowId+"");
            this.getContext().getContentResolver().notifyChange(uri,null);
            return cururi;
        }
    
        @Override
        public boolean onCreate() {
            // TODO Auto-generated method stub
            dbHelper = new DBHelper(getContext());
            return true;
        }
    
        @Override
        public Cursor query(Uri uri, String[] projection, String selection,
                String[] selectionArgs, String sortOrder) {
            // TODO Auto-generated method stub
            return null;
        }
    
        @Override
        public int update(Uri uri, ContentValues values, String selection,
                String[] selectionArgs) {
            // TODO Auto-generated method stub
            return 0;
        }
    
        
    }

    这里仅用了插入这个方法,但外部是怎么调用的呢?用到是个叫ContentResolver,这个类可以通过Context上下文获取,ContentResolver也有insert(),update(),query().delete()方法,但ContentResolver的方法是暴露在外面的方法,真正执行的是ContetnProvider。ContentResolver就像一辆车它会前进,后退,转弯,刹车,而ContetnProvider就是司机,外面看到的车在转弯在刹车都是司机在操作,而这些功能司机有吗?没有司机不能代表车转弯刹车,这些核心的功能是汽车方向盘和刹车的功能,所以SQLiteDatabase就是方向盘咯,这个比喻可能不是很恰当。

     (三)ContentResolver

    前面的都是功能接口服务的提供,接下来我们看如何去调用。这里用了一个ListActivity来调用以上定义的服务和数据可视化,主界面是个Listview,对数据库的操作用菜单来作用,四个菜单分别是增删查改。

    @Override
        public boolean onCreateOptionsMenu(Menu menu) {
            // TODO Auto-generated method stub
            
            menu.add(0, 0, 0, "添加");
            menu.add(0, 1, 1, "查询");
            menu.add(0, 2, 2, "更改");
            menu.add(0, 3, 3, "删除");
            
            return super.onCreateOptionsMenu(menu);
        }
    
        @Override
        public boolean onOptionsItemSelected(MenuItem item) {
            // TODO Auto-generated method stub
            
            switch(item.getItemId()){
            
            case 0:
                ContentValues cv = new ContentValues();
                cv.put("name", "楚凌");
                getContentResolver().insert(Config.CONTENT_URI, cv);
                
                break;
            case 1:
                
                break;
            case 2:
                dbHelper.getWritableDatabase().execSQL("update "+Config.TABLE_NAME+" set name = 'chuling' where _id = 2");
                adapter.notifyDataSetChanged();
                break;
            case 3:
                dbHelper.getWritableDatabase().delete(Config.TABLE_NAME, null, null);
                break;
            
            }
            
            return super.onOptionsItemSelected(item);
        }

    如果按以上代码,执行插入操作listview是不能及时先出来的,重启程序之后就可以看到新加的项。那要怎样才能插入一个就显示一个也就是更新数据及时刷新UI界面,因为ListView绑定的是CursorAdapter而这个cursor是充数据库查询出来的,所以要做的事情有两个。一个是数据源更新然后就是适配器去通知ui数据已改变,cursor就要重新查询一遍,或者adapter更换游标,然后再调用adapter.notifyDataSetChanged();但是cursor.requery()执行会影响效率,而光靠adapter.notifyDataSetChanged()界面是不会更新的,本来想用ContentObserver来实现,最后还是感觉不适合,有没有数据库变动及时更新Listview的良策???

    DBHelper dbHelper  = null;
        SimpleCursorAdapter adapter;
        Cursor cursor;
        Handler handler;
        MyObserver observer;
        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            //setContentView(R.layout.main);
            dbHelper = new DBHelper(this);
            handler = new Handler(){
    
                @Override
                public void handleMessage(Message msg) {
                    // TODO Auto-generated method stub
                    super.handleMessage(msg);
                    if(msg.what==2013){
                        if(cursor!=null&&!cursor.isClosed()&&adapter!=null){
                            adapter.notifyDataSetChanged();
                        }
                    }
                }
                
            };
           
            
            cursor = dbHelper.getReadableDatabase().rawQuery("select * from "+Config.TABLE_NAME, null);
            adapter = new SimpleCursorAdapter(this,android.R.layout.simple_list_item_1,cursor, new String[]{"name"}, new int[]{android.R.id.text1});
            setListAdapter(adapter);
            
            observer = new MyObserver(this,handler,cursor);
            getContentResolver().registerContentObserver(Config.CONTENT_URI, false, observer);
            
        }

    其实这里看到Config.CONTENT_URI,其实这个就是指向的数据库的路径,就是牵着风筝的一条线,牵着线的手是ContentResolver,风筝当然就是ContetnProvider咯!
    这里没看cursor.requery()哈,其实这个我已经放在ContentObserver里了。上面还有个handler,这个handler是用来注册ContentObserver的,这里将会处理观察者发出的消息。

    (四) ContentObserver

    这个类的构造方法必须有个Handler的参数来进行通信,还有个必须的就是必须覆盖onChanged()方法,用handler去发送message跟Activity去通信。

    package com.bvin.study.observer;
    
    import android.content.AsyncQueryHandler;
    import android.content.ContentResolver;
    import android.content.Context;
    import android.database.ContentObserver;
    import android.database.Cursor;
    import android.net.Uri;
    import android.os.AsyncTask;
    import android.os.Handler;
    import android.os.Looper;
    import android.os.Message;
    
    public class MyObserver extends ContentObserver{
    
        private Handler handler;
        private Cursor cursor;
        private Context context;
        public MyObserver(Context context,Handler handler,Cursor cursor){
            super(handler);
            this.context = context;
            this.handler = handler;
            this.cursor = cursor;
            
        }
        
        @Override
        public void onChange(boolean selfChange) {
            // TODO Auto-generated method stub
            super.onChange(selfChange);
            
            cursor.requery();
            handler.sendEmptyMessage(2013);
        }
    
        
        
    }

    我这里把cursor传进去,目的就是注册的URI指向的数据库更新时,就在onChanged()方法里再查询一边,然后Activity里的Handler处理消息的方法里用Adapter通知一下,界面就会及时更新了。
    但是用这个去更新Listview也不太现实,handler里处理一下其他的ui元素还是可以的,比如插入数据,就蹦出个对话框“数据插入完毕”。。。

    下面还是发下全部的代码,貌似还不可以传附件。。

    主界面:MainActivity.java

    package com.bvin.study.observer;
    
    import android.app.ListActivity;
    import android.content.AsyncQueryHandler;
    import android.content.ContentResolver;
    import android.content.ContentValues;
    import android.database.Cursor;
    import android.net.Uri;
    import android.os.Bundle;
    import android.os.Handler;
    import android.os.Looper;
    import android.os.Message;
    import android.view.Menu;
    import android.view.MenuItem;
    import android.widget.SimpleCursorAdapter;
    
    public class MainActivity extends ListActivity {
        /** Called when the activity is first created. */
        
        DBHelper dbHelper  = null;
        SimpleCursorAdapter adapter;
        Cursor cursor;
        Handler handler;
        MyObserver observer;
        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            //setContentView(R.layout.main);
            dbHelper = new DBHelper(this);
            handler = new Handler(){
    
                @Override
                public void handleMessage(Message msg) {
                    // TODO Auto-generated method stub
                    super.handleMessage(msg);
                    if(msg.what==2013){
                        if(cursor!=null&&!cursor.isClosed()&&adapter!=null){
                            adapter.notifyDataSetChanged();
                        }
                    }
                }
                
            };
           
            
            cursor = dbHelper.getReadableDatabase().rawQuery("select * from "+Config.TABLE_NAME, null);
            adapter = new SimpleCursorAdapter(this,android.R.layout.simple_list_item_1,cursor, new String[]{"name"}, new int[]{android.R.id.text1});
            setListAdapter(adapter);
            
            observer = new MyObserver(this,handler,cursor);
            getContentResolver().registerContentObserver(Config.CONTENT_URI, false, observer);
            
        }
    
        @Override
        public boolean onCreateOptionsMenu(Menu menu) {
            // TODO Auto-generated method stub
            
            menu.add(0, 0, 0, "添加");
            menu.add(0, 1, 1, "查询");
            menu.add(0, 2, 2, "更改");
            menu.add(0, 3, 3, "删除");
            
            return super.onCreateOptionsMenu(menu);
        }
    
        @Override
        public boolean onOptionsItemSelected(MenuItem item) {
            // TODO Auto-generated method stub
            
            switch(item.getItemId()){
            
            case 0:
                ContentValues cv = new ContentValues();
                cv.put("name", "楚凌");
                getContentResolver().insert(Config.CONTENT_URI, cv);
                
                break;
            case 1:
                
                break;
            case 2:
                dbHelper.getWritableDatabase().execSQL("update "+Config.TABLE_NAME+" set name = 'chuling' where _id = 2");
                adapter.notifyDataSetChanged();
                break;
            case 3:
                dbHelper.getWritableDatabase().delete(Config.TABLE_NAME, null, null);
                break;
            
            }
            
            return super.onOptionsItemSelected(item);
        }
    
        @Override
        protected void onDestroy() {
            // TODO Auto-generated method stub
            super.onDestroy();
            if(dbHelper!=null){
                dbHelper.close();
            }
             getContentResolver().unregisterContentObserver(observer);
        }
        
    }

    MyProvider.java

    package com.bvin.study.observer;
    
    import android.content.ContentProvider;
    import android.content.ContentValues;
    import android.database.Cursor;
    import android.net.Uri;
    
    public class MyProvide extends ContentProvider{
        
        DBHelper dbHelper;
    
        @Override
        public int delete(Uri uri, String selection, String[] selectionArgs) {
            // TODO Auto-generated method stub
            return 0;
        }
    
        @Override
        public String getType(Uri uri) {
            // TODO Auto-generated method stub
            return null;
        }
    
        @Override
        public Uri insert(Uri uri, ContentValues values) {
            // TODO Auto-generated method stub
            
            long rowId = -1;
            rowId =dbHelper.getWritableDatabase().insert(Config.TABLE_NAME, null, values);
            Uri cururi = Uri.withAppendedPath(Config.CONTENT_URI, rowId+"");
            this.getContext().getContentResolver().notifyChange(uri,null);
            return cururi;
        }
    
        @Override
        public boolean onCreate() {
            // TODO Auto-generated method stub
            dbHelper = new DBHelper(getContext());
            return true;
        }
    
        @Override
        public Cursor query(Uri uri, String[] projection, String selection,
                String[] selectionArgs, String sortOrder) {
            // TODO Auto-generated method stub
            return null;
        }
    
        @Override
        public int update(Uri uri, ContentValues values, String selection,
                String[] selectionArgs) {
            // TODO Auto-generated method stub
            return 0;
        }
    
        
    }

    DBHelper.java

    package com.bvin.study.observer;
    
    import android.content.Context;
    import android.database.sqlite.SQLiteDatabase;
    import android.database.sqlite.SQLiteOpenHelper;
    
    public class DBHelper extends SQLiteOpenHelper{
        
        public DBHelper(Context context){
            super(context,"cache",null,Config.DATA_VERSION);
        }
    
        @Override
        public void onCreate(SQLiteDatabase db) {
            // TODO Auto-generated method stub
            db.execSQL("create table person(_id integer primary key autoincrement,name string,sex string,age integer)");
            
        }
    
        @Override
        public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
            // TODO Auto-generated method stub
            
        }
    
        
        
    }

    MyObserver.java

    package com.bvin.study.observer;
    
    import android.content.AsyncQueryHandler;
    import android.content.ContentResolver;
    import android.content.Context;
    import android.database.ContentObserver;
    import android.database.Cursor;
    import android.net.Uri;
    import android.os.AsyncTask;
    import android.os.Handler;
    import android.os.Looper;
    import android.os.Message;
    
    public class MyObserver extends ContentObserver{
    
        private Handler handler;
        private Cursor cursor;
        private Context context;
        public MyObserver(Context context,Handler handler,Cursor cursor){
            super(handler);
            this.context = context;
            this.handler = handler;
            this.cursor = cursor;
            
        }
        
        @Override
        public void onChange(boolean selfChange) {
            // TODO Auto-generated method stub
            super.onChange(selfChange);
            
            cursor.requery();
            handler.sendEmptyMessage(2013);
        }
    
        
        
    }

    Config.java

    package com.bvin.study.observer;
    
    import android.net.Uri;
    
    public class Config {
    
        public static final String AOTHORITY = "com.bvin.study.observer.MyProvide";
        public static final String TABLE_NAME = "person";
        public static final Uri CONTENT_URI = Uri.parse("content://"+AOTHORITY+"/"+TABLE_NAME);
        public static final int DATA_VERSION =1;
    }

    AndroidManifest.xml

    <?xml version="1.0" encoding="utf-8"?>
    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
        package="com.bvin.study.observer"
        android:versionCode="1"
        android:versionName="1.0" >
    
        <uses-sdk android:minSdkVersion="8" />
    
        <application
            android:icon="@drawable/ic_launcher"
            android:label="@string/app_name" >
            <activity
                android:name=".MainActivity"
                android:label="@string/app_name" >
                <intent-filter>
                    <action android:name="android.intent.action.MAIN" />
    
                    <category android:name="android.intent.category.LAUNCHER" />
                </intent-filter>
            </activity>
            
            <provider android:name=".MyProvide" android:authorities="com.bvin.study.observer.MyProvide"/>
        </application>
    
    </manifest>

    ---恢复内容结束---

  • 相关阅读:
    Java实现 LeetCode 735 行星碰撞(栈)
    Java实现 LeetCode 735 行星碰撞(栈)
    Java实现 LeetCode 887 鸡蛋掉落(动态规划,谷歌面试题,蓝桥杯真题)
    Java实现 LeetCode 887 鸡蛋掉落(动态规划,谷歌面试题,蓝桥杯真题)
    Java实现 LeetCode 887 鸡蛋掉落(动态规划,谷歌面试题,蓝桥杯真题)
    Java实现 蓝桥杯算法提高 求最大值
    Java实现 蓝桥杯算法提高 求最大值
    Java实现 蓝桥杯算法提高 求最大值
    Python eval() 函数
    Python repr() 函数
  • 原文地址:https://www.cnblogs.com/bvin/p/2902148.html
Copyright © 2011-2022 走看看