For my project I need to check a URL to see if it exists or not.
So I created a HttpURLConnection and connected to the url and wait for the response code.
Since I can't use that HttpURLConnection in my Main Thread, i had to move it to an AsyncTask and let it run on a separate Thread.
This is what my code for that AsyncTask looks like (only the important parts):
private class URLExists extends AsyncTask<String, Void, Boolean> {
protected Boolean doInBackground(String... urls)
{
boolean isValid = false;
try
{
URL myurl = new URL(urls[0]);
HttpURLConnection.setFollowRedirects(false);
HttpURLConnection connection = (HttpURLConnection) myurl.openConnection();
connection.setUseCaches(true);
connection.setRequestMethod("HEAD");
connection.connect();
int code = connection.getResponseCode();
...
connection.disconnect();
if(code != 404)
isValid = true;
else
isValid = false;
}
...
return isValid;
}
protected void onPostExecute(Boolean isValid)
{
isTrue = isValid;
}
}
So basically i then get a boolean value isTrue which tells me if the url is valid. When I run this i get the right results, everything works.
But now, when i execute this AsyncTask, it runs parallel to my main Thread, obviously.
I have this code:
new URLExists().execute("https://www.example.com");
if(isTrue)
{
myButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
//Do Something
}
});
}
Since my AsyncTask runs parallel, my Main Thread executes the next operation without waiting for the result of the AsyncTask. Since isTrue is false by default, the if statement never runs.
Of course i know about the protected void onPostExecute() in the AsyncTask, but does that mean that all the code that follows in my main Thread has to be in that function in the parallel Thread? It all depends on the outcome of the URL check.
I know about the .get() method, but that freezes my MainThread and the UI, so that's not really an option for me.
Is there any other way of making the Main thread wait for the AsyncTask? I know the defeats the purpose of the AsyncTask, but all I want is to check if the URL exists and I can only do checks in an AsyncTask.
You don't need multithread for your task. All what you need is to check that url is available. Right? Of course it may take some time and you have to wait this time in your main thread. That's right. But you still need to wait. Don't create unnecessary complexity. Just read url, get response code, validate it, check for timeout exception and you are good to go.
We need to look at the specification of AsyncTask. Typically in any asynchronous method you have a callback function that lets you know the background operation has completed. In the case of Android it is onPostExecute()
It can be found here. http://developer.android.com/reference/android/os/AsyncTask.html
When an asynchronous task is executed, the task goes through 4 steps:
onPreExecute(), invoked on the UI thread before the task is executed. This step is normally used to setup the task, for instance by showing a progress bar in the user interface.
doInBackground(Params...), invoked on the background thread immediately after onPreExecute() finishes executing. This step is used to perform background computation that can take a long time. The parameters of the asynchronous task are passed to this step. The result of the computation must be returned by this step and will be passed back to the last step. This step can also use publishProgress(Progress...) to publish one or more units of progress. These values are published on the UI thread, in the onProgressUpdate(Progress...) step.
onProgressUpdate(Progress...), invoked on the UI thread after a call to publishProgress(Progress...). The timing of the execution is undefined. This method is used to display any form of progress in the user interface while the background computation is still executing. For instance, it can be used to animate a progress bar or show logs in a text field.
onPostExecute(Result), invoked on the UI thread after the background computation finishes. The result of the background computation is passed to this step as a parameter.
For your specific case you might want to do something like this..
yourAsyncTask{
#Override
protected Boolean doInBackground(Void... params){
// CHECK YOUR URL HERE
}
.
.
.
#Override
public void onPostExecute(Result result){
if(isTrue) {
myButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
//Do Something
}
});
}
}
}
Related
I have a pretty standard static class extending AsyncTask as follows:
public static class MyAsyncTask extends AsyncTask<Void, Void, Response<String>>{
// Some members, including a listener
public MyAsyncTask( // some params ){
// Init
}
#Override
protected void onCancelled() {
super.onCancelled();
}
#Override
protected Response<String> doInBackground(Void... voids) {
// some background work
return response; // e.g., a Response<T> object as found in Retrofit
}
#Override
protected void onPostExecute(Response<String> response) {
// Send result params to a listener for further processing
listener.onMyAsyncTaskResult( //params );
}
}
A main method generates time-series data. The main method calls MyAsyncTask for each data point as and when it is generated by the main method. MyAsyncTask handles some network calls (e.g. using Retrofit) and other async operations that are generated for each element in the time-series. State information is to be maintained corresponding to each data point in the time-series, before and after MyAsyncTask returns.
The main method may terminate either automatically or by user input, such that the network responses for some past data in the time-series are still pending.
The main method displays a final state to the user after it is terminated. Ideally, I would like to wait for all the network responses, using which the final state may be displayed on a "best-effort" basis. But if a waitingThreshold is crossed, I would like to terminate the pending callbacks, since waiting too much after having completed an action doesn't generally make for good UX. This is the trade-off here.
Further, after the main method is terminated, it can be relaunched either automatically or by user input, in which case, the callbacks from the previous instance of the main method are no longer required. Also, for example, any additional background work (such as database writes) that happens in the callbacks become unnecessary because the final state of the previous instance of the main method has already been set.
The main method and callbacks run inside a Service.
One way to do this is to simply track the state of the main method globally, such as using boolean isMainMethodTerminated, and ignore the response in the callback if it has been terminated.
isMainMethodTerminated = false;
if(time > waitingThreshold){
// Terminate the main time-series method
isMainMethodTerminated = true;
}
...
#Override
public void onMyAsyncTaskResult( //params ){
if(!isMainMethodTerminated){
// continue using the callback
}
}
Using this method, the callbacks will still keep happening, but we just side-step the work inside the callback.
Is it better to instead call .cancel() on each instance of the pending MyAsyncTasks?
While I can use the above interception method using isMainMethodTerminated, it doesn't solve the problem very neatly.
What would be the efficient method(s) to handle the trade-off?
I am using AsyncTask so that the function I want executes immediately and does not wait till the end to be executed..
but for some reason I don't why it executes in at the end of all process!
I looked at other solutions and found that Thread should be executed at the end but for AsyncTask it should be executed whenever it is called..
here is my code
private void LogMeIn()
{
string CheckValue;
// Here I call the AsyncTask
new GCM().execute(null,null,null);
//gcmRegID is a public variable and should has GCM value assigned to it by now, but I it is empty as GCM() has not been executed yet
//This is always return empty string
CheckValue = gcmRegID;
}
This is the AsyncTask that wait till the end to be executed
//This is the AsyncTask
private class GCM extends AsyncTask<String, String, String> {
private String resp;
private Context context;
#Override
protected String doInBackground(String... params) {
GCMHelper gcmRegistrationHelper = new GCMHelper (
getApplicationContext());
try {
gcmRegID = gcmRegistrationHelper.GCMRegister("123456789");
} catch (Exception e) {
e.printStackTrace();
}
return gcmRegID;
}
}
I tried to put the call for GCMRegister in onPreExecute but i get an error that it has to be in the main thread
it is like i am going in circles....
the call has to be in the main thread and the main thread will be executed at the end of the function...
it is like no way to get the GCM code in the middle!!!!
How can I make this AsyncTask executes when it called??
Thanks
Without seeing more of your code it's hard for me to tell but I would take a look at where you are calling LogMeIn(). Because your AsyncTask and call to execute are nested in the LogMeIn() function, it won't be called until LogMeIn() is first called.
AsyncTask goes through the following 4 steps in order after calling execute():
onPreExecute()
doInBackground(Params...)
onProgressUpdate(Progress...)
onPostExecute(Result)
These can be added to your GCM class and used however you like. Note that you don't call them directly. AsyncTask does it automatically after calling .execute().
Only the tasks specified in doInBackground(Params...) are executed on a background thread. The rest are all done on the UI(or main) thread. I would suggest putting either a toast or a log inside onPreExecute() and in onPostExecute() to debug where/when GCM().execute is actually being called and then to tell you when the background task is complete. This will give you a better idea of what is going on.
Make sure you aren't trying to update the UI in doInBackground().
Would love to help more but we would need to see more of your code.
#Override
public void onPreExecute() {
super.onPreExecute();
Log.d("GCM", "onPreExecute: called");
}
#Override
public void onPostExecute(String resultOfDoInBackground) {
super.onPostExecute(resultOfDoInBackground);
Log.d("GCM", "onPostExecute: called");
}
AsyncTask keeps a queue of tasks and a thread pool,the thread pool execute the tasks one by one,so if you have too more tasks ,you will find it not execute your tasks immediately.
And in one process ,all your AsyncTask share one thread pool.In this case,you should make one task queue by yourself,you can just use HandleThread to execute a timely task.
Try placing your new GCM().execute(null,null,null); in the protected void onCreate(Bundle savedInstanceState) method. this way it will be called once the app is ran. This way you will have your GCM id before you get to the LogMEIn method.
Try this -
if( Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB ) {
new GCM().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR,params);
} else {
new GCM().execute();
}
i am newbie on android development and i would like to ask how to wait some async tasks that already running. Also when i am trying to sleep the main Thread many of them are suspended by the system. When i use an arraylist to add them and then call to each of them get() many of them never finish on time. Please give me a code example because i searching it over of three days...
Thx!!
for(){
async...
async.execute();
arraylist.add(async);
}
...
for(arraylist.size){
arraylist.get().get();
}
I will try to answer your question here but the question is not clear.
If you want to check whether there is an AsyncTask completed or not in an arraylist, we can use getStatus call that return us a status, and one of the status, luckily, is FINISHED, so you can check your status of any given AsyncTask.
If you want to sleep until one of the AsyncTask is finished, then the best approach probably involves doing something in onPostExecute. When you override it, you can do something to notify the main thread. One of the ways you can do this is here:
public interface Callback {
public void callBack(int id);
}
public class MainActivity implements Callback {
private void function() {
//do your thing
AsyncTask task0 = new MyAsyncTask(this, 0); //implement your own asynctask here,
//with one of the parameters this activity so that you can get a callback.
//Also, optionally give in the id so that you know what index of asynctask is finished first.
//do the same thing for other tasks
task1.execute(params);
}
public void callBack(int id) {
arrayList.get(id).get(); //this is done
}
In your AsyncTask, you simply override the onPostExecute to something like this
protected void onPostExecute (Result result) {
//do your thing
mainActivity.callBack(id);
}
Hope this helps.
I've a method who return a result (return an integer), my method is executed in a Thread for load 40 000 objects, i return an integer who count the number objects loaded. My question is, How return the int with the Thread ? Actually, the result is returned directly and is equal to 0.
public int ajouter(params) throws DaoException, ConnectException {
final ProgressDialog dialog = ProgressDialog.show(mActivity, "Title",
"Message", true);
final Handler handler = new Handler() {
public void handleMessage(Message msg) {
dialog.dismiss();
}
};
Thread t = new Thread() {
public void run() {
try {
Str_Requete = "SELECT * FROM Mytable";
ResultSet result = ExecuteQuery(Str_Base, Str_Requete);
Index = addObjects(result);
handler.sendEmptyMessage(0);
} catch (SQLException e) {
e.printStackTrace();
}
}
};
t.start();
return Index;
}
When i call my method in my mainActivity :
int test = myObjs.ajouter(params);
test is equal to 0, the value is returned directly...
My constraint is didnt use AsyncTask.
The whole point of using a Thread is not to block the calling code while performing the task of the thread. Thread.start() returns immediately, but in the meantime a new thread is started in parallel to the current thread which will execute the code in the run() method.
So by definition there is no such thing as returning a value from a thread execution. You have to somehow send a signal back from the thread that performed the task to the thread in which you need the result. There are many ways of doing this, there's the standard Java wait/notify methods, there is the Java concurrency library etc.
Since this is Android, and I assume your calling code is running on the main thread, it's probably wise to use the functionality of Handler. And in fact, you are already doing that - you have a Handler that closes the dialog when the thread is done with its work - but for some reason you seem to expect the result of that work to be ready before it has even started. It would be reasonable to extend your existing Handler with some code that does something with the calculated value and remove the code that returns the value of a variable before or at the same time as it's being calculated by another thread.
I also strongly encourage you to study some concurrency tutorial such as Oracle's concurrency lesson or Android Thread guidelines to really understand what's going on in the background. Writing concurrent code without mastering the concepts is bound to fail sooner or later, because it's in the nature of concurrency that multiple things are happening at the same time, will finish in random order etc. It may not fail often, but you will go crazy wondering why something that works 90% of the time suddenly fails. That's why topics such as atomicity, thread synchronization etc are critical to comprehend.
Edit: Simple Android example of starting a worker thread, performing some work, posting back event to main thread.
public class MyActivity extends Activity {
private Handler mHandler = new Handler();
...
private void doSomeWorkInBackground() {
new Thread() {
public void run() {
// do slow work, this may be blocking
mHandler.post(new Runnable() {
public void run() {
// this code will run on main thread,
// updating your UI or whatever you need.
// Hence, code here must NOT be blocking.
}
});
}
}.start();
// This code will be executed immediately on the main thread, and main thread will not be blocked
}
You could in this example also use Activity.runOnUiThread(Runnable).
Please consider however that AsyncTask basically wraps this kind of functionality in a very convenient way, so if it suits your purposes you should consider using AsyncTask.
If you dont want to use AsyncTask or ForkJoin, then you could implement an Interface e.g. callback in your main class.
In your Example you dont wait until the Thread is done... thread.join
One Solution:
Your Thread is a extra class with an constructor to hold the reference to the calling class.
public Interface callback
{
public int done();
}
public class main implements callback
{
...
CustomThread t = new CustomThread(this)
...
}
public class CustomThread extends Thread
{
private Callback cb;
public CustomThread(Callback cb)
{
this.cb=cb;
}
.
.
.
//when done
cb.done(int)
}
I am following tutes from codelearn, and trying create an AsyncTask which generates tweets and executes another AsyncTask to write to a cache file.
I have Thread.sleep, so the UI on first load waits until the Tweets are written to cache file. First I execute AysncTask new AsyncWriteTweets(this.parent).execute(tweets); then sleep for 10 secs.
But in logcat I can see that AsyncWriteTweets also gets executed after 10 sec sleep. Hence onPostExecute gets executed before the tweets are written to the cache file, giving a blank screen.
public class AsyncFetchTweets extends AsyncTask<Void, Void, Void> {
private TweetListActivity parent;
ArrayList<Tweet> tweets = new ArrayList<Tweet>();
ArrayList[] temp;
public AsyncFetchTweets(TweetListActivity parent){
this.parent = parent;
}
#Override
protected Void doInBackground(Void... params) {
int result = 0;
Log.d("ASync", "Calling asycn");
for (int i=0;i<4;i++){
Tweet tweet = new Tweet();
tweet.setTitle("Title Async Very New" + i);
tweet.setBody("Body text for tweet no " + i);
tweets.add(tweet);
}
new AsyncWriteTweets(this.parent).execute(tweets);
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return null;
}
protected void onPostExecute(Void result){
Log.d("Async", "on Post execute");
this.parent.renderTweets();
}
}
PS: My assumption is AsyncTask should create a new thread, hence
Thread.sleep in parent should not stop child. If it is otherwise
please advise how can I overcome this issue.
This:
new AsyncWriteTweets(this.parent).execute(tweets);
is wrong, AsyncTask must be executed on UI thread and not Worker thread. You might use Handler and post runnable to execute it safely.
For reference look into Threading rules:
execute(Params...) must be invoked on the UI thread.
http://developer.android.com/reference/android/os/AsyncTask.html
another part of above link of interest is Order of execution, :
Starting with HONEYCOMB, tasks are executed on a single thread to avoid common application errors caused by parallel execution.
so your first asynctask must end before next one might start, but you migt bring back previous parallel behaviour by using executeOnExecutor(java.util.concurrent.Executor, Object[]) with THREAD_POOL_EXECUTOR. Still execute must be done on UI thread.
As per documentation on execute() method, a single thread is used for all async tasks. So, if you are sleeping in your async tasks, it will affect other async tasks.
Give executeOnExecutor a try.