How to get collection from Meteor server with Android DDP? - android

Let me to start explain my problem. There is repository with some explanations, but there are no methods how to get collection or json file from Meteor server(only insert). Also author did not explain properly methods onDataChanged, onDataAdded etc.
public class Login extends Activity implements MeteorCallback{
public static Meteor mMeteor;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login);
mMeteor = new Meteor(this, "some_socket_it_doesn't_matter");
mMeteor.setCallback(this);
}
}
public class ListOfElements extends ListFragment implements MeteorCallback{
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
String subscriptionId = Login.mMeteor.subscribe("notifications");
Log.d("Log", subscriptionId);
}
}
I didn't understand how i have to use subscription or how to get collection from server. Why there are only insert methods in github repository and no get? I really have no idea how make the code to get collection, use subscribe and so on. There are no any understandable explanations in the network. Please, can you help me with this by explaining how to realize getting, subscribing in this code.

There are two special things about Meteor: It works asynchronously and it has been designed specifically for real-time applications. Thus it has a few different concepts for retrieving data and for some other tasks.
In a synchronous application, you would just call insert(...) and immediately get the method's return value, e.g. a boolean value for success/error or a numeric value for the number of rows that have been inserted.
You would call get(...) and immediately receive a collection of rows as the method's return value.
But in Meteor, everything is asynchronous. This means that you get the results not immediately, but a few (milli)seconds later, in a callback method.
When you call insert(...), this is not so important, as you have noticed. You just call this method and often forget about the result, i.e. you don't wait and check for the result because insertions are usually successful. But this method is still asynchronous and you could (and sometimes should) listen for the result which will arrive a few (milli)seconds later, again.
When you want to call get(...), this would be possible in theory, with the important point again being that it's asynchronous. So you would say "get me all chat messages from the last 5 minutes". There would be no result or return value, as usual, but the result would arrive a short time later, asynchronously, in a callback method that you define. This is what onDataAdded(...), onDataChanged(...) and onDataRemoved(...) are for.
Now it's not clear, yet, why you can't call get(...) and wait for data to arrive in those methods.
The answer to that question is Meteor being designed for real-time applications. This is why you can't say "get me all chat messages from the last 5 minutes". Instead, you have to say "I want to subscribe to all chat messages from the last 5 minutes and always be updated about changes".
So, in Meteor, you subscribe to data sets instead of requesting them via get(...).
All in all, this means the following:
If you want to get some messages, you subscribe to your data set that holds those messages.
When the initial rows are sent (!) and whenever new rows are added to the collection, you receive those in your onDataAdded(...) callback. When rows are modified, you receive those changes in your onDataChanged(...) callback. And, finally, when rows are deleted, you are informed about those deletions in your onDataRemoved(...) callback.
When you don't want to get updates for your data set anymore, you unsubscribe from that set. This is optional.
With the Android-DDP library in your Android application, it translates to the following:
final String subscriptionId = mMeteor.subscribe("chats");
public void onDataAdded(String collection, String docID, String json) { ... }
mMeteor.unsubscribe(subscriptionId);
As you can see, what you have to learn is really Meteor and not the library Android-DDP. Meteor has some new concepts that one has to understand. But when you know how Meteor works, translating those things to Android-DDP is really simple and only a matter of looking up the method names.

Related

Android notify every time the value on Retrofit call changes

As is title I want to be able to notify me every time the value of Retrofit call changes. Is that possible with calling this code only once in onCreate()? The scenario is like this. I build an RPG game. For example want to be notified about amount of gold for specific user at application start (this works). Then user kills a monster and gain some coins (another Retrofit call is made) so amount of gold on server changes and now I want to be also notified (here is where it doesn't work).
ApiInterface:
#GET("/getGold")
Observable<String> getGold(#Query("name") String name);
Activity:
#Override
protected void onCreate(Bundle savedInstanceState) {
(...)
Api.getClient1Or2().getGold("Admin")
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(string -> Log.d("string", string));
}
How to modify this code then?
Thank you in advance!
Even though getGold is Observable, it will run request only once and emit a single item.
You need to either receive Gold from your WebSocket message (preferred), or use WebSocket message as a trigger to refresh Gold by subscribing to getGold again (not preferred because you can send your Gold directly in your WebSocket message).
Of course, you would need your backend to expose a WebSocket endpoint for you with the contract for constantly updating your Gold.
You could also use push notification as a trigger for a refresh, but they have quotas and they are built on WebSockets anyway.

Convert RxJava Subjects to Observables

I recently ran into discussion about usage of Subject, like this one here: https://github.com/JakeWharton/RxRelay/issues/7
I see a lot of people saying that Subject should be avoided and some people even say any usage of Subject is inherently a bad practice. While I agree on the theoretical level that Subject can be and should be avoided, I can hardly get rid of subjects in real practices. It seems impractical, or even impossible to do so.
Imagine a simple theoretical weather app that has just two things:
a view that displays current weather information
a refresh button which re-fetch the weather information from the server.
(Let's assume for simplicity that the app does not show the data at initial launch, but waits for the users to press refresh button at least once.)
Then you can think of a view model design like this:
ViewModel
interface IWeatherViewModel {
// Provides weather data
Flowable<WeatherData> getWeatherDataToDisplay();
// Lets view to refresh
void refresh();
}
If I use Subject then IWeatherViewModel can be implemented like this:
class WeatherViewModel implements IWeatherViewModel {
private final BehaviorProcessor<WeatherData> weatherData = BehaviorProcessor.create();
private final PublishProcessor<Boolean> eventRefresh = PublishProcessor.create();
WeatherViewModel() {
eventRefresh
.flatMapSingle(x -> getWeatherData())
.subscribe(weatherData);
}
// Provides weather data
public Flowable<WeatherData> getWeatherDataToDisplay() {
weatherData.hide();
}
// Lets view to refresh
public void refresh() {
eventRefresh.onNext(true);
}
private Single<WeatherData> getWeatherData() {
... // omitted for simplicity
}
}
The idea is to have a PublishProcessor that emits refresh event whenever refresh() is called which is then propagated to a BehaviorSubject. All subscribers that observe getWeatherDataToDisplay() will be notified once getWeatherData() is successful.
However I find it difficult to implement the same thing without Subject.
The app needs to propagate refresh() call to stream. I might be able to replace PublishProcessor using Flowable.create() but it doesn't look clean at all, the best I could do is:
private FlowableEmitter emitter;
private final Flowable<Boolean> eventRefresh = Flowable.create(emitter -> {
this.emitter = emitter;
}, BackpressureStrategy.BUFFER);
public void refresh() {
emitter.onNext(true);
}
Now suddenly I have to have a new instance variable that I cannot make final..
Also I am not able to find any operator that can effectively replace BehaviorProcessor, nor any hot observable that emits the latest item immediately on subscription. This behavior is necessary because the view should be able to detach and re-attach seamlessly, just like LiveData.
If you see any improvement that can be made, or have a different approach to the problem, please share your thougts.

Android MVP doubts about validating

I´m starting to implement the MVP pattern on an Android project and I have some doubts about where I should validate the fields before doing any action.
For example, If I have to send a form with three fields (name, email, text).
Should I validate the fields in the activity or I should send them to the Presenter for being validated?
I'm not 100% sure yet if the comunication with the presenter has to be only with the right data already validated or not.
It really depends, my recommendation is that (And what I normally do):
If the field can be validated without access to database or complex operations, I'd do it in the activity. Examples of such fields would be: Password (Passwords need to contain at least 7 characters), Age (Age must be numeric)
If the field needs to be validated by accessing the database (or by web service) or the operation requires complex logic and resource, do it in the presenter. Examples of such fields would be: Username (To check if it is a duplicated username by accessing the database)
Think of it as a front-end and back-end of a website, although not completely same, it does help you to clarify confusing concepts.
View should never decide to do things by itself, presenter keeps waiting by events notified by view and presenter decides what to do then, view only keeps waiting orders from presenter.
So, no, validation is a presenter task, even if it is a very simple task such as validating a field.
You can do like this in activity:
private Presenter mPrensenter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btn.setOnClickListener(new View.OnClickListener(){
#Override
public void onClick(View v) {
mPrensenter.load(name,email,text);
}
});
}
#Override
public void onRightDataValidated(){
}
then there is two interface MainView and Prensenter:
public interface MainView{
void onRightDataValidated();
}
public interface Presenter{
void load(String name,String email,String text);
}
int the impl of the Presenter,when the data need to be invalidate in load method,u can use MainView.onRightDataValidated to callback , u can find more in my github MVP Demo
Part of the point of MVP is to make testing easier. If you approach questions like these asking, "What if I never tested the view," then that gives the right perspective on what logic should or should not go there. The presenter should lend itself to fast JUnit testing and relieve the developer from needing to write Android instrumentation tests.
Bottom line, you're going to want to test your validation logic to be sure it is sound and if you put that in the Presenter, it makes life easier.
Well I believe you should do the validation in activity. And Simply presenter will call the validation method to check if the validation passes then it will complete the action otherwise show the error.!
In one of my client's project, There is detail page and on click of submit button it should check if detailed page filled then it will save the order with the detail otherwise show the error.
And this is how i have implemented--
Here you can see the isDetailFilledOut() is a validation method and it will return true if validation passes otherwise false.
If it returns true it checks if internet also available then it saves the order by calling model's saveOrder method otherwise shows the fill out detail warning.

RxJava and Cached Data

I'm still fairly new to RxJava and I'm using it in an Android application. I've read a metric ton on the subject but still feel like I'm missing something.
I have the following scenario:
I have data stored in the system which is accessed via various service connections (AIDL) and I need to retrieve data from this system (1-n number of async calls can happen). Rx has helped me a ton in simplifying this code. However, this entire process tends to take a few seconds (upwards of 5 seconds+) therefore I need to cache this data to speed up the native app.
The requirements at this point are:
Initial subscription, the cache will be empty, therefore we have to wait the required time to load. No big deal. After that the data should be cached.
Subsequent loads should pull the data from cache, but then the data should be reloaded and the disk cache should be behind the scenes.
The Problem: I have two Observables - A and B. A contains the nested Observables that pull data from the local services (tons going on here). B is much simpler. B simply contains the code to pull the data from disk cache.
Need to solve:
a) Return a cached item (if cached) and continue to re-load the disk cache.
b) Cache is empty, load the data from system, cache it and return it. Subsequent calls go back to "a".
I've had a few folks recommend a few operations such as flatmap, merge and even subjects but for some reason I'm having trouble connecting the dots.
How can I do this?
Here are a couple options on how to do this. I'll try to explain them as best I can as I go along. This is napkin-code, and I'm using Java8-style lambda syntax because I'm lazy and it's prettier. :)
A subject, like AsyncSubject, would be perfect if you could keep these as instance states in memory, although it sounds like you need to store these to disk. However, I think this approach is worth mentioning just in case you are able to. Also, it's just a nifty technique to know.
AsyncSubject is an Observable that only emits the LAST value published to it (A Subject is both an Observer and an Observable), and will only start emitting after onCompleted has been called. Thus, anything that subscribes after that complete will receive the next value.
In this case, you could have (in an application class or other singleton instance at the app level):
public class MyApplication extends Application {
private final AsyncSubject<Foo> foo = AsyncSubject.create();
/** Asynchronously gets foo and stores it in the subject. */
public void fetchFooAsync() {
// Gets the observable that does all the heavy lifting.
// It should emit one item and then complete.
FooHelper.getTheFooObservable().subscribe(foo);
}
/** Provides the foo for any consumers who need a foo. */
public Observable<Foo> getFoo() {
return foo;
}
}
Deferring the Observable. Observable.defer lets you wait to create an Observable until it is subscribed to. You can use this to allow the disk cache fetch to run in the background, and then return the cached version or, if not in cache, make the real deal.
This version assumes that your getter code, both cache fetch and non- catch creation, are blocking calls, not observables, and the defer does work in the background. For example:
public Observable<Foo> getFoo() {
Observable.defer(() -> {
if (FooHelper.isFooCached()) {
return Observable.just(FooHelper.getFooFromCacheBlocking());
}
return Observable.just(FooHelper.createNewFooBlocking());
}).subscribeOn(Schedulers.io());
}
Use concatWith and take. Here we assume our method to get the Foo from the disk cache either emits a single item and completes or else just completes without emitting, if empty.
public Observable<Foo> getFoo() {
return FooHelper.getCachedFooObservable()
.concatWith(FooHelper.getRealFooObservable())
.take(1);
}
That method should only attempt to fetch the real deal if the cached observable finished empty.
Use amb or ambWith. This is probably one the craziest solutions, but fun to point out. amb basically takes a couple (or more with the overloads) observables and waits until one of them emits an item, then it completely discards the other observable and just takes the one that won the race. The only way this would be useful is if it's possible for the computation step of creating a new Foo to be faster than fetching it from disk. In that case, you could do something like this:
public Observable<Foo> getFoo() {
return Observable.amb(
FooHelper.getCachedFooObservable(),
FooHelper.getRealFooObservable());
}
I kinda prefer Option 3. As far as actually caching it, you could have something like this at one of the entry points (preferably before we're gonna need the Foo, since as you said this is a long-running operation) Later consumers should get the cached version as long as it has finished writing. Using an AsyncSubject here may help as well, to make sure we don't trigger the work multiple times while waiting for it to be written. The consumers would only get the completed result, but again, that only works if it can be reasonably kept around in memory.
if (!FooHelper.isFooCached()) {
getFoo()
.subscribeOn(Schedulers.io())
.subscribe((foo) -> FooHelper.cacheTheFoo(foo));
}
Note that, you should either keep around a single thread scheduler meant for disk writing (and reading) and use .observeOn(foo) after .subscribeOn(...), or otherwise synchronize access to the disk cache to prevent concurrency issues.
I’ve recently published a library on Github for Android and Java, called RxCache, which meets your needs about caching data using observables.
RxCache implements two caching layers -memory and disk, and it counts with several annotations in order to configure the behaviour of every provider.
It is highly recommended to use with Retrofit for data retrieved from http calls. Using lambda expression, you can formulate expression as follows:
rxCache.getUser(retrofit.getUser(id), () -> true).flatmap(user -> user);
I hope you will find it interesting :)
Take a look at the project below. This is my personal take on things and I have used this pattern in a number of apps.
https://github.com/zsiegel/rxandroid-architecture-sample
Take a look at the PersistenceService. Rather than hitting the database (or MockService in the example project) you could simply have a local list of users that are updated with the save() method and just return that in the get().
Let me know if you have any questions.

Android - sending SeekBar values via TCP

I'm currently developing an android app that communicates with some other device, that acts like a server. Basically to build the application's views, I first have to send a query via a TCP connection to the server to get the info. I (successfully) execute these queries with the help of an async task:
private class TCPQuery extends AsyncTask<String, String, String> {
#Override
protected String doInBackground(String... params) {
//connect the socket send the query and receive feedback
}
#Override
protected void onPostExecute(String result) {
//parse server feedback and build the view
}
}
This approach works fine when it comes to single queries that are made only a couple of times during the application's lifetime. What I have trouble implementing is the following:
a certain view in the application, contains seekbars. So basically, every change of the seekbar value (every time the onProgressChange method fires) must be sent to the server(no feedback this time), so it can keep track of the actual values.
How would you go about implementing this? Of course, no networking in android may be done on the main thread. But here establishing a connection, sending a message and closing the connection every time the value changes is not acceptable. Sliding the bar only a little already results in a dozen such calls in a split second.
I've tried approaching this problem by implementing a service. The service had its own socket to communicate with the server. I would connect the socket to the server and keep it open, so that I would be able to call the service's send method any time a seekbar change has been made. But that seemed to interfere with the other queries I mentioned before (the ones executed with async tasks). I couldn't connect one while the other was active. Now I'm not sure whether my service implementation was just bad, or if I am misunderstanding a crucial networking concept here.
I have thought of only sending the data onStopTrackingTouch, but that is not really what I am after. Any help would be very much appreciated!
Use the system clock to check when the last query has been sent, and don't send another until a certain time has elapsed.
You can change seekbar's value as you want, but the query will be sent only every X milliseconds.
static long sendInterval = 600; //milliseconds
#Override
public void onStartTrackingTouch(SeekBar seekBar) {
long nextSend = 0;
}
#Override
public void onProgressChanged(......) {
if (nextSend < uptimeMillis()) {
...send the query and parse feedback...
nextSend = uptimeMillis() + sendInterval ;
}
Start with nextSend = 0, so the first time the query will be sent immediatly.
Choose sendInterval value according to server's response time. Start with a high value and decrease until you see that all is working well.
If the query itself and the response are small (a few bytes) consider using UDP instead of TCP, it's faster and you can use lower values of sendInterval.
Other way to do it, different and maybe better:
since the response time may vary much depending on network traffic, query complexity and server load, you can use a boolean flag. Set it to False before sending the query, set it to True after parsing the response. Use it in an If statement:
#Override
public void onStartTrackingTouch(SeekBar seekBar) {
boolean readyForQuery = true;
}
#Override
public void onProgressChanged(......) {
if (readyForQuery) {
readyForQuery = false;
<...asyncronous send the query, parse feedback and set readyForQuery=true;...>
}
Consider also the worst case: when the server is down and will not respond at all to the query.
Take care to find a way to set the flag True after a reasonable amount of time and/or when the query code generates an exception, otherwise you won't get further responses even when the server goes up again.

Categories

Resources