Okhttp use response - android

I am using an asynchronous Okhttp to do request and then use the response to fill in the UI.
My idea was to wait in the main thread for the response and then start a new activity. Is this the best way? If so, how can I wait and access the parsed data of the response in the main thread?
Main activity:
public void sendMessage(View view) throws IOException, InterruptedException {
Intent intent = new Intent(this, DisplayMessageActivity.class);
...
HttpHelper client = new HttpHelper();
String response = client.get("https://www.google.com");
...
intent.putExtra(EXTRA_MESSAGE, message+"\nresponse:\n"+response);
Bundle b = new Bundle();
b.putStringArray("DATA_GET", client.dataOut);
intent.putExtras(b);
startActivity(intent);
}
HttpHelper class:
public class HttpHelper {
OkHttpClient client = new OkHttpClient();
String[] dataOut;
String get(String url) throws IOException, InterruptedException {
Request request = new Request.Builder()
.url(url)
.build();
client.newCall(request).enqueue(new Callback() {
#Override public void onFailure(Request request, IOException e) {
e.printStackTrace();
}
#Override public void onResponse(Response response) throws IOException{
if (!response.isSuccessful()) throw new IOException("Unexpected code " + response);
// parsing response
dataOut = ...;
}
});
return "done";
}
}
Thanks,

No it is a bad way. I recommend using Retrofit, it will handle most of the boilerplate networking stuff for you on a background thread and will serve you the response via a callback when it completes.

Related

Separate Class for OkHttp Requests

I use OkHttp for requests to my raspberry. I am thinking about putting the requests in a separate class.
Currently I have one method to send requests. The code is as follows:
private void sendRequest(String url, JSONObject json) {
Log.d(TAG, "sendRequest: Das Json: " + json);
// Authentication for the request to raspberry
OkHttpClient.Builder client = new OkHttpClient.Builder();
client.authenticator(new Authenticator() {
#Override
public Request authenticate(Route route, Response response) throws IOException {
String credential = Credentials.basic("username", "password");
return response.request().newBuilder()
.header("Authorization", credential)
.build();
}
});
// Sending out the request to the raspberry
OkHttpClient okHttpClient = client.build();
RequestBody body = RequestBody.create(null, new byte[]{});
if( json != null) {
body = RequestBody.create(MediaType.parse(
"application/json"),
json.toString()
);
}
Request request = new Request.Builder()
.url(url)
.post(body)
.build();
okHttpClient.newCall(request).enqueue(new Callback() {
#Override
public void onFailure(Call call, IOException e) {
Log.d(LOG, "Big Fail");
e.printStackTrace();
}
#Override
public void onResponse(Call call, Response response) throws IOException {
try {
ResponseBody responseBody = response.body();
if( !response.isSuccessful() ) {
Log.d(TAG, "onResponse: We are in !response.successful()");
throw new IOException("Response not successful: " + response );
}
Log.d(LOG, "onResponse: Response is: " + responseBody.string());
} catch (Exception e) {
e.printStackTrace();
Log.d(LOG, "onResponse: failed!" + e);
}
}
});
}
Here is an example how the sendRequest() function is called:
private void makePremixCall(Premix premix) {
JSONArray jsonArray = new JSONArray();
ArrayList<Premixable> usedPremixables = premix.getUsedPremixables();
for(Premixable usedPremixable: usedPremixables) {
try {
JSONObject jsonObject = new JSONObject();
jsonObject.put("Silo", usedPremixable.getmSilo());
jsonObject.put("Gramm", usedPremixable.getmKgPerCow() * mFeeding.getmNumberOfCows());
jsonArray.put(jsonObject);
} catch (JSONException e) {
e.printStackTrace();
}
}
try {
JSONObject jsonObject = new JSONObject();
jsonObject.put("Components", jsonArray);
sendRequest("http://192.168.178.49:5000/evaluatePost", jsonObject);
} catch (JSONException e) {
e.printStackTrace();
Log.d(TAG, "makePremixCall: " + e);
}
}
My problem with this: I would like to have a separate class, which offers the function makePremix(Premix premix) and other functions that I need.
The only solution that comes to my mind is implementing the requests synchronously in the separate class and call that separate class in an AsyncTask in the class I am working in.
Do I oversee something? Is there a way to create a separate class and still use the OkHttp enqueue method?
You could extract makePremix(Premix premix) in a separate class and make sendRequest() public (or maybe package-private depending on your use case).
public void sendRequest(String url, JSONObject json)
However since sendRequest is generic and can be used by any other makeAnotherCall() in some other class you would need to get back result of every requests. Hence you can extract the Callback out of sendRequest()
public void sendRequest(String url, JSONObject json, Callback callback)
Now your sendRequest will look like
private void sendRequest(String url, JSONObject json) {
Log.d(TAG, "sendRequest: Das Json: " + json);
// Authentication for the request to raspberry
OkHttpClient.Builder client = new OkHttpClient.Builder();
client.authenticator(new Authenticator() {
#Override
public Request authenticate(Route route, Response response) throws IOException {
String credential = Credentials.basic("username", "password");
return response.request().newBuilder()
.header("Authorization", credential)
.build();
}
});
// Sending out the request to the raspberry
OkHttpClient okHttpClient = client.build();
RequestBody body = RequestBody.create(null, new byte[]{});
if( json != null) {
body = RequestBody.create(MediaType.parse(
"application/json"),
json.toString()
);
}
Request request = new Request.Builder()
.url(url)
.post(body)
.build();
okHttpClient.newCall(request).enqueue(callback);
}
Hope it makes sense!
Also as a side note, see that you are creating a new OkHttp Client every time you call sendRequest. You could probably optimise memory here by caching the client and reusing it.

OkHttp on Android

This is my code to get the JSON string from my PHP server.
When I run this the app crashes and says that there is an error with Response response = client.newCall(request).execute();
What am I doing wrong?
public class MainActivity extends Activity {
//private static final String TAG = "MainActivity";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
new AsyncTask<Void, Void, String>(){
#Override
protected String doInBackground(Void... params) {
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
.url(url)
.build();
try {
Response response = client.newCall(request).execute();
Log.d("OkHttp", "doInBackground() called with: " + "params = [" + response.body().string() + "]");
return response.body().string();
}
catch (IOException e) {
e.printStackTrace();
}
return null;
}
}.execute();
}
}
You don't need to put this into an async task as you can use the call back of the OKHttp library which itself is async.
Second thing is you are using the wrong method. Instead of execute() you should use enqueue() which has a callback as a parameter as I mentioned above.
Try this code:
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
.url(url)
.build();
Call call = client.newCall(request);
call.enqueue(new Callback() {
#Override
public void onFailure(Call call, IOException e) {
// Observe reason of failure using
e.printStackTrace();
}
#Override
public void onResponse(Call call, Response response) throws IOException {
if(response.isSuccessful()){
// Use response here
}
else{
// Observe error
}
}
});

Android twilio is returning a 500 server error from ngrok

I'm using Twilio with Android. Here is my code:
private Long sendSMS(String number) {
Random random = new Random();
Long verificationCode = (long) random.nextInt((3896 - 298) + 1) + 298;
try {
post("http://*******.ngrok.io/sms", new Callback() {
#Override
public void onFailure(Call call, IOException e) {
e.printStackTrace();
}
#Override
public void onResponse(Call call, Response response) throws IOException {
runOnUiThread(new Runnable() {
public void run() {
Toast.makeText(MainActivity.this, "SMS Sent", Toast.LENGTH_SHORT).show();
}
});
}
});
} catch (IOException e) {
e.printStackTrace();
}
return verificationCode;
}
And here is the post call:
Call post(String url, Callback callback) throws IOException {
RequestBody formBody = new FormBody.Builder()
.add("To", "CENSORED_NUMBER")
.add("Body", "It worked!!!")
.build();
Request request = new Request.Builder()
.url(url)
.post(formBody)
.build();
Call response = mClient.newCall(request);
response.enqueue(callback);
return response;
}
In my backend:
public static void main(String[] args) {
get("/", (req, res) -> "Hello, World!");
TwilioRestClient client = new TwilioRestClient("8*******", "******");
post("/sms", (req, res) -> {
String body = req.queryParams("Body");
String to = req.queryParams("To");
String from = "+17347208686";
Map<String, String> callParams = new HashMap<>();
callParams.put("To", to);
callParams.put("From", from);
callParams.put("Body", body);
Sms message = client.getAccount().getSmsFactory().create(callParams);
return message.getSid();
});
}
Back in ngrok, after trying the above code, I get:
HTTP Requests
-------------
POST /sms 500 Server Error
As you can see, the problem seems to be a 500 Server Error. How can I fix this problem? In the backend, I have my Twilio credentials setup correctly, and the from field filled in as: String from = "+1***2*8*8*"; (Number censored)
I can't find anything in the document saying anything about this error. I can't believe Twilio barely has anything for Android.
Nothing shows up in my logs. So the message wasn't even sent, although the Toast I have in the onResponse method appears.

Android JSON POST with OKHTTP

I´m looking for a solution to implement a JSON-POST request with OKHTTP. I´ve got an HTTP-Client.java file which handles all the methods (POST, GET, PUT, DELETE) and in the RegisterActivity I´d like to POST the user-data (from the input fields) JSON-formatted to the server.
This is my HTTP-Client.java
public class HttpClient{
public static final MediaType JSON
= MediaType.parse("application/json; charset=utf-8");
public static OkHttpClient client = new OkHttpClient.Builder()
.cookieJar(new CookieJar() {
private final HashMap<String, List<Cookie>> cookieStore = new HashMap<>();
#Override
public void saveFromResponse(HttpUrl url, List<Cookie> cookies) {
cookieStore.put(url.host(), cookies);
}
#Override
public List<Cookie> loadForRequest(HttpUrl url) {
List<Cookie> cookies = cookieStore.get(url.host());
return cookies != null ? cookies : new ArrayList<Cookie>();
}
})
.build();
public static Call post(String url, String json, Callback callback) throws IOException {
RequestBody body = RequestBody.create(JSON, json);
Request request = new Request.Builder()
.url(url)
.post(body.create(JSON, json))
.build();
Call call = client.newCall(request);
call.enqueue(callback);
return call;
}
}
... and this is the onClick-Part from the RegisterActivity
btnRegRegister.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
//TODO
String registerData = "{\"email\":\"" + etRegisterEmail.getText().toString() + "\",\"password\":\"" + etRegisterPasswort.getText().toString() + "\"}";
try {
HttpClient.post(ABSOLUTE_URL, registerData, new Callback(){
#Override
public void onFailure(Call call, IOException e) {
}
#Override
public void onResponse(Call call, Response response) throws IOException {
if (response.isSuccessful()) {
String resp = response.body().string();
if (resp != null) {
Log.d("Statuscode", String.valueOf(response.code()));
Log.d("Body", response.body().string());
}
}
}
});
} catch (Exception e) {
e.printStackTrace();
}
}
});
Everytime I start the app it crashes when I click the Register-Button caused by a FATAL EXPECTION 'android.os.NetworkOnMainThreadException'
I´ve alread read something about the AsyncTask but I don´t know exactly how to do this.
Try my code below
MediaType JSON = MediaType.parse("application/json; charset=utf-8");
Map<String, String> params = new HashMap<String, String>();
params.put("msisdn", "123123");
params.put("name", "your name");
JSONObject parameter = new JSONObject(param);
OkHttpClient client = new OkHttpClient();
RequestBody body = RequestBody.create(JSON, parameter.toString());
Request request = new Request.Builder()
.url(url)
.post(body)
.addHeader("content-type", "application/json; charset=utf-8")
.build();
client.newCall(request).enqueue(new Callback() {
#Override
public void onFailure(Call call, IOException e) {
Log.e("response", call.request().body().toString());
}
#Override
public void onResponse(Call call, Response response) throws IOException {
Log.e("response", response.body().string());
}
});
It's because you are trying to execute the HTTP query on the main thread (or UI thread). You shouldn't do a long task on the main thread because your app will hang, because the drawing routines are executed in that thread (hence his another name "UI Thread"). You should use another thread to make your request. For example:
new Thread(){
//Call your post method here.
}.start();
The Android asynctask is a simple class to do asynchronous work. It executes first his "onPreExecute" method on the calling thread, then his "doInBackground" method on a background thread, then his "onPostExecute" method back in the calling thread.
Try using Retrofit library for making Post request to the server. This provides a fast and reliable connection to the server.
You can also use Volley library for the same.

Wait for Callback inside AsyncTask

I'd like to do some work in AsyncTask including some server requests for downloading small files. When download is done continue logic inside AsyncTask and when all stuff is done I get the result in activity. Everything is working good but my AsyncTask is not waiting for callback method:
public class AsyncOperation extends AsyncTask<String, Integer, String> {
#Override
protected String doInBackground(String... params) {
String linkUrl = params[0];
functionDoStuff(linkUrl);
return "Executed";
}
public void functionDoStuff(String urlLink) {
... code ...
String str = getFile(urlLink);
!!! is not waiting for result !!!
... use 'str' ...
}
private String getFile(String urlLink) {
String savedFileDestination = null;
OkHttpClient client = new OkHttpClient();
final Request request = new Request.Builder()
.url(urlLink")
.build();
client.newCall(request).enqueue(new com.squareup.okhttp.Callback() {
#Override
public void onFailure(Request request, IOException e) {
//something goes wrong
}
#Override
public void onResponse(com.squareup.okhttp.Response response) throws IOException {
//get stream
InputStream inputStream = response.body().byteStream();
//this method save file and return file path
savedFileDestination = saveFileMethod(inputStream);
}
});
return savedFileDestination;
}
}
How can I wait for this callback to continue logic in functiobDoStuff() ?
put all the stuff inside onResponse method.Because onResponse method work asyncronusly
#Selvin is right, I have to make my request synchronous and my 'waiting problem' is gone!
The only change is into getFile() method, it should be smth like:
private void getFile(String urlLink) {
OkHttpClient client = new OkHttpClient();
final Request request = new Request.Builder()
.url(urlLink)
.build();
try {
Response response = client.newCall(request).execute();
if (response!=null){
InputStream inputStream = response.body().byteStream();
saveFile(inputStream);
}
} catch (IOException e) {
e.printStackTrace();
}
}

Categories

Resources