在android中经常会用到改变数据库内容后再去使用数据库更新的内容,很多人会重新去query一遍,但是这样的问题就是程序会特别占内存,而且有可能会搂关cursor而导致程序内存未释放等等。其实android内部提供了一种ContentObserver的东西来监听数据库内容的变化。
ContentObserver的构造函数需要一个参数Hanlder,因为ContentObserver内部使用了一个实现Runnable接口的内部类NotificationRunnable,来实现数据库内容的变化。需要使用hanlder去post消息。注册ContentObserver的方法是:getContentResolver().registerContentObserver(uri, notifyForDescendents, observer).
上面3个参数为:uri----Uri类型,是需要监听的数据库的uri.
notifyForDescendents---boolean true的话就会监听所有与此uri相关的uri。false的话则是直接特殊的uri才会监听。一般都设置为true.
observer-----ContentObserver 就是需要的contentobserver.
初始化一个ContentObserver对象,重载onChange(boolean ),在这个方法里去 *** 作数据库的使用,针对变化后的使用。
写了一个小demo,可以参考下。提示这种监听方式必须是contentprovider才能使用,因为contentprovider有uri.简单的那种sqlite数据库没有uri是使用不了的。
下面demo *** 作的是在一个activityA里点击button跳转至另外一个activityB,在B中点击button往数据库中加数据,加完后关闭B回到A。A的button的文字自动变化设置到数据库中的字符串。[code]
package ty.com.lto02
03 import android.app.Activity
04 import android.content.Intent
05 import android.database.ContentObserver
06 import android.os.Bundle
07 import android.os.Handler
08 import android.view.View
09 import android.widget.Button
10
11 public class ListenDataTest extends Activity{
12 private Button testBtn
13
14 @Override
15 protected void onCreate(Bundle savedInstanceState) {
16 super.onCreate(savedInstanceState)
17 setContentView(R.layout.listen_data_test)
18 getContentResolver().registerContentObserver(DataChangeProvider.CONTENT_URI,
19 true, cob)
20
21 testBtn = (Button)findViewById(R.id.test_btn)
22 testBtn.setOnClickListener(new View.OnClickListener() {
23
24 public void onClick(View v) {
25 Intent in = newIntent(ListenDataTest.this,DataChangeTest.class)
26 startActivity(in)
27
28 }
29 })
30
31 }
32
33 private ContentObserver cob = new ContentObserver(new Handler()) {
34
35 @Override
36 public boolean deliverSelfNotifications() {
37 return super.deliverSelfNotifications()
38 }
39
40 @Override
41 public void onChange(boolean selfChange) {
42 super.onChange(selfChange)
43 testBtn.setText(DataUtils.getChangeName(getApplicationContext()))
44 }
45
46 }
47
48 @Override
49 protected void onDestroy() {
50 super.onDestroy()
51 getContentResolver().unregisterContentObserver(cob)
52 }
53
54
55 }
[code]01 package ty.com.lto
02
03 import android.app.Activity
04 import android.content.ContentValues
05 import android.content.Intent
06 import android.database.ContentObservable
07 import android.database.ContentObserver
08 import android.os.Bundle
09 import android.os.Handler
10 import android.view.View
11 import android.widget.Button
12
13 public class DataChangeTest extends Activity{
14 private Button dataBtn
15 DataSqlite mDataSqlite
16 @Override
17 protected void onCreate(Bundle savedInstanceState) {
18 super.onCreate(savedInstanceState)
19 setContentView(R.layout.data_change_test)
20 dataBtn = (Button)findViewById(R.id.data_test_btn)
21 mDataSqlite = new DataSqlite(this)
22 dataBtn.setOnClickListener(new View.OnClickListener() {
23
24 public void onClick(View v) {
25 ContentValues con = new ContentValues()
26 con.put("name", "数据变化了")
27 getContentResolver().insert(DataChangeProvider.CONTENT_URI, con)
28 finish()
29 }
30 })
31 }
32 }
[code]view sourceprint?
001 package ty.com.lto
002
003
004 import android.content.ContentProvider
005 import android.content.ContentUris
006 import android.content.ContentValues
007 import android.content.Context
008 import android.content.UriMatcher
009 import android.database.Cursor
010 import android.database.SQLException
011 import android.database.sqlite.SQLiteDatabase
012 import android.database.sqlite.SQLiteOpenHelper
013 import android.database.sqlite.SQLiteQueryBuilder
014 import android.database.sqlite.SQLiteDatabase.CursorFactory
015 import android.net.Uri
016 import android.text.TextUtils
017
018 public class DataChangeProvider extends ContentProvider{
019 private SQLiteOpenHelper mOpenHelper
020 private static final int ALARMS = 1
021 private static final int ALARMS_ID = 2
022 private static final UriMatcher sURLMatcher = new UriMatcher(UriMatcher.NO_MATCH)
023 public static final Uri CONTENT_URI = Uri.parse("content://ty.com.lto/test")
024
025 static {
026 sURLMatcher.addURI("ty.com.lto", "test", ALARMS)
027 sURLMatcher.addURI("ty.com.lto", "test/#", ALARMS_ID)
028 }
029
030 private static class DatabaseHelper extends SQLiteOpenHelper{
031 private static final String TEST_DATABASE = "test.db"
032 private static final int VERSION = 1
033
034 public DatabaseHelper(Context context) {
035 super(context, TEST_DATABASE, null, VERSION)
036 // TODO Auto-generated constructor stub
037 }
038
039
040 @Override
041 public void onCreate(SQLiteDatabase db) {
042 String sql = "CREATE TABLE "+"test"+" (" +
043 "_id INTEGER PRIMARY KEY," +
044 "name TEXT "+
045 ")"
046 db.execSQL(sql)
047 }
048
049 @Override
050 public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
051 String sql = "DROP TABLE IF EXIST "+TEST_DATABASE
052 db.execSQL(sql)
053 onCreate(db)
054 }
055
056 }
057
058 public DataChangeProvider() {
059 }
060
061 @Override
062 public int delete(Uri url, String where, String[] whereArgs) {
063 SQLiteDatabase db = mOpenHelper.getWritableDatabase()
064 int count
065 long rowId = 0
066 switch (sURLMatcher.match(url)) {
067 case ALARMS:
068 count = db.delete("test", where, whereArgs)
069 break
070 case ALARMS_ID:
071 String segment = url.getPathSegments().get(1)
072
众所周知Android在4.4上增加了不少安全措施,除了把SELinux设置为enforce外,在短信方向也加强了限制。4.4之后,新增了一个default sms的机制,详细的描述,可以参考我的另一篇文章《谈谈4.4中的新增功能对安全类软件的影响》。简而言之,就是如果要在4.4之后实现短信拦截功能,就必须成为default sms,把所有短信相关的功能都包揽了,然后再做短信拦截。但这种做法,适配性和兼容性的工作是非常巨大的,短信、wapush(多种)、彩信、单双卡等等,相当于要求短信拦截类的软件要集成一个功能非常完善的通讯录类应用的功能。那么,是否有一种方法,可以在不成为default sms的同时也可以对短信进行“写 *** 作”(这可是让4.4一下子回到解放前啊。。。。)? 答案是有的。
XDA大牛有人发现了一种比较讨巧的方法,原文可以参考这里。
原理很简单,主要是利用4.2+后的添加的App Ops权限管理功能,在MESSAGE的TAB中找到自己的App,并进入相应的权限管理界面,如下图所示,FinalDemo是我自己测试的一个DEMO:
留意到Write SMS/MMS的开头,默认是OFF的,但我们可以把它打开。
打开之后,我们就可以通过监控短信数据库变化的方法实现短信拦截了,我也写了个简单的测试代码,测试成功,把代码和相关的配置也放了来吧
打开App Ops的代码
[java] view plaincopy
<span style="white-space:pre"> </span>Intent intent = new Intent(Intent.ACTION_MAIN)
ComponentName cn = new ComponentName("com.android.settings", "com.android.settings.Settings")
什么意思啊? 是 *** 作短信数据库吗?你可以使用 contentobserver类监控短信数据库,插入成功,短信数据库就会发生变化,就会触发这个监听,如果插入失败,这个监听就不会触发. 使用api *** 作数据库应该也会有返回值啊,判断返回值...欢迎分享,转载请注明来源:内存溢出
评论列表(0条)