I want to use OkHttp library for networking in Android.
I started with the simple post example as written in their website:
public static final MediaType JSON = MediaType.parse("application/json; charset=utf-8");
OkHttpClient client = new OkHttpClient();
String post(String url, String json) throws IOException {
RequestBody body = RequestBody.create(JSON, json);
Request request = new Request.Builder()
.url(url)
.post(body)
.build();
Response response = client.newCall(request).execute();
return response.body().string();
}
With this call:
String response = post("http://www.roundsapp.com/post", json);
This call ends with NetworkOnMainThreadException.
I could wrap the call with an AsyncTask, but as far as I understand from the examples, the OkHttp library should have already taken care of that..
Am I doing something wrong?
You should use OkHttp's async method.
public static final MediaType JSON = MediaType.parse("application/json; charset=utf-8");
OkHttpClient client = new OkHttpClient();
Call post(String url, String json, Callback callback) {
RequestBody body = RequestBody.create(JSON, json);
Request request = new Request.Builder()
.url(url)
.post(body)
.build();
Call call = client.newCall(request);
call.enqueue(callback);
return call;
}
And then your response would be handled in the callback (OkHttp 2.x):
post("http://www.roundsapp.com/post", json, new Callback() {
#Override
public void onFailure(Request request, Throwable throwable) {
// Something went wrong
}
#Override public void onResponse(Response response) throws IOException {
if (response.isSuccessful()) {
String responseStr = response.body().string();
// Do what you want to do with the response.
} else {
// Request not successful
}
}
});
Or OkHttp 3.x/4.x:
post("http://www.roundsapp.com/post", "", new Callback() {
#Override
public void onFailure(Call call, IOException e) {
// Something went wrong
}
#Override
public void onResponse(Call call, Response response) throws IOException {
if (response.isSuccessful()) {
String responseStr = response.body().string();
// Do what you want to do with the response.
} else {
// Request not successful
}
}
});
Take a look at their recipes for more examples: http://square.github.io/okhttp/recipes/
According to the OkHttp docs:
It supports both synchronous blocking calls and async calls with callbacks.
Your example is on main thread and Android since version 3.0 throws that exception if you try to do network calls on main thread
Better option is to use it together with retrofit and Gson:
http://square.github.io/retrofit/
https://code.google.com/p/google-gson/
Here are the examples:
http://engineering.meetme.com/2014/03/best-practices-for-consuming-apis-on-android/
http://heriman.net/?p=5
If you follows these steps to implement OKHTTP, then definitely you'll call multiple API on multiple screen by applying only two lines of code
UpdateListener updateListener = new UpdateListener(HitAPIActivity.this, baseHTTPRequest);
updateListener.getJsonData();
Step 1:
baseHTTPRequest = new BaseHTTPRequest();
// baseHTTPRequest.setURL("https://api.geonames.org/citiesJSON?north=44.1&south=-9.9&east=-22.4&west=55.2&lang=de&username=demohttps://api.geonames.org/citiesJSON?north=44.1&south=-9.9&east=-22.4&west=55.2&lang=de&username=demo");
baseHTTPRequest.setURL("http://jsonparsing.parseapp.com/jsonData/moviesDemoItem.txt");
baseHTTPRequest.setRequestCode(reqType);
baseHTTPRequest.setCachedRequired(true);
UpdateListener updateListener = new UpdateListener(HitAPIActivity.this, baseHTTPRequest);
updateListener.executeRequest();
Step 2 : Create a request class
/**
* Created by Deepak Sharma on 4/7/16.
* This is a HTTP request class which has the basic parameters.
* If you wants to add some more parameters, please make a subclass of that class
* and add with your subclass. Don't modify this class.
*/
public class BaseHTTPRequest<T> {
private Context context;
private String URL;
private int requestCode;
private List<T> listParameters;
private String header;
private boolean isCachedRequired;
public Context getContext() {
return context;
}
public void setContext(Context context) {
this.context = context;
}
public void setURL(String URL) {
this.URL = URL;
}
public String getURL() {
return URL;
}
public int getRequestCode() {
return requestCode;
}
public void setRequestCode(int requestCode) {
this.requestCode = requestCode;
}
public List<T> getListParameters() {
return listParameters;
}
public void setListParameters(List<T> listParameters) {
this.listParameters = listParameters;
}
public String getHeader() {
return header;
}
public void setHeader(String header) {
this.header = header;
}
public boolean isCachedRequired() {
return isCachedRequired;
}
public void setCachedRequired(boolean cachedRequired) {
isCachedRequired = cachedRequired;
}
}
step 4 : Create a listener class
import android.util.Log;
import com.google.gson.Gson;
import java.io.IOException;
import dxswifi_direct.com.wifidirectcommunication.base.model.request.BaseHTTPRequest;
import okhttp3.Call;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Callback;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
/**
* Created by Deepak Sharma on 4/7/16.
* #email : dpsharma.sharma1#gmail.com
* This is a Simple java class which will help you for HTTP request/response and it will
* throw the response to your correspondance activity.
*/
public class UpdateListener {
private OnUpdateViewListener onUpdateViewListener;
OkHttpClient okHttpClient = new OkHttpClient();
BaseHTTPRequest mRequestModel;
private String mURL = null;
private Request mRequest = null;
public interface OnUpdateViewListener {
void updateView(String responseString, boolean isSuccess,int reqType);
}
public UpdateListener(OnUpdateViewListener onUpdateView, final BaseHTTPRequest requestModel) {
this.mRequestModel = requestModel;
this.onUpdateViewListener = onUpdateView;
if (requestModel.isCachedRequired())
{
/*File httpCacheDirectory = new File(requestModel.getContext().getCacheDir(), "responses");
Cache cache = null;
cache = new Cache(httpCacheDirectory, 10 * 1024 * 1024);
if (cache != null) {
okHttpClient.setCache(cache);
}*/
}
/*mURL = null;
if (requestModel.getListParameters()!=null && requestModel.getListParameters().size()>0)
{
HttpUrl.Builder urlBuilder = HttpUrl.parse(requestModel.getURL()).newBuilder();
List<RequestParameter> requestParameters = requestModel.getListParameters();
for (int i=0; i<requestParameters.size();i++)
{
urlBuilder.addQueryParameter(requestParameters.get(i).getKey(),requestParameters.get(i).getValue());
}
mURL = urlBuilder.build().toString();
}
else
{
mURL = requestModel.getURL();
}*/
mURL = requestModel.getURL();
if (mRequestModel.getListParameters()!=null && mRequestModel.getListParameters().size()>1)
{
MediaType JSON = MediaType.parse("application/json; charset=utf-8");
mRequest = new Request.Builder()
.url(mURL)
.post(RequestBody.create(JSON, new Gson().toJson(BaseHTTPRequest.class)))
.build();
}
else
{
mRequest = new Request.Builder()
.url(mURL)
.build();
}
}
public void executeRequest()
{
Call call = okHttpClient.newCall(mRequest);
call.enqueue(new Callback() {
#Override
public void onFailure(Call call, IOException e) {
e.printStackTrace();
onUpdateViewListener.updateView(NetworkException.getErrorMessage(e), false, mRequestModel.getRequestCode());
}
#Override
public void onResponse(Call call, Response response) throws IOException {
if (!response.isSuccessful()) {
// You can also throw your own custom exception
throw new IOException("Unexpected code " + response);
} else {
Log.i("Response:",response.toString());
Log.i("Response body:",response.body().toString());
Log.i("Response message:",response.message());
onUpdateViewListener.updateView(response.body().string(),true, mRequestModel.getRequestCode());
}
// do something wih the result
}
});
}
}
step 5 : From the activity you requesting, implement listener
public class HitAPIActivity extends AppCompatActivity implements View.OnClickListener, UpdateListener.OnUpdateViewListener{
#Override
public void updateView(final String responseString, boolean isSuccess, int reqType) {
if (isSuccess)
{
if (!responseString.contains("failure")
&& !responseString.contains("Error")) {
// Handle request on the basis of Request Type.
switch (reqType) {
case ApiConstants.GET_CONTACTS:
break;
default:
break;
}
}
}
}
Related
From Android, I'm trying to request a simple POST-API that responses with a simple JSON object.
Say, I have a simple API (1.1.1.1/testApi) that respons with a JSON object that contains:
status: status value
name: name value
Calling the API using Postman works like a charm, so I assume that my API was fine.
I already tried some of the links below:
AsyncTask: there is no example on how to call the CallApi object and parse the API address (e.g. URL), so there is always an error when I try to invoke the object.
Apache HTTP Client: as the link said, nearly all of the answer are deprecated for Android 6.0
Retrofit: seems usable, but I can't find a proper example to use this in my case
I did take my time to search solutions regarding this, but afaik there is no "easy" way to call a POST-API.
Is there any simple method that takes an URL input, then returns a JSON object?
Let me know if this was a duplicated question.
Thanks in advance.
Hello I Have working Retrofit Example try it on your manner
Let's start
1) Gradle
compile 'com.google.code.gson:gson:2.2.4'
compile 'com.squareup.okhttp:okhttp:2.4.0'
compile 'com.squareup.retrofit:retrofit:2.0.0-beta2'
compile 'com.squareup.retrofit:converter-gson:2.0.0-beta2'
compile 'com.squareup.okhttp3:logging-interceptor:3.0.1'
2) Interface
public interface ServiceInterface {
#GET(HttpConstants.USERDATAJSON)
Call<ListData>taskData(#Query("method")String method,#Query("stdID")int stdID);
}
3) Service Class
public class ServiceClass {
static ServiceInterface serviceInterface;
// public static final String baseUrl= HttpConstants.BASE_URL_GEONAME;
public static final String baseUrl= HttpConstants.baseUrl;
public static ServiceInterface connection(){
if(serviceInterface==null){
HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
OkHttpClient client = new OkHttpClient();
client.interceptors().add(new Interceptor() {
#Override
public Response intercept(Chain chain) throws IOException {
Response response=chain.proceed(chain.request());
return response;
}
});
Retrofit retrofit = new Retrofit.Builder()
.client(client)
.addConverterFactory(GsonConverterFactory.create())
.baseUrl(baseUrl)
.build();
serviceInterface=retrofit.create(ServiceInterface.class);
}
return serviceInterface;
}
}
4) Calling the method from activity
public void getTaskData(){
ServiceInterface serviceInterface=ServiceClass.connection();
Call<ListData> call=serviceInterface.taskData("getAllUsersSimple",0);
call.enqueue(new Callback<ListData>() {
#Override
public void onResponse(Response<ListData> response, Retrofit retrofit) {
Log.v("###Response",""+response.toString());
if(response.isSuccess()){
listData=response.body();
dataList=listData.getData();
printStudentDetails(dataList);
}
}
#Override
public void onFailure(Throwable t) {
Log.v("###Failure"," Message"+t.getMessage());
}
});
}
5) The Pojo
public class ListData {
#SerializedName("data")
#Expose
private List<DataPojo> data = null;
#SerializedName("code")
#Expose
private Integer code;
#SerializedName("message")
#Expose
private String message;
public List<DataPojo> getData() {
return data;
}
public void setData(List<DataPojo> data) {
this.data = data;
}
public Integer getCode() {
return code;
}
public void setCode(Integer code) {
this.code = code;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}
public class DataPojo {
#SerializedName("user_id")
#Expose
private String userId;
#SerializedName("user_name")
#Expose
private String userName;
#SerializedName("user_age")
#Expose
private String userAge;
public String getUserId() {
return userId;
}
public void setUserId(String userId) {
this.userId = userId;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getUserAge() {
return userAge;
}
public void setUserAge(String userAge) {
this.userAge = userAge;
}
}
You can create your pojo using this link
http://www.jsonschema2pojo.org/
For more reference visit the link
https://github.com/pratikvyas1991/NetworkingExample/tree/master/app
AsyncTask Example
Personally I also prefer Retrofit/Volley depending on the project need.
If you want to set the header to you (testApi) Rest API.(Basic Authorization)
String credentials = email + ":" + password;
String basicAuth = "Basic " + new String(new Base64().encode(credentials.getBytes()));
connection.setRequestProperty ("Authorization", basicAuth);
connection..setRequestProperty("Content-Language", "en-US");
Note:
Network operations/call cannot be done in the main thread. You need to run it from another thread, asynchronous task or an intent service
All UI operation should be done onPostExecute,onPreExecute
Call AsyncTask where you want
The below code may help you.
import android.app.Activity;
import android.os.AsyncTask;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.Toast;
import org.json.JSONObject;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.util.HashMap;
import java.util.Map;
public class MainActivity extends AppCompatActivity {
String TEST_URL="http://172.16.68.4:8080/testApi";
Activity activity;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
activity=MainActivity.this;
new PostAsyncTask().execute();
}
private class PostAsyncTask extends AsyncTask<String,Void,JSONObject> {
#Override
protected void onPreExecute() {
super.onPreExecute();
}
#Override
protected JSONObject doInBackground(String... params) {
String value="test";
Map postData = new HashMap<>();
postData.put("key",value);
return post(TEST_URL,postData);
}
#Override
protected void onPostExecute(JSONObject response) {
super.onPostExecute(response);
//All your UI operation can be performed here
//Response string can be converted to JSONObject/JSONArray like
try {
Toast.makeText(activity, String.format("%s : %s",response.getString("status"),response.getString("name")), Toast.LENGTH_LONG).show();
} catch (Exception e) {
e.printStackTrace();
Toast.makeText(activity, String.format("%s","Something went wrong!!!!!!"), Toast.LENGTH_LONG).show();
}
System.out.println(response);
}
}
/**
* Method allows to HTTP POST request to the server to send data to a specified resource
* #param REQUEST_URL URL of the API to be requested
* #param params parameter that are to be send in the "body" of the request Ex: parameter=value&also=another
* returns response as a JSON object
*/
public JSONObject post(String REQUEST_URL,Map<String, Object> params) {
JSONObject jsonObject = null;
BufferedReader reader = null;
try { URL url = new URL(REQUEST_URL);
StringBuilder postData = new StringBuilder();
for (Map.Entry<String, Object> param : params.entrySet()) {
if (postData.length() != 0) postData.append('&');
postData.append(URLEncoder.encode(param.getKey(), "UTF-8"));
postData.append('=');
postData.append(URLEncoder.encode(String.valueOf(param.getValue()), "UTF-8"));
}
byte[] postDataBytes = postData.toString().getBytes("UTF-8");
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
connection.setConnectTimeout(8000);
connection.setRequestMethod("POST");
connection.setUseCaches(false);
connection.setDoOutput(true);
connection.getOutputStream().write(postDataBytes);
connection.connect();
StringBuilder sb;
int statusCode = connection.getResponseCode();
if (statusCode == 200) {
sb = new StringBuilder();
reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
String line;
while ((line = reader.readLine()) != null) {
sb.append(line);
}
jsonObject = new JSONObject(sb.toString());
}
connection.disconnect();
} catch (Exception e) {
e.printStackTrace();
} finally {
if (reader != null) {
try {
reader.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
return jsonObject;
}
}
Rahmat. You can try on Android Volley Library if you wish to send POST request to your Web API. You can refer the links below.
Android Volley Library
Android Volley Link Here
Tutorial
Android Hive Volley Tutorial
Dzone Volley Tutorial
Personally I prefer Retrofit, it's really easy and really nice to use
http://square.github.io/retrofit/
You can use RestTemplate using Restful service, it's pretty easy. Below is a sample code, in which I post an Object.
public MasterObject setMasterByBatch(MasterObject masterObject) {
try {
RestTemplate restTemplate = new RestTemplate();
restTemplate.getMessageConverters().add(new MappingJackson2HttpMessageConverter());
StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
StrictMode.setThreadPolicy(policy);
masterObject = restTemplate.postForObject(yourUrl, masterObject, MasterObject.class);
} catch (Exception e) {
e.printStackTrace();
Log.e("masterObjPost_WsCli_EX", e.toString());
}
return masterObject;
}
This needs few dependencies in your build.gradle(Module: app):
dependencies {
compile 'org.springframework.android:spring-android-rest-template:1.0.1.RELEASE'
compile 'com.fasterxml.jackson.core:jackson-core:2.6.0'
compile 'com.fasterxml.jackson.core:jackson-databind:2.6.0'
}
If shows any error regarding org.springframework you might need to download and insert spring library
AndroidManifest
<uses-permission android:name="android.permission.INTERNET" />
MainActivity
API apiInterface = RestClient.getRetrofit().create(API.class);
//JsonObject objFilterData = new JsonObject();
//objFilterData.addProperty("params", "0");
Call<JsonObject> call = apiInterface.apiname("0");
call.enqueue(new Callback<JsonObject>() {
#Override
public void onResponse(Call<JsonObject> call, Response<JsonObject> response) {
JsonObject jsonObject = new Gson().fromJson(response.body(), JsonObject.class);
//your response in json Object
}
#Override
public void onFailure(Call<JsonObject> call, Throwable t) {
Toast.makeText(MainActivity.this, "" + t.getMessage(), Toast.LENGTH_SHORT).show();
}
});
RestClient
public class RestClient {
public static String base_url = "your base url";
public static Retrofit retrofit;
public static Retrofit getRetrofit() {
if (retrofit == null) {
OkHttpClient client = new OkHttpClient.Builder()
.connectTimeout(100, TimeUnit.SECONDS)
.writeTimeout(100, TimeUnit.SECONDS)
.readTimeout(100, TimeUnit.SECONDS).build();
retrofit = new Retrofit.Builder()
.baseUrl(base_url)
.client(client)
.addConverterFactory(ScalarsConverterFactory.create())
.addConverterFactory(GsonConverterFactory.create())
.build();
}
return retrofit;
}
}
interface API Class
public interface API {
#FormUrlEncoded
#POST("apiname")
Call<JsonObject> apiname(#Field("params") String customer_id);
//#Headers("Content-Type:application/json")
//#POST("updateselleraddress")
//Call<JsonObject> updateselleraddress(#Body String body);
}
values/xml/network_security_config.xml
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
<base-config cleartextTrafficPermitted="true" />
</network-security-config>
Retrofit Dependencies
implementation 'com.squareup.okhttp3:okhttp:5.0.0-alpha.7'
implementation 'com.squareup.okhttp3:logging-interceptor:5.0.0-alpha.7'
implementation 'com.squareup.retrofit2:retrofit:2.9.0'
implementation 'com.squareup.retrofit2:converter-gson:2.9.0'
implementation 'com.squareup.retrofit2:converter-scalars:2.9.0'
if you need Response class
#SerializedName("data")
#Expose
private ArrayList<Data> data;
public ArrayList<Data> getData() {
return data;
}
public void setData(ArrayList<Data> data) {
this.data = data;
}
I was trying to develop a simple POST API call in Android so I made one thinking that the request content-type was a json. Turns out it is expecting a multipart/form-data format and I'm struggling changing my function.
I'd like to know if there is any library to manage this. If not, I'd like to know how to pass my arguments in a multipart format.
#Override
public boolean post(String poiId, String description, ArrayList<String> tags, Resource resource) {
RequestQueue queue = mRequestQueue;
poiId = "1";
description = "Test post";
final HashMap<String, Object> params = new HashMap<>();
params.put("poiID", poiId);
params.put("description", description);
System.out.println("POI ID " + description);
params.put("tags", tags);
params.put("resource", resource);
RequestFuture<JSONObject> future = RequestFuture.newFuture();
JsonObjectRequest request = new JsonObjectRequest(
Request.Method.POST,
API_POST_URL,
new JSONObject(params),
future, future) {
#Override
public HashMap<String, String> getHeaders() {
System.out.println(PostRepositoryImpl.this.getHeaders());
return PostRepositoryImpl.this.getHeaders();
}
};
queue.add(request);
try {
future.get(TIMEOUT, TIMEOUT_TIME_UNIT); // this will block
}catch (InterruptedException | ExecutionException | TimeoutException e){
e.printStackTrace();
return false;
}
return true;
}
I hardcoded some of the values because I wanted to test with poiID and description
So I want to send these kind of values in my multipart/form-date:
- poiID : String
- description : String
- resource : image
- tags
Is there any way to do this similar to the way I made my json request?
Kind regards
EDIT:
#Override
public boolean post(String poiId, String description, ArrayList<String> tags, Resource resource) {
RequestQueue queue = mRequestQueue;
StringRequest postRequest = new StringRequest(Request.Method.POST, API_POST_URL,
new Response.Listener<String>()
{
#Override
public void onResponse(String response) {
// response
Log.d("Response", response);
}
},
new Response.ErrorListener()
{
#Override
public void onErrorResponse(VolleyError error) {
// error
Log.d("Error.Response", "400");
}
}
) {
#Override
protected HashMap<String, String> getParams()
{
HashMap<String, String> params = new HashMap<String, String>();
params.put("poiID", "Alif");
params.put("description", "http://itsalif.info");
return params;
}
};
queue.add(postRequest);
return true;
}
How do I add the headers?
If it isn't JSON, simply use a StringRequest.
Not sure how to use Future with Volley, so change that accordingly
Then, params are added in an overridden method
Request request = new StringRequest(
Request.Method.POST,
API_POST_URL,
future, future) {
#Override
public HashMap<String, String> getHeaders() {
HashMap<String, String> headers = PostRepositoryImpl.this.getHeaders();
System.out.println(headers);
return headers;
}
#Override
public HashMap<String, String> getParams() {
// TODO: Put your params here
}
};
And for Multipart, see Working POST Multipart Request with Volley and without HttpEntity
Using Retrofit 2, you could do this:
//Lets Suppose this you have this postman or you want to make some request like this
//ServiceCreator (In my case i am using oauth2 so have AccessToken). This is a working and production sample, so you have to make your own changes, but i attach to example all components.
public class APIRestClient {
public static String API_BASE_URL = "http://186.151.238.14/";
private static OkHttpClient.Builder httpClient;
private static Retrofit.Builder builder;
public static Retrofit retrofit;
private static Activity mActivity;
private static AccessToken mToken;
/**
* setupBase URL
* #param _baseActivity
*/
public static void setupBaseUrl(Context _baseActivity){
String tmpBase = SharedPreferenceUtilities.getDomain(_baseActivity);
if (tmpBase != null && tmpBase.length() > 0){
if (tmpBase != API_BASE_URL) {
APIRestClient.API_BASE_URL = tmpBase;
}
}
}
/**
* auth2 Authorization Bearer...token create Service instance
* #param _serviceClass
* #param _baseActivity
* #param <S>
* #return
*/
public static <S> S createService(Class<S> _serviceClass, final Activity _baseActivity) {
AccessToken accessToken = TaskManagementApplication.getInstance().getAccessToken();
if (_baseActivity != null) {
setupBaseUrl(_baseActivity);
}
httpClient = new OkHttpClient.Builder();
httpClient.connectTimeout(30000, TimeUnit.SECONDS)
.readTimeout(30000,TimeUnit.SECONDS);
if (BuildConfig.DEBUG) {
HttpLoggingInterceptor logging = new HttpLoggingInterceptor();
logging.setLevel(HttpLoggingInterceptor.Level.BODY);
httpClient.addInterceptor(logging);
httpClient.addNetworkInterceptor(new StethoInterceptor());
}
builder = new Retrofit.Builder()
.baseUrl(API_BASE_URL)
.addConverterFactory(GsonConverterFactory.create());
if (accessToken == null){
accessToken = new AccessToken();
accessToken.setAccessToken("");
accessToken.setTokenType("Bearer");
accessToken.setScope("");
accessToken.setRefreshToken("");
accessToken.setClientID("");
accessToken.setClientSecret("");
accessToken.setExpiry(0);
}
if(accessToken != null) {
mActivity = _baseActivity;
mToken = accessToken;
final AccessToken token = accessToken;
httpClient.addInterceptor(new Interceptor() {
#Override
public Response intercept(Chain chain) throws IOException {
Request original = chain.request();
Request.Builder requestBuilder = original.newBuilder()
.header("Accept", "application/json")
.header("Content-type", "application/json")
.header("Authorization",
token.getTokenType() + " " + token.getAccessToken())
.method(original.method(), original.body());
Request request = requestBuilder.build();
return chain.proceed(request);
}
});
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.
LoginUtilities.initLogin(_baseActivity,LoginActivity.LOGININTENTRESULT,null);
return null;
}
// We need a new client, since we don't want to make another call using our client with access token
OAuthInterface tokenClient = createAuthService(OAuthInterface.class,mActivity);
Call<AccessToken> call = tokenClient.getRefreshAccessToken(
Grant_type.REFRESH_TOKEN.toString(),
token.getRefreshToken(),
StringUtilities.API_OAUTH_CLIENTID(_baseActivity),
StringUtilities.API_OAUTH_SECRET(_baseActivity),
"");
try {
retrofit2.Response<AccessToken> tokenResponse = call.execute();
if(tokenResponse.code() == 200) {
AccessToken newToken = tokenResponse.body();
mToken = newToken;
SharedPreferenceUtilities.setAccessToken(mActivity,mToken);
TaskManagementApplication.getInstance().setupToken(mToken);
return response.request().newBuilder()
.header("Authorization", newToken.getTokenType() + " " + newToken.getAccessToken())
.build();
} else {
LoginUtilities.initLogin(_baseActivity,LoginActivity.LOGININTENTRESULT,null);
return null;
}
} catch(IOException e) {
LoginUtilities.initLogin(_baseActivity,LoginActivity.LOGININTENTRESULT,null);
return null;
}
}
});
}
OkHttpClient client = httpClient.build();
Retrofit retrofit = builder.client(client).build();
return retrofit.create(_serviceClass);
}
/**
* not auth create Service instance
* #param _serviceClass
* #param _context
* #param <S>
* #return
*/
private static int responseCount(Response response) {
int result = 1;
while ((response = response.priorResponse()) != null) {
result++;
}
return result;
}
}
//ApiInterface
public interface StudentInterface
{
public static final String ENVIARTAREAAPI = "api/estudiante/entregatarea";
#Multipart
#POST(ENVIARTAREAAPI)
Call<TareaCalificacion> entregatarea(#Part("Descripcion") RequestBody Descripcion,
#Part("IdTarea") RequestBody IdTarea,
#Part("IdEstudiante") RequestBody IdEstudiante);
}
//ApiCall (in your activity, fragment or wetheaver) this should be used when you execute your api call
RequestBody descripcionRequestBody = RequestBody.create(
okhttp3.MediaType.parse("text/plain; charset=utf-8"),
mensageEntregaTmp);
RequestBody idTareaRequestBody = RequestBody.create(
okhttp3.MediaType.parse("text/plain; charset=utf-8"),
String.valueOf(mTarea.getIdTarea()));
RequestBody idEstudianteRequestBody = RequestBody.create(
okhttp3.MediaType.parse("text/plain; charset=utf-8"),
String.valueOf(currUser.getPerfil().getSisId()));
StudentInterface studentInterface = APIRestClient.createService(StudentInterface.class,DetalleTareaActivity.this);
Call<TareaCalificacion> call = studentInterface.entregatarea(
descripcionRequestBody,
idTareaRequestBody,
idEstudianteRequestBody);
call.enqueue(new Callback<TareaCalificacion>() {
#Override
public void onResponse(Call<TareaCalificacion> call, Response<TareaCalificacion> response) {
int statusCode = response.code();
if(statusCode == 200) {
Toast.makeText(getApplicationContext, "Success Request", Toast.LENGTH_SHORT).show();
} else {
//todo some kind of error
}
}
#Override
public void onFailure(Call<TareaCalificacion> call, Throwable t) {
//todo some kind of error
}
});
I have used this to upload photos, so i have to use this sample to do that, thats the reason i did not use Content Type application/json.
Hope that helps how to do.
Some class (pojo) like TareaCalificacion (that is what i expect from the response are just class, that i use with GSON), so TareaCalificacion.java is like:
public class TareaCalificacion {
#SerializedName("sisId")
#Expose
private long sisId;
#SerializedName("sisDescripcion")
#Expose
private String sisDescripcion;
#SerializedName("sisEstado")
#Expose
private String sisEstado;
#SerializedName("sis")
#Expose
private int sis;
#SerializedName("sisUsuario")
#Expose
private String sisUsuario;
#SerializedName("CalificacionObtenida")
#Expose
private double CalificacionObtenida;
#SerializedName("IdEstudiante")
#Expose
private long IdEstudiante;
#SerializedName("IdTarea")
#Expose
private long IdTarea;
#SerializedName("Adjunto")
#Expose
private int Adjunto;
#SerializedName("ObservacionCalificacion")
#Expose
private String ObservacionCalificacion;
#SerializedName("IdCatedratico")
#Expose
private long IdCatedratico;
public TareaCalificacion() {
}
}
Attach some links that could help you if you have doubts:
Retrofit Documentation
Another example using this
Lets me know if that works or if is not clear how to do
Regards.
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){
}
});
}}
}
When I'm working on networking functions in OkHttp, there are mainly 2 patterns I come across with:
Listener pattern
Callback pattern
Listener Pattern example:
// Listener class
public interface NetworkListener {
void onFailure(Request request, IOException e);
void onResponse(Response response);
}
// NetworkManager class
public class NetworkManager {
static String TAG = "NetworkManager";
public NetworkListener listener;
OkHttpClient client = new OkHttpClient();
public void setListener(NetworkListener listener) {
this.listener = listener;
}
void post(String url, JSONObject json) throws IOException {
//RequestBody body = RequestBody.create(JSON, json);
try {
JSONArray array = json.getJSONArray("d");
RequestBody body = new FormEncodingBuilder()
.add("m", json.getString("m"))
.add("d", array.toString())
.build();
Request request = new Request.Builder()
.url(url)
.post(body)
.build();
// Asynchronous Mode
client.newCall(request).enqueue(new Callback() {
#Override
public void onFailure(Request request, IOException e) {
Log.e(TAG, e.toString());
if(listener != null) {
listener.onFailure(request, e);
}
}
#Override
public void onResponse(Response response) throws IOException {
Log.w(TAG, response.body().string());
if(listener != null) {
listener.onResponse(response);
}
}
});
} catch (JSONException jsone) {
Log.e(TAG, jsone.getMessage());
}
}
}
// In the Activity
NetworkManager manager = new NetworkManager();
manager.setListener(this);
try {
requestState = RequestState.REQUESTING;
manager.post("http://www.example.com/api.php", reqObj);
} catch(IOException ioe) {
Log.e(TAG, ioe.getMessage());
}
Callback Pattern example:
// in onCreate
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
try {
doGET(new Callback() {
#Override
public void onFailure(Request request, IOException e) {
Log.d("OkHttp", "Shit happens");
}
#Override
public void onResponse(Response response) throws IOException {
if (response.isSuccessful()) {
String strResponse = response.body().string();
Gson gson = new Gson();
Wrapper wrapper = gson.fromJson(strResponse, Wrapper.class);
Log.d("OkHttp", wrapper.getListContents());
} else {
Log.d("OkHttp", "Request not successful");
}
}
});
} catch (IOException e) {
e.printStackTrace();
}
}
Call doGET(Callback callback) throws IOException {
// Start Network Request
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder().url("http://www.example.com/api.php").build();
Call call = client.newCall(request);
call.enqueue(callback);
return call;
}
What are the advantages and disadvantages of using the 2 patterns above?
IMHO, they are not different, actually you can find that Callback is also an interface.
package com.squareup.okhttp;
import java.io.IOException;
public interface Callback {
/**
* Called when the request could not be executed due to cancellation, a
* connectivity problem or timeout. Because networks can fail during an
* exchange, it is possible that the remote server accepted the request
* before the failure.
*/
void onFailure(Request request, IOException e);
/**
* Called when the HTTP response was successfully returned by the remote
* server. The callback may proceed to read the response body with {#link
* Response#body}. The response is still live until its response body is
* closed with {#code response.body().close()}. The recipient of the callback
* may even consume the response body on another thread.
*
* <p>Note that transport-layer success (receiving a HTTP response code,
* headers and body) does not necessarily indicate application-layer
* success: {#code response} may still indicate an unhappy HTTP response
* code like 404 or 500.
*/
void onResponse(Response response) throws IOException;
}
However, when I want to reuse some codes (or build an util class), I often use as the following:
Interface:
public interface OkHttpListener {
void onFailure(Request request, IOException e);
void onResponse(Response response) throws IOException;
}
Util class:
public class OkHttpUtils {
public static void getData(String url, final OkHttpListener listener){
OkHttpClient client = new OkHttpClient();
// GET request
Request request = new Request.Builder()
.url(url)
.build();
client.newCall(request).enqueue(new Callback() {
#Override
public void onFailure(Request request, IOException e) {
listener.onFailure(request, e);
}
#Override
public void onResponse(Response response) throws IOException {
listener.onResponse(response);
}
});
}
// the following uses built-in okhttp's Callback interface
public static void getData2(String url, Callback callbackListener){
OkHttpClient client = new OkHttpClient();
// GET request
Request request = new Request.Builder()
.url(url)
.build();
client.newCall(request).enqueue(callbackListener);
}
// other methods...
}
Then in activity classes:
OkHttpListener listener = new OkHttpListener() {
#Override
public void onFailure(Request request, IOException e) {
Log.e(LOG_TAG, e.toString());
}
#Override
public void onResponse(Response response) throws IOException {
String responseBody = response.body().string();
Log.i(LOG_TAG, responseBody);
}
};
String url = "http://myserver/api/getvalues";
OkHttpUtils.getData(url, listener);
String url1 = "http://myserver/api/getvalues/123";
OkHttpUtils.getData(url1, listener);
or
Callback callbackListener = new Callback() {
#Override
public void onFailure(Request request, IOException e) {
Log.e(LOG_TAG, e.toString());
}
#Override
public void onResponse(Response response) throws IOException {
String responseBody = response.body().string();
Log.i(LOG_TAG, responseBody);
}
};
String url = "http://myserver/api/getvalues";
OkHttpUtils.getData2(url, callbackListener);
String url1 = "http://myserver/api/getvalues/123";
OkHttpUtils.getData2(url1, callbackListener);
Hope it helps!
I want to use OkHttp library for networking in Android.
I started with the simple post example as written in their website:
public static final MediaType JSON = MediaType.parse("application/json; charset=utf-8");
OkHttpClient client = new OkHttpClient();
String post(String url, String json) throws IOException {
RequestBody body = RequestBody.create(JSON, json);
Request request = new Request.Builder()
.url(url)
.post(body)
.build();
Response response = client.newCall(request).execute();
return response.body().string();
}
With this call:
String response = post("http://www.roundsapp.com/post", json);
This call ends with NetworkOnMainThreadException.
I could wrap the call with an AsyncTask, but as far as I understand from the examples, the OkHttp library should have already taken care of that..
Am I doing something wrong?
You should use OkHttp's async method.
public static final MediaType JSON = MediaType.parse("application/json; charset=utf-8");
OkHttpClient client = new OkHttpClient();
Call post(String url, String json, Callback callback) {
RequestBody body = RequestBody.create(JSON, json);
Request request = new Request.Builder()
.url(url)
.post(body)
.build();
Call call = client.newCall(request);
call.enqueue(callback);
return call;
}
And then your response would be handled in the callback (OkHttp 2.x):
post("http://www.roundsapp.com/post", json, new Callback() {
#Override
public void onFailure(Request request, Throwable throwable) {
// Something went wrong
}
#Override public void onResponse(Response response) throws IOException {
if (response.isSuccessful()) {
String responseStr = response.body().string();
// Do what you want to do with the response.
} else {
// Request not successful
}
}
});
Or OkHttp 3.x/4.x:
post("http://www.roundsapp.com/post", "", new Callback() {
#Override
public void onFailure(Call call, IOException e) {
// Something went wrong
}
#Override
public void onResponse(Call call, Response response) throws IOException {
if (response.isSuccessful()) {
String responseStr = response.body().string();
// Do what you want to do with the response.
} else {
// Request not successful
}
}
});
Take a look at their recipes for more examples: http://square.github.io/okhttp/recipes/
According to the OkHttp docs:
It supports both synchronous blocking calls and async calls with callbacks.
Your example is on main thread and Android since version 3.0 throws that exception if you try to do network calls on main thread
Better option is to use it together with retrofit and Gson:
http://square.github.io/retrofit/
https://code.google.com/p/google-gson/
Here are the examples:
http://engineering.meetme.com/2014/03/best-practices-for-consuming-apis-on-android/
http://heriman.net/?p=5
If you follows these steps to implement OKHTTP, then definitely you'll call multiple API on multiple screen by applying only two lines of code
UpdateListener updateListener = new UpdateListener(HitAPIActivity.this, baseHTTPRequest);
updateListener.getJsonData();
Step 1:
baseHTTPRequest = new BaseHTTPRequest();
// baseHTTPRequest.setURL("https://api.geonames.org/citiesJSON?north=44.1&south=-9.9&east=-22.4&west=55.2&lang=de&username=demohttps://api.geonames.org/citiesJSON?north=44.1&south=-9.9&east=-22.4&west=55.2&lang=de&username=demo");
baseHTTPRequest.setURL("http://jsonparsing.parseapp.com/jsonData/moviesDemoItem.txt");
baseHTTPRequest.setRequestCode(reqType);
baseHTTPRequest.setCachedRequired(true);
UpdateListener updateListener = new UpdateListener(HitAPIActivity.this, baseHTTPRequest);
updateListener.executeRequest();
Step 2 : Create a request class
/**
* Created by Deepak Sharma on 4/7/16.
* This is a HTTP request class which has the basic parameters.
* If you wants to add some more parameters, please make a subclass of that class
* and add with your subclass. Don't modify this class.
*/
public class BaseHTTPRequest<T> {
private Context context;
private String URL;
private int requestCode;
private List<T> listParameters;
private String header;
private boolean isCachedRequired;
public Context getContext() {
return context;
}
public void setContext(Context context) {
this.context = context;
}
public void setURL(String URL) {
this.URL = URL;
}
public String getURL() {
return URL;
}
public int getRequestCode() {
return requestCode;
}
public void setRequestCode(int requestCode) {
this.requestCode = requestCode;
}
public List<T> getListParameters() {
return listParameters;
}
public void setListParameters(List<T> listParameters) {
this.listParameters = listParameters;
}
public String getHeader() {
return header;
}
public void setHeader(String header) {
this.header = header;
}
public boolean isCachedRequired() {
return isCachedRequired;
}
public void setCachedRequired(boolean cachedRequired) {
isCachedRequired = cachedRequired;
}
}
step 4 : Create a listener class
import android.util.Log;
import com.google.gson.Gson;
import java.io.IOException;
import dxswifi_direct.com.wifidirectcommunication.base.model.request.BaseHTTPRequest;
import okhttp3.Call;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Callback;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
/**
* Created by Deepak Sharma on 4/7/16.
* #email : dpsharma.sharma1#gmail.com
* This is a Simple java class which will help you for HTTP request/response and it will
* throw the response to your correspondance activity.
*/
public class UpdateListener {
private OnUpdateViewListener onUpdateViewListener;
OkHttpClient okHttpClient = new OkHttpClient();
BaseHTTPRequest mRequestModel;
private String mURL = null;
private Request mRequest = null;
public interface OnUpdateViewListener {
void updateView(String responseString, boolean isSuccess,int reqType);
}
public UpdateListener(OnUpdateViewListener onUpdateView, final BaseHTTPRequest requestModel) {
this.mRequestModel = requestModel;
this.onUpdateViewListener = onUpdateView;
if (requestModel.isCachedRequired())
{
/*File httpCacheDirectory = new File(requestModel.getContext().getCacheDir(), "responses");
Cache cache = null;
cache = new Cache(httpCacheDirectory, 10 * 1024 * 1024);
if (cache != null) {
okHttpClient.setCache(cache);
}*/
}
/*mURL = null;
if (requestModel.getListParameters()!=null && requestModel.getListParameters().size()>0)
{
HttpUrl.Builder urlBuilder = HttpUrl.parse(requestModel.getURL()).newBuilder();
List<RequestParameter> requestParameters = requestModel.getListParameters();
for (int i=0; i<requestParameters.size();i++)
{
urlBuilder.addQueryParameter(requestParameters.get(i).getKey(),requestParameters.get(i).getValue());
}
mURL = urlBuilder.build().toString();
}
else
{
mURL = requestModel.getURL();
}*/
mURL = requestModel.getURL();
if (mRequestModel.getListParameters()!=null && mRequestModel.getListParameters().size()>1)
{
MediaType JSON = MediaType.parse("application/json; charset=utf-8");
mRequest = new Request.Builder()
.url(mURL)
.post(RequestBody.create(JSON, new Gson().toJson(BaseHTTPRequest.class)))
.build();
}
else
{
mRequest = new Request.Builder()
.url(mURL)
.build();
}
}
public void executeRequest()
{
Call call = okHttpClient.newCall(mRequest);
call.enqueue(new Callback() {
#Override
public void onFailure(Call call, IOException e) {
e.printStackTrace();
onUpdateViewListener.updateView(NetworkException.getErrorMessage(e), false, mRequestModel.getRequestCode());
}
#Override
public void onResponse(Call call, Response response) throws IOException {
if (!response.isSuccessful()) {
// You can also throw your own custom exception
throw new IOException("Unexpected code " + response);
} else {
Log.i("Response:",response.toString());
Log.i("Response body:",response.body().toString());
Log.i("Response message:",response.message());
onUpdateViewListener.updateView(response.body().string(),true, mRequestModel.getRequestCode());
}
// do something wih the result
}
});
}
}
step 5 : From the activity you requesting, implement listener
public class HitAPIActivity extends AppCompatActivity implements View.OnClickListener, UpdateListener.OnUpdateViewListener{
#Override
public void updateView(final String responseString, boolean isSuccess, int reqType) {
if (isSuccess)
{
if (!responseString.contains("failure")
&& !responseString.contains("Error")) {
// Handle request on the basis of Request Type.
switch (reqType) {
case ApiConstants.GET_CONTACTS:
break;
default:
break;
}
}
}
}