I'm trying to explore Rxjava 2 and get some issue with fetching information from website. Actutally Observer give me an error.
My code:
observable.subscribe(getObserver());
Observable
Observable<String> observable = Observable.fromCallable(new Callable<String>() {
#Override
public String call() throws Exception {
String data = getHeadlines(SOURCE_WEB);
return data;
}
});
Observer
protected <String> Observer<String> getObserver() {
return new Observer<String>() {
#Override
public void onSubscribe(Disposable d) {
Log.i("Observer get: ", "mamy sub");
Toast.makeText(context, "Wait...", Toast.LENGTH_SHORT).show();
}
#Override
public void onNext(String value) {
Log.i("Observer get: ",value.toString());
}
#Override
public void onError(Throwable e) {
Log.i("Observer get ", "Error");
}
#Override
public void onComplete() {
Log.i("Observer ", "complete");
}
};
}
My fetching method
public String getHeadlines(String source) throws IOException {
Document doc = (Document) Jsoup.connect(source).get();
Elements newsHeadlines = doc.select("h2");
return newsHeadlines.toString();
}
When I'm using AsyncTask everything work fine...
Related
I am trying to use Google Nearby Connections API to connect two Android devices to exchange data but no success.
The devices can found eachother none of them can connect to the other. It always fails at onConnectionInitiated() with
STATUS_ENDPOINT_UNKNOWN when I try to accept the connection.
I tried it with Strategy.P2P_POINT_TO_POINT Strategy.CLUSTER and Strategy.STAR but I get the same result.
Anyone can help me what do I miss?
Both devices are physical and running on Android 9.0
This is the code:
public static ConnectionLifecycleCallback connectionLifecycleCallback;
public static EndpointDiscoveryCallback endpointDiscoveryCallback;
public static PayloadCallback payloadCallback;
public static String SERVICE_ID;
public Context ctx;
public static Strategy STRATEGY;
public NearbyHandler(Context ctx,Strategy STRATEGY){
this.ctx = ctx;
this.STRATEGY = STRATEGY;
SERVICE_ID = ctx.getPackageName();
payloadCallback = new PayloadCallback() {
#Override
public void onPayloadReceived(#NonNull String s, #NonNull Payload payload) {
Log.d("NEARBY_", "PAYLOAD RECEIVED " + s);
}
#Override
public void onPayloadTransferUpdate(#NonNull String s, #NonNull PayloadTransferUpdate payloadTransferUpdate) {
Log.d("NEARBY_", "PAYLOAD TRANSFER UPDATE " + s);
}
};
connectionLifecycleCallback = new ConnectionLifecycleCallback() {
#Override
public void onConnectionInitiated(#NonNull String s, #NonNull ConnectionInfo connectionInfo) {
Nearby.getConnectionsClient(ctx)
.acceptConnection(s, payloadCallback)
.addOnSuccessListener(new OnSuccessListener<Void>() {
#Override
public void onSuccess(Void aVoid) {
Log.d("NEARBY_", "SUCCESSFULLY CONNECTED");
}
})
.addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
e.printStackTrace();
}
});
}
#Override
public void onConnectionResult(#NonNull String s, #NonNull ConnectionResolution connectionResolution) {
switch (connectionResolution.getStatus().getStatusCode()) {
case ConnectionsStatusCodes.STATUS_OK:
Nearby.getConnectionsClient(ctx).stopAdvertising();
Nearby.getConnectionsClient(ctx).stopDiscovery();
break;
case ConnectionsStatusCodes.STATUS_CONNECTION_REJECTED:
break;
case ConnectionsStatusCodes.STATUS_ERROR:
break;
}
}
#Override
public void onDisconnected(#NonNull String s) {
Log.d("NEARBY_", "DISCONNECTED " + s);
}
};
endpointDiscoveryCallback = new EndpointDiscoveryCallback() {
#Override
public void onEndpointFound(#NonNull String s, #NonNull DiscoveredEndpointInfo discoveredEndpointInfo) {
Nearby.getConnectionsClient(ctx)
.requestConnection(
s,
ctx.getPackageName(),
connectionLifecycleCallback)
.addOnSuccessListener(new OnSuccessListener<Void>() {
#Override
public void onSuccess(Void aVoid) {
Log.d("NEARBY_", "ENDPOINT CONNECTED");
}
})
.addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
Log.d("NEARBY_", "FAILED TO CONNECT ENDPOINT " + e.getMessage());
e.printStackTrace();
}
});
}
#Override
public void onEndpointLost(#NonNull String s) {
Log.d("NEARBY_", "ENDPOINT LOST: " + s);
}
};
}
public void startDiscovering() {
Nearby.getConnectionsClient(ctx)
.startDiscovery(
SERVICE_ID,
endpointDiscoveryCallback,
new DiscoveryOptions.Builder()
.setStrategy(CONSTANTS.PEERTOPEER_STRATEGY).build())
.addOnSuccessListener(new OnSuccessListener<Void>() {
#Override
public void onSuccess(Void aVoid) {
Log.d("NEARBY_DISCOVERER_", "onSuccess");
}
})
.addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
e.printStackTrace();
}
});
}
public void startAdvertising() {
Nearby.getConnectionsClient(ctx)
.startAdvertising(
Build.MODEL,
SERVICE_ID,
connectionLifecycleCallback,
new AdvertisingOptions.Builder()
.setStrategy(CONSTANTS.PEERTOPEER_STRATEGY).build())
.addOnSuccessListener(new OnSuccessListener<Void>() {
#Override
public void onSuccess(Void aVoid) {
}
})
.addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
e.printStackTrace();
}
});
}
}
NearbyHandler nearby = new NearbyHandler(getApplicationContext(), Strategy.P2P_POINT_TO_POINT);
if (IS_DEVICE_A) {
nearby.startAdvertising();
} else {
nearby.startDiscovering();
}
Update: Google's walkietalkie demo app works fine on both phones.
Finally I've managed to get it working but not sure about the problem.
I managed the connection lifecycle a bit different way than in the API Docs.
So I created a private helper class
class Endpoint {
#NonNull
private final String id;
#NonNull
private final String name;
public Endpoint(#NonNull String id, #NonNull String name) {
this.id = id;
this.name = name;
}
#NonNull
public String getId() {
return id;
}
#NonNull
public String getName() {
return name;
}
#Override
public boolean equals(Object obj) {
if (obj instanceof Endpoint) {
Endpoint other = (Endpoint) obj;
return id.equals(other.id);
}
return false;
}
#Override
public int hashCode() {
return id.hashCode();
}
#Override
public String toString() {
return String.format("Endpoint{id=%s, name=%s}", id, name);
}
}
The ConnectionLifecycleCallback() and EndpointDiscoveryCallback() should look like this:
endpointDiscoveryCallback = new EndpointDiscoveryCallback() {
#Override
public void onEndpointFound(#NonNull String s, #NonNull DiscoveredEndpointInfo discoveredEndpointInfo) {
Endpoint endpoint = new Endpoint(s, discoveredEndpointInfo.getEndpointName());
ConnectionsClient c = Nearby.getConnectionsClient(ctx);
c.requestConnection(endpoint.getName(), endpoint.getId(), connectionLifecycleCallback).addOnSuccessListener(new OnSuccessListener < Void > () {
#Override
public void onSuccess(Void aVoid) {}
});
}
#Override
public void onEndpointLost(#NonNull String s) {}
};
connectionLifecycleCallback = new ConnectionLifecycleCallback() {
#Override
public void onConnectionInitiated(#NonNull String s, #NonNull ConnectionInfo connectionInfo) {
Nearby.getConnectionsClient(ctx).stopAdvertising();
Nearby.getConnectionsClient(ctx).stopDiscovery();
Endpoint endpoint = new Endpoint(s, connectionInfo.getEndpointName());
ConnectionsClient c = Nearby.getConnectionsClient(ctx);
c.acceptConnection(endpoint.getId(), payloadCallback).addOnSuccessListener(new OnSuccessListener < Void > () {
#Override
public void onSuccess(Void aVoid) {}
});
}
#Override
public void onConnectionResult(#NonNull String s, #NonNull ConnectionResolution connectionResolution) {
switch (connectionResolution.getStatus().getStatusCode()) {
case ConnectionsStatusCodes.STATUS_OK:
Nearby.getConnectionsClient(ctx).stopAdvertising();
Nearby.getConnectionsClient(ctx).stopDiscovery();
break;
case ConnectionsStatusCodes.STATUS_CONNECTION_REJECTED:
// The connection was rejected by one or both sides.
break;
case ConnectionsStatusCodes.STATUS_ERROR:
// The connection broke before it was able to be accepted.
break;
}
}
#Override
public void onDisconnected(#NonNull String s) {}
};
I am using MVVM pattern in which I am using SwipeRefresh layout to refresh recycler view in my layout.When I am pulling it then it continue to refresh even after method completed successfully.
Below is my code:
MainActivity.java
refresh.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
#Override
public void onRefresh() {
userRepository.getUserList();
}
});
UserRepository.java
public void getUserList(){
Retrofit retrofit = RetrofitClient.getInstance();
ApiService apiService = retrofit.create(ApiService.class);
Call<List<User>> userList = apiService.getUser();
userList.enqueue(new Callback<List<User>>() {
#Override
public void onResponse(Call<List<User>> call, final Response<List<User>> response) {
Completable.fromAction(new Action() {
#Override
public void run() throws Exception {
if(response.body() != null) {
List<User> list = response.body();
for (int i = 0; i < list.size(); i++) {
String id = list.get(i).get_id();
String names = list.get(i).getName();
String age = list.get(i).getAge();
User user = new User(id,names,age);
userDb.userDao().Insert(user);
}
}
}
}).subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new CompletableObserver() {
#Override
public void onSubscribe(Disposable d) {
}
#Override
public void onComplete() {
Toast.makeText(context,"Data inserted",Toast.LENGTH_SHORT).show();
}
#Override
public void onError(Throwable e) {
Toast.makeText(context,e.getMessage(),Toast.LENGTH_LONG).show();
}
});
}
#Override
public void onFailure(Call<List<User>> call, Throwable t) {
Toast.makeText(context,t.getMessage(),Toast.LENGTH_LONG).show();
}
});
}
Method fetching list is in another class UserRepository and I am calling method in another activity MainActivity.I am not getting any way how can I stop refreshing process.Someone please let me know a way to stop refreshing process.
Any help would be appreciated.
THANKS
To disable the progress dialog add this,
swipeLayout.setRefreshing(false);
I am new in rxJava.
Well, I was testing few examples to integrate operators in rxJava.
So, I have a problem with this:
Observable.just("JUAN", "LUCILA", "ARMANDO").map(new Function<String, Integer>() {
#Override
public Integer apply(String s) throws Exception {
return s.length();
}
}).all(new Predicate<Integer>() {
#Override
public boolean test(Integer integer) throws Exception {
return integer > 0;
}
}).filter(new Predicate<Boolean>() {
#Override
public boolean test(Boolean aBoolean) throws Exception {
return aBoolean;
}
}).subscribe(new Observer<Boolean>() {
#Override
public void onSubscribe(Disposable d) {
}
#Override
public void onNext(Boolean value) {
Log.d("STATUS: ", "OK");
}
#Override
public void onError(Throwable e) {
}
#Override
public void onComplete() {
Log.d("STATUS: ", "COMPLETE");
}
})
So, AndroidStudio marks me error on subscribe(new Observer).
My objective is transform the names to a number by the length, so with all I hope make a condition, obviously it will be true, and late, filter that TRUE, from filter, and next show me a log message saying OK!
I hope that you can help me!
Thanks!
Check Single at http://reactivex.io/RxJava/2.x/javadoc/
As said in the comment Observable.all(...) you have type Single then from Single.filter(...) you have type Maybe.
So use you need toObservable() and then subscribe.
#CheckReturnValue
#SchedulerSupport(SchedulerSupport.NONE)
public final Maybe<T> filter(Predicate<? super T> predicate) {
ObjectHelper.requireNonNull(predicate, "predicate is null");
return RxJavaPlugins.onAssembly(new MaybeFilterSingle<T>(this, predicate));
}
`
Change to
Observable.just("JUAN", "LUCILA", "ARMANDO").map(new Function<String, Integer>() {
#Override
public Integer apply(String s) throws Exception {
return s.length();
}
}).all(new Predicate<Integer>() {
#Override
public boolean test(Integer integer) throws Exception {
return integer > 0;
}
}).filter(new Predicate<Boolean>() {
#Override
public boolean test(Boolean aBoolean) throws Exception {
return aBoolean;
}
}).toObservable().subscribe(new Observer<Boolean>() {
#Override
public void onSubscribe(Disposable d) {
}
#Override
public void onNext(Boolean value) {
Log.d("STATUS: ", "OK");
}
#Override
public void onError(Throwable e) {
}
#Override
public void onComplete() {
Log.d("STATUS: ", "COMPLETE");
}
});
I am facing with the problem. As far as I know zip method from RxJava waits for all observables to complete.
But am I getting another behaviour.
Here is my code snippet
private PublishSubject<Void> firstSubject;
private PublishSubject<Void> secondSubject;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
loadData();
mDrawerHeaderView.postDelayed(new Runnable() {
#Override
public void run() {
// getSecondSubject().onNext(null);
}
}, 1000);
mDrawerHeaderView.postDelayed(new Runnable() {
#Override
public void run() {
getFirstSubject().onCompleted();
}
}, 1000);
}
protected PublishSubject<Void> createFirstSubject() {
firstSubject = PublishSubject.create();
return firstSubject;
}
protected PublishSubject<Void> createSecondSubject() {
secondSubject = PublishSubject.create();
return secondSubject;
}
protected PublishSubject<Void> getFirstSubject() {
return firstSubject;
}
protected PublishSubject<Void> getSecondSubject() {
return secondSubject;
}
private void loadData() {
Observable<Void> firstSubject = createFirstSubject();
Observable<Void> secondSubject = createSecondSubject();
Observable<Boolean> allDataTask = Observable.zip(firstSubject, secondSubject, new Func2<Void, Void, Boolean>() {
#Override
public Boolean call(Void aVoid, Void aVoid2) {
return true;
}
});
allDataTask
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Subscriber<Boolean>() {
#Override
public void onCompleted() {
Notifications.showSuccessMessage(getApplicationContext(), "COMPLETE");
}
#Override
public void onError(Throwable e) {
Notifications.showErrorMessage(getApplicationContext(), "ERROR");
}
#Override
public void onNext(Boolean aBoolean) {
Notifications.showSuccessMessage(getApplicationContext(), "NEXT");
}
});
}
In this case I got COMPLETE message, but I was expecting to get nothing because the second subject is not completed.
What I am doing wrong ?
Please help me to get desired behaviour.
Yes, it works as expected. It makes perfect sense to receive the onCompleted() here, because if one stream is done, as long as all the elements it emitted are "zipped", there's no way to "zip" anything more, so it's "completed". You can also play with the sequence here.
Say I have a method like the code below, in which a List is flatMapped to individual strings, each of which has some expensive operation applied to them. Is there any way to parallelise the expensive operations, in the same way that I'd use parallelStream() in Java 8?
final List<String> names = new ArrayList<String>() {{
add("Ringo");
add("John");
add("Paul");
add("George");
}};
Observable.just(names).subscribeOn(Schedulers.io())
.flatMap(new Func1<List<String>, Observable<String>>() {
#Override
public Observable<String> call(final List<String> names) {
return Observable.create(new Observable.OnSubscribe<String>() {
#Override
public void call(Subscriber<? super String> subscriber) {
for (String name : names) {
subscriber.onNext(name);
}
}
});
}
})
.map(new Func1<String, String>() {
#Override
public String call(String s) {
//Simulate expensive operation
try {
Thread.sleep(6000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return s.toUpperCase();
}
}).subscribe(new Subscriber<String>() {
#Override
public void onCompleted() {
}
#Override
public void onError(Throwable e) {
}
#Override
public void onNext(String s) {
Log.v("RXExample", s + " on " + Thread.currentThread().getName());
}
});
For completion, applying the change recommended in the answer looks like the following and works nicely!
final List<String> names = new ArrayList<String>() {{
add("Ringo");
add("John");
add("Paul");
add("George");
}};
Observable.just(names).subscribeOn(Schedulers.io())
.flatMap(new Func1<List<String>, Observable<String>>() {
#Override
public Observable<String> call(final List<String> names) {
return Observable.create(new Observable.OnSubscribe<String>() {
#Override
public void call(final Subscriber<? super String> subscriber) {
for (final String name : names) {
Observable
.just(name)
.subscribeOn(Schedulers.from(Executors.newFixedThreadPool(5)))
.map(new Func1<String, String>() {
#Override
public String call(String s) {
//Simulate expensive operation
try {
Thread.sleep(6000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return s.toUpperCase();
}
}).subscribe(new Observer<String>() {
#Override
public void onCompleted() {
}
#Override
public void onError(Throwable e) {
}
#Override
public void onNext(String s) {
subscriber.onNext(name);
}
});
}
}
});
}
})
.subscribe(new Subscriber<String>() {
#Override
public void onCompleted() {
}
#Override
public void onError(Throwable e) {
}
#Override
public void onNext(String s) {
Log.v("RXExample", s + " on " + Thread.currentThread().getName());
}
});
you can parallelise work with flatMap as in the following example. I am using RxJava2 for testing.
For further explanation please read the flatMap usage from here: http://tomstechnicalblog.blogspot.de/2015/11/rxjava-achieving-parallelization.html
#Test
public void name() throws Exception {
final List<String> names = new ArrayList<String>() {{
add("Ringo");
add("John");
add("Paul");
add("George");
}};
Observable<String> stringObservable = Observable.fromIterable(names)
.flatMap(s -> {
return longWork(s).doOnNext(s1 -> {
printCurrentThread(s1);
}).subscribeOn(Schedulers.newThread());
});
TestObserver<String> test = stringObservable.test();
test.awaitDone(2_000, TimeUnit.MILLISECONDS).assertValueCount(4);
}
private Observable<String> longWork(String s) throws InterruptedException {
return Observable.fromCallable(() -> {
Thread.sleep(1_000);
return s;
});
}
private void printCurrentThread(String additional) {
System.out.println(additional + "_" + Thread.currentThread());
}