Is publishProgress method of AsyncTask asynchronous? - java

I've used AsyncTask quite a bit - but I have come across a seemingly simple question that confused me. The question is this:
Is publishProgress(Progress... values) supposed to return
immediately? In other words, is this method asynchronous?
Some Context:
I'm trying to determine whether the following code
Fires an HTTP request every three seconds, regardless of the response OR
Fires an HTTP request, waits for the response, and then sleeps for three seconds before firing the next request.
public class MyAsyncTask {
#Override
protected void doInBackground(String... params) {
while (mRunning) {
// Call publishProgress
this.publishProgress(makeHttpRequest());
// Sleep for 3 seconds
synchronized (lock) {
try {
lock.wait(3 * 1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
return null;
}
private HttpResponse makeHttpRequest() {
HttpResponse ajaxResponse = null;
Throwable throwable = null;
try {
ajaxResponse = mHttpClient.execute(mHttpGet);
} catch (ClientProtocolException e) {
// Handle exception
} catch (IOException e) {
// Handle exception
} catch (Exception e) {
// Handle exception
}
return ajaxResponse;
}
#Override
protected void onProgressUpdate(HttpResponse... values) {
// Do something with the response
}
}

You're asking two different things here:
publishProgress() does indeed return instantly, it just posts a message to some Handler
Unrelated to how publishProgress() behaves, your code would always execute the HTTP request, wait for the response, then sleep three seconds. Just inlining method calls like publishProgress(makeHttpRequest()) doesn't mean that makeHttpRequest() isn't executed right where it's called, in your doInBackground() method.

this.publishProgress(makeHttpRequest());
is equals to (Java can't pass methods. Just the results)
HttpResponse resp = makeHttpRequest();
this.publishProgess(resp);
so makeHttpReqest is done in the background.
You than pass the HttpResponse Object to publishProgress which returns immediately. The progress Object is then asynchronously send to onProgressUpdate() in the UI thread.
-> it's the then sleeps way.

Related

Android - Return boolean value from within a Thread

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

Why does my Client freeze when awaiting a response from the Server? [duplicate]

I have a small bit of code that runs in an applet that contains SWING controls and is used to write information to a socket on a certain port and then listens for a response. This works fine, but there is a problem with it. The port listener is essentially in a loop until null is received by the server. I want users to be able to perform other actions in the GUI instantiated by the applet while waiting for the server to respond (this could take minutes to occur). I also need to worry about the connection between the server and the client disconnecting. But the way the code is written, the applet appears to freeze (its really in a loop) until the server responds. How can I allow the listener to do its listening in the background, allowing other things to occur in the program. I assume I need to use threads and I'm sure for this application, it is easy to implement, but my lack of a solid thread foundation is hampering me. Below is the code (you can see how simple it is). How can I improve it to make it do what I need it to do>
public String writePacket(String packet) {
/* This method writes the packet to the port - established earlier */
System.out.println("writing out this packet->"+packet+"<-");
out.println(packet);
String thePacket = readPacket(); //where the port listener is invoked.
return thePacket;
}
private String readPacket() {
String thePacket ="";
String fromServer="";
//Below is the loop that freezes everything.
try {
while ((fromServer = in.readLine()) != null) {
if (thePacket.equals("")) thePacket = fromServer;
else
thePacket = thePacket+newLine+fromServer;
}
return thePacket; //when this happens, all listening should stop.
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
return null;
}
}
Thanks,
Elliott
There lots of different means of getting the IO performed on a different thread, but in this case you probably want to use SwingWorker.
Your code would look something like:
private final Executor executor = Executors.newSingleThreadExecutor();
public void writePacket(final String packet)
{
// schedules execution on the single thread of the executor (so only one background operation can happen at once)
//
executor.execute(new SwingWorker<String, Void>()
{
#Override
protected String doInBackground() throws Exception
{
// called on a background thread
/* This method writes the packet to the port - established earlier */
System.out.println("writing out this packet->"+packet+"<-");
System.out.println(packet);
String thePacket = readPacket(); //where the port listener is invoked.
return thePacket;
}
#Override
protected void done()
{
// called on the Swing event dispatch thread
try
{
final String thePacket = get();
// update GUI with 'thePacket'
}
catch (final InterruptedException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
catch (final ExecutionException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
}
});
}
private String readPacket()
{
String thePacket ="";
String fromServer="";
//Below is the loop that freezes everything.
try
{
while ((fromServer = in.readLine()) != null)
{
if (thePacket.equals(""))
thePacket = fromServer;
else
thePacket = thePacket+newLine+fromServer;
}
return thePacket; //when this happens, all listening should stop.
}
catch (IOException e)
{
e.printStackTrace();
return null;
}
}
All the network I/O should be in a separate thread.
BTW readLine() returns null when the server closes the connection, not when it has finished sending data for the moment.

How would I implement my present threads into an AsyncTask to make the UI respond better?

For my activities to work, I have to get data from the internet.
I implemented threads, but I am not that good with Java or threads yet, so I kinda rushed through it just hoping it would work. Well it works, but the UI feels slow sometimes because it takes awhile until the activity appears.
Here is my code
an activity, lets call it MainActivity calls:
JSONObject Data = WebApi.getData(id);
the class WebApi pieces the url together:
public static JSONObject getData(String id) {
String url = URL;
url += DATA_URL;
url += VALUE_DATA_ID + id;
return WebInterface.executeWeb(url);
}
and hands it over to WebInterface, in WebInterface the whole thing gets executed:
public static String getUrl(final String url) {
final StringBuilder sb = new StringBuilder();
Thread thread = new Thread(new Runnable() {
public void run()
{
try
{
InputStream is = (InputStream) new URL(url).getContent();
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
String result, line = reader.readLine();
result = line;
while((line=reader.readLine())!=null){
result+=line;
}
sb.append(result);
} catch (Exception e)
{
// TODO: handle exception
e.printStackTrace();
}
}
});
thread.start();
try {
thread.join();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
String result = sb.toString();
Log.d(App.TAG, result);
return result;
}
public static JSONObject executeWeb(final String url) {
String result = WebInterface.getUrl(url);
JSONObject json = null;
try {
json = new JSONObject(result.trim());
} catch (JSONException e) {
try {
json = new JSONObject("{}");
} catch (JSONException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
}
return json;
}
well this works but i feel like this would work even better, if I would implement it with ASyncTask. My Activity could show some cached data until the "real" data appears. Would that be possible with AsyncTask? And would I need to redo a lot of my code for that?
thanks in advance for the help!
Edit:
thanks to whoever suggested AsyncTaskLoader (i think that one deleted his answer)
I did it with AsyncTaskLoader, very handy and very easy!
In effect your code is single threaded because of thread.join(). The current thread just waits for the newly spawned thread to finish. You have in effect not removed the network from the main thread, hence the UI "locks up" or feels slow.
You could have a callback that runs on the main thread when your thread is finished, but AsyncTask does this for you, and allows you to update a progress bar properly if desired. Read the documentation on how to implement AsyncTask.
svenoaks is correct that your use of thread.join() is making your code effectively single threaded. His solution of using an AsyncTask is also correct.
An alternative approach is to use a Handler in conjunction with the threads you already have. Create the Handler on your main thread, then in the spawned thread obtain() a new message and use the handler to send it. You then have code in the handler (which executes on the main thread) that receives the message and updates the UI.
Without seeing more of your code I can't be sure what it is you want to do with the data, but I can give you a basic example of how to use an AsyncTask. First you won't need any of that Thread stuff in getUrl(), so lets get rid of it. getUrl() should look something like this:
public static String getUrl(String url) {
final StringBuilder sb = new StringBuilder();
try
{
InputStream is = (InputStream) new URL(url).getContent();
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
String result, line = reader.readLine();
result = line;
while((line=reader.readLine())!=null){
result+=line;
}
sb.append(result);
} catch (Exception e)
{
// TODO: handle exception
e.printStackTrace();
}
String result = sb.toString();
return result;
}
Next lets wrap your call to WebApi.getData in an AsyncTask, so that it runs in the background.
new AsyncTask<Void, Void, JSONObject>(){
#Override
protected JSONObject doInBackground(Void... params) {
JSONObject data = WebApi.getData(id);
return data;
}
#Override
protected void onPostExecute(JSONObject result){
//here you can do something with result
}
}.execute();
AsynTask will execute whatever code is in doInBackground() in a background thread, and then return the result to onPostExecute(), which will be run on the UI thread. Please note id will have to be declared final in the example I gave above.
As has already been said, you should probably read the documentation on AsyncTask.

error: unreported exception InterruptedException; must be caught or declared to be thrown (calling AsyncTask)

This is my class that extends AsyncTask
public class JSONFunctions extends AsyncTask<Void, Void, String> {
#Override
protected String doInBackground(Void... urls) {
String line = "";
HttpClient httpclient = new DefaultHttpClient();
HttpGet httpget = new HttpGet("http://appDev.milasevicius.com/server/homeresults.php");
try {
HttpResponse response = httpclient.execute(httpget);
if(response != null) {
InputStream inputstream = response.getEntity().getContent();
line = convertStreamToString(inputstream);
} else {
line = "Unable to complete your request";
}
} catch (ClientProtocolException e) {
line = "Caught ClientProtocolException";
} catch (IOException e) {
line = "Caught IOException";
} catch (Exception e) {
line = "Caught Exception";
}
return line;
}
protected void onProgressUpdate(Integer... progress) {
}
protected void onPostExecute(String result) {
}
}
And this is my call:
String output = new JSONFunctions().execute().get();
But compilator says that
error: unreported exception InterruptedException; must be caught or declared to be thrown
sorry for my noobish question, but how to fix that? And am I doing right call to get result?
public final Result get ()
Added in API level 3
Waits if necessary for the computation to complete, and then retrieves its result.
Returns
The computed result.
Throws
CancellationException If the computation was cancelled.
ExecutionException If the computation threw an exception.
InterruptedException If the current thread was interrupted while waiting.
get() throws InterrruptedException. Your log says you need to catch those.
Also you should not call get() coz its blocks the ui thread waiting fro the result. You should not block the ui thread.
Remove get() and invoke as new JSONFunctions().execute().
To get the result in the activity use a interface
Example #
How do I return a boolean from AsyncTask?
Javadoc
A bare InterruptedException being thrown from .get() indicates that the current thread of execution
(the one calling .get()) was interrupted before calling get(), or while blocked in .get().
This is not the same thing as an executor thread or one of its tasks being interrupted.
Someone or
something is interrupting your "main" thread -- or at least the thread calling .get().
Use
new JSONFunctions().execute()
instead of
new JSONFunctions().execute().get();

Java Smack FileTransfer

Okay, I got the following code from the web, and it does work:
#Override
public void fileTransferRequest(FileTransferRequest request) {
// Check to see if the request should be accepted
final IncomingFileTransfer transfer = request.accept();
runnningFileTransfer = transfer;
try
{
final File file = new File("/Users/Akku/Downloads/in2" + request.getFileName());
transfer.recieveFile(file);
t = new Thread(new Runnable() {
#Override
public void run() {
// TODO Auto-generated method stub
try {
transfer.recieveFile(file);
System.out.println("DONE?");
} catch (XMPPException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
});
t.run();
This code runs, and in the case of my 10MB test file it takes quite a lot of time. Sadly, I need to know if the transfer is finished or what the progress is. Funnily, I also got this part (which just sleeps and checks for progress) from the web, when I append it, the file transfer does not work anymore:
while(!transfer.isDone())
{
if(transfer.getStatus().equals(Status.error))
{
System.out.println("ERROR"+transfer.getError() + " EX: " + transfer.getException());
}
else
{
System.out.println("Written: "+transfer.getAmountWritten());
System.out.println("STATUS"+transfer.getStatus());
System.out.println("PROGRESS"+transfer.getProgress());
}
try
{
Thread.sleep(10000);
System.out.println("Waiting...");
}
catch (Exception e)
{
e.printStackTrace();
}
}
Any hint why this might happen? I guess it's something Java, because the above snippet works flawlessly.
The case that works should be throwing an exception. You call receive twice on the transfer object. The second call should produce an exception when it tries to create the file again. The second call, along with the thread creation is not necessary in this case as the transfer() method is asynchronous and has it's own internal threading.
It is hard to say why it doesn't work with your status check, since you don't show where you are doing this check. My suspicion is that you are calling it on the read thread and thus blocking the reading of new packets. Your loop checking for the transfer status should be running in its own thread.

Categories