I created an example to see the difference between Single and Observable. the below posted example does not work. Also I can't see any difference between
Observable and Single.
How do the below examples work?
Code:
public static void main(String[] args) {
Single<List<List<Person>>> observables = Single.just(Main.getPersons());
observables
.flatMap(ll->Observable.fromIterable(ll)
.concatMap(p->Observable.fromIterable(p))
.map(s->s.getAge()))
.observeOn(Schedulers.io())
.subscribe(new SingleObserver() {
#Override
public void onError(Throwable arg0) {
// TODO Auto-generated method stub
}
#Override
public void onSubscribe(Disposable arg0) {
// TODO Auto-generated method stub
System.out.println("onSubscribe: " + arg0);
}
#Override
public void onSuccess(Object arg0) {
// TODO Auto-generated method stub
System.out.println("onSuccess: " + arg0);
}
});
private static <T> Observable<T> toObservable(T s) {
return Observable.just(s);
}
private static List<List<Person>> getPersons() {
return Arrays.asList(
Arrays.asList(new Person("Sanna1", 59, "EGY"), new Person(null, 59, "EGY"), new Person("Sanna3", 59, null)),
Arrays.asList(new Person("Mohamed1", 59, "EGY"), new Person(null, 59, "EGY")),
Arrays.asList(new Person("Ahmed1", 44, "QTR"), new Person("Ahmed2", 44, "QTR"), new Person(null, null, "QTR")),
Arrays.asList(new Person("Fatma", 29, "KSA")),
Arrays.asList(new Person("Lobna", 24, "EGY")));
}
}
Single is for emitting one object and Observable is to emit zero or many objects. An object could be an string, a list, or any composite class you define. Their respective JavaDocs should give some overview about them:
http://reactivex.io/RxJava/2.x/javadoc/io/reactivex/Single.html
http://reactivex.io/RxJava/2.x/javadoc/io/reactivex/Observable.html
In your learning example, you have to turn the sequence back into a Single if you want to consume it via the SingleObserver. You have many age numbers so you can just apply toList to get them all:
observables
.flatMap(ll ->
Observable.fromIterable(ll)
.concatMap(p -> Observable.fromIterable(p))
.map(s -> s.getAge())
.toList() // <--------------------------------------------------
)
Related
We are working with project reactor and having a huge problem right now. This is how we produce (publish our data):
public Flux<String> getAllFlux() {
return Flux.<String>create(sink -> {
new Thread(){
public void run(){
Iterator<Cache.Entry<String, MyObject>> iterator = getAllIterator();
ObjectMapper mapper = new ObjectMapper();
while(iterator.hasNext()) {
try {
sink.next(mapper.writeValueAsString(iterator.next().getValue()));
} catch (IOException e) {
e.printStackTrace();
}
}
sink.complete();
}
} .start();
});
}
As you can see we are taking data from an iterator and are publishing each item in that iterator as a json string. Our subscriber does the following:
flux.subscribe(new Subscriber<String>() {
private Subscription s;
int amount = 1; // the amount of received flux payload at a time
int onNextAmount;
String completeItem="";
ObjectMapper mapper = new ObjectMapper();
#Override
public void onSubscribe(Subscription s) {
System.out.println("subscribe");
this.s = s;
this.s.request(amount);
}
#Override
public void onNext(String item) {
MyObject myObject = null;
try {
System.out.println(item);
myObject = mapper.readValue(completeItem, MyObject.class);
System.out.println(myObject.toString());
} catch (IOException e) {
System.out.println(item);
System.out.println("failed: " + e.getLocalizedMessage());
}
onNextAmount++;
if (onNextAmount % amount == 0) {
this.s.request(amount);
}
}
#Override
public void onError(Throwable t) {
System.out.println(t.getLocalizedMessage())
}
#Override
public void onComplete() {
System.out.println("completed");
});
}
As you can see we are simply printing the String item which we receive and parsing it into an object using jackson wrapper. The problem we got now is that for most of our items everything works fine:
{"itemId": "someId", "itemDesc", "some description"}
But for some items the String is cut off like this for example:
{"itemId": "some"
And the next item after that would be
"Id", "itemDesc", "some description"}
There is no pattern for those cuts. It is completely random and it is different everytime we run that code. Ofcourse our jackson is gettin an error Unexpected end of Input with that behaviour.
So what is causing such a behaviour and how can we solve it?
Solution:
Send the Object inside the flux instead of the String:
public Flux<ItemIgnite> getAllFlux() {
return Flux.create(sink -> {
new Thread(){
public void run(){
Iterator<Cache.Entry<String, ItemIgnite>> iterator = getAllIterator();
while(iterator.hasNext()) {
sink.next(iterator.next().getValue());
}
}
} .start();
});
}
and use the following produces type:
#RequestMapping(value="/allFlux", method=RequestMethod.GET, produces="application/stream+json")
The key here is to use stream+json and not only json.
For a few days I have been trying to create a JPanel, that comes flying in from the side. I found the Universal Tween Engine and also saw a few demos but for some reason I was never able to make it work in my own code. For the sake of simplicity let's just attempt to move a JPanel (containing an image in a JLabel) from (0,0) to (600,0) on a JFrame. This is what I've got so far and the closest I have ever gotten to actually moving things with this framework, all it does it make the JPanel jump to its destination within the first tick or so. It is supposed to be so simple but I must be missing something...
SlideTest.java - Creating the UI, initializing the Thread + Tween
public class SlideTest {
TweeningPane p;
public TweenManager tweenManager;
public static void main(String[] args) {
new SlideTest();
}
public SlideTest() {
try {
setupGUI();
} catch (IOException e) {
e.printStackTrace();
}
tweenManager = new TweenManager();
AnimationThread aniThread = new AnimationThread();
aniThread.setManager(tweenManager);
aniThread.start();
Tween.to(p, 1, 10.0f).target(600).ease(Quad.OUT).start(tweenManager);
}
public void setupGUI() throws IOException {
JFrame f = new JFrame();
f.setSize(800, 600);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
p = new TweeningPane();
JLabel l = new JLabel(new ImageIcon("E:/Pictures/Stream/aK6IX4V.png"));
f.setLayout(null);
p.add(l);
p.setBounds(0, 0, 300, 300);
f.add(p);
f.setVisible(true);
}
}
AnimationThread.java - The Thread, that is supposed to keep my TweenManager updated as much/often as possible
public class AnimationThread extends Thread {
TweenManager tm;
public void setManager(TweenManager tweenmanager) {
this.tm = tweenmanager;
}
public void run() {
while (true) {
//System.out.println("MyThread running");
tm.update(MAX_PRIORITY);
try {
sleep(40);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
TweeningPane.java - My Object(JPanel), I want to move across the JPanel
public class TweeningPane extends JPanel implements TweenAccessor<JPanel> {
private static final long serialVersionUID = 1L;
#Override
public int getValues(JPanel arg0, int arg1, float[] arg2) {
return (int) arg0.getBounds().getX();
}
#Override
public void setValues(JPanel arg0, int arg1, float[] arg2) {
arg0.setBounds((int) arg2[0], 0, 300, 300);
}
}
I have finally figured it out. I was simply using the framework in a wrong way as I expected. I'm not sure whether all these steps were needed but this is what I went through in order to make it work: (for future reference)
I had to register my accessor to the engine:
Tween.registerAccessor(TweeningPane.class, new TweeningPane());
And the thread itself now looks like this; I had to give the manager's update method the elapsed time as a parameter.
public void run() {
long ms1 = System.currentTimeMillis();
while (true) {
//System.out.println("MyThread running");
tm.update((System.currentTimeMillis() - ms1) / 1000f);
try {
Thread.sleep(40);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
I have implemented simple RxEventBus which starts emitting events, even if there is no subscribers. I want to cache last emitted event, so that if first/next subscriber subscribes, it receive only one (last) item.
I created test class which describes my problem:
public class RxBus {
ApplicationsRxEventBus applicationsRxEventBus;
public RxBus() {
applicationsRxEventBus = new ApplicationsRxEventBus();
}
public static void main(String[] args) {
RxBus rxBus = new RxBus();
rxBus.start();
}
private void start() {
ExecutorService executorService = Executors.newScheduledThreadPool(2);
Runnable runnable0 = () -> {
while (true) {
long currentTime = System.currentTimeMillis();
System.out.println("emiting: " + currentTime);
applicationsRxEventBus.emit(new ApplicationsEvent(currentTime));
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
Runnable runnable1 = () -> applicationsRxEventBus
.getBus()
.subscribe(new Subscriber<ApplicationsEvent>() {
#Override
public void onCompleted() {
}
#Override
public void onError(Throwable throwable) {
}
#Override
public void onNext(ApplicationsEvent applicationsEvent) {
System.out.println("runnable 1: " + applicationsEvent.number);
}
});
Runnable runnable2 = () -> applicationsRxEventBus
.getBus()
.subscribe(new Subscriber<ApplicationsEvent>() {
#Override
public void onCompleted() {
}
#Override
public void onError(Throwable throwable) {
}
#Override
public void onNext(ApplicationsEvent applicationsEvent) {
System.out.println("runnable 2: " + applicationsEvent.number);
}
});
executorService.execute(runnable0);
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
executorService.execute(runnable1);
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
executorService.execute(runnable2);
}
private class ApplicationsRxEventBus {
private final Subject<ApplicationsEvent, ApplicationsEvent> mRxBus;
private final Observable<ApplicationsEvent> mBusObservable;
public ApplicationsRxEventBus() {
mRxBus = new SerializedSubject<>(BehaviorSubject.<ApplicationsEvent>create());
mBusObservable = mRxBus.cache();
}
public void emit(ApplicationsEvent event) {
mRxBus.onNext(event);
}
public Observable<ApplicationsEvent> getBus() {
return mBusObservable;
}
}
private class ApplicationsEvent {
long number;
public ApplicationsEvent(long number) {
this.number = number;
}
}
}
runnable0 is emitting events even if there is no subscribers. runnable1 subscribes after 3 sec, and receives last item (and this is ok). But runnable2 subscribes after 3 sec after runnable1, and receives all items, which runnable1 received. I only need last item to be received for runnable2. I have tried cache events in RxBus:
private class ApplicationsRxEventBus {
private final Subject<ApplicationsEvent, ApplicationsEvent> mRxBus;
private final Observable<ApplicationsEvent> mBusObservable;
private ApplicationsEvent event;
public ApplicationsRxEventBus() {
mRxBus = new SerializedSubject<>(BehaviorSubject.<ApplicationsEvent>create());
mBusObservable = mRxBus;
}
public void emit(ApplicationsEvent event) {
this.event = event;
mRxBus.onNext(event);
}
public Observable<ApplicationsEvent> getBus() {
return mBusObservable.doOnSubscribe(() -> emit(event));
}
}
But problem is, that when runnable2 subscribes, runnable1 receives event twice:
emiting: 1447183225122
runnable 1: 1447183225122
runnable 1: 1447183225122
runnable 2: 1447183225122
emiting: 1447183225627
runnable 1: 1447183225627
runnable 2: 1447183225627
I am sure, that there is RxJava operator for this. How to achieve this?
Your ApplicationsRxEventBus does extra work by reemitting a stored event whenever one Subscribes in addition to all the cached events.
You only need a single BehaviorSubject + toSerialized as it will hold onto the very last event and re-emit it to Subscribers by itself.
You are using the wrong interface. When you susbscribe to a cold Observable you get all of its events. You need to turn it into hot Observable first. This is done by creating a ConnectableObservable from your Observable using its publish method. Your Observers then call connect to start receiving events.
You can also read more about in the Hot and Cold observables section of the tutorial.
I'm building a UI in which I'm using ListView to hold data about questions that users ask. Whenever a new question is created by the user, I try to update the listview. The problem right now is that the data is updated but not right away. After adding a question, I need to navigate to another screen and then come back to see the updated list. This is also causing some other problems that I would like to fix (layout is not getting properly displayed)
This is the code for my Activity:
public class QuestionsScreen extends Activity {
.....
.....
.....
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_questions_screen);
.....
questions=new ArrayList<String>();
qId=new ArrayList<Integer>();
.....
.....
//building API
resourceApi = ApiBuilder.getResourceApi(token);
// calling API function to get questions from db
resourceApi.listQuestions(groupId, new Callback<List<Question>>(){
#Override
public void failure(RetrofitError arg0) {
// TODO Auto-generated method stub
}
#Override
public void success(List<Question> arg0, Response arg1) {
// TODO Auto-generated method stub
for(Question q:arg0)
{
questions.add(q.getTitle());
qId.add(q.getId());
}
}
});
adapter= new ArrayAdapter<String>this,android.R.layout.simple_list_item_1,questions);
lv.setAdapter(adapter);
.....
AlertDialog.Builder dialog = new AlertDialog.Builder(this);
LayoutInflater inflater = getLayoutInflater();
final View x;
x = inflater.inflate(R.layout.groupdialog, null);
dialog.setView(x);
dialog.setTitle("Add question");
TextView t= (TextView)x.findViewById(R.id.dialogTv);
t.setText("Please type in the question");
dialog.setPositiveButton("Ok", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface d, int which) {
// TODO Auto-generated method stub
name = (EditText) x.findViewById(R.id.dialog_groupName);
out = name.getText().toString();
addQuestion();
d.dismiss();
}
});
dialog.setNegativeButton("Cancel",
new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface d, int which) {
// TODO Auto-generated method stub
d.cancel();
}
});
alert = dialog.create();
//button to ask a new question
newQ.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
alert.show();
}
});
}
This is the function which is called when "Add new question" button is pressed:
public void addQuestion()
{
resourceApi.createQuestion(groupId, out, new Callback<Question>(){
#Override
public void failure(RetrofitError err) {
// TODO Auto-generated method stub
}
#Override
public void success(Question q, Response response) {
// TODO Auto-generated method stub
// adapter.add(q.getTitle());
questions.add(q.getTitle());
qId.add(q.getId());
}
});
adapter.notifyDataSetChanged();
Toast.makeText(QuestionsScreen.this, "New Question created",Toast.LENGTH_LONG).show();
}
The toast is displayed. However, the list view is not updated with the new question. I tried using adapter.add() as well but it just caused some other problems so I don't want to use that.
Can anyone suggest a better way or point out what I'm doing wrong?
You have to notify you data in the callback (success function)
Try something like this :
resourceApi.createQuestion(groupId, out, new Callback<Question>(){
#Override
public void failure(RetrofitError err) {
// TODO Auto-generated method stub
}
#Override
public void success(Question q, Response response) {
// TODO Auto-generated method stub
adapter.add(q.getTitle());
questions.add(q.getTitle());
qId.add(q.getId());
//Notify once you have add something in questions
adapter.notifyDataSetChanged();
}
});
I have a very simple Java bean, WatchedFile, which has a fileName field.
I would like to sort a fj.data.List of WatchedFile objects, but I'm struggling with defining an fj.Ord for the list's sort() method. This is what I came up with:
protected List<WatchedFile> getWatchedFileList(String path) throws IOException {
List<File> files = List.list(new File(path).listFiles());
return files
.map((file) -> new WatchedFile(file.getName(), false, file.length()))
.sort(Ord.ord(new F<WatchedFile, F<WatchedFile, Ordering>>()
{
#Override
public F<WatchedFile, Ordering> f(final WatchedFile watchedFile1)
{
return new F<WatchedFile, Ordering>()
{
#Override
public Ordering f(final WatchedFile watchedFile2)
{
int compareResult = watchedFile1.fileName.compareTo(watchedFile2.fileName);
return (compareResult < 0 ? Ordering.LT :
(compareResult > 0 ? Ordering.GT : Ordering.EQ));
}
};
}
}));
}
This is ugly! I'm sure there is a better way of instantiating an Ord object... Possibly utilizing some Java 8 magick?
protected List<WatchedFile> getWatchedFileList(String path) throws IOException {
List<File> files = Arrays.asList(new File(path).listFiles());
return files.stream()
.map(file -> new WatchedFile(file.getName(), false, file.length()))
.sorted((wf1, wf2)->wf1.fileName.compareTo(wf2.fileName))
.collect(Collectors.toList());
}
It’s recommended to have a method public String getFileName() in your class WatchedFile. In that case you can simply say:
protected List<WatchedFile> getWatchedFileList(String path) throws IOException {
List<File> files = Arrays.asList(new File(path).listFiles());
return files.stream()
.map(file -> new WatchedFile(file.getName(), false, file.length()))
.sorted(Comparator.comparing(WatchedFile::getFileName))
.collect(Collectors.toList());
}
And, using NIO2 for getting the directory entries, it may look like:
protected List<WatchedFile> getWatchedFileList(String path) throws IOException {
try {
return Files.list(Paths.get(path))
.map(p -> new WatchedFile(p.toString(), false, fileSize(p)))
.sorted(Comparator.comparing(WatchedFile::getFileName))
.collect(Collectors.toList());
} catch(UncheckedIOException ex) { throw ex.getCause(); }
}
private long fileSize(Path path) {
try { return Files.size(path); }
catch (IOException ex) { throw new UncheckedIOException(ex); }
}
If you want to stay within the “functional-java” API, a solution can look like:
protected List<WatchedFile> getWatchedFileList(String path) throws IOException {
List<File> files = List.list(new File(path).listFiles());
return files
.map(file -> new WatchedFile(file.getName(), false, file.length()))
.sort(Ord.stringOrd.comap(wf -> wf.fileName));
}
The key point is that you don’t need (shouldn’t) re-implement the way, Strings are compared. Instead, specify the function to get the property value to compare. Compare with Java 8 factory method Comparator.comparing used in the second code example.