I am attempting to use the Okhttp library to connect my android app to my server via API.
My API call is happening on a button click and I am receiving the following android.os.NetworkOnMainThreadException. I understand that this is due the fact I am attempting network calls on the main thread but I am also struggling to find a clean solution on Android as to how make this code use another thread (async calls).
#Override
public void onClick(View v) {
switch (v.getId()){
//if login button is clicked
case R.id.btLogin:
try {
String getResponse = doGetRequest("http://myurl/api/");
} catch (IOException e) {
e.printStackTrace();
}
break;
}
}
String doGetRequest(String url) throws IOException{
Request request = new Request.Builder()
.url(url)
.build();
Response response = client.newCall(request).execute();
return response.body().string();
}
Above is my code, and the exception is being thrown on the line
Response response = client.newCall(request).execute();
I've also read that Okhhtp supports Async requests but I really can't find a clean solution for Android as most seem to use a new class that uses AsyncTask<>?
To send an asynchronous request, use this:
void doGetRequest(String url) throws IOException{
Request request = new Request.Builder()
.url(url)
.build();
client.newCall(request)
.enqueue(new Callback() {
#Override
public void onFailure(final Call call, IOException e) {
// Error
runOnUiThread(new Runnable() {
#Override
public void run() {
// For the example, you can show an error dialog or a toast
// on the main UI thread
}
});
}
#Override
public void onResponse(Call call, final Response response) throws IOException {
String res = response.body().string();
// Do something with the response
}
});
}
& call it this way:
case R.id.btLogin:
try {
doGetRequest("http://myurl/api/");
} catch (IOException e) {
e.printStackTrace();
}
break;
Related
I want to cancel an AsyncTask after a timeout if the task is still running and I want to cancel it immediately. Here is my code:
HttpURLConnection connection = null;
//GetRequestTask extends AsyncTask
final GetRequestsTask requestTask = new GetRequestsTask();
requestTask.execute(createUrl());
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
Log.d("myapp", "entered handler");
if (requestTask.getStatus() == AsyncTask.Status.RUNNING) {
Log.d("myapp", "entered cancelling");
requestTask.cancel(true);
connection.disconnect();
}
}
}, TIME_OUT);
As you can see, I am calling a HTTP request in my AsyncTask's doInBackground method. and when I want to cancel the AsyncTask I also disconnect the connection.
The problem is that when I call cancel(true) and my app logs entered cancelling, the AsynkTask won't cancel immediately and will cancel with a minimum 10 to 20 seconds delay.
what should I do to cancel the task as soon as I call cancel?
UPDATE: This is my `AsyncTask code:
private class GetRequestsTask extends AsyncTask<URL, Void, JSONObject> {
#Override
protected void onPreExecute() {
Log.d("myapp", "entered onPreExecute");
mLoadingDialog.show();
}
#Override
protected JSONObject doInBackground(URL... urls) {
Log.d("myapp", "entered doInBackground");
try {
connection = (HttpURLConnection) urls[0].openConnection();
connection.setRequestProperty("Accept", "application/json");
int response = connection.getResponseCode();
if (response == HttpURLConnection.HTTP_OK) {
StringBuilder builder = new StringBuilder();
BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
try {
String line;
while ((line = reader.readLine()) != null) {
builder.append(line);
}
}
catch (IOException e) {
e.printStackTrace();
}
finally {
reader.close();
}
return new JSONObject(builder.toString());
}
else {
}
}
catch (Exception e) {
e.printStackTrace();
}
finally {
connection.disconnect();
}
return null;
}
#Override
protected void onPostExecute(JSONObject jsonObject) {
Log.d("myapp", "entered onPostExecute");
mLoadingDialog.dismiss();
if (jsonObject == null) {
showNoInternetDialog();
}
else {
convertJSONtoArrayList(jsonObject);
mRequestArrayAdapter.notifyDataSetChanged();
mListView.smoothScrollToPosition(0);
}
}
#Override
protected void onCancelled() {
Log.d("myapp", "entered onCancelled");
mLoadingDialog.dismiss();
showNoInternetDialog();
}
The problem is that my timeout is 20 seconds, but onCancelled is called after 35, 40 seconds.
From this question:
If you're doing computations:
You have to check isCancelled() periodically.
If you're doing a HTTP request:
Save the instance of your HttpGet or HttpPost somewhere (eg. a public field).
After calling cancel, call request.abort(). This will cause IOException be thrown inside your doInBackground.
Additionally if you use some library to provide convenient requests, then I think it should have some cancel() method. For example, for retrofit there is such method.
So in this case like for 'If you're doing a HTTP request' section. you need to:
Save the instance of your request (for retrofit it's Call)
After calling cancel, call 'cancel' method for saved instance of request.
And one more alternative is rxJava. With help of this library you can create Observable for your request and save reference to its subscription. Then you just need to call savedSubscription.unsubscribe() and that's it.
Also, please, do not use Async tasks as inner classes.
Using Jetty, I'm sending bytes to URL http://localhost:8080/input/ like so -
public static void sampleBytesRequest (String url)
{
try
{
HttpClient client = new HttpClient();
client.start();
client.newRequest(url)
.content(new InputStreamContentProvider(new ByteArrayInputStream("batman".getBytes())))
.send();
}
catch (Exception e) { e.printStackTrace(); }
}
My server (also Jetty) has a handler like so -
public final class JettyHandler extends AbstractHandler implements JettyConstants, LqsConstants
{
#Override
public void handle (String target,
Request baseRequest,
HttpServletRequest request,
HttpServletResponse response)
throws IOException, ServletException
{
response.setContentType(UTF_ENCODING);
String requestBody = null;
try { requestBody = baseRequest.getReader().readLine(); }
catch (IOException e) { e.printStackTrace(); }
System.out.println(new String(IOUtils.toByteArray(request.getInputStream())));
}
}
As you can see, I'm trying to recreate the original string from the binary data and print it to stdout.
However, if I set a break point at the print statement in the handler, when the request reaches that line, the server abruptly seems to skip over it.
What am I doing wrong? How can I get the binary data I'm sending over and recreate the string?
Thank you!
Turns out the issue was with my client.
Instead of
client.newRequest(url)
.content(new InputStreamContentProvider(new ByteArrayInputStream("batman".getBytes())))
.send();
The proper way to do this is -
client.newRequest(url)
.content(new BytesContentProvider("batman".getBytes()), "text/plain")
.send();
Im trying to return a boolean value from a runnable method within a Thread. I need to know whether a HTTPRequest method succeeded or not. The problem is I know the request is successful but I always get false as the response.
public boolean SmsDelivery;
SmsDelivery=sendSMS(prefix, number);
if(SmsDelivery){
//Do stuff
}
//The method itself
private boolean sendSMSinThread(final String str){
final AtomicBoolean b = new AtomicBoolean(false);
Thread thread = new Thread(new Runnable(){
HttpClient httpclient = new DefaultHttpClient();
HttpPost httppost = new HttpPost(str);
#Override
public void run() {
try {
// Execute HTTP Post Request
//HttpResponse response = httpclient.execute(httppost);
httpclient.execute(httppost);
b.set(true);
} catch (ClientProtocolException e) {
// TODO Auto-generated catch block
Log.e("Thread:","Unable to generate call"+e);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
Log.e("Thread:","Unable to generate call"+e);
}
}
});
thread.start();
return b.get();
}
UPDATE
Based on the advices here i managed to get the desired result, however, I dont know which method is more suitable for my needs. Can someone recommend whats the best usage in my case? Using AsyncTask or a Thread + join method.
First method is using AsyncTask in the following manner:
SmsTask smsTask = new SmsTask();
try{
smsResult = smsTask.execute(urlString).get();
}catch (InterruptedException e){
e.printStackTrace();
}catch (ExecutionException e){
e.printStackTrace();
}
//the class itself
class SmsTask extends AsyncTask<String,Void, Boolean> {
final AtomicBoolean b = new AtomicBoolean(false);
#Override
protected Boolean doInBackground(String... params) {
HttpClient httpclient = new DefaultHttpClient();
HttpPost httppost = new HttpPost(params[0]);
try {
httpclient.execute(httppost);
b.set(true);
} catch (IOException e) {
e.printStackTrace();
}
return b.get();
}
#Override
protected void onPostExecute(Boolean result) {
// result holds what you return from doInBackground
Log.i("result from async: ",""+result);
super.onPostExecute(result);
}
}
Second method, almost as I initially posted but with the 'thread.join()' method:
thread.start();
try {
thread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
return b.get();
You should wait until task will be performed. In this case you should run this code in single thread (new Thread is useless) or use Android's AsyncTask-like class and process result in onPostExecute method.
You could use some Observer pattern or something.
Something like this:
// have a custom Runnable
public class HTTPRequestRunnable implements Runnable {
HttpClient httpclient;
HttpPost httppost;
private HTTPRequestListner listner;
public HTTPRequestRunnable(String str, HTTPRequestListner listner) {
httpclient = new DefaultHttpClient();
httppost = new HttpPost(str);
this.listner = listner;
}
#Override
public void run() {
try {
// Execute HTTP Post Request
//HttpResponse response = httpclient.execute(httppost);
httpclient.execute(httppost);
if (listner != null)
listner.onSuccess();
} catch (ClientProtocolException e) {
if (listner != null)
listner.onFail();
Log.e("Thread:", "Unable to generate call" + e);
} catch (IOException e) {
if (listner != null)
listner.onFail();
e.printStackTrace();
Log.e("Thread:", "Unable to generate call" + e);
}
}
public void setListner(HTTPRequestListner listner) {
this.listner = listner;
}
/**
* here is your observer class
*/
public interface HTTPRequestListner {
void onSuccess();
void onFail();
}
}
Then use it like this in your method:
public void sendSMSinThread(final String str){
HTTPRequestRunnable httpRequestRunnable = new HTTPRequestRunnable(str,new HTTPRequestListner() {
#Override
public void onSuccess() {
//DO your logic here on success
}
#Override
public void onFail() {
//DO your logic here on fail
}
});
Thread thread = new Thread(httpRequestRunnable);
thread.start();
}
Here you go and i hope it will help you
There are multiple ways to achieve this.
Use a callable, instead of runnable, as callable's call method can return result
Stick to your approach, but before returning the result, call thread.join()
thread.start();
thread.join();
return b.get();
Drawbacks
If there are thousands of SMS to be sent, it will create those many threads.
There is no use of thread creation here as you can the incoming thread itself to send SMS.
Use Runnable and Future.
a. For each SMS create a SendSms object,
b. It will create a maximum of 10 threads.
c. The send SMS and getSMSdelivery will be synchronous events. So for each SMS sent, you can get the delivery status if that's your requirement.
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
public class SendSms
{
private static ExecutorService pool = Executors.newFixedThreadPool(10);
public boolean submitSms(String message,String phNo)
{
Runnable run = new SendSMSThread(message,phNo);
Future future = pool.submit(run);
try {
if(null ==future.get())
{
return true;
}
} catch (InterruptedException | ExecutionException e) {
// SMS Sending failed.
e.printStackTrace();
return false;
}
return false;
}
private class SendSMSThread implements Runnable
{
String message;
String phNo;
public SendSMSThread(String message,String phNo)
{
this.message = message;
this.phNo = phNo;
}
public void run()
{
//Send SMS
}
}
}
All the above three solution are blocking. So it will keep the threads in BLOCKING state, thereby posing significant threat to scalability of system.
a. Use a BlockingQueue.
b. For each SMS request, add a SMSObject to BlockingQueue.
c. Use a threadpool and process the objects in Queue.
d. Once the SMS is sent successfully, save the result to another data-structure.
e. Use a threadpool, read the data from above data-structure and notify about successful SMS delivery.
Try this
thread.start();
thread.join();
return b.get();
I'm having problems understanding how asynchronous servlets work, and in general how servlets deliver their response to the client.
What I'm trying to do is upload a video to a servlet via ajax. I thought that using an async servlet, I would obtain the response immediately in my browser and then the long task would be done in another thread.
I post my initial code here, before any code is written for file process, just an initial servlet to test asynchronism.
#WebServlet(name = "VideoUploader", urlPatterns = {"/VideoUploader"},
asyncSupported = true)
#MultipartConfig
public class VideoUploader extends HttpServlet {
#Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doPost(request, response);
}
#Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
final PrintWriter pw = response.getWriter();
final AsyncContext ac = request.startAsync();
ac.setTimeout(80000);
ac.addListener(new AsyncListener() {
#Override
public void onComplete(AsyncEvent event) throws IOException {
System.out.println("On complete");
}
#Override
public void onTimeout(AsyncEvent event) throws IOException {
System.out.println("On timeout");
}
#Override
public void onError(AsyncEvent event) throws IOException {
System.out.println("On error");
}
#Override
public void onStartAsync(AsyncEvent event) throws IOException {
System.out.println("On start async");
}
});
ac.start(new Runnable() {
#Override
public void run() {
for (int i = 0; i <= 10; i++) {
System.out.println("Async task: "
+ Thread.currentThread().getName());
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
}
}
ac.complete();
}
});
pw.write("end");
pw.close();
}
}
Then, the client part is:
<form id="formVideo">
<label for="videoFile">VĂdeo:</label>
<input id="videoFile" name="videoFile" type="file" /> <br/>
<input id="uploadVideoBtn" type="button" value="Subir" onClick="uploadVideo();"/>
</form>
<div id="notificaciones"/>
<script type="text/javascript">
function uploadVideo() {
var file = document.getElementById("videoFile").files[0];
var formdata = new FormData();
formdata.append("file", file);
var xhr = new XMLHttpRequest();
xhr.open("POST","/webapp/VideoUploader", true);
xhr.send(formdata);
xhr.onload = function(e) {
if (this.status == 200) {
alert(this.responseText);
}
};
}
</script>
When I didn't attach a video to the file input, the process is done as I expected, the response is immediately received in the browser. But when I attached a file of any size, my browser doesn't receive the response until the other thread is over.
I was researching on non blocking IO, but I'm not sure if it has something to do with this behaviour or not.
I'm still not sure how I want to implement this, although I'll listen to any advice, but what I would like is to understand the behaviour of this asynchronous servlets.
it is obivious, your browser will wait until the other thread completes. The following steps involved
Client Sent Request to Server
Server allocates Thread (Servlet Container) from ThreadPool
Servlet container creates Servlet instance / reuse existisng Servlet instance and invoke Servcie method in (Servlet Thread)
With in Service method by calling startAsync() will start new thread and pass the request,response instances to the new Thread to process the request note** New Thread is not blocking the http connection , it is just a thread in the jvm which is not bliocking any IO at this moment
Servlet Thread exists service method and returned to thread pool Note** here Response not yet sent to Client / Browser
Once the Process started in step 4 completed that thread will request Servlet Container to allocate to new Servlet thread to send the respond back to Client.
Only the at Step 6 the response will return back to Client. So there is no difference between the normal request and with "asyncSupported = true" from client point of view. Servlet 3.0 supports Threads per request by using "asyncSupported = true" instead of Thread per connection. Thread per connection will cause Thread Starvation.
#WebServlet(name = "VideoUploader", urlPatterns = { "/VideoUploader" }, asyncSupported = true)
#MultipartConfig
public class VideoUploader extends HttpServlet {
#Override
protected void doGet(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
doPost(request, response);
}
#Override
protected void doPost(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
final AsyncContext ac = request.startAsync();
ac.setTimeout(80000);
ac.addListener(new AsyncListener() {
public void onComplete(AsyncEvent event) throws IOException {
System.out.println("On complete");
}
public void onTimeout(AsyncEvent event) throws IOException {
System.out.println("On timeout");
}
public void onError(AsyncEvent event) throws IOException {
System.out.println("On error");
}
public void onStartAsync(AsyncEvent event) throws IOException {
System.out.println("On start async");
}
});
ac.start(new Runnable() {
public void run() {
System.out.println("Async task: "
+ Thread.currentThread().getName());
try {
for (Part part : ((HttpServletRequest) ac.getRequest())
.getParts()) {
System.out.println("File received"); // You Should write
// file here
// like
// part.write("fileName");
}
} catch (IOException e1) {
e1.printStackTrace();
} catch (ServletException e1) {
e1.printStackTrace();
}
ac.complete();
PrintWriter pw = null;
try {
pw = ac.getResponse().getWriter();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
pw.write("end");
pw.close();
}
});
}
}
Asynchronous servlet hands over the long running server side job to a different server thread. Non-Blocking IO, a new feature in servlet 3.1, deals with situation when incoming data is blocking or streamed slower than the server can read. Both are solutions to avoid servlet thread starvation. They are not about returning response to client immediately.
Since you are using Ajax, not a regular browser file upload, it should be easily implemented at the Ajax side with even a synchronous servlet, if you do not care about servlet thread starvation. Ajax is asynchronous in nature. Here is an example tutorial
http://www.javabeat.net/asynchronous-file-upload-using-ajax-jquery-progress-bar-and-java/
I am trying to develop a high load generating async HttpClient using Jetty 9 HttpClient API. I have written the basic code for doing POST requests
public void connectHttp() throws Exception {
HttpClient client = new HttpClient();
// Configure HttpClient here
client.setMaxConnectionsPerDestination(1000);
try {
client.start();
} catch(Exception e) {
System.out.println("Caught Exception in Client Start : ");
e.printStackTrace();
throw e;
}
try {
for(int i = 0 ; i<1000;i++) {
client.POST("http://localhost:8080/privaterestservice/jersey/privatedata/writedata")
.timeout(3, TimeUnit.SECONDS)
.file(Paths.get("stats_kestrel.txt"),"text/plain").send(new BufferingResponseListener() {
#Override
public void onComplete(Result res) {
System.out.println("Got Response : "+res.isSucceeded());
}
});
}
}
finally {
//client.stop();
}
System.out.println("I am Done!!");
System.out.println(client.getState());
}
I need to bombard the server with lot of requests. But when i run this code, it fails for the last few requests. I checked using Jmeter and there is no problem with the server. Also the code does not stop even after all the requests are completed.
How to make the code quit after all the responses are received instead of the threads going to sleep state?
Any help is greatly appreciated :)
You should use CountDownLatch, something like:
public void connectHttp() throws Exception {
HttpClient client = new HttpClient();
// Configure HttpClient here
client.setMaxConnectionsPerDestination(1000);
CountDownLatch countDown = new CountDownLatch(1000);
try {
client.start();
} catch(Exception e) {
System.out.println("Caught Exception in Client Start : ");
e.printStackTrace();
throw e;
}
try {
for(int i = 0 ; i<1000;i++) {
client.POST("http://localhost:8080/privaterestservice/jersey/privatedata/writedata")
.timeout(3, TimeUnit.SECONDS)
.file(Paths.get("stats_kestrel.txt"),"text/plain").send(new BufferingResponseListener() {
#Override
public void onComplete(Result res) {
System.out.println("Got Response : "+res.isSucceeded());
countDown.countDown();
}
#Override
public void onFailure(Response response, Throwable failure) {
countDown.countDown();
}
});
}
}
finally {
//client.stop();
}
countDown.await();
System.out.println("I am Done!!");
System.out.println(client.getState());
}
It will wait until all responses will complete.