Investigating OKHttp and want to use as docs claims possible: "It supports both synchronous blocking calls and async calls with callbacks".
But how can I set a callback, or a chunk of code needs to execute after response received? I have not find anything on their site.
Should I nest call into an Async thread like:
AsyncTask.execute(new Runnable() {
#Override
public void run() {
//TODO your background code
From the sample
https://github.com/square/okhttp/blob/master/samples/guide/src/main/java/okhttp3/recipes/AsynchronousGet.java
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 {
try (ResponseBody responseBody = response.body()) {
if (!response.isSuccessful()) throw new IOException("Unexpected code " + response);
Headers responseHeaders = response.headers();
for (int i = 0, size = responseHeaders.size(); i < size; i++) {
System.out.println(responseHeaders.name(i) + ": " + responseHeaders.value(i));
}
System.out.println(responseBody.string());
}
}
});
Related
I'm running multiple network requests(getResponse method) in a for loop and I'm trying to get list of the responses only when ALL of the network requests are done.
I am trying to use CompletableFuture. getResponse uses OKHttp (asynch request and response)
Log.d("api_log", "Started doing things");
List<CompletableFuture> futures = new ArrayList();
for (int i = 0; i < mylist.size(); i++) {
try {
int finalI = i;
futures.add(CompletableFuture.runAsync(() -> getResponse(context, mylist.get(finalI).id)));
}
catch (Exception e) {}
}
CompletableFuture.allOf(futures.toArray(new CompletableFuture[0]))
.thenRunAsync(() -> Log.d("api_log", "Ended doing things"));
This is the getResponse method:
private void getResponse(final Context context, final String id) {
Log.d("api_log", "id is: " + id);
final String url = context.getString(R.string.myurl) + "/" + id;
OkHttpClient client = new OkHttpClient().newBuilder()
.build();
Request request = new Request.Builder()
.url(url)
.method("GET", null)
.build();
client.newCall(request).enqueue(new Callback() {
#Override
public void onFailure(Call call, IOException e) {
e.printStackTrace();
}
#Override
public void onResponse(Call call, final Response response) throws IOException {
if (!response.isSuccessful()) {
return;
}
// response HAS RECEIVED
final String strResponse = response.body().string();
Log.d("api_log", "response: " + strResponse);
}
});
}
Actual: "Ended doing things" is printed before all the responses are printed.
Expected: "Ended doing things" should be printed after all the responses are printed.
How can I achieve it?
I use okhttp to get text of certain url.
url I try to get is
https://firebasestorage.googleapis.com/v0/b/famhouse.appspot.com/o/branchname%2Ftextfile?alt=media&token=a58b07a4-ddee-4ece-8222-0854a6c2a713
as you can see, it only have body saying "Testtest"
I get response well and I logged response.body().toString() but it says
okhttp3.internal.http.RealResponseBody#e640919
What I expect to see on log is Testtest
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mContext=this.getApplicationContext();
checkPermission();
OkHttpHandler okHttpHandler= new OkHttpHandler();
okHttpHandler.execute("https://firebasestorage.googleapis.com/v0/b/famhouse.appspot.com/o/branchname%2Ftextfile?alt=media&token=a58b07a4-ddee-4ece-8222-0854a6c2a713");
}
public class OkHttpHandler extends AsyncTask {
OkHttpClient client = new OkHttpClient();
#Override
protected Object doInBackground(Object[] objects) {
Request request = new Request.Builder()
.url("https://firebasestorage.googleapis.com/v0/b/famhouse.appspot.com/o/branchname%2Ftextfile?alt=media&token=a58b07a4-ddee-4ece-8222-0854a6c2a713").addHeader("Accept", "application/json")
.build();
client.newCall(request).enqueue(new Callback() {
#Override
public void onFailure(Call call, IOException e) {
e.printStackTrace();
}
#Override
public void onResponse(Call call, final Response response) throws IOException {
if (!response.isSuccessful()) {
throw new IOException("Unexpected code " + response);
} else {
Log.e("dialog","response is : "+response.body().toString());
Log.e("dialog","response is : "+response.code());
}
}
});
return null;
}
}
you should use response.body().string()
I try to get authorization token from Twitter (app-only), the code almost fully follows oficial guide, but get 503 Service unavailable code.
#Override
protected Boolean doInBackground(Void... params) {
String cred_enc = tw_cons_key + ":" + tw_priv_cons_key;
cred_enc = Base64.encodeToString(cred_enc.getBytes(), Base64.NO_WRAP);
Request request = new Request.Builder().url("https://api.twitter.com/oauth2/token")
.header("Authorization:", "Basic " + cred_enc)
.header("Content-Type:", "application/x-www-form-urlencoded;charset=UTF-8")
.post(RequestBody.create(MEDIA_TYPE_MARKDOWN, postBody))
.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 {
ResponseBody body = response.body();
if (response.isSuccessful()) {
Headers headers = response.headers();
//response check
for (int i = 0; i < headers.size(); i++) {
System.out.println("Headers: " + i + " " + headers.name(i) + " : " + headers.value(i));
}
System.out.println(body.string());
try {
JSONObject jsonObject = new JSONObject(body.string());
} catch (JSONException e) {
e.printStackTrace();
}
} else {
throw new IOException("Unexpected code" + response);
}
body.close();
}
});
return true;
}
What may be the possible reason?
It required me to write a simple server on localhost to find out what HTTP request was actually generated.
The problem was with colons: .header("Authorization:"resulted in Authorization:: in the network request!
After I removed colons from the header key values, both HttpUrlConnection and OkHttp code variants worked seamlessly.
So I need to figure out how to access the value I get from my first response in my second. I would think that I could just store it to a a variable and access it in another request. However, that does not seem to be the case.
Here is the bit that is giving me issues. So my first request is getting me a token and then I need to use that which is stored in commatoken in my second request.
private final OkHttpClient client = new OkHttpClient();
public void run() throws Exception {
Request request = new Request.Builder()
.url(API_URL + authPreferences.getToken())
.build();
client.newCall(request).enqueue(new Callback() {
public void onFailure(Call call, IOException e) {
e.printStackTrace();
}
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, size = responseHeaders.size(); i < size; i++) {
System.out.println(responseHeaders.name(i) + ": " + responseHeaders.value(i));
}
System.out.println(response.body().string());
String commatoken = response.body().string();
}
});
Request dataRequest = new Request.Builder()
.header("Authorization", "jwt"+commatoken)
.url(ChffrMe_URL).build();
client.newCall(dataRequest).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, size = responseHeaders.size(); i < size; i++) {
System.out.println(responseHeaders.name(i) + ": " + responseHeaders.value(i));
}
System.out.println(response.body().string());
}
});
}
I think we can call response.body().string() only once .... so save that data to a string variable first .. and access it wherever you need it.
String response_data;
..............
response_data = response.body().string();
You are calling response.body().string() twice ...
More info
https://stackoverflow.com/a/27922818/3552066
If you want to avoid about empty result:
assert response.body() != null;
String r = response.body().string();
And if you want access to each elements :
JSONObject json = new JSONObject(r);
Log.i("love", "Res: "+json.getString("result")); //Name -> Answer
See the result:
{"fname":"John","sname":"Alice","percentage":"46","result":"Can choose someone better."} // String from
I/love: Res: All the best! // Json form by Name
So I will be making multiple GET requests and would love for them to execute all at once. However, as it is right now I have to hit the sign in button twice for the second newCall to go off. I would prefer if more newCall went off. But looking at it, the second newCall needs the response from the first one before it can. Is there a way that once the first gets the response, the second one executes instead of having to hit the sign in button twice?
Button code:
SignInButton signInButton = (SignInButton) findViewById(R.id.sign_in_button);
signInButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (authPreferences.getUser() != null && authPreferences.getToken() != null) {
System.out.println(authPreferences.getToken());
doCoolAuthenticatedStuff();
try {
run();
} catch (Exception e) {
e.printStackTrace();
}
//new RetrieveFeedTask().execute();
} else {
chooseAccount();
}
}
});
run() code
public void run() throws Exception {
Request request = new Request.Builder()
.url(API_URL + authPreferences.getToken())
.build();
client.newCall(request).enqueue(new Callback() {
public void onFailure(Call call, IOException e) {
e.printStackTrace();
}
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, size = responseHeaders.size(); i < size; i++) {
System.out.println(responseHeaders.name(i) + ": " + responseHeaders.value(i));
}
try
{
String token = response.body().string();
JSONObject json = new JSONObject(token);
commatoken = json.getString("access_token");
} catch (JSONException e)
{
}
// commatoken = response.body().string();
// System.out.println(commatoken);
}
});
final Request dataRequest = new Request.Builder()
.header("content-type", "application/x-www-form-urlencoded")
.header("authorization", "JWT "+ commatoken)
.url(ChffrMe_URL).build();
client.newCall(dataRequest).enqueue(new Callback() {
#Override
public void onFailure(Call call, IOException e) {
e.printStackTrace();
}
#Override
public void onResponse(Call call, Response responseMe) throws IOException {
if (!responseMe.isSuccessful()) throw new IOException("Unexpected code " + responseMe);
Headers responseHeaders = responseMe.headers();
for (int i = 0, size = responseHeaders.size(); i < size; i++) {
System.out.println(responseHeaders.name(i) + ": " + responseHeaders.value(i));
}
try
{
String myInfo = responseMe.body().string();
JSONObject json = new JSONObject(myInfo);
commaMyInfo = json.getString("points");
} catch (JSONException e)
{
}
runOnUiThread(new Runnable() {
#Override
public void run() {
responseView.setText("Comma Points: " +commaMyInfo);
}
});
//responseView.setText(responseMe.body().string());
//System.out.println(responseMe.body().string());
}
});
}