I am trying to make an asynchronous request to the server, which should return me true or false. But the problem is that the function first returns false, and only then the retrofit function is triggered. How can I get the value I need while maintaining the speed of program execution?
My code:
private static boolean find;
public boolean checkAccountByPhone(String phone){
Log.d("dbHandler", "function started...");
DbHandler.getApi().checkAccountByPhone(phone).enqueue(new Callback<String>() {
#Override
public void onResponse(Call<String> call, Response<String> response) {
Log.d("dbHandler", "data is: "+response.body().equals("true"));
// return response.body().equals("true");
Log.d("dbHandler", "sent!");
}
#Override
public void onFailure(Call<String> call, Throwable t) {
Log.d("dbHandler", t.getMessage());
}
});
Log.d("dbHandler", "returned: "+DbHandler.find);
return DbHandler.find; // always false???
}
You can modify logic in Java, this code is for reference to avoid callback.
fun checkAccountByPhone(phone: String):String{
viewModelScope.launch(Dispatchers.IO) {
val response : Response<String> = try {
DbHandler.getApi().checkAccountByPhone(phone)
} catch (ex: Exception) {
ex.logException()
null
}
//you can check response.body() here and can post either response.body() or DbHandler.find
_yourLiveData.post(response.body() or DbHandler.find)
}
Related
I'm doing async http call such way
public CompletableFuture<String> doPost(String path, String json) {
CompletableFuture<String> result = new CompletableFuture<>();
Request request = new Request.Builder().url(this.address + path).post(RequestBody.create(json, JSON)).build();
httpClient.newCall(request).enqueue(new Callback() {
#Override
public void onFailure(#NotNull Call call, #NotNull IOException e) {
result.completeExceptionally(new TerminationException());
}
#Override
public void onResponse(#NotNull Call call, #NotNull Response response) throws IOException {
result.complete(response.body().string());
}
});
}
But it is possible that response will have one of the codes that I'll need to retry and the code should be
#Override
public void onResponse(#NotNull Call call, #NotNull Response response) throws IOException {
if (!retries.contains(responce.code()) {
result.complete(response.body().string());
} else {
// Do retry here
}
}
In retry I want to call doPost recursively and use it's return value as a result of initial call.
So it returns some completable future, how complete initial CF with it's result in async way (without doint .get())?
Thanks.
You can use delegation, e.g.
public CompletableFuture<String> doPost(String path, String json) {
CompletableFuture<String> result = new CompletableFuture<>();
doPostImpl(this.address + path, json, result, 10);
return result;
}
private void doPostImpl(
String url, String json, CompletableFuture<String> result, int maxRetries) {
Request request = new Request.Builder()
.url(url).post(RequestBody.create(json, JSON)).build();
httpClient.newCall(request).enqueue(new Callback() {
#Override
public void onFailure(#NotNull Call call, #NotNull IOException e) {
result.completeExceptionally(new TerminationException());
}
#Override
public void onResponse(
#NotNull Call call, #NotNull Response response) throws IOException {
if(maxRetries <= 0 || !retries.contains(response.code())) {
result.complete(response.body().string());
} else {
doPostImpl(url, json, result, maxRetries - 1);
}
}
});
}
The front-end method delegates to a method receiving the target future. When retrying, the implementation method is invoked again with the same future. Therefore, there is no need to transfer results from one future to another.
Taking the question literally, you can transfer the result of a future to another using
future2.whenComplete((value,throwable) -> {
if(throwable != null) future1.completeExceptionally(throwable);
else future1.complete(value);
});
but this could create a dependency chain as long as the number of retries. As shown above, there is no need for that.
All the thing working fine but how to call the the user{first_name,last_name,email}
You have to call a retrofit method in this way,
#FormUrlEncoded
#POST("employer/login")
Call<ResponseModelEmplyrLogin> loginEmployer(
#Field("data") String data);
public void loginEmployer(String data, final MyApiCallbackEmplyrLogin<EmployrDataBean> callback) {
ApiInterface apiService = ApiClient.createService();
Call<ResponseModelEmplyrLogin> call = apiService.loginEmployer(data);
call.enqueue(new Callback<ResponseModelEmplyrLogin>() {
#Override
public void onResponse(Call<ResponseModelEmplyrLogin> call, Response<ResponseModelEmplyrLogin> response) {
//Write your code
}
#Override
public void onFailure(Call<ResponseModelEmplyrLogin> call, Throwable t) {
//Write your code
}
});
}
Check out this link https://www.androidtutorialpoint.com/networking/retrofit-android-tutorial/ ...I think this will be helpful
i'm having issues getting Retrofit 2.0 to send POST requests to Python-Django.
Here's my Retrofit method.
public void sendNetworkRequest(User user) {
//Cria instância retrofit
final Retrofit retrofit = new Retrofit.Builder()
.baseUrl("http://127.0.0.1:8000/")
.addConverterFactory(GsonConverterFactory.create())
.build();
UserService services = retrofit.create(UserService.class);
Call<User> call = services.createAccount(user);
call.enqueue(new Callback<User>() {
#Override
public void onResponse(Call<User> call, Response<User> response) {
Toast.makeText(CadastrarActivity.this, "Você foi cadastrado com sucesso!", Toast.LENGTH_SHORT).show();
}
#Override
public void onFailure(Call<User> call, Throwable t) {
CheckConnection checkConnection = new CheckConnection();
if (checkConnection.equals(null)){
Toast.makeText(CadastrarActivity.this, "Conecte-se a internet!", Toast.LENGTH_SHORT).show();
}
else {
Log.e("heurys", t.getMessage());
System.out.println(t.getStackTrace());
Toast.makeText(CadastrarActivity.this, "Algo deu errado!", Toast.LENGTH_SHORT).show();
}
}
});
}
Here's my interface method used in the Rest call:
public interface UserService {
#POST("rest/cadastro")
Call<User> createAccount(#Body User user);
}
And here's my traceback error:
04-03 12:58:43.726 18692-18692/com.example.ccyrobuosi.estudos E/heurys: Failed to connect to /127.0.0.1:8000
In advance, my Python code works just fine, i used Postman to test it, and its getting the requests properly.
I am building a Login system for an Android app. I am using OkHttp to connect to my server and get a JSON response.
I have defined a class with the login return data (right now just a true/false response based on whether the user exists in the database), and then written the code to connect to the server, as shown below:
class UserLogin {
boolean status;
public void setStatus(boolean status) {
this.status = status;
}
public boolean getStatus() {
return status;
}
}
public class ClientServerInterface {
OkHttpClient client = new OkHttpClient();
boolean login(Request request) {
final Gson gson = new Gson();
client.newCall(request).enqueue(new Callback() {
UserLogin login;
#Override
public void onFailure(Call call, IOException e) {
}
#Override
public void onResponse(Call call, Response response) throws IOException {
login = gson.fromJson(response.body().charStream(), UserLogin.class);
login.setStatus(login.status);
}
});
// need to return the boolean response (status) here
}
}
The code which passes the Request variable to the login method works perfectly. I want login to return a boolean response so that I can pass that to other methods in other classes.
However, because the UserLogin object is defined in the callback I can't access it in the parent method. I have made a getStatus method but not sure how to use it properly to get the status in the main login method.
The code which passes the Request variable to the login method works
perfectly. I want login to return a boolean response so that I can
pass that to other methods in other classes.
you can't. enqueue executes the code in Async way. You don't know when the callback is invoked. What you could do is to add the Callback as parameter to your login method. E.g.
boolean login(Request request, final Callback callback) {
and either pass it to enqueue,
client.newCall(request).enqueue(callback);
or call the callback manually. E.g.
#Override
public void onResponse(Call call, Response response) throws IOException {
if (callback != null) {
callback.onResponse(call, response);
}
}
in both cases the caller of login will receive the callback on the provided object and, accordingly to the content it receives, can decide wha actions undertake
You can do this using a SynchronousQueue:
final SynchronousQueue<Boolean> queue = new SynchronousQueue<>();
client.newCall(request).enqueue(new Callback() {
UserLogin login;
#Override
public void onFailure(Call call, IOException e) {
queue.put(false);
}
#Override
public void onResponse(Call call, Response response) throws IOException {
queue.put(true);
}
});
return queue.take();
Add loginStatus variable to class like below and one more to indicate login operation completion.
public class ClientServerInterface {
OkHttpClient client = new OkHttpClient();
private boolean loginStatus = false;
private boolean isLoginOperationDone = false;
boolean login(Request request) {
final Gson gson = new Gson();
client.newCall(request).enqueue(new Callback() {
UserLogin login;
#Override
public void onFailure(Call call, IOException e) {
}
#Override
public void onResponse(Call call, Response response) throws IOException {
login = gson.fromJson(response.body().charStream(), UserLogin.class);
loginStatus = login.setStatus(login.status);
isLoginOperationDone = true;
}
});
// need to return the boolean response (status) here
while( !isLoginOperationDone )
{
//not to do anything.
}
return loginStatus;
}
}
Note that this might be a little hacky but will do solve your problem.
The way to go is with AsyncTask. Override the doInBackground method to perform the http requests and get the result by overriding the onPostExecute method.
Read more here: http://developer.android.com/reference/android/os/AsyncTask.html
An even better way to go is to run a background Service for all your API calls.
I'm working with retrofit and I want to know which is the generated url.
I've tried with setRequestInterceptor and setProfiler.
The last one gives me the url but not query params... so It's not the complete one.
Thanks
This works for me:
service.yourRequest(params...).enqueue(new Callback<ResponseBody>() {
#Override
public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
Log.d(TAG, call.request().url().toString()); // here
}
#Override
public void onFailure(Call<ResponseBody> call, Throwable t) {
}
});
For those who want to know
RestAdapter restAdapter = new RestAdapter.Builder()
.setLogLevel(RestAdapter.LogLevel.BASIC)
.setEndpoint(Metadata.CURRENT_SERVER)
.setRequestInterceptor(requestInterceptor)
.build();
call.request().url(), where call is an instance of retrofit2.Call