I have created an AsyncTsak class in my project which downloads some information from web server. I am sure that it works well because when it is called by onCreate() , I can see the result . But unfortunately when I call it again via a button it doesn't work.
I am not sure but i think i have read somewhere about this problem . It said , we are permitted to use AsyncTask class only once.
AsyncTask class
class DownloadAdvertismentLevel2 extends AsyncTask<String,String,String>{
String [] ImageInformation=null;
protected void onPreExecute(){
// do nothing !
}
protected String doInBackground(String...Urls){
String Data="";
HttpURLConnection urlConnection = null;
try{
URL myUrl=new URL("http://10.0.2.2:80/Urgence/ads.aspx?Action=DownloadIds&TB="+TopBoundry+"&LB="+LowBoundry);
urlConnection = (HttpURLConnection)myUrl.openConnection();
BufferedReader in = new BufferedReader (new InputStreamReader(urlConnection.getInputStream()));
String temp="";
// Data is used to store Server's Response
while((temp=in.readLine())!=null)
{
Data=Data+temp;
}
}
catch(Exception ex){
Log.d("Er>doInBackground", ex.toString());
urlConnection.disconnect();
}
finally{
urlConnection.disconnect();
}
return Data;// it sends Result to onPostExcute
}
protected void onPostExecute(String Data){
createPhotoAlbum();
pb.closedProg();
}
}
onCreate
Here I don't have any problem . It works fine
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.ads);
new DownloadAdvertismentLevel2().execute();
}
Via Button
ButtonSeeMore.setOnClickListener(new View.OnClickListener(){
public void onClick(View view) {
Counting();
}});
Counting
public void Counting(){
if(TotalRows-6>0){
TopBoundry=TotalRows;
LowBoundry=TotalRows-6;
TotalRows=LowBoundry;
}
new DownloadAdvertismentLevel2().execute();
}
Please consider that I need to use this class till it shows the information. What would you suggest ?
To expand on what JVN said about AsyncTask
Each instance of Async task can only be executed once.
The task can be executed only once (an exception will be thrown if a second execution is attempted.)
http://developer.android.com/reference/android/os/AsyncTask.html (Under 'Threading Rules')
This doesn't stop you making a new instance -
public void Counting(){
if(TotalRows-6>0){
TopBoundry=TotalRows;
LowBoundry=TotalRows-6;
TotalRows=LowBoundry;
}
new DownloadAdvertismentLevel2().execute();
new DownloadAdvertismentLevel2().execute();
}
^ The code above will run your task twice.
Your code looks fine.
I would guess that the problem is (in order of likelihood)
1) On click isn't working
2) Post Execute isn't working as expected
3) The server response isn't being read correctly
4) Your Server isn't handling the request properly
But this would be obvious if you run your debugger or add some extra log outputs
1) I think you might be able to use the Async task only once in the class. But definitely it can be called multiple times.
2) please check if your button onclicklistener() function is really getting called on button click. try some logs in that.
because the code seems to be fine.
To allow multiple asycnh tasks run at the same time you need to use the 'executeOnExceuter mechanism:
See this note from the Android doucmentation:
When first introduced, AsyncTasks were executed serially on a single background thread. Starting with DONUT, this was changed to a pool of threads allowing multiple tasks to operate in parallel. Starting with HONEYCOMB, tasks are executed on a single thread to avoid common application errors caused by parallel execution.
If you truly want parallel execution, you can invoke executeOnExecutor(java.util.concurrent.Executor, Object[]) with THREAD_POOL_EXECUTOR.
An example invocation would look like (this particular example is from a video manipulation app - the 'distributionTask' is an instance of a class that extends AsynchTask):
//Now execute synch task - to allow multiple AsynchTasks execute in parallel the
//'executeOnExecutor' call is required. It needs to be used with caution to avoid the usual synchronization issues and also
//to avoid too many threads being created
distributionTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, Environment.getExternalStorageDirectory() + "/videoChunk_"+i+".mp4");
Related
My Android app handle the business logic in a thread implemented by using AsyncTask which is now call the BL thread.
BL want to prompt user to enter some personal data (name, password...) by adding a Fragment on the UI thread. At this point I want to stop the BL thread, wait for user to enter their name, password..., press the OK button and then continue the BL thread.
How can I achieve that on Android?
Pausing AsynkTask is not best choice. Still you may find example of pausing AsynkTask in Google sample app DisplayingBitmaps in ImageWorker class.
private class BitmapWorkerTask extends AsynkTask<Void, Void, BitmapDrawable> {
#Override
protected BitmapDrawable doInBackground(Void... params) {
synchronized (mPauseWorkLock) {
while (mPauseWork && !isCancelled()) {
try {
mPauseWorkLock.wait();
} catch (InterruptedException e) {}
}
}
}
...
}
public void setPauseWork(boolean pauseWork) {
synchronized(mPauseWorkLock) {
mPauseWork = pauseWork;
if (!mPauseWork) {
mPauseWorkLock.notifyAll();
}
}
}
AsyncTask is supposed to do a single/one time task.
That is not a good use of AsyncTask. AsyncTasks should do work and be done, not try hanging around.
You will find dirty solutions on the web with Thread.sleep() for example. Those are really bad solutions.
If you need two different process you should create two different tasks
For your issue you can cancel() your background thread or asynsTask, and when needed create a new one with updated parameters maybe
You should not do it all inside one AsyncTask..
When creating the fragment with the OK button define new button listener which create new thread and will do the rest of the work.
You might want to use service or service intent and not AsyncTask for that so you could seperate the task to seprate functions and still maintain the background running.
I have a class extending an AsyncTask that sends messages to a WCF web service. Simple messages one by one will work fine, but if I send a message on a new thread that takes 30 seconds to complete, then midway through that I send a quick request it won't execute the AsyncTask until the long one has returned.
I thought the whole idea of AsyncTask was these two messages would run on different threads and therefore wouldn't stack?
Here is my code:
private class RunnableTask extends AsyncTask<RunnableObj, RunnableObj, RunnableObj> {
#Override
protected RunnableObj doInBackground(RunnableObj... params) {
try {
if (params[0].requestBody != (null)) {
params[0].request.body(new JSONObject(params[0].requestBody));
}
params[0].request.asVoid();
return params[0];
}
catch (Throwable e) {
params[0].handler.onFailure(e);
e.printStackTrace();
}
return null;
}
#Override
protected void onPostExecute(RunnableObj runnableObj) {
super.onPostExecute(runnableObj);
runnableObj.handler.onSuccess();
}
}
This is my AsyncTask above.
public void put(final String urlStr, final String requestBody, final HttpResponseHandler httpResponseHandler) {
RunnableObj obj = new RunnableObj();
obj.handler = httpResponseHandler;
obj.request = webb.put(urlStr)
.header(ServiceConstants.SessionTokenHeader, MyApplication.getSessionToken())
.ensureSuccess();
obj.requestBody = requestBody;
new RunnableTask().execute(obj);
}
This is the method I use to call the Async.
As you can see in the method I use to call the service, I initialise a new instance of RunnableTask each time.
How it performs:
The long request will go to the web service and start it's 30 seconds of doing things.
10 seconds later my quick little PUT creates it's object, then the last thing the debugger shows is the break point on the "new RunnableTask().execute(obj);" line and then it just disappears.
20 seconds later the first line of my RunnableTasks doInBackground method will hit and it will perform the PUT.
Please can someone help? Or at least tell me I'm doing something very stupid..
You can execute multiple AsyncTask by using executeOnExecutor
if( Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB ) {
new MyAsyncTask().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
} else {
new MyAsyncTask().execute();
}
For more check the AsyncTask documentation
According to the AsyncTask Docs:
When first introduced, AsyncTasks were executed serially on a single
background thread. Starting with DONUT, this was changed to a pool of
threads allowing multiple tasks to operate in parallel. Starting with
HONEYCOMB, tasks are executed on a single thread to avoid common
application errors caused by parallel execution.
If you truly want parallel execution, you can invoke
executeOnExecutor(java.util.concurrent.Executor, Object[]) with
THREAD_POOL_EXECUTOR.
As you can see, AsyncTasks currently only operate on a single background thread, meaning multiple queued tasks will have to fire one after another. If you would like to execute concurrent tasks, you'll want to follow the instructions above.
I am developing an Android application and when it launches :
1) I make an HTTP Request to my server to send a small JSON file.
2) Open a webView to show a URL.
When the server is running properly there is absolutely no problem and everything goes smoothly.
HOWEVER , if for any reason the server is down , the HTTP request literally hangs and i need to wait till there is an HTTP timeOut which is around 30seconds till i actually see the webView with the URL loading.
I read that i shouldn't make any networking inside the UI thread and i should use another thread for that.
In BlackBerry , that i have already developed the application for , this is as simple as that :
new Thread(){
public void run(){
HttpConnection hc =
(HttpConnection)Connector.open("http://www.stackoverflow.com");
}
}.start();
I just start a new thread and inside i make the requests and all the necessary networking. That way , even when my server is not reachable the webView is loaded immediately without making the user wait and sense that the app is actually hanging.
How could i do exactly the same in Android , easiest way possible ?
Why not to use the same method as you use it for BlackBerry?
new Thread() {
public void run() {
new URL("http://www.stackoverflow.com").getContent();
}
}.start();
Use AsyncTask, it's the simplest way to do that. For more details:
http://developer.android.com/reference/android/os/AsyncTask.html
In icecream sandwich and above you are not allowed to use any web cal in UI thread. However you may use threads, but best way proposed by android is to use Async task. A very simple example is as follow.
"AsyncTask < Parameters Type, Progress Value Type, Return Type >"
class MyAsyncTask extends AsyncTask<String, String, String> {
#Override
protected void onPreExecute() {
// Runs on UI thread- Any code you wants
// to execute before web service call. Put it here.
// Eg show progress dialog
}
#Override
protected String doInBackground(String... params) {
// Runs in background thread
String result = //your web service request;
return result;
}
#Override
protected void onProgressUpdate(String... values) {
super.onProgressUpdate(values);
}
#Override
protected void onPostExecute(String resp) {
// runs in UI thread - You may do what you want with response
// Eg Cancel progress dialog - Use result
}
}
I have 3 AsyncTasks and 1 ProgressBar. I want when any of task executes, the progress bar is visible and when all of them finish, the progress bar is invisible.
In Java, there is ExecutorService::isTerminated to check if all runnables finished but Android doesn't have it.
Update: 3 tasks execute at the same time.
Figure.
Nice graphic. But I am afraid there is no build in mechanism for this. You'll have to implement it by yourself. There are few solutions you could use -
Keep a reference to all 3 task. When task finishes check if the other two tasks are finished too, if yes than close the progress dialog if no wait for some other task to finish and check again. Make sure you free the references when you're done.
If you don't want to keep a reference store a counter. When the task finishes, increment the counter and check if it's equal to 3. If all tasks finished and you are done. If you implement this make sure to synchronized the access to the counter.
Try using AsyncTask.getStatus(). This works perfectly fine. Refer below sample code.
List<AsyncTask<String, String, String>> asyncTasks = new ArrayList<AsyncTask<String, String, String>>();
AsyncTask<String, String, String> asyncTask1 = new uploadTask().execute(string);
AsyncTask<String, String, String> asyncTask2 = new downloadTask().execute(string);
AsyncTask<String, String, String> asyncTask3 = new createTask().execute(string);
asyncTasks.add(asyncTask1);
asyncTasks.add(asyncTask2);
asyncTasks.add(asyncTask3);
You can later loop the AsyncTaskList and find each of the tasks' status as below.
for(int i=0;i<asyncTasks.size();i++){
AsyncTask<String, String, String> asyncTaskItem = (AsyncTask<String, String, String>)asyncTasks.get(i);
// getStatus() would return PENDING,RUNNING,FINISHED statuses
String status = asyncTaskItem.getStatus().toString();
//if status is FINISHED for all the 3 async tasks, hide the progressbar
}
A simple workaround would be to use three boolean variables one each for each AsyncTask and then check them accordingly.
A better approach would be to create a separate class that extends AsynTask and defines a callback interface which is fired in onPostExecute.
create a field to hold all tasks:
private ArrayList<HtmlDownloaderTask> mTasks;
Start your tasks this way:
HtmlDownloaderTask = new HtmlDownloaderTask(page.getHtml());
task.execute(page.getUrl());
//if you want parallel execution try this:
//task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR,page.getUrl());
mTasks.add(task);
on the onPostExecute of MyAsyncTask:
int unfinishedTasks = 0;
for (HtmlDownloaderTask myDT : mTasks){
if(!(myDT.getStatus() == AsyncTask.Status.FINISHED)){
unfinishedTasks++;
}
}
if (unfinishedTasks == 1){
//We are all done. 1 Because its the current one that hasnt finished post execute
callWhateverMethod();
}
Well as you do know when an AsyncTask ends (when onPostExecute gets called):
one solution could be to create a method setProgressBarVisible() that keeps a counter and when first called sets visible, and a method setProgressBarInvisible() that decreases the counter and when zero sets the progress bar invisible.
:-? i think it's just a trick. you will return some message at onPostExecute of each Asyntask and compare it. (this message can contain a time, for example)
A official support of CompletableFuture was introduced since API level 24.
It's also available in Java 8 here.
Can use simply use something like:
taskA.thenCombine(taskB).thenCombine(taskC)
I would simply notify it at onPostExecute(), refer to onPostExecute and 4 steps in the document for detail and you can use EventBus to do some subscribe things.
This is a common question when you want to run a bunch of AsynTasks on a THREAD_POOL_EXECUTOR. It's much more faster than if you just call .execute() and all your tasks are done one by one.
So if you have multiple jobs and objects are not depending on each other states - try to run on a thread pool.
But the question is: how do I know that all of my tasks are done?
There is no built in methods in AsyncTask so you should do a little workaround.
In my case I added a static Hashmap field to my Asynctask class to keep track of all started and finished tasks. As a bonus of a map I can always know which task is currently in progress.
private static HashMap<Uri, Boolean> mapOfAttachmentTasks = new HashMap<>();
and ad simple three methods to access this map.
Important: they should be synchronized
public static synchronized void addTask(Uri uri){
mapOfAttachmentTasks.put(uri, true);
}
public static synchronized void removeTask(Uri uri){
mapOfAttachmentTasks.remove(uri);
}
public static synchronized boolean isTasksEmpty(){
return mapOfAttachmentTasks.isEmpty();
}
You want to add a new item to the tracking Map in an AsyncTask constructor and remove it in onPostExecute():
public AttachmentTask(Uri uri) {
this.uri = uri;
addTask(uri);
}
#Override
protected void onPostExecute(Attachment attachment) {
removeTask(uri);
if(isTasksEmpty())
EventBus.getDefault().post(new AttachmentsTaskFinishedEvent(attachment));
}
Everytime a task is finished it calls onPostEexecute and you check if it was the last task. If there is no tasks left - send a signal that you're done.
Now, here I used EventBus to send event to my Fragment but you can use a callback. In this case you should create an interface with callbackMethod, your Fragment (any of your UI components which are waiting for the event) should implement this interface and have that method. Then in AsyncTask constructor you get your Fragment as an argument and keep a reference to it, so you can call it's callback method when everything is done.
But I dont like such approach. First you need to keep the reference of your Fragment (or any other UI) in a WeakReference wrapper becasue you will get a memory leak when your fragment is dead (but still kept in memory becasue your AsyncTask has it's reference).
Also you would need to make a lot of checks and it will look something like that:
private boolean isAlive() {
return mFragmentWeakReference != null
&& mFragmentWeakReference.get() != null
&& mFragmentWeakReference.get().isAdded()
&& mFragmentWeakReference.get().getActivity() != null
&& !mFragmentWeakReference.get().getActivity().isFinishing();
yep, in production you should be a little paranoic and do all these checks :)
That's why you can use EventBus and if your UI is dead - whatever.
try this, maybe can help you...
final ImageUploader _upload = new ImageUploader();
_upload.setValue(getApplicationContext(), _imagepath, _urlPHP);
_upload.execute();
Runnable _run;
Handler _h2;
_run = new Runnable() {
public void run() {
_h2 = new Handler();
_h2.postDelayed(this, 1000);
Toast.makeText(getApplicationContext(), "not finished", Toast.LENGTH_LONG).show();
if (_upload.getStatus() == AsyncTask.Status.FINISHED) {
Toast.makeText(getApplicationContext(), "finished", Toast.LENGTH_LONG).show();
_h2.removeCallbacks(_run);
}
}
};
_h2 = new Handler();
_h2.postDelayed(_run, 1);
I have AsyncTask that processes some background HTTP stuff. AsyncTask runs on schedule (Alarms/service) and sometime user executes it manually.
I process records from SQLite and I noticed double-posts on server which tells me that sometime scheduled task runs and at the same time user runs it manually causing same record to be read and processed from DB twice. I remove records after they processed but still get this.
How should I handle it ? Maybe organize some kind of queing?
You can execute your AsyncTask's on an Executor using executeOnExecutor()
To make sure that the threads are running in a serial fashion please use: SERIAL_EXECUTOR.
Misc: How to use an Executor
If several activities are accessing your DB why don't create a sort of gateway database helper and use the synchronized block to ensure only one thread has access to it at an instant
Or, you can try this to see if the Task is currently running or not:
if (katitsAsyncTask.getStatus().equals(AsyncTask.Status.FINISHED))
katitsAsyncTask.execute();
else
// wait until it's done.
Initialize the AsyncTask to null. Only create a new one if it is null. In onPostExecute, set it to null again, at the end. Do the same in onCancelled, in case the user cancels this. Here's some untested code to illustrate the basic idea.
import android.app.Activity;
import android.os.AsyncTask;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
public class FooActivity extends Activity {
private class MyAsyncTask extends AsyncTask<Foo, Foo, Foo> {
#Override
protected void onPostExecute(Foo foo) {
// do stuff
mMyAsyncTask = null;
}
#Override
protected void onCancelled() {
// TODO Auto-generated method stub
mMyAsyncTask = null;
}
#Override
protected Foo doInBackground(Foo... params) {
try {
// dangerous stuff
} catch (Exception e) {
// handle. Now we know we'll hit onPostExecute()
}
return null;
}
}
private MyAsyncTask mMyAsyncTask = null;
#Override
public void onCreate(Bundle bundle) {
Button button = (Button) findViewById(R.id.b2);
button.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
if (mMyAsyncTask == null) {
mMyAsyncTask = new MyAsyncTask();
mMyAsyncTask.execute(null);
}
}
});
}
}
I know this was a while ago now, and you have solved your problem. but I just had a similar problem. Reno's suggestion put me on the right track, but for those who have been finding it difficult to fill in the gaps. Here is how I overcame a similar issue to that of katit's.
I wanted a particular AsyncTask to only run if it was not currently running. And as a forward from Reno's suggestion, the AsyncTask interface has been created to handle all the nitty gritty processes in properly dealing with threads for Android. Which means, the Executor is built in. As this blog suggests:
"When execute(Object.. params) is invoked on an AsyncTask the task is executed in a background thread. Depending on the platform AsyncTasks may be executed serially (pre 1.6 and potentially again in 4+), or concurrently (1.6-3.2).
To be sure of running serially or concurrently as you require, from API Level 11 onwards you can use the executeOnExecutor(Executor executor, Object.. params) method instead, and supply an executor. The platform provides two executors for convenience, accessable as AsyncTask.SERIAL_EXECUTOR and AsyncTask.THREAD_POOL_EXECUTOR respectively. "
So with this in mind, you can do thread blocking via the AsyncTask interface, it also implies you can simply use the AsyncTasks.getStatus() to handle thread blocking, as DeeV suggests on this post.
In my code, I managed this by:
Creating a global variable defined as:
private static AsyncTask<String, Integer, String> mTask = null;
And in onCreate, initialising it as an instance of my AsyncTask called CalculateSpecAndDraw:
mTask = new CalculateAndDrawSpec();
Now when ever I wish to call this AsyncTask I surround the execute with the following:
if(mTask.getStatus() == AsyncTask.Status.FINISHED){
// My AsyncTask is done and onPostExecute was called
mTask = new CalculateAndDrawSpec().execute(Integer.toString(progress));
}else if(mTask.getStatus() == AsyncTask.Status.PENDING){
mTask.execute(Integer.toString(progress));
}else{
Toast.makeText(PlaySpecActivity.this, "Please Wait..", 1000).show();
}
This spawns a new thread if it is finished, or if the thread state is PENDING, the thread is defined but has not been started we start it. But otherwise if the thread is running we don't re-run it, we simply inform the user that it is not finished, or perform what ever action we wish. Then if you wanted to schedule the next event rather than just block it from re running, take a look at this documentation on using executors.
How about just wrapping your check-what-to-send and send-it logic in a synchronized method? This approach seems to work for us.
try having some instance boolean value that gets set to "true" on the asynctask's preexecute then "false" on postexecute. Then maybe in doinbackground check if that boolean is true. if so, then call cancel on that particular duplicate task.
You could keep the state of the task in shared preferences. Check the value (Boolean perhaps) before starting the task. Set the state to finished(true?) in onPostExecute and false in onPreExecute or in the constructor