I'm working on social application like Instagram and LinkedIn, and I'm confusing how to manage multiple data sources ( roomLocalDataSource, remoteDataSource ).
I want load data directly from roomLocalDataSource after open the app and display it in RecyclerView if exist, also get data from remoteDataSource and on success show button to user to display new posts like mechanism happens in Instagram and LinkedIn,
Here is my RemoteDataSource:
public Single<List<Movie>> getMoviesFromRemote() {
return moviesApiService.getMovies();
}
Here is my RoomLocalDataSource:
public Single<List<Movie>> getMoviesFromLocal() {
return moviesDao.getMovies();
}
Here is my MoviesDao:
#Query("SELECT * FROM movies)
Single<List<Movie>> getMovies();
Here is my MoviesApiService:
#GET("movies")
Single<List<Movie>> getMovies();
Here is my MoviesRepository:
public List<Movie> getMovies() {
// Here i will get data using (roomLocalDataSource, remoteDataSource) and send to viewModel
}
I have tried concat operator to handle two data sources but internet i get data from remote only and didn't get from local.
I know it call be handled by RXJava operators but i don't know which specific operator could help me in my case.
You could do something like below code
getMoviesFromLocal()
.doOnSuccess(localData -> //Update the UI)
//Now fetch from Remote
.flatMap(
//Get movie list from remote, map to new List with Local and remote movie
localData -> getMoviesFromRemote().map(remoteData -> Collections.addAll(localData, remoteData)
)
.subscribe(
result -> //List of Movies from remote and Local,
error -> //Handle error
)
In your MoviesRepository you can fetch first the data in your RoomLocalDataSource and concatenate with RemoteDataSource
public Flowable<Movie> getMovies() {
return roomLocalDataSource.getMoviesFromLocal()
.concatWith(remoteDataSource.getMoviesFromRemote());
}
Then you subscribe to the Flowable and your onNext method will be called twice, first time with the list returned by Room and the second time with the list fetched from your remote data source
public class MoviesSubscriber extends DisposableSubscriber<List<Movie>>(){
#Override
public void onNext(List<Movie> movies) {
// TODO: handle the list
}
#Override
public void onError(Throwable t) {
// ...
}
#Override
public void onComplete() {
// ...
}
}
Related
When I click on an AjaxLink, I would like to have a validation via JavaScript on the client side first (because the LocalStorage is queried) and then depending on the result, further JavaScript calls are made. How can i achieve this?
In a pseudo code it would look like this:
new AjaxLink<>("myId", myModel) {
#Override
public void onClick(AjaxRequestTarget target) {
boolean isCounterValid = target.appendJavaScript(checkCounter()); // i know that this is not possible, therefore pseudo code
if(isCounterValid) {
target.appendJavaScript(someOtherJavaScript());
}
else {
target.appendJavaScript(anotherJavaScript());
}
}
private String checkCounter() {
return "var count = window.localStorage.getItem('myCounter'); return count !== 1;";
}
private String someOtherJavaScript() {
return "change something";
}
private String anotherJavaScript() {
return "change other thing";
}
};
You need to send extra request parameters with the Ajax call when the link is clicked. For that you should override updateAjaxAttributes(AjaxRequestAttributes attributes) method of AjaxLink:
#Override
protected void updateAjaxAttributes(AjaxRequestAttributes attributes)
{
attributes.getDynamicExtraParameters().add("var count = window.localStorage.getItem('myCounter'); return [{\"name\":\"count\", \"value\": count}]");
}
This way inside AjaxLink#onClick() you can read the count via:
int count = getRequest().getRequestParameters().getParameterValue("count").toInt();
AJAX components and behaviors can customize AJAX attributes overriding updateAjaxAttributes and using a custom implementation of AjaxCallListener which exposes different method to hook into the AJAX request cycle. In you case you could use AjaxCallListener#getBeforeSendHandler.
For a full introduction to this topic (with examples) see user guide:
https://ci.apache.org/projects/wicket/guide/8.x/single.html#_ajax_request_attributes_and_call_listeners
I have a table and a button and I want to emit an event ItemsSelected with the selected items of the table when the button is clicked.
The button should not know the table and it should remain only as a stream of clicks.
So this solution is discarded:
final ETable table = ...
PublishSubject<ItemSelected> selected = PublishSubject.create();
button.addSelectionListener(new SelectionListener(){
#Override
public void widgetSelected(SelectionEvent e) {
for (TableItem item : table.getSelection()) {
selected.onNext(new ItemSelected(item));
}
}
});
I would prefer a way to compose the click stream of the button with the item selection stream of the table in order to keep loose coupling between this two elements.
Because the table allows multiple selection I must first scan the items selected in order to emit an event with all the items. Something like:
public static class ItemsSelected<T> {
final List<T> items = new ArrayList<T>();
}
public abstract static class ItemSelection<T> {
public abstract void apply(ItemsSelected<T> selection);
}
public static class ItemUnselected<T> extends ItemSelection<T> {
final T item;
public ItemUnselected(T item) {
this.item = item;
}
public void apply(ItemsSelected<T> selection) {
selection.items.remove(item);
}
}
public static class ItemSelected<T> extends ItemSelection<T> {
final T item;
public ItemSelected(T item) {
this.item = item;
}
public void apply(ItemsSelected<T> selection) {
selection.items.add(item);
}
}
public static class ObservableTable<T> extends Table {
private PublishSubject<ItemSelection<T>> clicks = PublishSubject.create();
public Observable<ItemsSelected<T>> selection = clicks.scan(new ItemsSelected<T>(),
new Func2<ItemsSelected<T>, ItemSelection<T>, ItemsSelected<T>>() {
#Override
public ItemsSelected<T> call(ItemsSelected<T> t1, ItemSelection<T> t2) {
// breaking events immutability
t2.apply(t1);
return t1;
}
});
public ObservableTable(Composite parent, int style) {
super(parent, style);
this.addSelectionListener(new SelectionListener() {
#SuppressWarnings("unchecked")
#Override
public void widgetSelected(SelectionEvent e) {
if (((TableItem) e.item).getChecked())
clicks.onNext(new ItemSelected<T>((T) e.item.getData()));
else
clicks.onNext(new ItemUnselected<T>((T) e.item.getData()));
}
#Override
public void widgetDefaultSelected(SelectionEvent e) {
}
});
}
}
Then, I must combine the table.selection stream with the button.clicks stream in a selectionForAction stream. The idea is that when a ButtonClick is emitted, an SelectionForAction will be emitted if and only if an ItemSelected was previously emitted.
-------S1--U1-----S2---S3--------- table.clicks
(scan)
-------(1)--()---(2)---(2,3)------ table.selection
----O----------O-------------O---- button.clicks
(?)
-----------------------------(2,3) selectionForAction
So, wich operation should I use?
Zip: It doesn't work because if I click the button and later select an item, it should not do nothing, but with zip it will emit an event.
Join: I end up with a "solution" using join but it doesn't seem to be a good one. Somethinkg like:
table.selection.join(button.clicks, new Func1<ItemsSelected,Observable<Long>>() {
#Override
public Observable<Long> call(ItemsSelected t) {
// it doesn't seem a good idea
return Observable.timer(1, TimeUnit.DAYS);
}
}, new Func1<ClickEvent, Observable<Long>>() {
#Override
public Observable<Long> call(ClickEvent t) {
// this makes the ClickEvent be dropped if there is no previous ItemsSelected event emitted
return Observable.timer(1, TimeUnit.MILLISECONDS);
}
}, new Func2<ItemsSelected, ClickEvent, SelectionForAction>() {
#Override
public SelectionForActioncall(ItemsSelected t1, ClickEvent t2) {
return new SelectionForAction(t1.items);
}
});
Any idea?
I've found the operator that I needed to achieve the join behaviour with a very large time unit (DAYS in the example) and a very small one (MILLISECONDS).
With a variant of sample that takes another Observable as the sampler I could emit an event A only after an event of B would be emitted.
In my example the click acts as the sampler and the stream selection emits the events that I'm interested in. (This also requires to ignore the last event that is being emitted when the stream completes).
Another possible solution will be use the buffer(boundary):
The clicks stream would act as the boundary and I could avoid the scan operator because the list of items selected is created by the buffer operator. However with this solution I would not be considering unselection.
So, with sample I've achieved my original goal, however, I'm not happy with the way I handle items unselection and the final list of items selected.
In this case I need to maintain the state of the items selected in order to perform some operation on all of them when a ClickEvent occurs.
I could subscribe to the items selection/unselection and maintain a List of the items selected but then I'll have lost the possibility of compose the clicks observable with the selection observable.
With scan I maintain state and also keep the composability of observables, but representing the list of current selection as an event seems a little forced, in fact this represents a new issue: if I select x items and then click the button, an event with the selection is being emitted as expected, but if neither the items are unselected nor a new one is selected and then click again the button, nothing happens. So, it seems that selection doesn't fit as an event.
I have an MVC application in which I have to update the view with the current value of a stream.
In the model I have this method:
public Observable<Integer> getStreamInstance(){
if(stream == null){
this.stream = Observable.create((Subscriber<? super Integer> subscriber) -> {
new HeartbeatStream(frequence,subscriber).start();
});
}
return stream;
}
which I use in the controller to get the stream. Then, in the controller I have these two methods:
public void start(){
this.sb = stream.subscribe((Integer v) -> {
view.updateCurrValue(v);
});
}
public void stop(){
this.sb.unsubscribe();
}
With the start method I simply update a label in the view with the current value.
This works fine until I try to stop the updating with the unsubscribing; infact, when I press the button "stop" in the view, the label keeps updating with the current value and, if I press "start" again, the label shows the values from two different streams, the one that I first created with the first "start" and the second that seems has been created with the second pressing of "start".
Where am I wrong?
EDIT:
public class HeartbeatStream extends Thread{
private Subscriber<? super Integer> subscriber;
private int frequence;
private HeartbeatSensor sensor;
public HeartbeatStream(int freq, Subscriber<? super Integer> subscriber){
this.frequence = freq;
this.subscriber = subscriber;
sensor = new HeartbeatSensor();
}
public void run(){
while(true){
try {
subscriber.onNext(sensor.getCurrentValue());
Thread.sleep(frequence);
} catch (Exception e) {
subscriber.onError(e);
}
}
}
This is the HeartbeatStream class. HeartbeatSensor is a class that periodically generates a value that simulates the heartbeat frequence.
I'm guessing you tried to periodically signal some event that triggers the screen update. There is an operator for that:
Observable<Long> timer = Observable.interval(period, TimeUnit.MILLISECONDS,
AndroidSchedulers.mainThread());
SerialSubscription serial = new SerialSubscription();
public void start() {
serial.set(timer.subscribe(v -> view.updateCurrValue(v)));
}
public void stop() {
serial.set(Subscriptions.unsubscribed());
}
public void onDestroy() {
serial.unsubscribe();
}
Observable by design unsubscribe your observer once that all items are emitted and onComplete callback is invoked.
Look this example https://github.com/politrons/reactive/blob/master/src/test/java/rx/observables/creating/ObservableSubscription.java
I guess you're not handling the unsubscribe - although I can't see what's going on in your HeartbeatStream class.
If you're creating an Observable with Observable.create then you need to handle unsubscribing explicitly with subscriber.isUnsubscribed().
Where possible use some of the utility methods to create an Observable - they handle this all for you eg Observable.just() or Observable.from().
If this doesn't help, please post your HeartbeatStream class.
See the the docs for more details:
https://github.com/ReactiveX/RxJava/wiki/Creating-Observables
https://github.com/ReactiveX/RxJava/wiki/Async-Operators
I'm fairly new to Wicket but I've already run into a very strange problem.
I'm creating a page with a pretty basic search form and a results table (a DataView) which is initially empty. When the user enters data into the fields and clicks "Search", the app calls some backend services which are then used to populate the DataView.
However the user has to click "Search" twice for the data to be displayed.
I finally tracked this down, and it's because Wicket is using zero for the number of items to be displayed for the first "Search" click. At the second click, the rows have already been added and Wicket has already calculated the proper number of rows to display, so it decides it will show the data.
In AbstractPageableView.getItemModels(), the size of the results to display is initially zero, because I don't load the table with any initial data probably.
I got around this problem by loading the DataView with empty rows on page load. This seems to trick the DataView into using the displaying the data for the first "Search" click.
My question is: am I doing this right? Is there another repeater that is better for this task? Is this a bug or something?
Finally cracked it: it was because I was loading the data in my data provider only in the iterator() method, and the data provider's size() method is usually called before the iterator() method is. I should have been loading the data in its own method and calling that method from iterator() and size(). Doing that fixed it.
Data Provider before (Splc is the DTO):
SearchResultsDataProvider implements IDataProvider<Splc> {
/**
* The list of search results
*/
private List<Splc> models;
#Override
public void detach() {
// Do nothing
}
#Override
public Iterator<Splc> iterator(int first, int count) {
// load the data into the list of models
models = service.getSplcModels();
return models.subList(....).iterator();
}
#Override
public IModel<Splc> model(Splc object) {
return new Model<Splc>(object);
}
#Override
public int size() {
return models.size();
}
}
Data Provider after:
SearchResultsDataProvider implements IDataProvider<Splc> {
private List<Splc> getModels() {
// load the data into the list of models
return service.getSplcModels();
}
#Override
public void detach() {
// Do nothing
}
#Override
public Iterator<Splc> iterator(int first, int count) {
return getModels().subList(....).iterator();
}
#Override
public IModel<Splc> model(Splc object) {
return new Model<Splc>(object);
}
#Override
public int size() {
return getModels().size();
}
}
ref:
http://www.lunatech-research.com/playframework-file-upload-blob
I'm uneasy about one point in this example
#{list items:models.User.findAll(), as:'user'}
<img src="#{userPhoto(user.id)}">
#{/list}
At this point I'm already holding the user object (including the image blob). Yet the userPhoto() method makes another dip into the backend to get the Image user.photo
public static void userPhoto(long id) {
final User user = User.findById(id);
notFoundIfNull(user);
response.setContentTypeIfNotSet(user.photo.type());
renderBinary(user.photo.get());
}
Any way to avoid this unnecessary findById call?
You're not actually holding the user object any more though, because the userPhoto action is invoked in a separate request that's sent when the browser tries to load the image from the URL generated by #{userPhoto(user.id)}.
Of course, you could use the cache to store data from each user's photo Blob, which would reduce the likelihood that you had to go to the database on the image request. It's more trouble than it's worth in this case though since you're just doing a simple primary key lookup for the user object, and that should be relatively inexpensive. Plus Blobs aren't serializable, so you have to pull out each piece of information separately.
Still, if you were to try that it might look something like this:
// The action that renders your list of images
public static void index() {
List<User> users = User.findAll();
for (User user : users) {
cachePhoto(user.photo);
}
render(users);
}
// The action that returns the image data to display
public static void userPhoto(long id) {
InputStream photoStream;
String path = Cache.get("image_path_user_" + id);
String type = Cache.get("image_type_user_" + id);
// Was the data we needed in the cache?
if (path == null || type == null) {
// No, we'll have to go to the database anyway
User user = User.findById(id);
notFoundIfNull(user);
cachePhoto(user.photo);
photoStream = user.photo.get();
type = user.photo.type();
} else {
// Yes, just generate the stream directly
try {
photoStream = new FileInputStream(new File(path));
} catch (Exception ex) {
throw new UnexpectedException(ex);
}
}
response.setContentTypeIfNotSet(type);
renderBinary(photoStream);
}
// Convenience method for caching the photo information
private static void cachePhoto(Blob photo) {
if (photo == null) {
return;
}
Cache.set("image_path_user_" + user.id,
photo.getFile.getAbsolutePath());
Cache.set("image_type_user_" + user.id,
photo.getType());
}
Then you'd still have to worry about appropriately populating/invalidating the cache in your add, update, and delete actions too. Otherwise your cache would be polluted with stale data.