From 605ecdfd56af2b45edc200aedc49629168231cc4 Mon Sep 17 00:00:00 2001 From: Mitchell Tilbrook Date: Thu, 28 Jan 2016 08:22:00 +1100 Subject: [PATCH 001/122] fix: added ButterKnife unbind s, and cleaned up if not null unsubscribe --- .../rxjava/fragments/BufferDemoFragment.java | 5 +++++ ...ConcurrencyWithSchedulersDemoFragment.java | 6 +++--- .../DebounceSearchEmitterFragment.java | 6 +++--- .../DoubleBindingTextViewFragment.java | 6 +++--- .../fragments/ExponentialBackoffFragment.java | 6 ++++++ .../FormValidationCombineLatestFragment.java | 11 +++++++--- .../rxjava/fragments/MainFragment.java | 6 ++++++ .../fragments/PseudoCacheConcatFragment.java | 11 +++++++--- .../fragments/PseudoCacheMergeFragment.java | 20 +++++++++++++------ .../RetrofitAsyncTaskDeathFragment.java | 6 ++++++ .../rxjava/fragments/RetrofitFragment.java | 7 ++++++- .../fragments/RotationPersist1Fragment.java | 6 ++++++ .../rxjava/fragments/TimingDemoFragment.java | 6 ++++++ .../rxjava/volley/VolleyDemoFragment.java | 6 ++++++ 14 files changed, 86 insertions(+), 22 deletions(-) diff --git a/app/src/main/java/com/morihacky/android/rxjava/fragments/BufferDemoFragment.java b/app/src/main/java/com/morihacky/android/rxjava/fragments/BufferDemoFragment.java index 04df144d..f6e10a24 100644 --- a/app/src/main/java/com/morihacky/android/rxjava/fragments/BufferDemoFragment.java +++ b/app/src/main/java/com/morihacky/android/rxjava/fragments/BufferDemoFragment.java @@ -79,6 +79,11 @@ public View onCreateView(LayoutInflater inflater, return layout; } + @Override public void onDestroyView() { + super.onDestroyView(); + ButterKnife.unbind(this); + } + // ----------------------------------------------------------------------------------- // Main Rx entities diff --git a/app/src/main/java/com/morihacky/android/rxjava/fragments/ConcurrencyWithSchedulersDemoFragment.java b/app/src/main/java/com/morihacky/android/rxjava/fragments/ConcurrencyWithSchedulersDemoFragment.java index 9d630603..e97e0b62 100644 --- a/app/src/main/java/com/morihacky/android/rxjava/fragments/ConcurrencyWithSchedulersDemoFragment.java +++ b/app/src/main/java/com/morihacky/android/rxjava/fragments/ConcurrencyWithSchedulersDemoFragment.java @@ -13,6 +13,7 @@ import android.widget.ProgressBar; import com.morihacky.android.rxjava.R; +import com.morihacky.android.rxjava.RxUtils; import java.util.ArrayList; import java.util.List; @@ -41,9 +42,8 @@ public class ConcurrencyWithSchedulersDemoFragment @Override public void onDestroy() { super.onDestroy(); - if (_subscription != null) { - _subscription.unsubscribe(); - } + RxUtils.unsubscribeIfNotNull(_subscription); + ButterKnife.unbind(this); } @Override diff --git a/app/src/main/java/com/morihacky/android/rxjava/fragments/DebounceSearchEmitterFragment.java b/app/src/main/java/com/morihacky/android/rxjava/fragments/DebounceSearchEmitterFragment.java index 4967364f..86ebe05e 100644 --- a/app/src/main/java/com/morihacky/android/rxjava/fragments/DebounceSearchEmitterFragment.java +++ b/app/src/main/java/com/morihacky/android/rxjava/fragments/DebounceSearchEmitterFragment.java @@ -15,6 +15,7 @@ import com.jakewharton.rxbinding.widget.RxTextView; import com.jakewharton.rxbinding.widget.TextViewTextChangeEvent; import com.morihacky.android.rxjava.R; +import com.morihacky.android.rxjava.RxUtils; import java.util.ArrayList; import java.util.List; @@ -44,9 +45,8 @@ public class DebounceSearchEmitterFragment @Override public void onDestroy() { super.onDestroy(); - if (_subscription != null) { - _subscription.unsubscribe(); - } + RxUtils.unsubscribeIfNotNull(_subscription); + ButterKnife.unbind(this); } @Override diff --git a/app/src/main/java/com/morihacky/android/rxjava/fragments/DoubleBindingTextViewFragment.java b/app/src/main/java/com/morihacky/android/rxjava/fragments/DoubleBindingTextViewFragment.java index 25b491a4..e3891c4a 100644 --- a/app/src/main/java/com/morihacky/android/rxjava/fragments/DoubleBindingTextViewFragment.java +++ b/app/src/main/java/com/morihacky/android/rxjava/fragments/DoubleBindingTextViewFragment.java @@ -9,6 +9,7 @@ import android.widget.TextView; import com.morihacky.android.rxjava.R; +import com.morihacky.android.rxjava.RxUtils; import butterknife.Bind; import butterknife.ButterKnife; @@ -69,8 +70,7 @@ public void onNumberChanged() { @Override public void onDestroyView() { super.onDestroyView(); - if (_subscription != null) { - _subscription.unsubscribe(); - } + RxUtils.unsubscribeIfNotNull(_subscription); + ButterKnife.unbind(this); } } diff --git a/app/src/main/java/com/morihacky/android/rxjava/fragments/ExponentialBackoffFragment.java b/app/src/main/java/com/morihacky/android/rxjava/fragments/ExponentialBackoffFragment.java index a9e9a194..c6bf8397 100644 --- a/app/src/main/java/com/morihacky/android/rxjava/fragments/ExponentialBackoffFragment.java +++ b/app/src/main/java/com/morihacky/android/rxjava/fragments/ExponentialBackoffFragment.java @@ -66,6 +66,12 @@ public void onPause() { RxUtils.unsubscribeIfNotNull(_subscriptions); } + @Override + public void onDestroyView() { + super.onDestroyView(); + ButterKnife.unbind(this); + } + // ----------------------------------------------------------------------------------- @OnClick(R.id.btn_eb_retry) diff --git a/app/src/main/java/com/morihacky/android/rxjava/fragments/FormValidationCombineLatestFragment.java b/app/src/main/java/com/morihacky/android/rxjava/fragments/FormValidationCombineLatestFragment.java index 3a655888..b3301c4c 100644 --- a/app/src/main/java/com/morihacky/android/rxjava/fragments/FormValidationCombineLatestFragment.java +++ b/app/src/main/java/com/morihacky/android/rxjava/fragments/FormValidationCombineLatestFragment.java @@ -10,6 +10,7 @@ import com.jakewharton.rxbinding.widget.RxTextView; import com.morihacky.android.rxjava.R; +import com.morihacky.android.rxjava.RxUtils; import butterknife.Bind; import butterknife.ButterKnife; @@ -57,9 +58,13 @@ public View onCreateView(LayoutInflater inflater, @Override public void onPause() { super.onPause(); - if (_subscription != null) { - _subscription.unsubscribe(); - } + RxUtils.unsubscribeIfNotNull(_subscription); + } + + @Override + public void onDestroyView() { + super.onDestroyView(); + ButterKnife.unbind(this); } private void _combineLatestEvents() { diff --git a/app/src/main/java/com/morihacky/android/rxjava/fragments/MainFragment.java b/app/src/main/java/com/morihacky/android/rxjava/fragments/MainFragment.java index fbf68624..1313f604 100644 --- a/app/src/main/java/com/morihacky/android/rxjava/fragments/MainFragment.java +++ b/app/src/main/java/com/morihacky/android/rxjava/fragments/MainFragment.java @@ -27,6 +27,12 @@ public View onCreateView(LayoutInflater inflater, return layout; } + @Override + public void onDestroyView() { + super.onDestroyView(); + ButterKnife.unbind(this); + } + @OnClick(R.id.btn_demo_schedulers) void demoConcurrencyWithSchedulers() { clickedOn(new ConcurrencyWithSchedulersDemoFragment()); diff --git a/app/src/main/java/com/morihacky/android/rxjava/fragments/PseudoCacheConcatFragment.java b/app/src/main/java/com/morihacky/android/rxjava/fragments/PseudoCacheConcatFragment.java index 7e460a44..f4affcbc 100644 --- a/app/src/main/java/com/morihacky/android/rxjava/fragments/PseudoCacheConcatFragment.java +++ b/app/src/main/java/com/morihacky/android/rxjava/fragments/PseudoCacheConcatFragment.java @@ -9,6 +9,7 @@ import android.widget.ListView; import com.morihacky.android.rxjava.R; +import com.morihacky.android.rxjava.RxUtils; import com.morihacky.android.rxjava.retrofit.Contributor; import com.morihacky.android.rxjava.retrofit.GithubApi; import com.morihacky.android.rxjava.retrofit.GithubService; @@ -49,9 +50,13 @@ public View onCreateView(LayoutInflater inflater, @Override public void onPause() { super.onPause(); - if (_subscription != null) { - _subscription.unsubscribe(); - } + RxUtils.unsubscribeIfNotNull(_subscription); + } + + @Override + public void onDestroyView() { + super.onDestroyView(); + ButterKnife.unbind(this); } @OnClick(R.id.btn_start_pseudo_cache) diff --git a/app/src/main/java/com/morihacky/android/rxjava/fragments/PseudoCacheMergeFragment.java b/app/src/main/java/com/morihacky/android/rxjava/fragments/PseudoCacheMergeFragment.java index 777ff3ae..cd27c8ed 100644 --- a/app/src/main/java/com/morihacky/android/rxjava/fragments/PseudoCacheMergeFragment.java +++ b/app/src/main/java/com/morihacky/android/rxjava/fragments/PseudoCacheMergeFragment.java @@ -8,16 +8,20 @@ import android.view.ViewGroup; import android.widget.ArrayAdapter; import android.widget.ListView; -import butterknife.Bind; -import butterknife.ButterKnife; -import butterknife.OnClick; + import com.morihacky.android.rxjava.R; +import com.morihacky.android.rxjava.RxUtils; import com.morihacky.android.rxjava.retrofit.Contributor; import com.morihacky.android.rxjava.retrofit.GithubApi; import com.morihacky.android.rxjava.retrofit.GithubService; + import java.util.ArrayList; import java.util.HashMap; import java.util.List; + +import butterknife.Bind; +import butterknife.ButterKnife; +import butterknife.OnClick; import rx.Observable; import rx.Subscriber; import rx.Subscription; @@ -48,9 +52,13 @@ public View onCreateView(LayoutInflater inflater, @Override public void onPause() { super.onPause(); - if (_subscription != null) { - _subscription.unsubscribe(); - } + RxUtils.unsubscribeIfNotNull(_subscription); + } + + @Override + public void onDestroyView() { + super.onDestroyView(); + ButterKnife.unbind(this); } @OnClick(R.id.btn_start_pseudo_cache) diff --git a/app/src/main/java/com/morihacky/android/rxjava/fragments/RetrofitAsyncTaskDeathFragment.java b/app/src/main/java/com/morihacky/android/rxjava/fragments/RetrofitAsyncTaskDeathFragment.java index a8ff66a1..718d9601 100644 --- a/app/src/main/java/com/morihacky/android/rxjava/fragments/RetrofitAsyncTaskDeathFragment.java +++ b/app/src/main/java/com/morihacky/android/rxjava/fragments/RetrofitAsyncTaskDeathFragment.java @@ -64,6 +64,12 @@ public View onCreateView(LayoutInflater inflater, return layout; } + @Override + public void onDestroyView() { + super.onDestroyView(); + ButterKnife.unbind(this); + } + @OnClick(R.id.btn_demo_retrofit_async_death) public void onGetGithubUserClicked() { _adapter.clear(); diff --git a/app/src/main/java/com/morihacky/android/rxjava/fragments/RetrofitFragment.java b/app/src/main/java/com/morihacky/android/rxjava/fragments/RetrofitFragment.java index daf9a811..32ee5208 100644 --- a/app/src/main/java/com/morihacky/android/rxjava/fragments/RetrofitFragment.java +++ b/app/src/main/java/com/morihacky/android/rxjava/fragments/RetrofitFragment.java @@ -75,10 +75,15 @@ public void onResume() { @Override public void onPause() { super.onPause(); - RxUtils.unsubscribeIfNotNull(_subscriptions); } + @Override + public void onDestroyView() { + super.onDestroyView(); + ButterKnife.unbind(this); + } + @OnClick(R.id.btn_demo_retrofit_contributors) public void onListContributorsClicked() { _adapter.clear(); diff --git a/app/src/main/java/com/morihacky/android/rxjava/fragments/RotationPersist1Fragment.java b/app/src/main/java/com/morihacky/android/rxjava/fragments/RotationPersist1Fragment.java index 31344672..9a6afd77 100644 --- a/app/src/main/java/com/morihacky/android/rxjava/fragments/RotationPersist1Fragment.java +++ b/app/src/main/java/com/morihacky/android/rxjava/fragments/RotationPersist1Fragment.java @@ -119,6 +119,12 @@ public void onPause() { RxUtils.unsubscribeIfNotNull(_subscriptions); } + @Override + public void onDestroyView() { + super.onDestroyView(); + ButterKnife.unbind(this); + } + private void _setupLogger() { _logs = new ArrayList<>(); _adapter = new LogAdapter(getActivity(), new ArrayList()); diff --git a/app/src/main/java/com/morihacky/android/rxjava/fragments/TimingDemoFragment.java b/app/src/main/java/com/morihacky/android/rxjava/fragments/TimingDemoFragment.java index c59605c6..1a5767b8 100644 --- a/app/src/main/java/com/morihacky/android/rxjava/fragments/TimingDemoFragment.java +++ b/app/src/main/java/com/morihacky/android/rxjava/fragments/TimingDemoFragment.java @@ -54,6 +54,12 @@ public View onCreateView(LayoutInflater inflater, return layout; } + @Override + public void onDestroyView() { + super.onDestroyView(); + ButterKnife.unbind(this); + } + // ----------------------------------------------------------------------------------- @OnClick(R.id.btn_demo_timing_1) diff --git a/app/src/main/java/com/morihacky/android/rxjava/volley/VolleyDemoFragment.java b/app/src/main/java/com/morihacky/android/rxjava/volley/VolleyDemoFragment.java index 6d67d8d8..44a7c4da 100644 --- a/app/src/main/java/com/morihacky/android/rxjava/volley/VolleyDemoFragment.java +++ b/app/src/main/java/com/morihacky/android/rxjava/volley/VolleyDemoFragment.java @@ -65,6 +65,12 @@ public void onPause() { _compositeSubscription.unsubscribe(); } + @Override + public void onDestroyView() { + super.onDestroyView(); + ButterKnife.unbind(this); + } + public Observable newGetRouteData() { return Observable.defer(new Func0>() { @Override From b6ee8d903b8ff57fb025454766b021d56c70549f Mon Sep 17 00:00:00 2001 From: Mitchell Tilbrook Date: Thu, 28 Jan 2016 08:27:31 +1100 Subject: [PATCH 002/122] fix: replaced deprecated onAttach with correct override --- .../fragments/RotationPersist1WorkerFragment.java | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/com/morihacky/android/rxjava/fragments/RotationPersist1WorkerFragment.java b/app/src/main/java/com/morihacky/android/rxjava/fragments/RotationPersist1WorkerFragment.java index 58bdede1..4c727e1c 100644 --- a/app/src/main/java/com/morihacky/android/rxjava/fragments/RotationPersist1WorkerFragment.java +++ b/app/src/main/java/com/morihacky/android/rxjava/fragments/RotationPersist1WorkerFragment.java @@ -1,11 +1,14 @@ package com.morihacky.android.rxjava.fragments; -import android.app.Activity; +import android.content.Context; import android.os.Bundle; import android.support.v4.app.Fragment; + import com.morihacky.android.rxjava.MainActivity; + import java.util.List; import java.util.concurrent.TimeUnit; + import rx.Observable; import rx.Subscription; import rx.functions.Func1; @@ -24,10 +27,10 @@ public class RotationPersist1WorkerFragment * we can talk back to the master and send results */ @Override - public void onAttach(Activity activity) { - super.onAttach(activity); + public void onAttach(Context context) { + super.onAttach(context); - List frags = ((MainActivity) activity).getSupportFragmentManager().getFragments(); + List frags = ((MainActivity) context).getSupportFragmentManager().getFragments(); for (Fragment f : frags) { if (f instanceof IAmYourMaster) { _masterFrag = (IAmYourMaster) f; From 85979da659184f6ac7d48d4038699ac3c07fca27 Mon Sep 17 00:00:00 2001 From: Mitchell Tilbrook Date: Thu, 4 Feb 2016 10:22:02 +1100 Subject: [PATCH 003/122] update theme to be more material --- app/build.gradle | 3 ++- app/src/main/res/values/colors.xml | 4 ++++ app/src/main/res/values/styles.xml | 8 +++++--- 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 8db2ecbf..209d4a41 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -1,7 +1,8 @@ apply plugin: 'com.android.application' dependencies { - compile 'com.android.support:support-v13:23.0.1' + compile 'com.android.support:support-v13:23.1.1' + compile 'com.android.support:appcompat-v7:23.1.1' compile 'io.reactivex:rxandroid:1.0.1' // Because RxAndroid releases are few and far between, it is recommended you also diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml index c7cd3707..432d108f 100644 --- a/app/src/main/res/values/colors.xml +++ b/app/src/main/res/values/colors.xml @@ -1,5 +1,9 @@ + #3F51B5 + #303F9F + #FF4081 + #eb676b #488cef #3bc4a2 diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml index 0810d6e8..a11c0b30 100644 --- a/app/src/main/res/values/styles.xml +++ b/app/src/main/res/values/styles.xml @@ -1,9 +1,11 @@ - From b661f0f3e5efa58f5a6838a9183f5b7d8712a38d Mon Sep 17 00:00:00 2001 From: Mitchell Tilbrook Date: Mon, 25 Jan 2016 00:09:31 +1100 Subject: [PATCH 004/122] fix: finished polling demo --- .../rxjava/fragments/MainFragment.java | 5 + .../rxjava/fragments/PollingFragment.java | 105 +++++++++++++----- app/src/main/res/layout/fragment_main.xml | 5 +- 3 files changed, 86 insertions(+), 29 deletions(-) diff --git a/app/src/main/java/com/morihacky/android/rxjava/fragments/MainFragment.java b/app/src/main/java/com/morihacky/android/rxjava/fragments/MainFragment.java index 1313f604..b8df6c3e 100644 --- a/app/src/main/java/com/morihacky/android/rxjava/fragments/MainFragment.java +++ b/app/src/main/java/com/morihacky/android/rxjava/fragments/MainFragment.java @@ -53,6 +53,11 @@ void demoRetrofitCalls() { clickedOn(new RetrofitFragment()); } + @OnClick(R.id.btn_demo_polling) + void demoPolling() { + clickedOn(new PollingFragment()); + } + @OnClick(R.id.btn_demo_double_binding_textview) void demoDoubleBindingWithPublishSubject() { clickedOn(new DoubleBindingTextViewFragment()); diff --git a/app/src/main/java/com/morihacky/android/rxjava/fragments/PollingFragment.java b/app/src/main/java/com/morihacky/android/rxjava/fragments/PollingFragment.java index c0a44571..1a588d01 100644 --- a/app/src/main/java/com/morihacky/android/rxjava/fragments/PollingFragment.java +++ b/app/src/main/java/com/morihacky/android/rxjava/fragments/PollingFragment.java @@ -12,6 +12,7 @@ import android.widget.ListView; import com.morihacky.android.rxjava.R; +import com.morihacky.android.rxjava.RxUtils; import java.util.ArrayList; import java.util.List; @@ -21,7 +22,9 @@ import butterknife.ButterKnife; import butterknife.OnClick; import rx.Observable; +import rx.Scheduler; import rx.Subscriber; +import rx.Subscription; import rx.functions.Action0; import rx.functions.Action1; import rx.schedulers.Schedulers; @@ -39,17 +42,14 @@ public class PollingFragment private List _logs; private CompositeSubscription _subscriptions; private int _counter = 0; - - @Override - public void onDestroy() { - super.onDestroy(); - _subscriptions.unsubscribe(); - } + private Scheduler.Worker _worker; @Override public void onActivityCreated(@Nullable Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); _subscriptions = new CompositeSubscription(); + _worker = Schedulers.newThread() + .createWorker(); _setupLogger(); } @@ -62,31 +62,82 @@ public View onCreateView(LayoutInflater inflater, return layout; } + @Override + public void onDestroy() { + super.onDestroy(); + RxUtils.unsubscribeIfNotNull(_subscriptions); + ButterKnife.unbind(this); + } + @OnClick(R.id.btn_start_simple_polling) public void onStartSimplePollingClicked() { - _subscriptions.add(Observable.create(new Observable.OnSubscribe() { - @Override - public void call(final Subscriber observer) { - - Schedulers.newThread().createWorker() // - .schedulePeriodically(new Action0() { - @Override - public void call() { - observer.onNext(_doNetworkCallAndGetStringResult()); - } - }, INITIAL_DELAY, POLLING_INTERVAL, TimeUnit.MILLISECONDS); - } - }).take(10).subscribe(new Action1() { - @Override - public void call(String s) { - _log(String.format("String polling - %s", s)); - } - })); + _setupLogger(); + _log(String.format("Simple String polling - %s", _counter)); + _subscriptions.add(Observable.create( + new Observable.OnSubscribe() { + @Override + public void call(final Subscriber subscriber) { + Subscription subscription = _worker + .schedulePeriodically(new Action0() { + @Override + public void call() { + subscriber.onNext(_doNetworkCallAndGetStringResult()); + } + }, INITIAL_DELAY, POLLING_INTERVAL, TimeUnit.MILLISECONDS); + subscriber.add(subscription); + } + }) + .take(10) + .subscribe(new Action1() { + @Override + public void call(String s) { + _log(String.format("String polling - %s", s)); + } + }) + ); + } + + @OnClick(R.id.btn_start_increasingly_delayed_polling) + public void onStartIncreasinglyDelayedPolling() { + _setupLogger(); + _log(String.format("Increasingly delayed String polling - %s", _counter)); + continueIncreasinglyDelayedPolling(1000, 10); } + private void continueIncreasinglyDelayedPolling(final int delay, final int limit) { + _subscriptions = _unsubscribeAndGetNewCompositeSub(_subscriptions); + Observable.create( + new Observable.OnSubscribe() { + @Override + public void call(final Subscriber subscriber) { + + Subscription subscription = _worker.schedule(new Action0() { + @Override + public void call() { + subscriber.onNext(_doNetworkCallAndGetStringResult()); + } + }, delay, TimeUnit.MILLISECONDS); + subscriber.add(subscription); + } + }) + .take(limit) + .subscribe(new Action1() { + @Override + public void call(String s) { + continueIncreasinglyDelayedPolling(delay + 1000, limit - 1); + Timber.d("delay of %d", delay); + _log(String.format("String polling - %s", s)); + } + }); + } // ----------------------------------------------------------------------------------- // Method that help wiring up the example (irrelevant to RxJava) + private static CompositeSubscription _unsubscribeAndGetNewCompositeSub(CompositeSubscription subscription){ + RxUtils.unsubscribeIfNotNull(subscription); + return RxUtils.getNewCompositeSubIfUnsubscribed(subscription); + } + private String _doNetworkCallAndGetStringResult() { try { @@ -120,9 +171,11 @@ public void run() { } private void _setupLogger() { - _logs = new ArrayList(); + _logs = new ArrayList<>(); _adapter = new LogAdapter(getActivity(), new ArrayList()); _logsList.setAdapter(_adapter); + _subscriptions = _unsubscribeAndGetNewCompositeSub(_subscriptions); + _counter = 0; } private boolean _isCurrentlyOnMainThread() { @@ -130,7 +183,7 @@ private boolean _isCurrentlyOnMainThread() { } private class LogAdapter - extends ArrayAdapter { + extends ArrayAdapter { public LogAdapter(Context context, List logs) { super(context, R.layout.item_log, R.id.item_log, logs); diff --git a/app/src/main/res/layout/fragment_main.xml b/app/src/main/res/layout/fragment_main.xml index aba0cd1d..66fc53f4 100644 --- a/app/src/main/res/layout/fragment_main.xml +++ b/app/src/main/res/layout/fragment_main.xml @@ -52,12 +52,11 @@ android:text="@string/btn_demo_double_binding_textview" /> - + android:text="@string/btn_demo_polling" />