I have something like this
Retrofit retrofit =new retrofit2.Retrofit.Builder()
.baseUrl("URL")
.addConverterFactory(GsonConverterFactory.create())
.build();
requestService = retrofit.create(RequestInterface.class);
call = requestService.getData(page);
call.enqueue(new Callback<List<Cats>>() {
#Override
public void onResponse(Call<List<Cats>> call, Response<List<Cats>> response) {
....
}
#Override
public void onFailure(Call<List<Cats>> call, Throwable t) {
...
}
});
However when i want to get the second page, when i make a request for the second page within the same class, retrofit callback methods is not getting called.
call = requestService.getData(page); // page incremnted
call and requestService is globally defined
in Retrofit, each "call" instance is linked to one API call (single network request) and cannot be reused. You can reuse your RetrofitSerive instance, but for every new API call you will have to create a new Call object and enqueue it separately
You can use a generic response and use an url each time.
#GET
Call<Generic<T>> getUsers(#Url String url);
Related
I am trying to send an io.reactivex.Flowable from a Spring RestController to an Android application that uses Retrofit and Rxjava. If I use the browser to check what the Rest endpoint returns, I get a series of values as expected but in Android I get only one value and then it calls the onComplete method. What am I missing?
Spring Controller:
#GetMapping("/api/reactive")
public Flowable<String> reactive() {
return Flowable.interval(1, TimeUnit.SECONDS).map(sequence -> "\"Flowable-" + LocalTime.now().toString() + "\"");
}
Retrofit repository:
#GET("reactive")
Flowable<String> testReactive();
Main service:
public useReactive() {
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(Values.BASE_URL)
.addConverterFactory(JacksonConverterFactory.create())
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.build();
userRepository = retrofit.create(UserRepository.class);
Flowable<String> reactive = userRepository.testReactive();
Disposable disp = reactive.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribeWith(new ResourceSubscriber<String>() {
#Override
public void onNext(String s) {
logger.log(Level.INFO, s);
Toast.makeText(authActivity, s, Toast.LENGTH_SHORT).show();
}
#Override
public void onError(Throwable t) {
t.printStackTrace();
}
#Override
public void onComplete() {
logger.log(Level.INFO, "Completed");
Toast.makeText(authActivity, "Completed", Toast.LENGTH_SHORT).show();
}
});
}
Upon calling the useReactive() method, I get only one value "Flowable-..." and then "Completed".
Even though the Retrofit service has return type Flowable<String>, calling testReactive() will only make one HTTP call on the Android device.
The type Flowable is merely for compatibility, in practice it will end up being a Flowable that emits a single value and then terminates.
This is just how Retrofit works.
You would need to find another solution if you want to continually receive new values that are being emitted from the server, perhaps GRPC or polling the server.
I have an application in Android, it sends several data in short time. Aprox. 2500 request.
This process is very time-consuming.
What advice can you give me to improve the time?
Thanks
You can use multiple Thread to send data to the server in the background.
If you are updating UI component after the execution use AsyncTask. But you have to run AsyncTask parallelly. You can do that by AsyncTaskCompat.executeParallel(Your AsyncTask);
If you wish to send data even your app closed. You can use service.
I'd recommend using Retrofit. It handles a lot of threading issues you might be struggling with.
Here's an example from their website.
You'd create an interface for the API you're looking to receive:
public interface GitHubService {
#GET("users/{user}/repos")
Call<List<Repo>> listRepos(#Path("user") String user);
}
You build a retrofit class
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://api.github.com/")
.build();
GitHubService service = retrofit.create(GitHubService.class);
And finally you get a call object:
Call<List<Repo>> repos = service.listRepos("octocat");
Consuming the call object requires enqueueing a Callback. Here's an example using a different Retrofit service (TaskService in this case):
TaskService taskService = ServiceGenerator.createService(TaskService.class);
Call<List<Task>> call = taskService.getTasks();
call.enqueue(new Callback<List<Task>>() {
#Override
public void onResponse(Call<List<Task>> call, Response<List<Task>> response) {
if (response.isSuccessful()) {
// tasks available
} else {
// error response, no access to resource?
}
}
#Override
public void onFailure(Call<List<Task>> call, Throwable t) {
// something went completely south (like no internet connection)
Log.d("Error", t.getMessage());
}
}
Source
I can't get the data outside onResponse in Restrofit
this is my code
List<Categorie> categorylist=new ArrayList<>();
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(baseUrl)
.addConverterFactory(GsonConverterFactory.create())
.build();
final CategoryApi api = retrofit.create(CategoryApi.class);
Call<List<Categorie>> categoryCall = api.categories();
categoryCall.enqueue(new Callback<List<Categorie>>() {
#Override
public void onResponse(Call<List<Categorie>> call, Response<List<Categorie>> response) {
categorylist = (List<Categorie>)response.body();
Log.i("success","Inside "+categorylist.toString());
// here i get the data
}
#Override
public void onFailure(Call<List<Categorie>> call, Throwable t) {
System.out.println("Erreur");
}
});
Log.i("success","Outside "+categorylist.toString());
// here i get null
i've tried making categorylist volatile and static and it didn't work
It appears you're trying to access categorylist immediately after calling categoryCall.enqueue. enqueue is an asynchronous operation which will not complete before the next line ( containing categorylist.toString()) is executed.
Try calling another method where you've left the comment "here i get the data"
public void onResponse(/*...*/ response) {
categorylist = (List<Categorie>)response.body();
Log.i("success","Inside "+categorylist.toString());
// here i get the data
businessLogic(categorieslist);
}
private void businessLogc(List<Categorie> categories) {
myView.showCategories(categories); // or whatever you're doing with data
}
You know, http request is a process that require time, so it should be done asynchronously. Fortunately retrofit handle everything for us.
What you need to do, is when we get response from OnResponse, you need to update your current view, for example if you're using recyclerview, there is recyclerview.notifyDataSetChanged() method.
If you want to get the result from beginning. I'm suggest you call the enqueue method in other activity or somewhere else, and then when you get the result, save it into sqlite database.
And then when you open CategoryActivity load it from database.
You can add refresh button to call the enqueue again to update the database.
I've setup retrofit 2.1 and it is not making calls to my api at all. I just setup a lamp stack and made my ip publicly accessible. I'm trying to send information via a POST to my php script which would add data to my db. For some reason, retrofit will not make the call to my api... I'm not sure what I'm doing wrong.
#POST("/sendInformation.php")
Call<JSONObject> sendUserInfo(#Body JSONObject userViewModel);
OkHttpClient.Builder client = new OkHttpClient.Builder();
HttpLoggingInterceptor logging = new HttpLoggingInterceptor(message -> Log.d(TAG, message));
logging.setLevel(HttpLoggingInterceptor.Level.BASIC);
client.addInterceptor(logging);
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(BASE_URL)
.client(client.build())
.addConverterFactory(JacksonConverterFactory.create())
.build();
UserInformationService userService = retrofit.create(UserInformationService.class);
Call<JSONObject> call = userService.sendUserInfo(jsonObject);
call.enqueue(new Callback<JSONObject>() {
#Override
public void onResponse(Call<JSONObject> call, Response<JSONObject> response) {
Toast.makeText(HomeActivity.this, response.body().toString(), Toast.LENGTH_SHORT).show();
}
#Override
public void onFailure(Call<JSONObject> call, Throwable t) {
}
});
I tried to add logging but it won't make the call so I can't even see the logging. Anyone have any ideas?
EDIT: The BASE_URL I'm using is my public IP. I just forwarded my ports so it's accessible. I tried doing a POST on hurl.it and it works fine. It's only retrofit not working. I've also tried this with an asyncTask and httpURLConnection and it also works. I must be missing something really minor...
Call<JSONObject> call = userService.sendUserInfo(jsonObject);
This line is not enough. The Call<T> object represents an 'intent' of a call rather than the operation itself, and you need to execute it by calling one of two methods on the object: execute and enqueue.
Execute works in a blocking manner and will return your JSONObject through the response.getBody() method:
Response<JSONObject> response = call.execute();
Enqueue works asynchronously and will provide your JSONObject through the callback object - if call is successful, onResponse method will be called with your response as a call parameter.
call.enqueue(new Callback<JSONObject>() {
#Override
public void onResponse(Call<JSONObject> call, Response<JSONObject> response) {
}
#Override
public void onFailure(Call<JSONObject> call, Throwable t) {
}
});
I have some problems using retrofit as my web communication interface against a php webservice contained in a worpress website - upon a call for one of the JSON API methods in the WP site I get an SSL exception on my android client even though I run over http and not https.
Here is my code -
public class RestApi {
private static final String API_URL = "https://tmc.co.nf/api";
private SmokeTalkRest service;
interface SmokeTalkRest {
#FormUrlEncoded
#POST("/get_nonce")
void getNonce(#Field("controller") String controller, #Field("method") String method, Callback<String> callback);
}
public RestApi() {
// Create a very simple REST adapter which points the GitHub API
// endpoint.
RestAdapter restAdapter = new RestAdapter.Builder()
.setServer(API_URL).build();
// Create an instance of our GitHub API interface.
service = restAdapter.create(SmokeTalkRest.class);
}
public void getNonceForMethod(Method method, Callback<String> callback) {
service.getNonce("user", method.name(), callback);
}
}
The get nonce is called upon a button click, did someone already bumped into that?
I believe the issue you are having is your trying to call retrofit but not using the async version. The callback is probably the easiest to use.
#GET("/user/{id}")
void listUser(#Path("id") int id, Callback<User> cb);
RestAdapter restAdapter = new RestAdapter.Builder()
.setServer("baseURL")
.build();
ClientInterface service = restAdapter.create(ClientInterface.class);
Callback callback = new Callback() {
#Override
public void success(Object o, Response response) {
//do something
}
#Override
public void failure(RetrofitError retrofitError) {
}
};
service.listUser(1, callback);
How to implement an async Callback using Square's Retrofit networking library
Android now requires you to do any webrequests async otherwise it will error out.
Also, retorfit will convert/parse the object for you so you dont have to. It saves time when it comes to creating async tasks and setting up the parsing. It also give a nice standard to go by when doing requests as well.