关于Android中使用Uri监听数据库的变化

网上原创的关于监听数据库变化的文章很少,基本没找到有用的一篇,所以自己去看了一下蓝牙传输的源码,写了一个Demo,放在这里给大家参考一下,看源码:

src里面有三个文件MyDataProvider、MainActivity和MyBean,看下面:

MyDataProvider.java:

public class MyDataProvider extends ContentProvider
{

    // public static final String SCHEME = "test";
    public static final String SCHEME = "content"; // 源码里面规定这样写,所以这个地方改变不了

    public static final String HOST = "com.zyj";
    public static final String PORT = "497393102";
    public static final String PATH = "simple";

    public static final int ALARMS = 1;
    public static final String SHARE_LIST_TYPE = "com.zyj.test.dir/";
    public static final int ALARMS_ID = 2;
    public static final String SHARE_TYPE = "com.zyj.test.item/";

    private static final UriMatcher sURIMatcher = new UriMatcher(UriMatcher.NO_MATCH);

    private SQLiteOpenHelper mDB = null;

    // ===content://com.zyj:497393102/simple
    public static final Uri CONTENT_URI = Uri.parse(SCHEME + "://" + HOST + ":" + PORT + "/" + PATH);

    // 添加Uri的匹配方式,返回的就是上面自定义的整数类型,1代表操作的是一个批量,2操作的是单独的一个对象
    static
    {
        sURIMatcher.addURI(HOST + ":" + PORT, PATH, ALARMS);
        sURIMatcher.addURI(HOST + ":" + PORT, PATH + "/#", ALARMS_ID);
    }

    @Override
    public boolean onCreate()
    {
        mDB = new MyDB(getContext()); // 获取数据库的引用
        return mDB != null;
    }

    @Override
    public String getType(Uri uri)
    {
        // 得到我们自定义的Uri的类型,看上面你自己的定义
        int match = sURIMatcher.match(uri);
        switch (match)
        {
            case ALARMS:
            {
                return SHARE_LIST_TYPE;
            }
            case ALARMS_ID:
            {
                return SHARE_TYPE;
            }
            default:
            {
                throw new IllegalArgumentException("Unknown URI: " + uri);
            }
        }
    }

    @Override
    public Uri insert(Uri uri, ContentValues values)
    {
        // 首先是看Uri和我们自定义的是否匹配,,匹配则将数据属性插入到数据库中并同志更新
        SQLiteDatabase db = mDB.getWritableDatabase();
        if (sURIMatcher.match(uri) != ALARMS)
        {
            throw new IllegalArgumentException("Unknown/Invalid URI " + uri);
        }

        ContentValues filteredValues = new ContentValues();
        filteredValues.put(MyDB.BEAN_ID, values.getAsInteger(MyDB.BEAN_ID));
        filteredValues.put(MyDB.MESSAGE, values.getAsString(MyDB.MESSAGE));
        filteredValues.put(MyDB.TASK_PROGRESS, values.getAsFloat(MyDB.TASK_PROGRESS));
        long rowID = db.insert(MyDB.TABLET, null, filteredValues);
        if (rowID != -1)
        {
            getContext().getContentResolver().notifyChange(uri, null);
        }
        return CONTENT_URI;
    }

    @Override
    public int delete(Uri uri, String selection, String[] selectionArgs)
    {

        // 首先是看Uri和我们自定义的是否匹配,,匹配则进行删除

        SQLiteDatabase db = mDB.getWritableDatabase();
        int count = 0;
        int match = sURIMatcher.match(uri);
        switch (match)
        {
            case ALARMS:
            case ALARMS_ID:
                String where = null;
                // 这里对selection进行匹配操作,看你传递的是一个批量还是一个单独的文件
                if (selection != null)
                {
                    if (match == ALARMS)
                    {
                        where = "( " + selection + " )";
                    }
                    else
                    {
                        where = "( " + selection + " ) AND ";
                    }
                }
                else
                {
                    where = "";
                }
                if (match == ALARMS_ID)
                {
                    // 如果你传递的是一个单独的文件,也就是Uri后面添加了/item的,那么在这里把该值与数据库中的属性段进行比较,返回sql语句中的where
                    String segment = uri.getPathSegments().get(1);
                    long rowId = Long.parseLong(segment);
                    where += " ( " + MyDB.BEAN_ID + " = " + rowId + " ) ";
                }
                count = db.delete(MyDB.TABLET, where, selectionArgs);
                break;
            default:
                throw new UnsupportedOperationException("Cannot delete URI: " + uri);
        }
        getContext().getContentResolver().notifyChange(uri, null);
        return count;
    }

    @Override
    public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs)
    {
        // 基本同上了
        SQLiteDatabase db = mDB.getWritableDatabase();

        int count;
        long rowId = 0;

        int match = sURIMatcher.match(uri);
        switch (match)
        {
            case ALARMS:
            case ALARMS_ID:
            {
                String myWhere;
                if (selection != null)
                {
                    if (match == ALARMS)
                    {
                        myWhere = "( " + selection + " )";
                    }
                    else
                    {
                        myWhere = "( " + selection + " ) AND ";
                    }
                }
                else
                {
                    myWhere = "";
                }
                if (match == ALARMS_ID)
                {
                    String segment = uri.getPathSegments().get(1);
                    rowId = Long.parseLong(segment);
                    myWhere += " ( " + MyDB.BEAN_ID + " = " + rowId + " ) ";
                }

                if (values.size() > 0)
                {
                    count = db.update(MyDB.TABLET, values, myWhere, selectionArgs);
                }
                else
                {
                    count = 0;
                }
                break;
            }
            default:
            {
                throw new UnsupportedOperationException("Cannot update URI: " + uri);
            }
        }
        getContext().getContentResolver().notifyChange(uri, null);

        return count;
    }

    @Override
    public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder)
    {
        SQLiteDatabase db = mDB.getReadableDatabase();
        SQLiteQueryBuilder qb = new SQLiteQueryBuilder(); //SQLiteQueryBuilder是一个构造SQL查询语句的辅助类

        int match = sURIMatcher.match(uri);
        switch (match)
        {
            case ALARMS:
            {
                qb.setTables(MyDB.TABLET);
                break;
            }
            case ALARMS_ID:
            {
                qb.setTables(MyDB.TABLET);
                qb.appendWhere(MyDB.BEAN_ID + "=");
                qb.appendWhere(uri.getPathSegments().get(1));
                break;
            }
            default:
                throw new IllegalArgumentException("Unknown URI: " + uri);
        }
        Cursor ret = qb.query(db, projection, selection, selectionArgs, null, null, sortOrder);

        if (ret != null)
        {
            ret.setNotificationUri(getContext().getContentResolver(), uri);
            Log.d("zyj", "created cursor " + ret + " on behalf of ");
        }
        else
        {
            Log.d("zyj", "query failed in downloads database");
        }
        return ret;
    }

    private static class MyDB extends SQLiteOpenHelper
    {

        // 这里就是数据库了,数据库字段、名称、表名等...
        private static final String DATABASE = "test_database";
        public static final String TABLET = "test_table";
        public static String ID = "_id";
        public static String BEAN_ID = "_bean_id";
        public static String MESSAGE = "_message";
        public static String TASK_PROGRESS = "_progress";

        private SQLiteDatabase mDB = null;

        private final String msql = "CREATE TABLE IF NOT EXISTS " + TABLET + "( " + ID
                + " INTEGER PRIMARY KEY AUTOINCREMENT, " + BEAN_ID + " TEXT, " + MESSAGE + " TEXT, " + TASK_PROGRESS
                + " TEXT )";

        private MyDB(Context context)
        {
            super(context, DATABASE, null, 1);
        }

        @Override
        public void onCreate(SQLiteDatabase db)
        {
            mDB = db;
            mDB.execSQL(msql);
        }

        @Override
        public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion)
        {
            // 升级,自己可以去实现
        }
    }
}

MyBean.java一个实例对象

public class MyBean
{

    public int id = 0;

    public String message = null;

    public float progress = 0.0f;

    public MyBean(int id)
    {
        this.id = id;
    }

}

MainActivity.java主界面了

public class MainActivity extends Activity
{

    TextView mMessage = null;

    private ContentObserver mDatabaseListener = null;
    private Handler mHand = null;

    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mMessage = (TextView) findViewById(R.id.message);

        init();

        // 注册数据库的监听,对应的是特定的Uri
        getContentResolver().registerContentObserver(MyDataProvider.CONTENT_URI, true, mDatabaseListener);
    }

    @Override
    protected void onDestroy()
    {
        super.onDestroy();
        // 注销掉监听
        getContentResolver().unregisterContentObserver(mDatabaseListener);
    }

    private void init()
    {
        mHand = new Handler();
        // 数据库变动时的回调
        mDatabaseListener = new ContentObserver(mHand)
        {
            @Override
            public boolean deliverSelfNotifications()
            {
                System.out.println("deliverSelfNotifications ---------------- ");
                return super.deliverSelfNotifications();
            }

            @Override
            public void onChange(boolean selfChange, Uri uri)
            {
                System.out.println("onChange ---------------- " + uri.toString());
                super.onChange(selfChange, uri);
            }

            @Override
            public void onChange(boolean selfChange)
            {
                System.out.println("onChange ---------------- ...");
                super.onChange(selfChange);
            }
        };
    }

    private int count = 0;

    public void onViewClick(View view)
    {
        switch (view.getId())
        {
            case R.id.add:
                // 插入数据
                ContentValues calues = new ContentValues();
                calues.put("_bean_id", count++);
                calues.put("_message", "AAAAAAAAAAAAAAAAAAAAA");
                calues.put("_progress", 0.0f);
                getContentResolver().insert(MyDataProvider.CONTENT_URI, calues);
                break;
            case R.id.del:
                // 如果找不到指定的_bean_id=1、2、3的,则数据库不进行增减,但还是会调用回调方法
                getContentResolver().delete(Uri.parse(MyDataProvider.CONTENT_URI.toString() + "/1"), null, null);
                getContentResolver().delete(Uri.parse(MyDataProvider.CONTENT_URI.toString() + "/2"), null, null);
                getContentResolver().delete(Uri.parse(MyDataProvider.CONTENT_URI.toString() + "/3"), null, null);
                break;
            case R.id.modify:
                ContentValues values = new ContentValues();
                values.put("_message", "ZZZZZZZZZZZZZZZZZZZZZ");
                // 这两中方法一样,这样就可以更加明白Uri中在后面添加的/item了数字的意思了
                getContentResolver()
                        .update(Uri.parse(MyDataProvider.CONTENT_URI.toString() + "/5"), values, null, null);
                getContentResolver().update(MyDataProvider.CONTENT_URI, values, "_bean_id=?", new String[] { "6" });
                break;
            case R.id.query:
                showMessage(getContentResolver().query(MyDataProvider.CONTENT_URI, null, null, null, null));
                break;
        }
    }

    private void showMessage(Cursor c)
    {
        if (c == null)
        {
            return;
        }
        final StringBuffer sb = new StringBuffer();
        if (c.getCount() > 0)
        {
            while (c.moveToNext())
            {
                MyBean bean = new MyBean(c.getInt(c.getColumnIndex("_bean_id")));
                bean.message = c.getString(c.getColumnIndex("_message"));
                bean.progress = c.getFloat(c.getColumnIndex("_progress"));
                sb.append(bean.id + "\t\t\t:" + bean.message + "\t\t\t,progress = " + bean.progress + "\n");
            }
        }

        c.close();

        mHand.post(new Runnable()
        {
            public void run()
            {
                mMessage.setText(sb.toString());
            }
        });
    }
}

activity_main.xml    上面就是四个按钮,下面就是一个TextView显示控件

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:padding="10.0dip" >

    <LinearLayout
        android:layout_width="fill_parent"
        android:layout_height="0dip"
        android:layout_weight="1"
        android:orientation="vertical" >

        <Button
            android:id="@+id/add"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:onClick="onViewClick"
            android:text="Add" />

        <Button
            android:id="@+id/del"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:onClick="onViewClick"
            android:text="Delete" />

        <Button
            android:id="@+id/modify"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:onClick="onViewClick"
            android:text="Modify" />

        <Button
            android:id="@+id/query"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:onClick="onViewClick"
            android:text="Query" />
    </LinearLayout>

    <ScrollView
        android:layout_width="fill_parent"
        android:layout_height="0dip"
        android:layout_weight="1"
        android:maxHeight="20dip" >

        <TextView
            android:id="@+id/message"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:textSize="20sp" />
    </ScrollView>

</LinearLayout>

最后就是AndroidManifest.xml了,和平时一样的,只不过在里面将你自己定义的ContentProvider写上,类似我的这样:

<provider

android:name="com.example.databasetest.MyDataProvider"

android:authorities="com.zyj:497393102" />

上面的authorities属性是一定要写的,它就是上面MyDataProvider.java里面的CONTENT_URI的HOST + ":" + PORT,可以看下面画的,就比较清楚了。

content://com.example.project:200/folder/subfolder/etc

\---------/  \---------------------------/ \---/ \--------------------------/

scheme                 host               port        path

\--------------------------------/

authority

然后就没有了,可以自己运行,感受一下Uri和数据库的监听。

有错误之处希望能够之出来,谢谢!!!

时间: 2024-10-05 05:46:40

关于Android中使用Uri监听数据库的变化的相关文章

Android中检查、监听电量和充电状态的方法

Android中检查.监听电量和充电状态的方法 这篇文章主要介绍了Android中检查.监听电量和充电状态的方法,如判断当前充电状态.监听充电状态的改变.判断当前剩余电量等,需要的朋友可以参考下 当你在更改后台更新频率来减少这些更新对电池寿命的影响时,检查当前电量和充电状态是一个好的开始. 电池寿命通过剩余电量和充电状态来影响应用更新的执行.当用交流电充电时,执行更新操作对设备的影响是微不足道的,所以在大多数案例里,你可以把更新频率调到最快.如果设备不在充电,降低更新频率可以帮助延长电池寿命.

【Android进阶学习】监听EditText的变化

之前博客上的有关EditText的文章,只是介绍EditText的一些最基本的用法,这次来深入学习一下EditText. 监听EditText的变化 使用EditText的addTextChangedListener(TextWatcher watcher)方法对EditText实现监听,TextWatcher是一个接口类,所以必须实现TextWatcher里的抽象方法: 当EditText里面的内容有变化的时候,触发TextChangedListener事件,就会调用TextWatcher里面

06课Android中的Button监听---【呼啸Android开发视频教程】

今天是第六课,主要讲了android中的为点击组件添加点击响应事件的几种常用方式. 播放地址: 点击打开链接 关于呼啸Android视频: 这套视频的最大特点是实用,哪些该讲,哪些不该讲,我都做了细致的考虑.没有虚头八脑,卖弄学问,也没用冗长的东西.一切都力求简单明了,清晰透彻.

android控件edittext-addTextChangedListener监听文本的变化

前言:edittext的addTextChangedListener监听事件用于监听edittext的输入文本的变化,他都用于密码框,或者那种检测用户输入过程中的变化. 1.使用方式   ①为edittext添加监听器 1 mEtPassword = (EditText) findViewById(R.id.id_et_password); 2 //添加监听器 3 mEtPassword.addTextChangedListener(new MyWatcher()); ②创建一个实现TextWa

Android使用ContentObserver监听数据库变化(转自:http://www.blogjava.net/zhaojianhua/archive/2011/10/27/362204.html)

android 使用contentobserver监听数据库内容变化 android 使用contentobserver监听数据库内容变化 在 android中经常会用到改变数据库内容后再去使用数据库更新的内容,很多人会重新去query一遍,但是这样的问题就是程序会特别占内存,而且有可能 会搂关cursor而导致程序内存未释放等等.其实android内部提供了一种ContentObserver的东西来监听数据库内容的变化.ContentObserver 的构造函数需要一个参数Hanlder,因为

Android简易实战教程--第二十一话《内容观察者监听数据库变化》

当数据库的数据发生改变,我们又想知道具体改变的情况时,就需要对数据库的变化情况做一个监控.这个任务,就由内容观察者来完成.下面这个案例,为短信数据库注册内容观察者,来监控短信的变化情况,当短信数据库发生改变的时候,去做相应的业务处理即可(这里只是打印log) 布局文件选择默认,因为用不到任何界面. 看一下主活动中的代码: package com.itydl.contentobserver; import android.net.Uri; import android.os.Bundle; imp

Android截屏事件监听

转载注明出处:http://blog.csdn.net/xiaohanluo/article/details/53737655 1. 前言 Android系统没有直接对截屏事件监听的接口,也没有广播,只能自己动手来丰衣足食,一般有三种方法. 利用FileObserver监听某个目录中资源变化情况 利用ContentObserver监听全部资源的变化 监听截屏快捷按键 由于厂商自定义Android系统的多样性,再加上快捷键的不同以及第三方应用,监听截屏快捷键这事基本不靠谱,可以直接忽略. 本文使用

Android中内容提供者ContentProvider实现数据库增删改查

1.我们首先new一个我们自己的类集成ContentProvider,并实现方法如下 package com.wzw.sqllitedemo.providers; import com.wzw.sqllitedemo.db.PersonSQLiteOpenHelper; import android.content.ContentProvider; import android.content.ContentUris; import android.content.ContentValues;

Android对ScrollView滚动监听,实现美团、大众点评的购买悬浮效果

我之前写了一篇关于美团网,大众点评的购买框效果的文章Android对ScrollView滚动监听,实现美团.大众点评的购买悬浮效果,我自己感觉效果并不是很好,如果快速滑动界面,显示悬浮框的时候会出现一卡的现象,有些朋友说有时候会出现两个布局的情况,特别是对ScrollView滚动的Y值得监听,我还使用了Handler来获取,还有朋友给我介绍了Scrolling Tricks这个东西,我下载试了下,确实美团网,大众点评的购买框用的是这种效果,但是Scrolling Tricks只能在API11以上