Skip to content

Commit 2f883a7

Browse files
author
Kaushik Gopal
committed
merge: networking example with volley (courtesy: offbye)
2 parents ecbcd0e + f7c38d9 commit 2f883a7

File tree

9 files changed

+250
-3
lines changed

9 files changed

+250
-3
lines changed

README.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,11 @@ This is the debounce/throttleWithTimeout method in RxJava.
4141

4242
Since it was a presentation, Jake only put up the most important code snippets in [his slides](https://speakerdeck.com/jakewharton/2014-1). Also he uses Java 8 in them, so I flushed those examples out in ~~good~~ old Java 6. (Note: you're most likely to hit the GitHub API quota pretty fast so send in an OAuth-token as a parameter if you want to keep running these examples often).
4343

44+
### Volley Demo
45+
46+
[Volley](http://developer.android.com/training/volley/index.html) is another networking library introduced by [Google at IO '13](https://www.youtube.com/watch?v=yhv8l9F44qo). A kind citizen of github contributed this example so we know how to integrate Volley with RxJava.
47+
48+
4449
### Orchestrating Observables. Make parallel network calls, then combine the result into a single data point (flatmap + zip)
4550

4651
The below ascii diagram expresses the intention of our next example with panache. f1,f2,3,f4,f5 are essentially network calls that when made, give back a result that's needed for a future calculation.

app/build.gradle

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,15 @@ dependencies {
1717
compile 'com.squareup.retrofit2:converter-gson:2.0.0-beta3'
1818
compile 'com.squareup.okhttp3:okhttp:3.0.1'
1919
compile 'com.squareup.okhttp3:okhttp-urlconnection:3.0.1'
20+
compile 'com.mcxiaoke.volley:library:1.0.19'
2021

2122
debugCompile 'com.squareup.leakcanary:leakcanary-android:1.3'
2223
releaseCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.3'
2324
}
2425

2526
android {
2627
compileSdkVersion 23
27-
buildToolsVersion '23.0.1'
28+
buildToolsVersion '23.0.2'
2829

2930
defaultConfig {
3031
applicationId "com.morihacky.android.rxjava"

app/src/main/java/com/morihacky/android/rxjava/MyApp.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
package com.morihacky.android.rxjava;
22

33
import android.app.Application;
4+
5+
import com.morihacky.android.rxjava.volley.MyVolley;
46
import com.squareup.leakcanary.LeakCanary;
57
import com.squareup.leakcanary.RefWatcher;
68
import timber.log.Timber;
@@ -26,6 +28,9 @@ public void onCreate() {
2628
_instance = (MyApp) getApplicationContext();
2729
_refWatcher = LeakCanary.install(this);
2830

31+
// Initialize Volley
32+
MyVolley.init(this);
33+
2934
Timber.plant(new Timber.DebugTree());
3035
}
3136
}

app/src/main/java/com/morihacky/android/rxjava/fragments/MainFragment.java

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,14 @@
77
import android.view.LayoutInflater;
88
import android.view.View;
99
import android.view.ViewGroup;
10-
1110
import com.morihacky.android.rxjava.R;
1211
import com.morihacky.android.rxjava.rxbus.RxBusDemoFragment;
1312

1413
import butterknife.ButterKnife;
1514
import butterknife.OnClick;
1615

16+
import com.morihacky.android.rxjava.volley.VolleyDemoFragment;
17+
1718
public class MainFragment
1819
extends BaseFragment {
1920

@@ -82,6 +83,11 @@ void demoRotationPersist() {
8283
//clickedOn(new RotationPersist1Fragment());
8384
}
8485

86+
@OnClick(R.id.btn_demo_volley)
87+
void demoVolleyRequest() {
88+
clickedOn(new VolleyDemoFragment());
89+
}
90+
8591
private void clickedOn(@NonNull Fragment fragment) {
8692
final String tag = fragment.getClass().toString();
8793
getActivity().getSupportFragmentManager()
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
package com.morihacky.android.rxjava.volley;
2+
3+
import android.content.Context;
4+
import com.android.volley.RequestQueue;
5+
import com.android.volley.toolbox.Volley;
6+
7+
/**
8+
* Helper class that is used to provide references to initialized RequestQueue(s) and ImageLoader(s)
9+
*
10+
* @author Ognyan Bankov
11+
*/
12+
public class MyVolley {
13+
private static RequestQueue mRequestQueue;
14+
15+
private MyVolley() {
16+
// no instances
17+
}
18+
19+
public static void init(Context context) {
20+
mRequestQueue = Volley.newRequestQueue(context);
21+
}
22+
23+
public static RequestQueue getRequestQueue() {
24+
if (mRequestQueue != null) {
25+
return mRequestQueue;
26+
} else {
27+
throw new IllegalStateException("RequestQueue not initialized");
28+
}
29+
}
30+
}
Lines changed: 159 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,159 @@
1+
package com.morihacky.android.rxjava.volley;
2+
3+
import android.os.Bundle;
4+
import android.os.Handler;
5+
import android.os.Looper;
6+
import android.support.annotation.Nullable;
7+
import android.util.Log;
8+
import android.view.LayoutInflater;
9+
import android.view.View;
10+
import android.view.ViewGroup;
11+
import android.widget.ListView;
12+
import butterknife.Bind;
13+
import butterknife.ButterKnife;
14+
import butterknife.OnClick;
15+
import com.android.volley.Request;
16+
import com.android.volley.VolleyError;
17+
import com.android.volley.toolbox.JsonObjectRequest;
18+
import com.android.volley.toolbox.RequestFuture;
19+
import com.morihacky.android.rxjava.R;
20+
import com.morihacky.android.rxjava.fragments.BaseFragment;
21+
import com.morihacky.android.rxjava.wiring.LogAdapter;
22+
import java.nio.charset.Charset;
23+
import java.util.ArrayList;
24+
import java.util.List;
25+
import java.util.concurrent.ExecutionException;
26+
import org.json.JSONObject;
27+
import rx.Observable;
28+
import rx.Observer;
29+
import rx.android.schedulers.AndroidSchedulers;
30+
import rx.functions.Func0;
31+
import rx.schedulers.Schedulers;
32+
import rx.subscriptions.CompositeSubscription;
33+
import timber.log.Timber;
34+
35+
public class VolleyDemoFragment
36+
extends BaseFragment {
37+
38+
public static final String TAG = "VolleyDemoFragment";
39+
40+
@Bind(R.id.list_threading_log) ListView _logsList;
41+
42+
private List<String> _logs;
43+
private LogAdapter _adapter;
44+
45+
private CompositeSubscription _compositeSubscription = new CompositeSubscription();
46+
47+
@Override
48+
public View onCreateView(LayoutInflater inflater,
49+
@Nullable ViewGroup container,
50+
@Nullable Bundle savedInstanceState) {
51+
View layout = inflater.inflate(R.layout.fragment_volley, container, false);
52+
ButterKnife.bind(this, layout);
53+
return layout;
54+
}
55+
56+
@Override
57+
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
58+
super.onActivityCreated(savedInstanceState);
59+
_setupLogger();
60+
}
61+
62+
@Override
63+
public void onPause() {
64+
super.onPause();
65+
_compositeSubscription.unsubscribe();
66+
}
67+
68+
public Observable<JSONObject> newGetRouteData() {
69+
return Observable.defer(new Func0<Observable<JSONObject>>() {
70+
@Override
71+
public Observable<JSONObject> call() {
72+
try {
73+
return Observable.just(getRouteData());
74+
} catch (InterruptedException | ExecutionException e) {
75+
Log.e("routes", e.getMessage());
76+
return Observable.error(e);
77+
}
78+
}
79+
});
80+
}
81+
82+
@OnClick(R.id.btn_start_operation)
83+
void startRequest() {
84+
startVolleyRequest();
85+
}
86+
87+
private void startVolleyRequest() {
88+
_compositeSubscription.add(newGetRouteData().subscribeOn(Schedulers.io())
89+
.observeOn(AndroidSchedulers.mainThread())
90+
.subscribe(new Observer<JSONObject>() {
91+
@Override
92+
public void onCompleted() {
93+
Log.e(TAG, "onCompleted");
94+
Timber.d("----- onCompleted");
95+
_log("onCompleted ");
96+
}
97+
98+
@Override
99+
public void onError(Throwable e) {
100+
VolleyError cause = (VolleyError) e.getCause();
101+
String s = new String(cause.networkResponse.data, Charset.forName("UTF-8"));
102+
Log.e(TAG, s);
103+
Log.e(TAG, cause.toString());
104+
_log("onError " + s);
105+
106+
}
107+
108+
@Override
109+
public void onNext(JSONObject jsonObject) {
110+
Log.e(TAG, "onNext " + jsonObject.toString());
111+
_log("onNext " + jsonObject.toString());
112+
113+
}
114+
}));
115+
}
116+
117+
private JSONObject getRouteData() throws ExecutionException, InterruptedException {
118+
RequestFuture<JSONObject> future = RequestFuture.newFuture();
119+
String url = "http://www.weather.com.cn/adat/sk/101010100.html";
120+
final Request.Priority priority = Request.Priority.IMMEDIATE;
121+
JsonObjectRequest req = new JsonObjectRequest(Request.Method.GET, url, future, future);
122+
MyVolley.getRequestQueue().add(req);
123+
return future.get();
124+
}
125+
126+
// -----------------------------------------------------------------------------------
127+
// Methods that help wiring up the example (irrelevant to RxJava)
128+
129+
private void _setupLogger() {
130+
_logs = new ArrayList<>();
131+
_adapter = new LogAdapter(getActivity(), new ArrayList<String>());
132+
_logsList.setAdapter(_adapter);
133+
}
134+
135+
private void _log(String logMsg) {
136+
137+
if (_isCurrentlyOnMainThread()) {
138+
_logs.add(0, logMsg + " (main thread) ");
139+
_adapter.clear();
140+
_adapter.addAll(_logs);
141+
} else {
142+
_logs.add(0, logMsg + " (NOT main thread) ");
143+
144+
// You can only do below stuff on main thread.
145+
new Handler(Looper.getMainLooper()).post(new Runnable() {
146+
147+
@Override
148+
public void run() {
149+
_adapter.clear();
150+
_adapter.addAll(_logs);
151+
}
152+
});
153+
}
154+
}
155+
156+
private boolean _isCurrentlyOnMainThread() {
157+
return Looper.myLooper() == Looper.getMainLooper();
158+
}
159+
}

app/src/main/res/layout/fragment_main.xml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,5 +100,11 @@
100100
android:layout_width="match_parent"
101101
android:text="@string/btn_demo_rotation_persist"
102102
/>
103+
<Button
104+
android:id="@+id/btn_demo_volley"
105+
android:layout_height="wrap_content"
106+
android:layout_width="match_parent"
107+
android:text="@string/btn_demo_volley"
108+
/>
103109
</LinearLayout>
104110
</ScrollView>
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
3+
<LinearLayout
4+
android:orientation="vertical"
5+
android:layout_height="match_parent"
6+
android:layout_width="match_parent"
7+
xmlns:android="http://schemas.android.com/apk/res/android"
8+
>
9+
10+
<TextView
11+
android:layout_height="wrap_content"
12+
android:layout_width="match_parent"
13+
android:padding="10dp"
14+
android:gravity="center"
15+
android:text="@string/msg_demo_volley"
16+
/>
17+
18+
<Button
19+
android:id="@+id/btn_start_operation"
20+
android:layout_height="wrap_content"
21+
android:layout_width="match_parent"
22+
android:layout_marginLeft="90dp"
23+
android:layout_marginRight="90dp"
24+
android:textSize="16dp"
25+
android:text="tap me"
26+
/>
27+
28+
<ListView
29+
android:id="@+id/list_threading_log"
30+
android:layout_height="match_parent"
31+
android:layout_width="match_parent"
32+
/>
33+
34+
</LinearLayout>

app/src/main/res/values/strings.xml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,8 @@
1919
<string name="btn_demo_timing">Variations of timing/intervals/delays</string>
2020
<string name="btn_demo_exponential_backoff">Exponential backoff</string>
2121
<string name="btn_demo_rotation_persist">Rotation persist</string>
22-
22+
<string name="btn_demo_volley">Volley request demo</string>
23+
<string name="msg_demo_volley">This is a Volley request demo</string>
2324
<string name="msg_demo_concurrency_schedulers">This is a demo of how long running operations can be offloaded to a background thread. After the operation is done, we resume back on the main thread. All using RxJava! \n\n To really see this shine. Hit the button multiple times and see how the button click which is a ui operation is never blocked because the long operation only runs in the background</string>
2425
<string name="msg_demo_buffer">This is a demo of how events can be accumulated using the "buffer" operation. Tap the button below repetitively and you will notice in the logs that button taps are collected over a span of 2s and printed below.</string>
2526
<string name="msg_demo_debounce">As you type in the input box, it will not shoot out log messages at every single input character change, but rather only pick the last one.</string>

0 commit comments

Comments
 (0)