OkHttp and Retrofit, refresh token with concurrent requests - android

In my application I implemented Retrofit to call WebServices and I'm using OkHttp to use Interceptor and Authenticator. Some requests need token, and I have implemented Authenticator interface to handle the refresh (following the official documentation). But I have the following issue : time to time in my app I have to call more than one request at once. Because of that, for one of them I will have the 401 error.
Here is my code for request calls :
public static <S> S createServiceAuthentication(Class<S> serviceClass, boolean hasPagination) {
final String jwt = JWT.getJWTValue(); //Get jwt value from Realm
if (hasPagination) {
Gson gson = new GsonBuilder().
registerTypeAdapter(Pagination.class, new PaginationTypeAdapter()).create();
builder =
new Retrofit.Builder()
.baseUrl(APIConstant.API_URL)
.addConverterFactory(GsonConverterFactory.create(gson));
}
OkHttpClient.Builder httpClient =
new OkHttpClient.Builder();
httpClient.addInterceptor(new AuthenticationInterceptor(jwt));
httpClient.authenticator(new Authenticator() {
#Override
public Request authenticate(Route route, Response response) throws IOException {
if (responseCount(response) >= 2) {
// If both the original call and the call with refreshed token failed,
// it will probably keep failing, so don't try again.
return null;
}
if (jwt.equals(response.request().header("Authorization"))) {
return null; // If we already failed with these credentials, don't retry.
}
APIRest apiRest = createService(APIRest.class, false);
Call<JWTResponse> call = apiRest.refreshToken(new JWTBody(jwt));
try {
retrofit2.Response<JWTResponse> refreshTokenResponse = call.execute();
if (refreshTokenResponse.isSuccessful()) {
JWT.storeJwt(refreshTokenResponse.body().getJwt());
return response.request().newBuilder()
.header(CONTENT_TYPE, APPLICATION_JSON)
.header(ACCEPT, APPLICATION)
.header(AUTHORIZATION, "Bearer " + refreshTokenResponse.body().getJwt())
.build();
} else {
return null;
}
} catch (IOException e) {
return null;
}
}
});
builder.client(httpClient.build());
retrofit = builder.build();
return retrofit.create(serviceClass);
}
private static int responseCount(Response response) {
int result = 1;
while ((response = response.priorResponse()) != null) {
result++;
}
return result;
}
The issue is simple, the first request will refresh the token successfully but others will failed because they will try to refresh a token already refreshed. The WebService return an error 500. Is there any elegant solution to avoid this ?
Thank you !

If I understand your issue, some requests are sent while the token is being updated, this gives you an error.
You could try to prevent all the requests while a token is being updated (with a 'synchronized' object) but this will not cover the case of an already sent request.
Since the issue is difficult to avoid completely, maybe the right approach here is to have a good fallback behavior. Handling the error you get when you've made a request during a token update by re-running the request with the updated token for instance.

Write Service.
public class TokenService extends Service {
private static final String TAG = "HelloService";
private boolean isRunning = false;
OkHttpClient client;
JSONObject jsonObject;
public static String URL_LOGIN = "http://server.yoursite";
String phone_number, password;
#Override
public void onCreate() {
Log.i(TAG, "Service onCreate");
jsonObject = new JSONObject();
client = new OkHttpClient();
SharedPreferences pref_phone = getSharedPreferences("Full_Phone", MODE_PRIVATE);
phone_number = pref_phone.getString("Phone", "");
SharedPreferences pref_password = getSharedPreferences("User_Password", MODE_PRIVATE);
password = pref_password.getString("Password", "");
isRunning = true;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.i(TAG, "Service onStartCommand");
try {
jsonObject.put("phone_number", phone_number);
jsonObject.put("password", password);
} catch (JSONException e) {
e.printStackTrace();
}
new Thread(new Runnable() {
#Override
public void run() {
for (; ; ) {
try {
Thread.sleep(1000 * 60 * 2);
} catch (Exception e) {
}
if (isRunning) {
AsyncTaskRunner myTask = new AsyncTaskRunner();
myTask.execute();
} else {
Log.d("CHECK__", "Check internet connection");
}
}
}
}).start();
return Service.START_STICKY;
}
#Override
public IBinder onBind(Intent arg0) {
Log.i(TAG, "Service onBind");
return null;
}
#Override
public void onDestroy() {
isRunning = false;
Log.i(TAG, "Service onDestroy");
}
String post(String url, JSONObject login) {
try {
MediaType mediaType = MediaType.parse("application/json");
RequestBody body = RequestBody.create(mediaType, login.toString());
okhttp3.Request request = new okhttp3.Request.Builder()
.url(url)
.post(body)
.build();
okhttp3.Response response = client.newCall(request).execute();
try {
return response.body().string();
} catch (IOException e) {
e.printStackTrace();
}
} catch (Exception e) {
e.printStackTrace();
}
return "";
}
String response;
private class AsyncTaskRunner extends AsyncTask<String, String, String> {
#Override
protected void onPreExecute() {
}
#Override
protected String doInBackground(String... params) {
try {
response = post(
URL_LOGIN, jsonObject);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
#Override
protected void onPostExecute(String result) {
Log.d("---OKHTTP---", response);
}
}
}

Related

Android - Skipping frames when trying to login to server from application. (async)

public class AppApi extends AsyncTask<String, Void, String> {
private OkHttpClient client;
private Request request;
private MediaType JSON;
private String URL;
private RequestBody body;
public AppApi(JSONObject obj) {
client = new OkHttpClient();
JSON = MediaType.parse("application/json; charset=utf-8");
URL = "http://serverapi.domain.com/user/login";
Log.d("Information",obj.toString());
body = RequestBody.create(JSON, obj.toString());
request = new Request.Builder()
.url(URL)
.post(body)
.build();
}
#Override
protected String doInBackground(String... strings) {
// execute fonksiyonu cagrilarak calistirilir
try {
Response response = client.newCall(request).execute();
return response.body().string();
} catch (Exception ex) {
Log.e("doInBackground()", ex.getMessage());
return null;
}
}
protected void onProgressUpdate(Integer... progress) {
// setProgressPercent(progress[0]);
}
protected void onPostExecute(Long result) {
// showDialog("Downloaded " + result + " bytes");
}
}
btnLogin.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
login();
}
}
LoginActivity.Java below.
private void login() {
JSONObject data = new JSONObject();
try {
data.put("email", "email");
data.put("password", "pass");
} catch (JSONException e) {
}
AppApi api = new AppApi(data);
try {
String result = api.execute().get();
Log.d("login()", result);
} catch (Exception e) {
e.printStackTrace();
}
}
So the problem with the application is that we can't properly login to our https server. Android Studio says it is skipping frames.
I/Choreographer: Skipped 77 frames! The application may be doing too
much work on its main thread.
When we try to enter the wrong password intentionally, it skips even more frames.(200ish)
I think we did most of the coding correctly on the Async task side. How can we check the return value? How can we solve the problem?
Try to put the build request into the background thread as well .i.e
private JSONObject obj;
public AppApi(JSONObject obj) {
this.obj = obj;
}
#Override
protected String doInBackground(String... strings) {
// execute fonksiyonu cagrilarak calistirilir
try {
client = new OkHttpClient();
JSON = MediaType.parse("application/json; charset=utf-8");
URL = "http://serverapi.domain.com/user/login";
Log.d("Information",obj.toString());
body = RequestBody.create(JSON, obj.toString());
request = new Request.Builder()
.url(URL)
.post(body)
.build();
Response response = client.newCall(request).execute();
return response.body().string();
} catch (Exception ex) {
Log.e("doInBackground()", ex.getMessage());
return null;
}
}

OnResponse body is null and return 500 error code

I have a request and response Json. When i submit the request then it will show response in my app. Url shows postman request and response [1]: https://i.stack.imgur.com/UW4jo.png I tried below code but the problem is facing that i got the correct JSONObject response but at the debug time when cursor goes in onResponse method of retrofit then body shows null and 500 error code. But in postman works everything fine.I lost 2 days with this problem.Please help me.
APIService
#Headers("Content-Type: application/json")
#POST("api/Conveyance/SubmitConveyanceRequest")
Call<List<ModelFileInsertID>> saveTravelRequestDetails(#Body JSONObject submitRequest);
calling api
public void btnOnClickSave() {
JSONObject jsonObject = new JSONObject();
try {
jsonObject.put(AppConstants.SaveKeyData.KEY_REIMBURSEMENT_HDR_ID, "");
jsonObject.put(AppConstants.SaveKeyData.KEY_PROCESS_ID, 1);
jsonObject.put(AppConstants.SaveKeyData.KEY_INSTANCE_ID, "");
jsonObject.put(AppConstants.SaveKeyData.KEY_REQUEST_NO, requestNo);
jsonObject.put(AppConstants.SaveKeyData.KEY_RAISED_BY, raisedBy.getText().toString());
jsonObject.put(AppConstants.SaveKeyData.KEY_RAISED_DATE, "");
jsonObject.put(AppConstants.SaveKeyData.KEY_APPROVER, selectedItemText);
jsonObject.put(AppConstants.SaveKeyData.KEY_APPROVER_DATE, "");
jsonObject.put(AppConstants.SaveKeyData.KEY_TRAVEL_TOTAL_AMOUNT, textViewTotal.getText().toString());
jsonObject.put(AppConstants.SaveKeyData.KEY_STATUS, "");
jsonObject.put(AppConstants.SaveKeyData.KEY_IS_DEVIATED, "");
jsonObject.put(AppConstants.SaveKeyData.KEY_IS_DEVIATED_REASON, "");
jsonObject.put(AppConstants.SaveKeyData.KEY_PENDING_WITH, "");
jsonObject.put(AppConstants.SaveKeyData.KEY_RAISED_BY_NAME, "");
jsonObject.put(AppConstants.SaveKeyData.KEY_APPROVED_BY_NAME, "");
jsonObject.put(AppConstants.SaveKeyData.KEY_REMARK, remark.getText().toString());
jsonObject.put(AppConstants.SaveKeyData.KEY_APPROVER_REMARK, "");
jsonObject.put(AppConstants.SaveKeyData.KEY_PERFORMER, "");
jsonObject.put(AppConstants.SaveKeyData.KEY_POSTING_CODE, "");
jsonObject.put(AppConstants.SaveKeyData.KEY_STEP_ACTION, stepAction);
jsonObject.put(AppConstants.SaveKeyData.KEY_DETAILS, getAddDetails());
jsonObject.put(AppConstants.SaveKeyData.KEY_DOCUMENT_LIST, getFilePath());
jsonObject.put(AppConstants.SaveKeyData.KEY_AUDITTRAIL, getAuditTrailDetails());
} catch (JSONException e) {
e.printStackTrace();
}
if (Utility.getInstance().isNetworkConnected(getParent())) {
Call<List<ModelFileInsertID>> call = HDFCService.setSaveTravelRequestDetails().saveTravelRequestDetails(jsonObject);
call.enqueue(new Callback<List<ModelFileInsertID>>() {
#Override
public void onResponse(Call<List<ModelFileInsertID>> modelInsertID, Response<List<ModelFileInsertID>> response) {
AlertDialog.Builder mAlertDialog = new AlertDialog.Builder(getActivity());
try {
List<ModelFileInsertID> insertIDs = response.body();
if (insertIDs.get(0).getIsSuccess() == true) {
mAlertDialog.setMessage(insertIDs.get(0).getMessage());
//progressBar.dismiss();
} else {
// progressBar.dismiss();
mAlertDialog.setMessage(AppConstants.SaveKeyData.DATANOTSAVE);
}
} catch (Exception e) {
e.printStackTrace();
}
mAlertDialog.setTitle(AppConstants.AppText.HDFC);
mAlertDialog.setPositiveButton(AppConstants.AppText.OK, new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
getParent().clearBackStack();
//getParent().openHomeFragment();
//progressBar.dismiss();
}
});
mAlertDialog.show();
}
#Override
public void onFailure(Call<List<ModelFileInsertID>> call, Throwable t) {
Toast.makeText(getActivity(), AppConstants.AppText.SERVICE_ERROR, Toast.LENGTH_LONG).show();
}
});
}
}
public JSONArray getAddDetails() {
JSONArray detailsArray = new JSONArray();
JSONObject jsonObj;
for (int i = 0; i < travelRequestAddDetailses.size(); i++) {
jsonObj = new JSONObject();
try {
jsonObj.put(AppConstants.SaveKeyData.KEY_REIMBURSEMENT_DTL_ID, 0);
jsonObj.put(AppConstants.SaveKeyData.KEY_REIMBURSEMENT_HDR_ID, 0);
jsonObj.put(AppConstants.SaveKeyData.KEY_TRAVEL_DATE, travelRequestAddDetailses.get(i).getTravellingDate());
jsonObj.put(AppConstants.SaveKeyData.KEY_TRAVEL_FROM, travelRequestAddDetailses.get(i).getTravellingFrom());
jsonObj.put(AppConstants.SaveKeyData.KEY_TRAVEL_TO, travelRequestAddDetailses.get(i).getTravellingTo());
jsonObj.put(AppConstants.SaveKeyData.KEY_TRAVEL_DESCRIPTION, travelRequestAddDetailses.get(i).getTravellingDesc());
jsonObj.put(AppConstants.SaveKeyData.KEY_TRAVEL_AMOUNT, travelRequestAddDetailses.get(i).getTravellingAmount());
detailsArray.put(jsonObj);
} catch (IndexOutOfBoundsException e) {
e.printStackTrace();
} catch (JSONException e) {
e.printStackTrace();
}
}
return detailsArray;
}
ModelFileInsertID pojo class
public class ModelFileInsertID {
#SerializedName("Message")
#Expose
private String message;
#SerializedName("Request")
#Expose
private String request;
#SerializedName("IsSuccess")
#Expose
private Boolean isSuccess;
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public String getRequest() {
return request;
}
public void setRequest(String request) {
this.request = request;
}
public Boolean getIsSuccess() {
return isSuccess;
}
public void setIsSuccess(Boolean isSuccess) {
this.isSuccess = isSuccess;
}}
Update
public class HDFCService {
private static OkHttpClient client = new OkHttpClient.Builder()
.connectTimeout(10, TimeUnit.MINUTES)
.readTimeout(10, TimeUnit.MINUTES)
.build();
private static final Retrofit RETROFIT = new Retrofit.Builder()
.baseUrl(AppConstants.AppText.SERVICE_BASE_URL).client(client)
.addConverterFactory(GsonConverterFactory.create())
.build();
private static final TravelRequestService TRAVEL_REQUEST_SERVICE = RETROFIT.create(TravelRequestService.class);
public static TravelRequestService setSaveTravelRequestDetails(){
return TRAVEL_REQUEST_SERVICE;
}
}
Try to pass the JSONObject as RequestBody
RequestBody requestBody = RequestBody.create(MediaType.parse("application/json; charset=utf-8"), jsonObject);
Call<List<ModelFileInsertID>> call = HDFCService.setSaveTravelRequestDetails().saveTravelRequestDetails(requestBody);
API Service Interface:
#POST("api/Conveyance/SubmitConveyanceRequest")
Call<List<ModelFileInsertID>> saveTravelRequestDetails(#Body RequestBody body);

okhttp3 how to return value from async GET call

I am implementing Helper class in Android studio to service Activity
public void getLastId()
{
//init OkHttpClient
OkHttpClient client = new OkHttpClient();
//backend url
Request request = new Request.Builder()
.url("http://192.168.1.102:8080/aquabackend/public/customers/lastid")
.build();
client.newCall(request).enqueue(new Callback() {
#Override
public void onFailure(Call call, IOException e) {
}
#Override
public void onResponse(Call call, Response response) throws IOException {
String jsonData = response.body().string();
try {
JSONObject jobject = new JSONObject(jsonData);
String id = jobject.getString("id");
//increment current id +1
String last_id = String.valueOf(Integer.parseInt(id)+1);
Log.i("new id", last_id);
} catch (Exception e) {
e.printStackTrace();
}
//Log.i("ok", response.body().string());
}
});
My function call in activity class
Helper helper = new Helper();
helper.getLastId();
//I want to get method to return lastId and then manipulate with the data
How can I make method return value of the id?
As it is an asynchronous process you won't be able to return a value from the method itself. However, you can use a callback to provide you the value when the asynchronous process has been completed. Below is an example of how you might want to do this.
public interface GetLastIdCallback {
void lastId(String id);
}
You would modify getLastId as follows:
public void getLastId(GetLastIdCallback idCallback) {
...
String last_id = String.valueOf(Integer.parseInt(id)+1);
idCallback.lastId(last_id);
...
}
Your Helper class usage would now look like this:
Helper helper = new Helper();
helper.getLastId(new GetLastIdCallback() {
#Override
public void lastId(String id) {
// Do something with your id
}
});
I'd suggest making your callback a bit more generic than I have suggested above. It could look like this:
public interface GenericCallback<T> {
void onValue(T value);
}
...
Helper helper = new Helper();
helper.getLastId(new GenericCallback<String>() {
#Override
public void onValue(String value) {
// Do something
}
});
If you used an interface like above you would be able to work with any return type.
Create a interface.
public interface Result{
void getResult(String id);
}
Now, pass interface to method as parameter.
Helper helper = new Helper();
helper.getLastId(new Result(){
#Override
void getResult(String id){
}
});
And In your method :
public void getLastId(final Result result)
{
//init OkHttpClient
OkHttpClient client = new OkHttpClient();
//backend url
Request request = new Request.Builder()
.url("http://192.168.1.102:8080/aquabackend/public/customers/lastid")
.build();
client.newCall(request).enqueue(new Callback() {
#Override
public void onFailure(Call call, IOException e) {
}
#Override
public void onResponse(Call call, Response response) throws IOException {
String jsonData = response.body().string();
try {
JSONObject jobject = new JSONObject(jsonData);
String id = jobject.getString("id");
//increment current id +1
String last_id = String.valueOf(Integer.parseInt(id)+1);
Log.i("new id", last_id);
result.getResult(last_id);
} catch (Exception e) {
e.printStackTrace();
}
//Log.i("ok", response.body().string());
}
});
You have to create interface for it.
public interface getResponse {
void getJsonResponse(final String id);
}
In Your code :
public void getLastId(fianl getResponse response)
{
//init OkHttpClient
OkHttpClient client = new OkHttpClient();
//backend url
Request request = new Request.Builder()
.url("http://192.168.1.102:8080/aquabackend/public/customers/lastid")
.build();
client.newCall(request).enqueue(new Callback() {
#Override
public void onFailure(Call call, IOException e) {
}
#Override
public void onResponse(Call call, Response response) throws IOException {
String jsonData = response.body().string();
try {
JSONObject jobject = new JSONObject(jsonData);
String id = jobject.getString("id");
//increment current id +1
String last_id = String.valueOf(Integer.parseInt(id)+1);
Log.i("new id", last_id);
if(response!=null){
response.getJsonResponse(last_id)
}
} catch (Exception e) {
e.printStackTrace();
}
//Log.i("ok", response.body().string());
}
});
In Activity :
public class HomeActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Helper helper = new Helper();
helper.getLastId(new getResponse(){
#Override
void getJsonResponse(String id){
}
});
}}
}

Logical error in getting a text from URL with okHttp

Im trying to write an app to read a text file from an url like this "http://chemvaaj.xzn.ir/test/words.txt"
it seems right but it doesn't return what it should :\
here's my code :
public String DL (){
OkHttpHandler handler = new OkHttpHandler();
String text ="";
try {
text = handler.execute().get();
if (text!= null && text.length()> 0){
System.out.println("not empty");
return text;
}
} catch (Exception e) {
text= "empty !!";
}
return text;
}
and here is OkHttpHandler class :
public class OkHttpHandler extends AsyncTask<Void, Void, String> {
private final String DB_URL = "http://chemvaaj.xzn.ir/test/words.txt";
OkHttpClient httpClient = new OkHttpClient();
#Override
protected String doInBackground(Void... params) {
Request.Builder builder = new Request.Builder();
builder.url(DB_URL);
Request request = builder.build();
try {
Response response = httpClient.newCall(request).execute();
return response.body().toString();
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
#Override
protected void onPostExecute(String s) {
super.onPostExecute(s);
Log.e("ANSWER", "" + s);
}
}
and here's my logcat after call DL() function :
10-28 00:23:25.167 17288-17288/erfan.bagheri.chemvaaj E/ANSWER﹕ com.squareup.okhttp.internal.http.RealResponseBody#423bc6b8
You should replace return response.body().toString(); by return response.body().string();
Please refer to my following working sample code:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mTextView = (TextView) findViewById(R.id.textView);
new GetFileRequest().execute();
}
...
private class GetFileRequest extends AsyncTask<Void, Void, String> {
#Override
protected String doInBackground(Void... voids) {
try {
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
.url("http://chemvaaj.xzn.ir/test/words.txt")
.build();
Response response = client.newCall(request).execute();
return response.body().string();
} catch (IOException e) {
e.printStackTrace();
return e.toString();
}
}
#Override
protected void onPostExecute(String result) {
super.onPostExecute(result);
if (mTextView != null && result != null) {
mTextView.setText(result);
}
}
}
Here is the screenshot
Hope this helps!
First of all, please check how an AsyncTask works. Here's the official, easy to understand how-to-use.
Then you'll find that the method execute() returns the task itself, not the resulting String object.
It seems that OkHttpClient's returned Response object can be transformed to string in the following way:
response.body().toString();
Just one more hint: please avoid returning null in any method, it's considered very bad practice.
OkHttpClient is used in the wrong way(Suppose you want to use async). OkHttp is a full featured Http client library and has Asynchronous requests implemented in itself.
So there is no need to Android AsyncTask.
Here is the right way:
private final OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
.url("http://chemvaaj.xzn.ir/test/words.txt")
.build();
client.newCall(request).enqueue(new Callback() {
#Override public void onResponse(Response response) throws IOException {
if (!response.isSuccessful()) throw new IOException("Unexpected code " + response);
System.out.println(response.body().string());
}
#Override public void onFailure(Request request, Throwable throwable) {
throwable.printStackTrace();
}
});
I am not familiar with OkHttpClient but from the log I am guessing that the body response is a complex object that does not have a toString() that will show you a human readable response. You will probably have to print a specific member of that object to get your readable response.
try this
OkHttpClient and callback:
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
.url("http://publicobject.com/helloworld.txt")
.build();
client.newCall(request).enqueue(new Callback() {
#Override
public void onFailure(Call call, IOException e) {
e.printStackTrace();
}
#Override
public void onResponse(Call call, Response response) throws IOException {
if (!response.isSuccessful()) throw new IOException("Unexpected code " + response);
// Headers responseHeaders = response.headers();
// for (int i = 0; i < responseHeaders.size(); i++) {
// System.out.println(responseHeaders.name(i) + ": " + responseHeaders.value(i));
// }
// System.out.println(response.body().string());
InputStream in = response.body().byteStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(in));
String result, line = reader.readLine();
result = line;
while((line = reader.readLine()) != null) {
result += line;
}
System.out.println(result);
}
});

HttpResponse.getEntity() NetworkOnMainThreadException [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
NetworkOnMainThreadException
For a long time, I've been using generic code that does http requests in an AsyncTask. The AsyncTask returns an HttpResponse object. Everything worked great and the GUI thread never froze or anything.
Now, suddenly, this creates a NetworkOnMainThreadException:
serverResponse.getEntity().getContent();
What the heck?? Why is getEntity() considered networking?? In my mind, that line merely converts a response to an inputstream and should not need a network connection. Who made this decision? WHY did they decide this should be networking?
The async task:
public class AsyncHttpTask extends AsyncTask<HttpRequestInfo, Integer, HttpRequestInfo> {
public AsyncHttpTask() {
super();
}
protected HttpRequestInfo doInBackground(HttpRequestInfo... params) {
HttpRequestInfo rinfo = params[0];
try{
HttpClient client = new DefaultHttpClient();
HttpResponse resp = client.execute(rinfo.getRequest());
rinfo.setResponse(resp);
}
catch (Exception e) {
rinfo.setException(e);
}
return rinfo;
}
#Override
protected void onPostExecute(HttpRequestInfo rinfo) {
super.onPostExecute(rinfo);
rinfo.requestFinished();
}
Callback interface:
public interface HttpCallback {
public void onResponse(HttpResponse serverResponse);
public void onError(Exception e);
}
HttpRequestInfo:
public class HttpRequestInfo {
private HttpUriRequest request_;
private HttpCallback callback_;
private Exception exception_;
private HttpResponse response_;
public HttpRequestInfo(HttpUriRequest request, HttpCallback callback) {
super();
request_ = request;
callback_ = callback;
}
public HttpUriRequest getRequest() {
return request_;
}
public void setRequest(HttpUriRequest request) {
request_ = request;
}
public HttpCallback getCallback() {
return callback_;
}
public void setCallback(HttpCallback callback) {
callback_ = callback;
}
public Exception getException() {
return exception_;
}
public void setException(Exception exception) {
exception_ = exception;
}
public HttpResponse getResponse() {
return response_;
}
public void setResponse(HttpResponse response) {
response_ = response;
}
public void requestFinished(){
if(exception_ != null){
callback_.onError(exception_);
}
else {
callback_.onResponse(response_);
}
}
}
Then I use jackson to convert the json response to an object. That's this is where the exception occurs:
#Override
public <T> T handleResponse(HttpResponse serverResponse, Class<T> typeOfResponse) {
ObjectMapper mapper = new ObjectMapper();
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
T responseObject = null;
try {
responseObject = mapper.readValue(serverResponse.getEntity().getContent(),typeOfResponse); //THIS LINE IS EVIL
} catch (JsonParseException e) {
throw new ARException("Couldn't handle the response because the http response contained malformed json.",e);
} catch (JsonMappingException e) {
throw new ARException("Mapping the json response to the response object " + typeOfResponse + " failed.",e);
} catch (IllegalStateException e) {
throw new ARException("Couldn't convert the http response to an inputstream because of illegal state.",e);
} catch (IOException e) {
throw new ARException("Couldn't convert the http response to an inputstream.",e);
}
return responseObject;
}
Because you must work with network in separate thread and not main. You can use AsyncTask or Thread + Handler. If you are using AsyncTask all work with network you must perform in doInBackground part.

Categories

Resources