here is my code:
by this method, I send some data to my API server
if data received successfully success variable will be true inside onResponse method
private boolean success=false;
public boolean commit(){
requestHandler.insertFields(tableName,values).enqueue(new Callback<DatabaseModel>() {
#Override
public void onResponse(Call<DatabaseModel> call,
Response<DatabaseModel> response) {
if (response.isSuccessful())
Log.i("debug8","result is:"+response.body().toString());
else
Log.e("debug8","error in server response:"+response.toString());
success=true;
}
#Override
public void onFailure(Call<DatabaseModel> call, Throwable t) {
Log.e("tempo",t.getMessage());
}
});
return success;//returns false before finishing the request
}
and in my activity i want to check the result like this:
Database db=new Database("cars");
db.put("field1","val1")
.put("field2","val2");
if(db.commit())
Toast.makeText(this, "data inserted successfully", Toast.LENGTH_SHORT).show();
else
Toast.makeText(this, "failed to insert new record", Toast.LENGTH_SHORT).show();
the problem is that always the commit method result is false because code returns false before retrofit enqueue method finishes its job
is it a good idea to make a custom listener or something like that to do this?
thanks in advance
Yes,you need to create listener for this because these calls happen asynchronously that's why it's returning always false.
You can create a interface like below.
public interface RetrofitResponseListener {
void onSuccess();
void onFailure();
}
And pass it as a argument in your method.
public void commit(final RetrofitResponseListener retrofitResponseListener) {
requestHandler.insertFields(tableName, values).enqueue(new Callback<DatabaseModel>() {
#Override
public void onResponse(Call<DatabaseModel> call,
Response<DatabaseModel> response) {
if (response.isSuccessful())
retrofitResponseListener.onSuccess();
else
retrofitResponseListener.onFailure();
}
#Override
public void onFailure(Call<DatabaseModel> call, Throwable t) {
retrofitResponseListener.onFailure();
}
});
}
And finally use this where you like:
private void setListener() {
commit(new RetrofitResponseListener() {
#Override
public void onSuccess() {
}
#Override
public void onFailure() {
}
});
}
Now do anything you want onSuccess or onFailure.
what happens there is the next: the request method is an async task, when you call it, it´ll start working on a second plane and your commit function continues with its sync flow which is return (the false value in this case).
you can try 2 things:
something like this,
public XX(whatever correspond) commit(){
return requestHandler.insertFields(tableName,values).enqueue(new Callback<DatabaseModel>() {
#Override
public void onResponse(Call<DatabaseModel> call,
Response<DatabaseModel> response) {
if (response.isSuccessful())
Log.i("debug8","result is:"+response.body().toString());
else
Log.e("debug8","error in server response:"+response.toString());
return true;
}
#Override
public void onFailure(Call<DatabaseModel> call, Throwable t) {
Log.e("tempo",t.getMessage()); return false;
}
});
}
and fix the if at the other side
or this way
public void commit(){
requestHandler.insertFields(tableName,values).enqueue(new Callback<DatabaseModel>() {
#Override
public void onResponse(Call<DatabaseModel> call,
Response<DatabaseModel> response) {
if (response.isSuccessful())
Log.i("debug8","result is:"+response.body().toString());
else
Log.e("debug8","error in server response:"+response.toString());
Toast.makeText(this, "data inserted successfully", Toast.LENGTH_SHORT).show();
}
#Override
public void onFailure(Call<DatabaseModel> call, Throwable t) {
Toast.makeText(this, "failed to insert new record", Toast.LENGTH_SHORT).show();
}
});}
Related
I've seen a few similar questions but they don't seem to answer my problem exactly. I've got a method that is supposed to return a string. I am using retrofit, but in onresponse, I can't return a string? Below is the code.
public String getInformation(String information, String username) {
String result;
Call<DefaultResponse> call = RetrofitClient.getInstance().getApi().getInformation(information,username);
call.enqueue(new Callback<DefaultResponse>() {
#Override
public void onResponse(Call<DefaultResponse> call, Response<DefaultResponse> response) {
result = response.body().getMsg();
}
#Override
public void onFailure(Call<DefaultResponse> call, Throwable t) {
}
});
return result;
}
The .enqueue method will take time to get the response, so your method will return before onResponse callback gets called.
Try using a callback approach for getInformation method and make it void:
public void getInformation(String information, String username, MyCallback callback) {
Call<DefaultResponse> call = RetrofitClient.getInstance().getApi().getInformation(information,username);
call.enqueue(new Callback<DefaultResponse>() {
#Override
public void onResponse(Call<DefaultResponse> call, Response<DefaultResponse> response) {
result = response.body().getMsg();
callback.success(result);
}
#Override
public void onFailure(Call<DefaultResponse> call, Throwable t) {
callback.failure(t)
}
});
}
With the MyCallback interface:
interface MyCallback {
void success(String result);
void failure(Throwable t);
}
Then you can call the method like this:
getInformation("Information", "Username", new MyCallback() {
#Override
public void success(String result) {
// Use result
}
#Override
public void failure(Throwable t) {
// Display error
}
});
You can use Result as output String wherever you want, as I used it in my adapter class in onBindViewHolder method, simply making object of the class from which string was sent and then calling the method (in which Interface was kept as parameter) & override success and failure method in adapter class and do whatever u want to do with this string......... Thanks a lot #y.allam & #Anonymous Cardinal :):)
I'm using RxAndroid for my app to send a request to the backend and handle the result.
public Observable<Response> getBrands() {
return new Observable<Response>() {
#Override
protected void subscribeActual(Observer<? super Response> observer) {
RequestHelper.GetRequest("getbrands");
}
};
}
public void GetBrands(){
getBrands().subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(new Observer<Response>() {
#Override
public void onSubscribe(Disposable d) {
}
#Override
public void onNext(Response value) {
Log.w("Reactive",value.toString());
Toast.makeText(getActivity(),"Yaaaaay request 5alas",Toast.LENGTH_SHORT).show();
}
#Override
public void onError(Throwable e) {
Log.w("response brands= "+e.toString(),"MyTAG");
}
#Override
public void onComplete() {
}
});
}
RequestHelper.GetRequest("getbrands") is successfully called (Checked backend logs, it's called and returns the response.
the problem is onNext not getting called at all, neither the log or the toast shows up.
Anyone knows why ?
EDIT: i'm using this in a fragment where GetBrands() is called in oncreateview
Just changed my observable function to
public Observable<Response> getBrands() {
return Observable.fromCallable(new Callable<Response>() {
#Override
public Response call() throws Exception {
return RequestHelper.GetRequest("getbrands");
}
});
}
it's working now
I want to start new activity after call and finish 7 difference requests in parallel using retrofit.
Where should I call startActivity() method?
here is my wrong trying.
new Thread(new Runnable() {
#Override
public void run() {
api.method1(args..).enqueue(new Callback<Response1>() {
#Override
public void onResponse(Call<Response1> call, Response<Response1> response) {
//do some things
}
#Override
public void onFailure(Call<Response1> call, Throwable t) {
t.printStackTrace();
}
});
..
..
..
api.method7(args..).enqueue(new Callback<Response7>() {
#Override
public void onResponse(Call<Response7> call, Response<Response7> response) {
//do some things
}
#Override
public void onFailure(Call<Response7> call, Throwable t) {
t.printStackTrace();
}
});
startActivity(new Intent(current.this,next.class));
}).start();
Use Rxjava with Retrofit and then you can do something like (assuming method1,method2 etc return Observable<Response1>, Observable<Response2> etc)
Observable.zip(api.method1, api.method2, ...)
I've an Observable something like this:
#GET("endpoint")
Observable<Something> getSomething();
and Subscriber like this
Subscriber<Something> somethingSubscriber = new Subscriber<Something>() {
public void onCompleted() {
}
public void onError(Throwable e) {
//handle exceptions
}
public void onNext() {
//do something
}
In my OnClickListener associated with a button, i make a subscription
getSomething()
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(somethingSubscriber);
If i don't have an internet connection, onError is called and i do some exception handling. when I press the button again (assume i want to retry), the callback methods do not get called.
I want that onNext / onError callbacks get called everytime I press the button.
There is extention for RxJava. It has a lot of "cool tools", but for handling retrofit errors you can use ResponseOrError class.
So in you case it would looks like:
final PublishSubject<Object> clickSubject = PublishSubject.create();
final Observable<ResponseOrError<Something>> responseOrErrorObservable = clickSubject
.flatMap(new Func1<Object, Observable<ResponseOrError<Something>>>() {
#Override
public Observable<ResponseOrError<Something>> call(Object o) {
return getSomething()
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.compose(ResponseOrError.<Something>toResponseOrErrorObservable());
}
})
.replay(1)
.refCount();
final Observable<Throwable> error = responseOrErrorObservable
.compose(ResponseOrError.<Something>onlyError())
.subscribe(new Action1<Segment>() {
#Override
public void call(Throwable throwable) {
// what to do on error, some toast or what ever yu need
}
});
final Observable<UserInfoResponse> success = responseOrErrorObservable
.compose(ResponseOrError.<Something>onlySuccess())
.subscribe(new Action1<Something>() {
#Override
public void call(Something some) {
// code what to do on success
}
});
And now, into onClick you just need to put clickSubject.onNext(null)
.replay(1).refCount(); needed because there are 2 Observables that uses responseOrErrorObservable, so without it retrofit request will "happens" two times.
You are reusing the same Subscriber. Once you get the onError or a result (so it completes) the subscriber is unsubscribed. Try to pass every time a new subscriber.
use this code
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
getSomething()
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Action1<Something>() {
#Override
public void call(Something something) {
//do something
}
},
new Action1<Throwable>() {
#Override
public void call(Throwable throwable) {
//handle exceptions
}
},
new Action0() {
#Override
public void call() {
}
});
}
});
Addition
or
replace this
Subscriber<Something> somethingSubscriber = new Subscriber<Something>() {
public void onCompleted() {
}
public void onError(Throwable e) {
//handle exceptions
}
public void onNext() {
//do something
}
};
to
Subscriber<String> somethingSubscriber = new Subscriber<String>() {
#Override
public void onCompleted() {
}
#Override
public void onError(Throwable e) {
}
#Override
public void onNext(String s) {
}
};
In my Case onNext() and onError() methods are not getting called because of my model class wrong parsing, I was taking a double object as Integer so NumberFormatException was thrown and nothing was happening after getting the result from retrofit.
I have a fragment where I post request to server. This type of action should be in onResume() method, but I don't want to post request to server every time when I put app on background. Is exist any solution?
request which I want to post
FactoryAPI.getContacts().getContacts(user.getToken()).enqueue(new Callback<ContactsResponse>() {
#Override
public void onResponse(Call<ContactsResponse> call, Response<ContactsResponse> response) {
if(response.isSuccessful()) {
contactList = response.body().getContactsList();
sortList();
progressDialog.dismiss();
setRecyclerView();
}
}
#Override
public void onFailure(Call<ContactsResponse> call, Throwable t) {}
});
In your Fragment class, create a data member of type boolean like,
private boolean isResponseSend;
In your onResume() method,
#Override
public void onResume() {
super.onResume();
if(!isResponseSend)
{
isResponseSend = true;
//your code
FactoryAPI.getContacts().getContacts(user.getToken()).enqueue(new Callback<ContactsResponse>() {
#Override
public void onResponse(Call<ContactsResponse> call, Response<ContactsResponse> response) {
if(response.isSuccessful()) {
contactList = response.body().getContactsList();
sortList();
progressDialog.dismiss();
setRecyclerView();
}
}
#Override
public void onFailure(Call<ContactsResponse> call, Throwable t) {}
});
}
}
According to
https://developer.android.com/guide/components/fragments.html#Creating
you can post the request on
https://developer.android.com/reference/android/app/Fragment.html#onAttach(android.content.Context)
Use some variable like flag, and initialise it in the onCreate. and based on the flag, you can handle the request.