Android: OkHttp request within AsyncTask is called twice - android

I have a OkHttp request within an async taks doInBackgroun(), The resquest is a bit heavy and takes some time on my backend. Unfortunatly it looks like when OKHttp doesn't get an answer straight away it tries again, this makes my server blow up !
I have tried to disable this function but it seems to ignore it... What could i do ?
public class AsyncUpdateNewPatients extends AsyncTask<Object, Void, Boolean> {
private static OkHttpClient okHttpClient;
private static DatabaseHandler db;
ActivityMain activityMain;
public AsyncUpdateNewPatients (ActivityMain atv)
{
this.activityMain = atv;
}
#Override
protected void onPreExecute() {
super.onPreExecute();
HttpLoggingInterceptor httpLoggingInterceptor = new HttpLoggingInterceptor(new HttpLoggingInterceptor.Logger() {
#Override
public void log(String message) {
Stormpath.logger().d(message);
}
});
httpLoggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
okHttpClient = new OkHttpClient.Builder()
.addNetworkInterceptor(httpLoggingInterceptor)
.retryOnConnectionFailure(false)
.connectTimeout(15, TimeUnit.SECONDS)
.readTimeout(15L, TimeUnit.SECONDS)
.writeTimeout(15L, TimeUnit.SECONDS)
.build();
db = new DatabaseHandler(activityMain);
}
#Override
protected Boolean doInBackground(Object... objects) {
List<PatientData> allNewPatients = db.getAllNewPatients();
JSONArray allNewPatientJSONArray = new JSONArray();
for (PatientData tempPatientObject : allNewPatients) {
JSONObject tempPatientJSON = new JSONObject();
try {
tempPatientJSON.put("firstName", tempPatientObject.getFirstName());
tempPatientJSON.put("lastName", tempPatientObject.getLastName());
tempPatientJSON.put("height", tempPatientObject.getHeight());
tempPatientJSON.put("weight", tempPatientObject.getWeight());
tempPatientJSON.put("vaccines", tempPatientObject.getVaccinHistory());
tempPatientJSON.put("address", tempPatientObject.getAddress());
tempPatientJSON.put("zone", tempPatientObject.getZone());
tempPatientJSON.put("id", tempPatientObject.getId());
String dateOfBirth = tempPatientObject.getDateOfBirth().get(Calendar.DAY_OF_MONTH) + "/" + tempPatientObject.getDateOfBirth().get(Calendar.MONTH) + "/" + tempPatientObject.getDateOfBirth().get(Calendar.YEAR);
tempPatientJSON.put("dob",dateOfBirth);
} catch (JSONException e) {
e.printStackTrace();
}
allNewPatientJSONArray.put(tempPatientJSON);
}
if(allNewPatients.size() > 0){
JSONObject bodyJSON = new JSONObject();
try {
bodyJSON.put("allNewPatients", allNewPatientJSONArray);
} catch (JSONException e) {
e.printStackTrace();
}
final MediaType JSON = MediaType.parse("application/json; charset=utf-8");
final RequestBody body = RequestBody.create(JSON, String.valueOf(bodyJSON));
Request request = new Request.Builder()
.url(activityMain.getString(R.string.main_url) + "/api/syncFromOffLine")
.headers(buildStandardHeaders(Stormpath.accessToken()))
.post(body)
.build();
okHttpClient.newCall(request).enqueue(new Callback() {
#Override
public void onFailure(Call call, IOException e) {
Log.d("DEBEUG", "error: " + e.getMessage());
}
#Override
public void onResponse(Call call, Response response) throws IOException {
if(response.code() == 200){
Log.d("DEBEUG", "response: " + response.body().string());
} else {
Log.d("DEBEUG", "there was an error: " + response.message().toString());
}
}
});
}
return true;
}

Related

Get results of multiple network requests when they are all done

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?

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;
}
}

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
}
}
});

async method is not running when clicking on button

There is a button in my app and when I click on it , it declares the method insertintodatabase. But, nothing is happening when I am clicking on it , even the log is not showing anything.
Where is the problem ? Please suggest.
private final OkHttpClient client = new OkHttpClient();
public void SignUp(View view)
{
insertToDatabase();
}
private void insertToDatabase(){
class SendPostReqAsyncTask extends AsyncTask<String, Void, String> {
#Override
protected void onPreExecute()
{
name = usernam.getText().toString();
pass = passw.getText().toString();
emails = email.getText().toString();
Log.e("GetText","called");
}
#Override
protected String doInBackground(String... params) {
String json = "";
try {
JSONObject jsonObject = new JSONObject();
jsonObject.accumulate("name", name);
jsonObject.accumulate("password", pass);
jsonObject.accumulate("email", emails);
json = jsonObject.toString();
Log.e("MYAPP", "getjson");
} catch (JSONException e) {
Log.e("MYAPP", "unexpected JSON exception", e);
}
try{
RequestBody formBody = new FormEncodingBuilder()
.add("result", json)
.build();
Request request = new Request.Builder()
.url("https://justedhak.comlu.com/receiver.php")
.post(formBody)
.build();
Response response = client.newCall(request).execute();
if (!response.isSuccessful()) throw new IOException("Unexpected code " + response);
} catch (IOException e){
Log.e("MYAPP", "unexpected JSON exception", e);
}
return "success";
}
#Override
protected void onPostExecute(String result) {
super.onPostExecute(result);
Toast.makeText(getApplicationContext(), result, Toast.LENGTH_LONG).show();
}
php
$username= $_POST['username'];
$password= $_POST['password'];
$email= $_POST['email'];
$image =$_POST['image'];
$sql = "insert into USERS (username,password,email) values ('$username','$password','$email')";
if(mysqli_query($con,$sql)){
echo 'success';
}
else{
echo 'failure';
}
mysqli_close($con);
Because OkHttp supports asynchronous, I think you can also refer to the following way:
Let's assume you have mHandler = new Handler(Looper.getMainLooper()); inside onCreate
private void updateToDatabase() {
// POST request
OkHttpClient client = new OkHttpClient();
RequestBody requestBody = new FormEncodingBuilder()
.add("key1", "value1")
.add("key2", "value2")
.build();
Request request = new Request.Builder()
.url("http://...")
.post(requestBody)
.build();
client.newCall(request).enqueue(new Callback() {
#Override
public void onFailure(final Request request, final IOException e) {
mHandler.post(new Runnable() {
#Override
public void run() {
Toast.makeText(mContext, e.toString(), Toast.LENGTH_SHORT).show();
}
});
}
#Override
public void onResponse(Response response) throws IOException {
mHandler.post(new Runnable() {
#Override
public void run() {
Toast.makeText(mContext, response.body().string(), Toast.LENGTH_SHORT).show();
}
});
}
});
}
If you still want to use with AsyncTask, update your code as the following:
public class MainActivity extends AppCompatActivity {
...
public void SignUp(View view)
{
new SendPostReqAsyncTask().execute();
}
...
private class SendPostReqAsyncTask extends AsyncTask<String, Void, String> {
#Override
protected void onPreExecute() {
name = usernam.getText().toString();
pass = passw.getText().toString();
emails = email.getText().toString();
Log.e("GetText", "called");
}
#Override
protected String doInBackground(String... params) {
String json = "";
try {
JSONObject jsonObject = new JSONObject();
jsonObject.accumulate("name", name);
jsonObject.accumulate("password", pass);
jsonObject.accumulate("email", emails);
json = jsonObject.toString();
Log.e("MYAPP", "getjson");
} catch (JSONException e) {
Log.e("MYAPP", "unexpected JSON exception", e);
}
try {
OkHttpClient client = new OkHttpClient();
RequestBody formBody = new FormEncodingBuilder()
.add("result", json)
.build();
Request request = new Request.Builder()
.url("https://justedhak.comlu.com/receiver.php")
.post(formBody)
.build();
Response response = client.newCall(request).execute();
if (!response.isSuccessful()) throw new IOException("Unexpected code " + response);
} catch (IOException e) {
Log.e("MYAPP", "unexpected JSON exception", e);
}
return "success";
}
#Override
protected void onPostExecute(String result) {
super.onPostExecute(result);
Toast.makeText(getApplicationContext(), result, Toast.LENGTH_LONG).show();
}
}
}
Somewhere you have to create object of SendPostReqAsyncTask and call execute method passing arguments ...
// Example class
class DownloadFilesTask extends AsyncTask<URL, Integer, Long> {
// some code
}
// Call the execute method of Async Task
new DownloadFilesTask().execute(url1, url2, url3);
// Use like this ..
public class <Your Root class> extends Activity{
#Override
public void onCreate(Bundle savedInstanceState) {
// some code
private final OkHttpClient client = new OkHttpClient();
public void SignUp(View view)
{
new SendPostReqAsyncTask().execute();
}
}
class SendPostReqAsyncTask extends AsyncTask<String, Void, String> {
#Override
protected void onPreExecute()
{
name = usernam.getText().toString();
pass = passw.getText().toString();
emails = email.getText().toString();
Log.e("GetText","called");
}
#Override
protected String doInBackground(String... params) {
String json = "";
try {
JSONObject jsonObject = new JSONObject();
jsonObject.accumulate("name", name);
jsonObject.accumulate("password", pass);
jsonObject.accumulate("email", emails);
json = jsonObject.toString();
Log.e("MYAPP", "getjson");
} catch (JSONException e) {
Log.e("MYAPP", "unexpected JSON exception", e);
}
try{
RequestBody formBody = new FormEncodingBuilder()
.add("result", json)
.build();
Request request = new Request.Builder()
.url("https://justedhak.comlu.com/receiver.php")
.post(formBody)
.build();
Response response = client.newCall(request).execute();
if (!response.isSuccessful()) throw new IOException("Unexpected code " + response);
} catch (IOException e){
Log.e("MYAPP", "unexpected JSON exception", e);
}
return "success";
}
#Override
protected void onPostExecute(String result) {
super.onPostExecute(result);
Toast.makeText(getApplicationContext(), result, Toast.LENGTH_LONG).show();
}
}

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);
}
});

Categories

Resources