I currently am using AsynchttpClient to make a POST request to a web server. When I debug, I can clearly see the JSON that is being returned. However, when I set the variable to a static method in the ECUser class, I always get that the ECUser.getCurrentUser() is null which shouldn't be correct. Since all the methods in ECUser is static, I don't see what my problem is.
The same thing happens if I try to assign a jsonobject to the responseBody from the asynchttpclient call. After the anonymous class terminates, the jsonobject is always null for some reason.
private void attemptLogin(){
RequestParams params = new RequestParams();
params.put("email", userEmail.getText().toString());
params.put("password", userPass.getText().toString());
ECApiManager.post(Constants.loginAPI, params, new JsonHttpResponseHandler() {
#Override
public void onSuccess(int statusCode, Header[] headers, JSONObject responseBody) {
//called when response code 200
try{
ECUser.setCurrentUser(new ECUser(responseBody));
Log.d("login", responseBody.toString());
}catch(JSONException e){
e.printStackTrace();
}
}
});
if (ECUser.getCurrentUser() == null) {
((OnLoginListener) getActivity()).loginSuccessful(false);
}
This is my ECUser Class.
public class ECUser {
private static ECUser currentUser;
private static String userToken;
private String firstName;
private String lastName;
private static String userID;
private JSONObject jObject;
private boolean loginSuccess;
public ECUser(JSONObject data) throws JSONException {
this.jObject = data;
try {
this.loginSuccess = Boolean.parseBoolean(this.jObject.getString("success"));
if (this.loginSuccess) {
this.userToken = this.jObject.getString("token");
this.firstName = this.jObject.getJSONObject("user").getString("firstname");
this.lastName = this.jObject.getJSONObject("user").getString("lastname");
this.userID = this.jObject.getJSONObject("user").getString("id");
}
} catch (JSONException e) {
e.printStackTrace();
}
}
/**
* Method that refreshes the state of the current user by calling the API again.
*/
public static void refreshCurrentUser() {
RequestParams params = new RequestParams();
params.put("token", userToken);
//Gotta put in user ID too.
params.put("user_id", userID);
// TODO: This should only call https://edu.chat/api/user, #JACOB
ECApiManager.get(Constants.refreshUserAPI, params, new JsonHttpResponseHandler() {
#Override
public void onSuccess(int statusCode, Header[] headers, JSONObject responseBody) {
try {
ECUser.setCurrentUser(new ECUser(responseBody));
} catch (JSONException e) {
e.printStackTrace();
}
}
});
}
// Static
public static ECUser getCurrentUser() {
return ECUser.currentUser;
}
public static void setCurrentUser(ECUser user) {ECUser.currentUser = user;}
public static String getUserToken() {
return ECUser.userToken;
}
// Dynamic
public String getLastName() {
return this.lastName;
}
public String getFirstName() {
return this.firstName;
}
public boolean getLoginSuccessful() {
return this.loginSuccess;
}
}
You treat the login attempt in ECApiManager#post as a synchronous method, e.g. one that returns once the attempt is completed. And so, right after calling post you check the current user.
But, clearly from the name of the http client (AsynchttpClient) you can understand that the post is an asynchronous call, which means that the HTTP request will be performed in the background, and once completed successfully, it will call your JsonHttpResponseHandler#onSuccess method. This means that although the ECApiManager#post will return immediately, the current user is not set yet.
When programming in asynchronous mode, you need to handle events as they occur, and not just call everything in sequence. If you do want to make this synchronous, you will need either to use a synchronous http client (such as HttpClient or HttpUrlConnection), or add a Semaphore to wait for your HTTP request to be completed.
For example:
private void attemptLogin(){
Semaphore sema = Semaphore(1);
sema.acquire();
// ....
ECApiManager.post(Constants.loginAPI, params, new JsonHttpResponseHandler() {
#Override
public void onSuccess(int statusCode, Header[] headers, JSONObject responseBody) {
//called when response code 200
try{
ECUser.setCurrentUser(new ECUser(responseBody));
Log.d("login", responseBody.toString());
}catch(JSONException e){
e.printStackTrace();
}
finally {
sema.release();
}
}
});
sema.acquire();
if (ECUser.getCurrentUser() == null) {
((OnLoginListener) getActivity()).loginSuccessful(false);
}
Note, that if you use a semaphore you will need to release it upon failure as well.
Related
Hy!
I want to make some http calls to a restserver from my android client. I created a class for rest calls.
I followed the http://loopj.com/android-async-http/ description:
My question is that how can I send back anything from onSucces() method? For example I have the following function:
public class RestController {
public String getName() throws JSONException {
TwitterRestClient.get(url, null, new JsonHttpResponseHandler() {
#Override
public void onSuccess(int statusCode, Header[] headers, JSONObject response) {
String name;
try {
name = response.getString("name");
} catch (JSONException e) {
e.printStackTrace();
}
}
});
}
}
How can I return the name to getName function?
function () {
...
String name = restController.getName();
...
do something with the name
Thank you very much!
I will apreciate any kind of help!
I have Authentication class which have method Auth with 2 arguments.
after calling that method a volley request generated and response catch through other function because of aSync. that object is a Static object and accessible in other class but that shows null always after making object or initializing it onCreate of activity.
Let check my Authenticate class:
public class Authenticate {
private static final String URL = "http://allskkc/zaigham/idsrs_authentication.php";
public static JSONObject finalresult;
public Authenticate() {
}
public static void Auth(String IEMI, String PIN) throws TimeoutException {
final JSONObject params = new JSONObject();
finalresult = new JSONObject();
RequestQueue queue = Volley.newRequestQueue(Splash.context);
try {
params.put("iemi", IEMI);
params.put("pin", PIN);
} catch (JSONException e) {
e.printStackTrace();
}
Log.e("params to server", params.toString());
JsonObjectRequest jsOBJRequest = new JsonObjectRequest
(Request.Method.POST, URL, params, new Response.Listener<JSONObject>() {
#Override
public void onResponse(JSONObject response) {
Log.e("response from server", response.toString());
ftn(response);
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
Log.e("Response error",error.toString());
}
});
queue.add(jsOBJRequest);
}
public static void ftn(JSONObject jsonObject) {
finalresult = jsonObject;
Log.e("as", "Response in ftn() = " + finalresult.toString());
}
}
final finalresult have value when I call that Auth() method but in my Login class it shows {}
let check my method call:
try {
Authenticate.Auth("358607051299527","1122");
} catch (TimeoutException e) {
e.printStackTrace();
}
Log.e("as","Prefrences Saved");
Log.e("as","My final result = "+Authenticate.finalresult.toString());
I attached my Log.e Image that may help more to understand.
You can see in your logs that application tries to get the result of request before request is done. Network request is asynchronous, it is done on background thread.
You should get the result after request is finished in some sort of callback.
I'm trying to do implement login using a ASP.Net Web Api into an Android application.
What I have so far are functions that work, just that I want to make the login request kind of synchronous instead of asynchronous.
I'm using Android Asynchronous Http Client like they say on their website.
public class ApiInterface {
public static final String ApiURL = "http://******/api/";
private static AsyncHttpClient client = new AsyncHttpClient();
public static void get4Login(String url, RequestParams params, AsyncHttpResponseHandler responseHandler) {
client.get(getAbsoluteUrl(url), params, responseHandler);
}
private static String getAbsoluteUrl(String relativeUrl) {
return ApiURL + relativeUrl;
}
}
And I have this function in LoginActivity:
private boolean doLogIn(String user, String pass) {
boolean result = false;
if (user.trim().isEmpty() || pass.trim().isEmpty()) {
return false;
}
RequestParams params = new RequestParams();
params.add("user", user);
params.add("pass", pass);
ApiInterface.get4Login("Auth", params, new TextHttpResponseHandler() {
#Override
public void onFailure(int statusCode, Header[] headers, String responseString, Throwable error) {
Toast.makeText(MyApp.getContext(), "Error: " + error.getMessage(), Toast.LENGTH_LONG).show();
}
#Override
public void onSuccess(int statusCode, Header[] headers, String responseString) {
//***Here I want to set the doLogIn() function result depending on the response from the server;***
Toast.makeText(MyApp.getContext(), "Lista sesizari incarcata!", Toast.LENGTH_LONG).show();
}
});
return result;
}
Is there any way to do this?
On your MyTextHttpResponseHandler class should define a variable named result and set type is boolean,default to false,then define a method to get the result value,like
public boolean getResult(){return this.result;}
then you can change the result value on onSuccess and onFailure method.
Next your doLogIn method will like this
private boolean doLogIn(String user, String pass) {
//boolean result = false;
if (user.trim().isEmpty() || pass.trim().isEmpty()) {
return false;
}
RequestParams params = new RequestParams();
params.add("user", user);
params.add("pass", pass);
MyTextHttpResponseHandler myTextHttpResponseHandler = new MyTextHttpResponseHandler(this);
ApiInterface.get4Login("Auth", params, myTextHttpResponseHandler);
return myTextHttpResponseHandler.getResult();
}
I'm trying to use setUseSynchronousMode on loopj to wait for results of http call before continuing in one case. I tried:
AsyncHttpResponseHandler responseHandler = new AsyncHttpResponseHandler() {
#Override
public void onSuccess(int statusCode, Header[] headers, byte[] response) {
Log.d("TEST", "Got results");
}
};
AsyncHttpClient client = new AsyncHttpClient();
responseHandler.setUseSynchronousMode(true);
client.get("http://www.google.com", responseHandler);
Log.d("TEST", "Don't want to get here until after getting results");
But the result is:
07-11 19:48:05.631 D/TEST﹕ Don't want to get here until after getting results
07-11 19:48:05.814 D/TEST﹕ Got results
Am I misunderstanding what setUseSynchronousMode should do?
You should have used SyncHttpClient instead of AsyncHttpClient. setUseSynchronousMode doesn't have the desired effect for AsyncHttpClient.
To have synchronous version of AsyncHttpClient with an ability to cancel it, I do everything on the main thread. Previously I was running it in AsyncTask and as soon as AsyncHttpClient.post() was called, the AsyncTask would finish and I was unable to keep track the AsyncHttpClient instance.
SyncHttpClient didn't allow me to cancel the uploading so I knew I had to use AsyncHttpClient and make appropriate changes.
Following is my class to upload a file which uses AsyncHttpClient and allows cancellation:
public class AsyncUploader {
private String mTitle;
private String mPath;
private Callback mCallback;
public void AsyncUploader(String title, String filePath, MyCallback callback) {
mTitle = title;
mPath = filePath;
mCallback = callback;
}
public void startTransfer() {
mClient = new AsyncHttpClient();
RequestParams params = new RequestParams();
File file = new File(mPath);
try {
params.put("title", mTitle);
params.put("video", file);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
mClient.setTimeout(50000);
mClient.post(mContext, mUrl, params, new ResponseHandlerInterface() {
#Override
public void sendResponseMessage(HttpResponse response) throws IOException {
HttpEntity entity = response.getEntity();
if (entity != null) {
InputStream instream = entity.getContent();
// TODO convert instream to JSONObject and do whatever you need to
mCallback.uploadComplete();
}
}
#Override
public void sendProgressMessage(int bytesWritten, int bytesTotal) {
mCallback.progressUpdate(bytesWritten, bytesTotal);
}
#Override
public void sendFailureMessage(int statusCode, Header[] headers, byte[] responseBody, Throwable error) {
mCallback.failedWithError(error.getMessage());
}
});
}
/**
* Cancel upload by calling this method
*/
public void cancel() {
mClient.cancelAllRequests(true);
}
}
This is how you can run it:
AsyncUploader uploader = new AsyncUploader(myTitle, myFilePath, myCallback);
uploader.startTransfer();
/* Transfer started */
/* Upon completion, myCallback.uploadComplete() will be called */
To cancel the upload, just call cancel() like:
uploader.cancel();
I'm using the Android Asynchronous Http Client. My code looks like this and is working fine.
DataUtil.post("RegisterUser", params, new AsyncHttpResponseHandler() {
#Override
public void onSuccess(String answer) {
// initialize variables
JSONObject json = new JSONObject();
String message = null;
try {
// turn string into JSONObject
json = new JSONObject(answer);
message = json.getString("message");
} catch (JSONException e) {
Log.e("ERROR", e.getMessage());
}
// registration was successful
if (message.equals("success")) {
// forward to login page
} else {
// error
}
}
});
I implemented a static HTTP Client. My server returns this JSON data {"message":"success"}. I do not want to treat it as a String and cast it back to JSON. But when I change it to public void onSuccess(JSONObject answer) eclipse tells me
The method onSuccess(JSONObject) of type new
AsyncHttpResponseHandler(){} must override or implement a supertype
method
The correct method signature would be this public void onSuccess(int statusCode, Header[] headers, JSONObject response) or any of the other available methods in the JsonHttpResponseHandler class