From c11e0c2ad8482437b4360b966e75c3223709a573 Mon Sep 17 00:00:00 2001 From: Yaroslav Heriatovych Date: Fri, 10 Oct 2014 18:02:06 +0300 Subject: [PATCH 1/2] Add fromSharedPreferencesChanges Observable this useful to listen for SharedPreferences changes --- .../observables/AndroidObservable.java | 11 ++++ .../OperatorSharedPreferenceChange.java | 51 +++++++++++++++ .../OperatorSharedPreferencesChangeTest.java | 64 +++++++++++++++++++ 3 files changed, 126 insertions(+) create mode 100644 src/main/java/rx/operators/OperatorSharedPreferenceChange.java create mode 100644 src/test/java/rx/android/operators/OperatorSharedPreferencesChangeTest.java diff --git a/src/main/java/rx/android/observables/AndroidObservable.java b/src/main/java/rx/android/observables/AndroidObservable.java index 7ad293de..900f6367 100644 --- a/src/main/java/rx/android/observables/AndroidObservable.java +++ b/src/main/java/rx/android/observables/AndroidObservable.java @@ -17,6 +17,7 @@ import static rx.android.schedulers.AndroidSchedulers.mainThread; +import android.content.SharedPreferences; import rx.Observable; import rx.functions.Func1; import rx.operators.OperatorBroadcastRegister; @@ -30,6 +31,7 @@ import android.content.IntentFilter; import android.os.Build; import android.os.Handler; +import rx.operators.OperatorSharedPreferenceChange; public final class AndroidObservable { @@ -150,4 +152,13 @@ public static Observable fromBroadcast(Context context, IntentFilter fil public static Observable fromLocalBroadcast(Context context, IntentFilter filter){ return Observable.create(new OperatorLocalBroadcastRegister(context, filter)); } + + /** + * Create Observable that emits String keys whenever it changes in provided SharedPreferences + * + * Items will be observed on the main Android UI thread + */ + public static Observable fromSharedPreferencesChanges(SharedPreferences sharedPreferences){ + return Observable.create(new OperatorSharedPreferenceChange(sharedPreferences)); + } } diff --git a/src/main/java/rx/operators/OperatorSharedPreferenceChange.java b/src/main/java/rx/operators/OperatorSharedPreferenceChange.java new file mode 100644 index 00000000..4bd91a62 --- /dev/null +++ b/src/main/java/rx/operators/OperatorSharedPreferenceChange.java @@ -0,0 +1,51 @@ +/** + * Copyright 2014 Netflix, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package rx.operators; + +import android.content.SharedPreferences; +import rx.Observable; +import rx.Subscriber; +import rx.functions.Action0; +import rx.subscriptions.Subscriptions; + +public class OperatorSharedPreferenceChange implements Observable.OnSubscribe{ + + private final SharedPreferences sharedPreferences; + + public OperatorSharedPreferenceChange(SharedPreferences sharedPreferences) { + this.sharedPreferences = sharedPreferences; + } + + @Override + public void call(final Subscriber subscriber) { + final SharedPreferences.OnSharedPreferenceChangeListener listener = new SharedPreferences.OnSharedPreferenceChangeListener() { + @Override + public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { + if(!subscriber.isUnsubscribed()) + subscriber.onNext(key); + } + }; + + subscriber.add(Subscriptions.create(new Action0() { + @Override + public void call() { + sharedPreferences.unregisterOnSharedPreferenceChangeListener(listener); + } + })); + + sharedPreferences.registerOnSharedPreferenceChangeListener(listener); + } +} diff --git a/src/test/java/rx/android/operators/OperatorSharedPreferencesChangeTest.java b/src/test/java/rx/android/operators/OperatorSharedPreferencesChangeTest.java new file mode 100644 index 00000000..78b53e7d --- /dev/null +++ b/src/test/java/rx/android/operators/OperatorSharedPreferencesChangeTest.java @@ -0,0 +1,64 @@ +/** + * Copyright 2014 Netflix, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package rx.android.operators; + +import android.app.Application; +import android.content.SharedPreferences; +import android.preference.PreferenceManager; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.InOrder; +import org.robolectric.Robolectric; +import org.robolectric.RobolectricTestRunner; +import rx.Observable; +import rx.Observer; +import rx.Subscription; +import rx.android.observables.AndroidObservable; +import rx.observers.TestObserver; + +import static org.mockito.Matchers.any; +import static org.mockito.Mockito.*; + +@RunWith(RobolectricTestRunner.class) +public class OperatorSharedPreferencesChangeTest { + + @Test + public void testSharedPreferences() { + Application application = Robolectric.application; + SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(application); + Observable observable = AndroidObservable.fromSharedPreferencesChanges(sharedPreferences); + final Observer observer = mock(Observer.class); + final Subscription subscription = observable.subscribe(new TestObserver(observer)); + + final InOrder inOrder = inOrder(observer); + + inOrder.verify(observer, never()).onNext(any(String.class)); + + sharedPreferences.edit().putBoolean("a", true).commit(); + inOrder.verify(observer, times(1)).onNext("a"); + + sharedPreferences.edit().putInt("b", 9).commit(); + inOrder.verify(observer, times(1)).onNext("b"); + + subscription.unsubscribe(); + + sharedPreferences.edit().putInt("c", 42).commit(); + inOrder.verify(observer, never()).onNext(any(String.class)); + inOrder.verify(observer, never()).onError(any(Throwable.class)); + inOrder.verify(observer, never()).onCompleted(); + } + +} From 6dde4b2b0f223f3bfd35cf1351211929c7aab177 Mon Sep 17 00:00:00 2001 From: Yaroslav Heriatovych Date: Mon, 13 Oct 2014 12:30:50 +0300 Subject: [PATCH 2/2] remove isUnsubscribed call befor item emittion --- src/main/java/rx/operators/OperatorSharedPreferenceChange.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/rx/operators/OperatorSharedPreferenceChange.java b/src/main/java/rx/operators/OperatorSharedPreferenceChange.java index 4bd91a62..e8c09429 100644 --- a/src/main/java/rx/operators/OperatorSharedPreferenceChange.java +++ b/src/main/java/rx/operators/OperatorSharedPreferenceChange.java @@ -34,7 +34,6 @@ public void call(final Subscriber subscriber) { final SharedPreferences.OnSharedPreferenceChangeListener listener = new SharedPreferences.OnSharedPreferenceChangeListener() { @Override public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { - if(!subscriber.isUnsubscribed()) subscriber.onNext(key); } };