Where to attach the reference to a Retrofit adapter in Android? - android

I am referencing this post Where to keep Retrofit Adapter in Android App? but I am not allowed to comment there due to stackoverflow limitations [thank you stackoverflow for treating new users like kids].
Where does the Retrofit RestAdpater go when using Android? Can anybody please elaborate on #Jake Wharton 's answer of above post.
When I place the RestAdapter in my Activity, it will probably get GCed when the Activity is destroyed, so the Singleton loses its reference and needs to be recreated the next time (I assume).
Further, the first thing that I did for testing is exactly this and Android tells me I cannot do a network request on the Main thread. I understand that I can't do that, but I thought Retrofit would automatically create a separate thread for me.
Will I need to create an AsyncTask to host the RestAdapter? Or how exactly does this work for Android? Where is the adapter best instantiated? Which is the recommended point to attach the Retrofit reference?

So what #JakeWharton was saying is that the RestAdapter and the api interface instances should be created once. How you achieve that is pretty much an implementation details.
In a straight forward manner you could create a class which would hold a single instance to your RestAdapter. You would be responsible of making only a single instance of that class. You'd probably want to hold a reference to this class in your Application class. You could also approach this using the Singleton pattern
Here's a small class to get you started. I took this from a previous post which you can see here
public class RestApiDispencer {
private Map<String, Object> restApiInstances = new HashMap<String, Object>();
private RestAdapter restAdapter;
public RestApiDispencer(RestAdapter restAdapter) {
this.restAdapter = restAdapter;
}
public <T> T getRestApi(Class<T> clazz) {
T client = null;
if ((client = (T) restApiInstances.get(clazz.getCanonicalName())) != null) {
return client;
}
client = restAdapter.create(clazz);
restApiInstances.put(clazz.getCanonicalName(), client);
return client;
}
}
If you're familiar with dependency injection then that would be another way to go. Personally I prefer to use dependency injection when it comes to hiding implementation details from use.
Creating the RestAdapter directly into your Activity would not the way you'd want to go. Instead in your activity would want to get a reference to this RestApiDispencer class from above and have it return the instance of the rest api of your choise by providing its class like so.
MyClassApi myClassApi = restApiDispencer.getRestApi(MyClassApi.class);
There are other ways to achieve this but as I said it's up to you to decide which implementation fits best your needs.
As for Retrofit doing request on a separate thread, yes it does but you need to create your Api interfaces accordingly.
#GET(/some/rest/api/path)
Response getApiData() // Synchronous declaration as the Response is returned from the method.
#GET(/some/rest/api/path)
void getApiData(Callback<Response> callback); // Asynchronous as the Response is delivered in the callback.
#GET(/some/rest/api/path)
Observable<Response> getApiData(); // Asynchronous again but you'll need to read up on rx-java before using this.
Read on rx-java here
So if you do decide to create your rest api by using the asynchronous signature then you won't have to worry about threading when invoking your interface. If you use the synchronous signature then it's all up to you.

Related

RxJava: unpack object

I am using RxJava in my Android project and I'm happy about it. I'm currently using it to make all my DAO methods asynchronous and make UI listens on them.
But I have a big problem, that is, when I retrieve some data from database using Observable<List<User>> getLists(), I need to use List<User> in my ViewModels, but I cannot extract it from the observable.
I would like to know what is the common approach to solve this kind of problem ? I searched on Internet and people said it's not recommended to extract the objects, but in this case how can I use the data from database and at the same time still enable the observers listening ?
Should I create another method using AsyncTask ??
Thanks.
In my UserRepo.java
public Observable<List<User>> getUsers() {
return colisDao.getUsers();
}
In HomeScreenViewModel.java:
public List<User> getUsers() {
return userRepo.getUsers(); // do not work because I need a List<User>
}
In HomeActivity.java:
UserListAdapter userListAdapter = new UserListAdapter(this,
vm.getUsers());
Central idea of reactive extensions is to make use of events' streams observation and timely processing.
So actually, if you need to retrieve data in a straightforward way, I'd say you don't need RxJava2 at all. Still, if you want to stick to the reactive approach, the data stream should be listened to instead.
All RxJava2 types provide a subscribe method that "notifies" the source of data that's lazy by nature that here is an observer that wants to receive the data, so all the data processing flow described by use of RxJava2 operators will become alive.
The most painless approach is to change HomeActivity's code to this:
vm.getUsers()
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(userListAdapter::populateWithNewDataSet);
, assuming that adapter will have the mentioned method that will update the UI data set using something like notifyDataSetChanged() (or DiffUtil, for instance) internally.
By doing that the data source is now observed and every time the update is emitted the UI will be repopulated with the most recent data.
P.S.: I've just demonstrated the simplest way to do the thing, but it is up to the developer where to place RxJava-related code: be it ViewModel, Activity, or even some other component. RxJava is a convenient tool to use and it can make complicated asynchronous flow simple, but the problem with RxJava arises when all the code base is dependent on it. The code base can then quickly become unmanageable, fragile and rigid if the tool was used in an improper place.
Adding on #AndreyIlyunin very good answer, You could also use MutableLivedata in your Viewmodel to save the List in the viewmodel as Livedata and observe changes to it in your Activity. This is suggested by Google as a way to maintain MVVM architecture. Something like:
In HomeScreenViewModel.java:
private final MutableLivedata<List<User>> users = new MutableLivedata<>();
public void getUsers() {
return userRepo.getUsers()
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(this::onUsers)
}
private void onUsers(List<> list){
users.setValue(list);
}
public MutableLivedata<List<User>> getUserList(){
return users;
}
In HomeActivity.java, in onCreate() add:
vm.getUserList().observe(this,this::onUserList);
and add following methods to activity:
private void onUserList(List<> list){
userListAdapter = new UserListAdapter(this,list);
}
and then from your activity call:
vm.getUsers();
The getUsers() call is made asynchronously in the background, and you get the userList reactivly.

Adavantage of Retrofit with RxJava externally

AFAAIK, Retrofit uses RxJava internally.Then what is the advantage of integrating Retrofit with RxJava externally like here, if I don't want to filter,sort or modify the data received from api?Does it reduces the time for fetching response from api?In what way does it helps in improving performance of our api calls?
Retrofit started as project before RxJava and you used to retrieve the API via callbacks. Then came RXJava and a more strict integration between the two was possible. So that you change Call<T> with an Observable/Flowable interface, and instead to use a call back into the code you retrieve the result directly exploiting the power of the reactive paradigm.
Please consider you have to specify you are using RXJava when you build Retrofit
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(baseUrl);
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())//here
.addConverterFactory(GsonConverterFactory.create())
.build();
Saying that RXJava implements internally Retrofit is kind of tricky, Retrofit remain indipendent, just RXJava offers some binding code so that you can adapt Retrofit2 to be an Observable.
This code taken from here, explain how to bind the two
public interface UserService {
#POST("/me")
Observable<User> me();
}
// this code is part of your activity/fragment
Observable<User> observable = userService.me();
observable
.observeOn(AndroidSchedulers.mainThread())
.subscribeOn(Schedulers.io())
.subscribe(new Subscriber<User>() {
#Override
public void onCompleted() {
// handle completed
}
#Override
public void onError(Throwable e) {
// handle error
}
#Override
public void onNext(User user) {
// handle response
}
});
Then you ask to many questions, in stackoverflow you get one reply per post.
Just please consider that the advantage of using RXJava and Retrofit integrated are a lot, for instance you have a come much more clean, testable and you do not have to consider concurrency issues. Regarding the performance I get is the same for a normal case.
EDIT:
To understand better when to use RXJAVA+Retrofit and when just Retrofit you can see this post
Outside from that content please consider that is really useful to see all the succesion in a functional way inside a single class, plus you have OnComplete, you can operate any sort of transformation.
Furthermore is much easier to combine multiple calls as here, the advantages are really clear in real life situations,
and also to do testing and maintain the code clean, that just taken alone these two, are two great advantages.
You also may want to explore the new Google Architecture functionalities components with Retrofit, where you can use both RXJava or LiveData

One Class Pattern for All Web API calls

In my app I have a-lot of Web API calls which returns me JSON. I am trying to do this thing simple. I don't want to create AsyncTask in every fragment. I have tried many things but nothing give me the solution how to do this. I need one Class solution in which I call a method with a url argument and get result in calling fragment or activity. Can someone share best practice to do this?
I have tried otto library but It seems it don't fulfill my requirements.
Web communication should not be done in main thread, therefore, some kind of threading is necessary. I think AsyncTask is the easiest way. I suggest creating abstract class, implementing network-stuff, and leave parsing output for child classes. Something like this:
abstract class DownloadJSON extends AsyncTask<...>{
DownloadJSON(List<NameValuePair> httpParams){...}
JSONObject doInBackground(String... urls){... return mJSONObject}
abstract void onPostExecute(JSONObject json);
}
You may override doInBackground for further background parsing or just display contents in onPostExecute.
Please check the library called Retrofit. It turns your REST API into a Java interface and has asynchronous execution of requests. It even converts your JSON response into Java objects.

How to use Mockito to test APIs along Robospice and Retrofit?

I've been following this blog entry which shows how to mock requests with Mockito and Retrofit. The problem is I'm using both along Robospice, which it doesn't require to provide a Callback as parameter on the service interface (as it would be a synchronous call):
#GET("/foo/bar")
User foo(#Query("bar") String baz);
So I cannot intercept the callback on my tests on this way:
Mockito.verify(mockApi).repositories(Mockito.anyString(), cb.capture());
User user = new User();
cb.getValue().success(user, null);
Is any way to achieve this?. Thanks!
Mock the service interface and then script it to return the value you desire.
doReturn(new User()).when(service).foo(anyString());
You can later verify that this method was called.
verify(service).foo(anyString())

How to cancel DefaulHttpClient execution process in multithread

I am developing an android application that rely very much on internet, I retrieve data frequently using this RestClient Class, that wrap some detail on using DefaultHttpClient to do network request.
And I always use different thread to do the HTTP request, I create a class like this:
public class AsyncWorker {
final String SERVER_URL = "http://api.blabla.com";
RestClient client = new RestClient();
public void requestHttp(final String url, final ArrayList<NameValuePair> params, final RequestListener listener) {
new Thread(new Runnable() {
public void run() {
try {
client.setUrl(url);
client.setParams(params);
client.Execute(RestClient.RequestMethod.POST);
String response = client.getResponse();
listener.onComplete(response);
} catch (Exception ex) {
Log.d("LOGIN", ex.getMessage());
}
}
}).start();
}
etc...
So whenever I need to do a HTTP request, I only need to create AsyncWorker object, and provide the RequestListener callback interface.
But the problem is, how can I cancel the HTTP Request when the user press the back/cancel button? and in this case the application still is in one activity, for example I create a dialog, and the user do a request from that dialog, and then back button pressed, the dialog dismissed, and I need to cancel the request on that time.
I had the same issue and was able to find a fix. Here is what I did:
I used CloseableHttpClient along with other related classes, instead of the DefaultHttpClient that by default comes with Android.
These classes are from https://hc.apache.org/downloads.cgi. OR for direcet access: http://apache.mirrors.hoobly.com//httpcomponents/httpclient/binary/httpcomponents-client-4.3.2-bin.tar.gz
With this, calling the abort() method on the Request object will actually halt the connection. However, using this library is not the solution; reason being that Android already has the outdated HTTPCLIENT library inbuilt, and most classes in the library pointed to by the above link would appear to be missing at runtime.
The problem is that both the packages in the above library and the inbuilt org.apache httpclient package have same namespace, and would result in the use of only the inbuilt org.apache classes provided by Android at compilation.
An example of this issue is found here: java.lang.NoSuchFieldError: org.apache.http.message.BasicLineFormatter.INSTANCE.
Thanks to the guys who provided http://code.google.com/p/httpclientandroidlib/ as an option (found in the answer section of java.lang.NoSuchFieldError: org.apache.http.message.BasicLineFormatter.INSTANCE)
Recommendation: one place to actually cancel an http request could be within OnCancel Listener of a progress dialog, instead of the AyncTask's onCancelled() callback method.
The RestClient object your using doesn't expose any interrupt() method of DefaultHttpClient (which is the backing object doing most of the work). Not a problem - the DefaultHttpClient doesn't seem to have any interrupt or abort functionality to expose in the first place.
So, your left with a blocking operation on client.Execute().
Your half way to having a solution - which is to put the blocking operation into a Thread. Where your falling down is your architecture - your using a Thread/Listener setup which doesn't give you alot of wiggle room.
Try switching your anonymous Thread to an AsyncTask. This won't solve the problem of you're client.Execute() from blocking but will allow you to throw away the listener (replacing it with onProgressUpdate() or onPostExecute()).
What this will do is allow you call task.cancel(), signalling to the Task it is no longer needed. This will allow you to reassign a new AsyncTask, orphaning the cancelled task, the orphaned thread will then finish quickly as its able and die quietly while the rest of your application gets on with what it needs to.
((On an unrelated note, "Execute()" is a method and shouldn't be capitalised))
I suggest you take a look at the ClientConnectionManager interface. This allows you to do stuff like releasing a connection, shutting down a connection etc. You may need to enhance the implementation of RestClient though - since your RestClient does not expose the underlying DefaultHttpClient object (from which you can get to the ClientConnectionManager using the getClientConnectionManager() method).
Use the threading primitives. Have a flag running and set it to true initially. Do your REST requests in a while(running) loop.
In your onPause(), set the running flag to false.

Categories

Resources