Skip to content

Commit 86de059

Browse files
author
Jeff Brown
committed
Clean up content observer code.
Improved the documentation a little bit. Fixed a bug in ContentService wherein if a ContentObserver was passed as an argument and its deliverSelfNotifications() method returned true, then notifyChange would tell all observers that the change was a self-change even though it was only a self-change from the perspective of the provided observer. Deprecated ContentObservable.notifyChange since it is never used and in general it shouldn't be because we want the notification to be posted to the handler. Change-Id: Idde49eb40777e011a068f2adae8a32f779dfb923
1 parent bd4c9f1 commit 86de059

File tree

7 files changed

+127
-96
lines changed

7 files changed

+127
-96
lines changed

api/current.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6792,7 +6792,7 @@ package android.database {
67926792
public class ContentObservable extends android.database.Observable {
67936793
ctor public ContentObservable();
67946794
method public void dispatchChange(boolean);
6795-
method public void notifyChange(boolean);
6795+
method public deprecated void notifyChange(boolean);
67966796
method public void registerObserver(android.database.ContentObserver);
67976797
}
67986798

core/java/android/content/ContentResolver.java

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1034,8 +1034,11 @@ public final void unregisterContentObserver(ContentObserver observer) {
10341034
* To register, call {@link #registerContentObserver(android.net.Uri , boolean, android.database.ContentObserver) registerContentObserver()}.
10351035
* By default, CursorAdapter objects will get this notification.
10361036
*
1037-
* @param uri
1038-
* @param observer The observer that originated the change, may be <code>null</null>
1037+
* @param uri The uri of the content that was changed.
1038+
* @param observer The observer that originated the change, may be <code>null</null>.
1039+
* The observer that originated the change will only receive the notification if it
1040+
* has requested to receive self-change notifications by implementing
1041+
* {@link ContentObserver#deliverSelfNotifications()} to return true.
10391042
*/
10401043
public void notifyChange(Uri uri, ContentObserver observer) {
10411044
notifyChange(uri, observer, true /* sync to network */);
@@ -1046,8 +1049,11 @@ public void notifyChange(Uri uri, ContentObserver observer) {
10461049
* To register, call {@link #registerContentObserver(android.net.Uri , boolean, android.database.ContentObserver) registerContentObserver()}.
10471050
* By default, CursorAdapter objects will get this notification.
10481051
*
1049-
* @param uri
1050-
* @param observer The observer that originated the change, may be <code>null</null>
1052+
* @param uri The uri of the content that was changed.
1053+
* @param observer The observer that originated the change, may be <code>null</null>.
1054+
* The observer that originated the change will only receive the notification if it
1055+
* has requested to receive self-change notifications by implementing
1056+
* {@link ContentObserver#deliverSelfNotifications()} to return true.
10511057
* @param syncToNetwork If true, attempt to sync the change to the network.
10521058
*/
10531059
public void notifyChange(Uri uri, ContentObserver observer, boolean syncToNetwork) {

core/java/android/content/ContentService.java

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,7 @@ public void notifyChange(Uri uri, IContentObserver observer,
176176
for (int i=0; i<numCalls; i++) {
177177
ObserverCall oc = calls.get(i);
178178
try {
179-
oc.mObserver.onChange(oc.mSelfNotify);
179+
oc.mObserver.onChange(oc.mSelfChange);
180180
if (Log.isLoggable(TAG, Log.VERBOSE)) {
181181
Log.v(TAG, "Notified " + oc.mObserver + " of " + "update at " + uri);
182182
}
@@ -218,13 +218,12 @@ public void notifyChange(Uri uri, IContentObserver observer,
218218
public static final class ObserverCall {
219219
final ObserverNode mNode;
220220
final IContentObserver mObserver;
221-
final boolean mSelfNotify;
221+
final boolean mSelfChange;
222222

223-
ObserverCall(ObserverNode node, IContentObserver observer,
224-
boolean selfNotify) {
223+
ObserverCall(ObserverNode node, IContentObserver observer, boolean selfChange) {
225224
mNode = node;
226225
mObserver = observer;
227-
mSelfNotify = selfNotify;
226+
mSelfChange = selfChange;
228227
}
229228
}
230229

@@ -668,44 +667,46 @@ public boolean removeObserverLocked(IContentObserver observer) {
668667
}
669668

670669
private void collectMyObserversLocked(boolean leaf, IContentObserver observer,
671-
boolean selfNotify, ArrayList<ObserverCall> calls) {
670+
boolean observerWantsSelfNotifications, ArrayList<ObserverCall> calls) {
672671
int N = mObservers.size();
673672
IBinder observerBinder = observer == null ? null : observer.asBinder();
674673
for (int i = 0; i < N; i++) {
675674
ObserverEntry entry = mObservers.get(i);
676675

677676
// Don't notify the observer if it sent the notification and isn't interesed
678677
// in self notifications
679-
if (entry.observer.asBinder() == observerBinder && !selfNotify) {
678+
boolean selfChange = (entry.observer.asBinder() == observerBinder);
679+
if (selfChange && !observerWantsSelfNotifications) {
680680
continue;
681681
}
682682

683683
// Make sure the observer is interested in the notification
684684
if (leaf || (!leaf && entry.notifyForDescendents)) {
685-
calls.add(new ObserverCall(this, entry.observer, selfNotify));
685+
calls.add(new ObserverCall(this, entry.observer, selfChange));
686686
}
687687
}
688688
}
689689

690690
public void collectObserversLocked(Uri uri, int index, IContentObserver observer,
691-
boolean selfNotify, ArrayList<ObserverCall> calls) {
691+
boolean observerWantsSelfNotifications, ArrayList<ObserverCall> calls) {
692692
String segment = null;
693693
int segmentCount = countUriSegments(uri);
694694
if (index >= segmentCount) {
695695
// This is the leaf node, notify all observers
696-
collectMyObserversLocked(true, observer, selfNotify, calls);
696+
collectMyObserversLocked(true, observer, observerWantsSelfNotifications, calls);
697697
} else if (index < segmentCount){
698698
segment = getUriSegment(uri, index);
699699
// Notify any observers at this level who are interested in descendents
700-
collectMyObserversLocked(false, observer, selfNotify, calls);
700+
collectMyObserversLocked(false, observer, observerWantsSelfNotifications, calls);
701701
}
702702

703703
int N = mChildren.size();
704704
for (int i = 0; i < N; i++) {
705705
ObserverNode node = mChildren.get(i);
706706
if (segment == null || node.mName.equals(segment)) {
707707
// We found the child,
708-
node.collectObserversLocked(uri, index + 1, observer, selfNotify, calls);
708+
node.collectObserversLocked(uri, index + 1,
709+
observer, observerWantsSelfNotifications, calls);
709710
if (segment != null) {
710711
break;
711712
}

core/java/android/database/ContentObservable.java

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -17,20 +17,28 @@
1717
package android.database;
1818

1919
/**
20-
* A specialization of Observable for ContentObserver that provides methods for
21-
* invoking the various callback methods of ContentObserver.
20+
* A specialization of {@link Observable} for {@link ContentObserver}
21+
* that provides methods for sending notifications to a list of
22+
* {@link ContentObserver} objects.
2223
*/
2324
public class ContentObservable extends Observable<ContentObserver> {
24-
25+
// Even though the generic method defined in Observable would be perfectly
26+
// fine on its own, we can't delete this overridden method because it would
27+
// potentially break binary compatibility with existing applications.
2528
@Override
2629
public void registerObserver(ContentObserver observer) {
2730
super.registerObserver(observer);
2831
}
2932

3033
/**
31-
* invokes dispatchUpdate on each observer, unless the observer doesn't want
32-
* self-notifications and the update is from a self-notification
33-
* @param selfChange
34+
* Invokes {@link ContentObserver#dispatchChange} on each observer.
35+
*
36+
* If <code>selfChange</code> is true, only delivers the notification
37+
* to the observer if it has indicated that it wants to receive self-change
38+
* notifications by implementing {@link ContentObserver#deliverSelfNotifications}
39+
* to return true.
40+
*
41+
* @param selfChange True if this is a self-change notification.
3442
*/
3543
public void dispatchChange(boolean selfChange) {
3644
synchronized(mObservers) {
@@ -43,9 +51,13 @@ public void dispatchChange(boolean selfChange) {
4351
}
4452

4553
/**
46-
* invokes onChange on each observer
47-
* @param selfChange
54+
* Invokes {@link ContentObserver#onChange} on each observer.
55+
*
56+
* @param selfChange True if this is a self-change notification.
57+
*
58+
* @deprecated Use {@link #dispatchChange} instead.
4859
*/
60+
@Deprecated
4961
public void notifyChange(boolean selfChange) {
5062
synchronized(mObservers) {
5163
for (ContentObserver observer : mObservers) {

core/java/android/database/ContentObserver.java

Lines changed: 65 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -19,62 +19,19 @@
1919
import android.os.Handler;
2020

2121
/**
22-
* Receives call backs for changes to content. Must be implemented by objects which are added
23-
* to a {@link ContentObservable}.
22+
* Receives call backs for changes to content.
23+
* Must be implemented by objects which are added to a {@link ContentObservable}.
2424
*/
2525
public abstract class ContentObserver {
26+
private final Object mLock = new Object();
27+
private Transport mTransport; // guarded by mLock
2628

27-
private Transport mTransport;
28-
29-
// Protects mTransport
30-
private Object lock = new Object();
31-
32-
/* package */ Handler mHandler;
33-
34-
private final class NotificationRunnable implements Runnable {
35-
36-
private boolean mSelf;
37-
38-
public NotificationRunnable(boolean self) {
39-
mSelf = self;
40-
}
41-
42-
public void run() {
43-
ContentObserver.this.onChange(mSelf);
44-
}
45-
}
46-
47-
private static final class Transport extends IContentObserver.Stub {
48-
ContentObserver mContentObserver;
49-
50-
public Transport(ContentObserver contentObserver) {
51-
mContentObserver = contentObserver;
52-
}
53-
54-
public boolean deliverSelfNotifications() {
55-
ContentObserver contentObserver = mContentObserver;
56-
if (contentObserver != null) {
57-
return contentObserver.deliverSelfNotifications();
58-
}
59-
return false;
60-
}
61-
62-
public void onChange(boolean selfChange) {
63-
ContentObserver contentObserver = mContentObserver;
64-
if (contentObserver != null) {
65-
contentObserver.dispatchChange(selfChange);
66-
}
67-
}
68-
69-
public void releaseContentObserver() {
70-
mContentObserver = null;
71-
}
72-
}
29+
Handler mHandler;
7330

7431
/**
75-
* onChange() will happen on the provider Handler.
32+
* Creates a content observer.
7633
*
77-
* @param handler The handler to run {@link #onChange} on.
34+
* @param handler The handler to run {@link #onChange} on, or null if none.
7835
*/
7936
public ContentObserver(Handler handler) {
8037
mHandler = handler;
@@ -86,7 +43,7 @@ public ContentObserver(Handler handler) {
8643
* {@hide}
8744
*/
8845
public IContentObserver getContentObserver() {
89-
synchronized(lock) {
46+
synchronized (mLock) {
9047
if (mTransport == null) {
9148
mTransport = new Transport(this);
9249
}
@@ -101,8 +58,8 @@ public IContentObserver getContentObserver() {
10158
* {@hide}
10259
*/
10360
public IContentObserver releaseContentObserver() {
104-
synchronized(lock) {
105-
Transport oldTransport = mTransport;
61+
synchronized (mLock) {
62+
final Transport oldTransport = mTransport;
10663
if (oldTransport != null) {
10764
oldTransport.releaseContentObserver();
10865
mTransport = null;
@@ -112,27 +69,74 @@ public IContentObserver releaseContentObserver() {
11269
}
11370

11471
/**
115-
* Returns true if this observer is interested in notifications for changes
116-
* made through the cursor the observer is registered with.
72+
* Returns true if this observer is interested receiving self-change notifications.
73+
*
74+
* Subclasses should override this method to indicate whether the observer
75+
* is interested in receiving notifications for changes that it made to the
76+
* content itself.
77+
*
78+
* @return True if self-change notifications should be delivered to the observer.
11779
*/
11880
public boolean deliverSelfNotifications() {
11981
return false;
12082
}
12183

12284
/**
123-
* This method is called when a change occurs to the cursor that
124-
* is being observed.
125-
*
126-
* @param selfChange true if the update was caused by a call to <code>commit</code> on the
127-
* cursor that is being observed.
85+
* This method is called when a content change occurs.
86+
*
87+
* @param selfChange True if this is a self-change notification.
12888
*/
129-
public void onChange(boolean selfChange) {}
89+
public void onChange(boolean selfChange) {
90+
// Do nothing. Subclass should override.
91+
}
13092

93+
/**
94+
* Dispatches a change notification to the observer.
95+
*
96+
* If a {@link Handler} was supplied to the {@link ContentObserver} constructor,
97+
* then a call to the {@link #onChange} method is posted to the handler's message queue.
98+
* Otherwise, the {@link #onChange} method is invoked immediately on this thread.
99+
*
100+
* @param selfChange True if this is a self-change notification.
101+
*/
131102
public final void dispatchChange(boolean selfChange) {
132103
if (mHandler == null) {
133104
onChange(selfChange);
134105
} else {
135106
mHandler.post(new NotificationRunnable(selfChange));
136107
}
137108
}
109+
110+
private final class NotificationRunnable implements Runnable {
111+
private final boolean mSelf;
112+
113+
public NotificationRunnable(boolean self) {
114+
mSelf = self;
115+
}
116+
117+
@Override
118+
public void run() {
119+
ContentObserver.this.onChange(mSelf);
120+
}
121+
}
122+
123+
private static final class Transport extends IContentObserver.Stub {
124+
private ContentObserver mContentObserver;
125+
126+
public Transport(ContentObserver contentObserver) {
127+
mContentObserver = contentObserver;
128+
}
129+
130+
@Override
131+
public void onChange(boolean selfChange) {
132+
ContentObserver contentObserver = mContentObserver;
133+
if (contentObserver != null) {
134+
contentObserver.dispatchChange(selfChange);
135+
}
136+
}
137+
138+
public void releaseContentObserver() {
139+
mContentObserver = null;
140+
}
141+
}
138142
}

core/java/android/database/DataSetObservable.java

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,15 @@
1717
package android.database;
1818

1919
/**
20-
* A specialization of Observable for DataSetObserver that provides methods for
21-
* invoking the various callback methods of DataSetObserver.
20+
* A specialization of {@link Observable} for {@link DataSetObserver}
21+
* that provides methods for sending notifications to a list of
22+
* {@link DataSetObserver} objects.
2223
*/
2324
public class DataSetObservable extends Observable<DataSetObserver> {
2425
/**
25-
* Invokes onChanged on each observer. Called when the data set being observed has
26-
* changed, and which when read contains the new state of the data.
26+
* Invokes {@link DataSetObserver#onChanged} on each observer.
27+
* Called when the contents of the data set have changed. The recipient
28+
* will obtain the new contents the next time it queries the data set.
2729
*/
2830
public void notifyChanged() {
2931
synchronized(mObservers) {
@@ -38,8 +40,9 @@ public void notifyChanged() {
3840
}
3941

4042
/**
41-
* Invokes onInvalidated on each observer. Called when the data set being monitored
42-
* has changed such that it is no longer valid.
43+
* Invokes {@link DataSetObserver#onInvalidated} on each observer.
44+
* Called when the data set is no longer valid and cannot be queried again,
45+
* such as when the data set has been closed.
4346
*/
4447
public void notifyInvalidated() {
4548
synchronized (mObservers) {

0 commit comments

Comments
 (0)