ContentObserver -- 内容观察者, 目的是观察(捕捉)特定Uri 引起的数据库的变化,继而做一些相应的处理。
它类似于数据库技术中的触发器(Trigger),当ContentObserver所观察的Uri发生变化时,便会触发它。触发器分为表触发器、行触发器,相应地ContentObserver也分为“表“ContentObserver、“行”ContentObserver,当然这是与它所监听的Uri MIME Type有关的。
一、使用ContentObserver来观察蓝牙打开和关闭状态的步骤
1. 创建一个子类,继承ContentObserver;
2. 在此子类中重写 onChange() 方法;
3. 根据Uri 来注册内容观察者。
具体步骤如下所示:
1. 创建一个子类,继承ContentObserver。
/**
* 用于观察 sysem 中的 手电筒是否打开或者关闭
* Created by czj on 2016/12/2.
*/
public class BluetoothObserver extends ContentObserver {
private Context mContext;
private Handler mHandler;
private static final int MSG_BLUETOOTH_ON = 3;
/**
* Creates a content observer.
*
* @param handler The handler to run {@link #onChange} on, or null if none.
*/
public BluetoothObserver(Context context, Handler handler) {
super(handler);
mContext = context;
mHandler = handler;
Log.e("TAG", "FlashlightObserver: " );
}
@Override
public void onChange(boolean selfChange) {
Log.e("TAG", "FlashlightObserver onChange" );
try {
int bluetoothOn = Settings.System.getInt(mContext.getContentResolver(), Settings.Global.BLUETOOTH_ON);
mHandler.obtainMessage(MSG_BLUETOOTH_ON,bluetoothOn).sendToTarget();
} catch (Settings.SettingNotFoundException e) {
e.printStackTrace();
}
}
}
3. 根据Uri 来注册内容观察者。
public class MainActivity extends AppCompatActivity {
private static final String TAG = "MainActivity";
private TextView tvAirplane;
//Message 类型值
private static final int MSG_FLASHLIGHT_ON = 3;
private BluetoothObserver bluetoothObserver;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tvAirplane = (TextView) findViewById(R.id.tvAirplane);
bluetoothObserver = new BluetoothObserver(this, mHandler);
//注册内容观察者
registerContentObservers();
}
private void registerContentObservers() {
Uri flashlightUri = Settings.System.getUriFor(Settings.System.BLUETOOTH_ON);
getContentResolver().registerContentObserver(flashlightUri, false, bluetoothObserver);
}
private Handler mHandler = new Handler(){
@Override
public void handleMessage(Message msg) {
Log.e("TAG", "handleMessage" + msg.what);
switch (msg.what){
case MSG_FLASHLIGHT_ON:
int isFlashlightOpen = (int) msg.obj;
if (isFlashlightOpen == 0){
tvAirplane.setText("蓝牙关闭");
}else{
tvAirplane.setText("蓝牙打开");
}
break;
}
}
};
}
xml 文件
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
app:layout_behavior="@string/appbar_scrolling_view_behavior"
tools:context="com.example.zhengjunchen.observerdemo.MainActivity"
tools:showIn="@layout/activity_main">
<TextView
android:id="@+id/tvAirplane"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!"/>
<EditText
android:id="@+id/smsoutboxContent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</LinearLayout>
注册/取消注册ContentObserver方法,抽象类ContentResolver类中的方法原型如下:
public final void registerContentObserver(Uri uri, boolean notifyForDescendents, ContentObserver observer)
功能:为指定的Uri注册一个ContentObserver派生类实例,当给定的Uri发生改变时,回调该实例对象去处理。
参数:uri 需要观察的Uri(需要在UriMatcher里注册,否则该Uri也没有意义了)
notifyForDescendents 为false 表示精确匹配,即只匹配该Uri
为true 表示可以同时匹配其派生的Uri,举例如下:
假设UriMatcher 里注册的Uri共有一下类型:
1 、content://com.qin.cb/student (学生)
2 、content://com.qin.cb/student/#
3、 content://com.qin.cb/student/schoolchild(小学生,派生的Uri)
假设我们当前需要观察的Uri为content://com.qin.cb/student,如果发生数据变化的 Uri 为
content://com.qin.cb/student/schoolchild ,当notifyForDescendents为 false,那么该ContentObserver会监听不到,
但是当notifyForDescendents 为ture,能捕捉该Uri的数据库变化。
observer ContentObserver的派生类实例
public final void unregisterContentObserver(ContentObserver observer)
功能:取消对给定Uri的观察
参数: observer ContentObserver的派生类实例
ContentObserver类介绍
构造方法 public void ContentObserver(Handler handler)
说明:所有 ContentObserver的派生类都需要调用该构造方法
参数: handler Handler对象。可以是主线程Handler(这时候可以更新UI 了),也可以是任何Handler对象。
常用方法
void onChange(boolean selfChange)
功能:当观察到的Uri发生变化时,回调该方法去处理。所有ContentObserver的派生类都需要重载该方法去处理逻辑。
参数:selfChange 回调后,其值一般为false,该参数意义不大(我也不懂,理解方法最重要)。
另外两个方法,用处不大,我也不懂,大家参照SDK自行理解,冒昧了。
boolean deliverSelfNotifications()
说明:Returns true if this observer is interested in notifications for changes made through the cursor the observer is registered with.
final void dispatchChange(boolean selfChange)
观察特定Uri的步骤如下:
1、 创建我们特定的ContentObserver派生类,必须重载父类构造方法,必须重载onChange()方法去处理回调后的功能实现
2、 利用context.getContentResolover()获得ContentResolove对象,接着调用registerContentObserver()方法去注册内容观察者
3、 由于ContentObserver的生命周期不同步于Activity和Service等,因此,在不需要时,需要手动的调用
unregisterContentObserver()去取消注册。