I have 30 threads (AsyncTask) executed in the same time. Before execute them, I will show progressdialog. After threads finish execution, I will dismiss progressdialog.
Any suggestion on How to dismiss ProgressDialog after finish all threads?
If you are using exact 30 threads then initialze a variable with 30 and after every task completion decrease the count by one and also check if the variable is zero . if it is zero it indicate that all the tasks has been completed. so you can dismiss the ProgressDialog.
The best way to do this is use an AsyncTask() to execute your work and dismiss the dialog in onPOstExecute() of it. This will ensure that the task has completed and the ProgressDialog finished. If you still want to continue using Threads , you need to impplement a custom listener which is fired whenever a thread has completed, and you can maintain a counter of how many times it has been fired. I could have given you a code, better example is at this link: How to know if other threads have finished?
you can use a global class:
public abstract class Global{
private static int counter = 30;
private static ProgressDialog pd;
private static Activity a;
public static synchronized void updateCounter(){
counter--;
if(counter<=0){
a.runOnUiThread(new Runnable() {
#Override
public void run() {
pd.dismiss();
}
});
}
}
}
you need to use the "synchronized" because of the concurrent access of the threads.
And in your main activity start the ProgressDialog and initialize the variables:
Global.a = this;
Global.pd = ProgressDialog.show(this, "Tittle","Message ...", true);
and then start the threads.
On the end of each thread you can then call Global.updateCounter();
Related
Scenario:
The user has a list of items, let's say 10 items. Each item has an Operation button, which calls an AsyncTask which makes a web call. When a call is made, the item displays a spinner during the execution of the task
Problem:
Some of the users abuse this, and press quickly more Operation buttons, quicklt one after another, executing the web calls too often. So I want to be able to somehow, execute each of the AsyncTasks one after another with a delay of 2 seconds between executions. I do not want to switch to something else from AsyncTask if possible. So basically if there are 3 Operation buttons pressed, the execution should be:
-> Operation 1
-> 2 seconds delay
-> Operation 2
-> 2 seconds delay
-> Operation 3
-> ....
What would be the best way to do this in Android?
LE:
I have just realized something, for executing my task I ran the following code:
myTask = new MyTask();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
myTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
} else {
myTask.execute();
}
Well, I've been using this code for a lot of time now, knowing that after honeycomb the tasks were not executed in parallel anymore without using an Executor. So it seems that only doing a simple myTask.execute() and adding a Thread.sleep() makes my AsyncTasks execute, one after another just as expected.
You will need to maintain a list of the operations that needs to be performed.
on click of the button add the task in the list, call a method which check the list for the task and executes it if there is no other task is running..
in onPostExecute method call the same method to check if there is any other task / operation that needs to be performed..
It may not be the full code you require... but may give you some idea..
public class TestActivity extends AppCompatActivity {
private static boolean isTaskRunning =false;
static ArrayList<CustomTask> customTaskList = new ArrayList();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_test);
}
public void onBtnClick(View view)
{
// create custom task with required values and actions
CustomTask customTask = new CustomTask();
customTaskList.add(customTask);
checkAndExecuteTask();
}
private static void checkAndExecuteTask()
{
//checks if there is any task in the list and is there any other running task
if(customTaskList.size()>0 && !isTaskRunning) {
new MyAsync(customTaskList.get(0)).execute();
}
}
static class MyAsync extends AsyncTask<Void,Void,Void>
{
CustomTask currentCustomTask;
public MyAsync(CustomTask customTask)
{
currentCustomTask = customTask;
}
#Override
protected void onPreExecute() {
super.onPreExecute();
isTaskRunning= true;
}
#Override
protected Void doInBackground(Void... voids) {
// do your stuff
return null;
}
#Override
protected void onPostExecute(Void aVoid) {
super.onPostExecute(aVoid);
customTaskList.remove(currentCustomTask);
isTaskRunning =false;
checkAndExecuteTask(); // task is completed so check for another task and execute (if any).
}
}
class CustomTask
{
// create class with required fields and method
}
}
There are a number of ways you can do this in android.
One way is to use a handler.
What you need to do is to, create a seperate thread and run handler.postDelayed in it.
private void startWebCall() {
Thread thread = new Thread() {
public void run() {
Looper.prepare();
final Handler handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
// Do your web calls here
handler.removeCallbacks(this);
Looper.myLooper().quit();
}
}, 2000);
Looper.loop();
}
};
thread.start();
}
You should call above method whenever user clicks a item.
Another way that I can think of is using an IntentService
An IntentService is a service that is used for doing asynchronous tasks in background. It maintains a queue of the tasks it needs to do. It is different from the above approach in the sense that it executes these tasks in a sequential order. So when you make requests to it to make web calls it will queue them, make the first call and then after it finishes it will make the second call. So the different web calls will not execute in parallel. They will execute in a sequential order but in a different thread. Also it is a service so it can run even in the background, i.e if user closes the app.
This is a good tutorial to get start with IntentService.
AsyncTaks should be generally avoided unless the work one needs to do is quite trivial. This blog explains its pitfalls.
I want to implement something like the following on Android:
for(int i=0; i<num; i++){
//a,b.. are changing
aTask = new myAsyncTask(a,b..);
aTask.execute();
//Code to wait for myAsyncTask to finish
}
The problem is how can I wait for myAsyncTask to finish before starting the new iteration. One possible solution I thought is to put a Handler inside to wait for some seconds. For example:
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
public void run() {
}
}, 5000);
But this is not right even if it is working, because you have to put a standard time to wait for myAsyncTask. And it isn't sure if myAsyncTask finishes early or late because the a,b.. parameters change in every iteration.
Another solution I thought is to ask every time in a loop the object aTask to get the Status of myAsyncTask and check if it is FINISHED. For example:
while(!aTask.getStatus().equalsTo(AsyncTask.Status.FINISHED)){
}
But this isn't working because myAsyncTask is always RUNNING.
Can somebody help me?
//Code to wait for myAsyncTask to finish
If you wait there, you would freeze the UI. What is the point of another thread if you plan on waiting?
My guess what you need is to make use of the optional parameters in the execute(Params...) method. You can put your 'a','b' or what ever those objects are and how many you put doesn't matter. This will allow your task to execute all of them and have better contorl.
protected Long doInBackground(Objects... objs){
for(int i = 1; i < objs.length; i++){
// Do Work
}
}
In Android you must not stay in the UI Thread and wait for something. This includes waiting for AsyncTasks that run in the background. If you would wait in the calling Thread, it would block the user and would freeze your device.
You must separate the code into two pieces.
First start the AsyncTasks:
for(int i=0; i<num; i++){
//a,b.. are changing
aTask = new myAsyncTask(a,b..);
aTask.execute();
// dont wait here. It would freeze the UI Thread
}
Second run code when Task has finished just overwrite the onPostExecute() method in MyAsyncTask.
Then Android can do its work while the AsyncTasks run.
a simple suggestion, depending on what your for loop is actually doing, is to use the loop to create a 'queue' of items you want processed. then, fire off an asynctask with the first object in the queue, and upon completion of that task, fire off the next object in the queue until the length of your queue is zero
The easiest way is to create a method from where you call asynTask.execute() and call that method from onPostExecute().
public class ParentClass extends Activity
{
int asyncCalls = 0;
......
public void callAsyncTaskAgain()
{
aTask = new myAsyncTask(a,b..);
aTask.execute();
asyncCalls++;
}
public class AnotherClass extends AsyncTask
{
protected Void onPostExecute(Void result)
{
....
if(asyncCalls < SOME_NUMBER)
callAsyncTaskAgain();
}
}
}
Hope this helps
I have created an AsyncTask and I have to create an while(true) on my AsyncTask.
How can I execute such an unbounded loop upon handling a button click in my Activity class without blocking?
How others said a infinit loop without a break condition isn't a nice user experience.
First get a instance for your AsyncTask:
PostTask pt = new PostTask(this);
pt.execute();
Try this in your doInBackground():
while(!this.isCancelled()){
// doyourjobhere
}
If the app is getting closed by the user the AsyncTask have to be stopped in your onPause().
#Override
public void onPause(){
pt.cancel(false);
}
TheAsyncTask.cancel(boolean) sets isCancelled() to true, calls the AsyncTask.onCanceled() method instead of onPostExecute() and can be overwritten for your own purpose.
If you don't like this put your task in a Service.
As said by the others, you should put your 'infinite loop' inside the doInBackground() method of AsyncTask.
However, this loop is not so infinite, because it must end when you exist the activity, or the application.
I suggest changing your while (true) { } to while (! mustStop) { } and set the boolean mustStop as an instance variable of your activity. So you'll be able to cleanly stop the process by setting mustStop=true (it would be a good idea to set this in the onPause method).
So this will be :
public class AsyncBigCalculActivity extends Activity {
private boolean mustStop = false;
#Override
public void onPause() {
super.onPause();
mustStop=true; // Stop the infinite loop
}
....
#Override
protected String doInBackground(String... params) {
mustStop=false;
while (!mustStop) {
...
}
}
you can put the loop within the doInBackground() method of the AsyncTask. As a suggestion, you can add the AsyncTask as an inner class within your Activity.That way you can easily access the variables declared in your activity. Although the android documentation suggests to use AsyncTask only for short tasks. Its more advisable to create a runnable object and put your while loop within the run() method and execute it using ExecutorService, which allows you to run asynchronous code in android in a thread-safe manner.
http://docs.oracle.com/javase/6/docs/api/java/util/concurrent/ExecutorService.html
http://developer.android.com/reference/java/util/concurrent/ExecutorService.html
I have a problem with progress dialog on opening an activity (called activity 2 in example).
The activity 2 has a lot of code to execute in this OnCreate event.
final ProgressDialog myProgressDialog = ProgressDialog.show(MyApp.this,getString(R.string.lstAppWait), getString(R.string.lstAppLoading), true);
new Thread() {
public void run() {
runOnUiThread(new Runnable() {
#Override
public void run() {
showApps();
}
});
myProgressDialog.dismiss();
}
}.start();
The showApps function launch activity 2.
If I execute this code on my button click event on activity 1, I see the progress, but she doesn't move and afeter I have a black screen during 2 or 3 seconds the time for android to show the activity.
If I execute this code in the OnCreate of Activity2 and if I replace the showApps by the code on OnCreate, Activity1 freeze 2 seconds, I don't see the progress dialog, and freeze again 2 seconds on activity 2 before seeing the result.
I had the same issue and using an AsyncTask is working for me.
There are 3 important methods to override in AsyncTask.
doInBackground : this is where the meat of your background
processing will occur.
onPreExecute : show your ProgressDialog here ( showDialog )
onPostExecute : hide your ProgressDialog here ( removeDialog or dismissDialog
)
If you make your AsyncTask subclass as an inner class of your activity, then you can call the framework methods showDialog, dismissDialog, and removeDialog from within your AsyncActivity.
Here's a sample implementation of AsyncTask:
class LoginProgressTask extends AsyncTask<String, Integer, Boolean> {
#Override
protected Boolean doInBackground(String... params) {
try {
Thread.sleep(4000); // Do your real work here
} catch (InterruptedException e) {
e.printStackTrace();
}
return Boolean.TRUE; // Return your real result here
}
#Override
protected void onPreExecute() {
showDialog(AUTHORIZING_DIALOG);
}
#Override
protected void onPostExecute(Boolean result) {
// result is the value returned from doInBackground
removeDialog(AUTHORIZING_DIALOG);
Intent i = new Intent(HelloAndroid.this, LandingActivity.class);
startActivity(i);
}
}
AFAIK you cannot preload any activity with progress dialog displayed. Are you testing on a real device or in emulator?
I've seen workarounds that opened an activity with a ViewFlipper having a progress animation in the center, and in the next View, it was loaded an activity, but it's not something is recommended and hard to implement to work as you wish.
GeeXor
I would suggest you to avoid performing lots of operations in Activity 2's OnCreate.Writing lots of operations in OnCreate is a reason for the black screen between activities.So perform those operations asynchronously using AsyncTask or in a Thread (or write them in onStart if they are unavoidable).
The other suggestion is to start another progressDialog in activity 2's onCreate which will run until all of your data is loaded & user will know that something is happening in background.
this is what i would do. create a handler on the ui thread, start the background processing thread and then show the progressdialog. when the background thread has finished it's work get it to post a runnable on the ui thread via the handler to dismiss the dialog.
I have a class which extends AsyncTask, which is intended to serve as a generic task manager class for my application.
Problem:The strange behavior is that the progress dialog shows up, but is never dismissed.
I am sure that onPostExecute() gets called for every task instance, as any Log.d("","") statements fire if placed in here, even the Toast messages show up from within this method, but I am not able to dismiss the static dialog.
I understand that AsyncTask(s) have access to UI thread at only 2 places [onPreExecute() and onPostExecute()], so I think trying to dismiss the dialog in runOnUiThread() is unnecessary.
All calls to executeTask() are made from different onCreate() methods of different activities that need to fetch some data over network before populating some of their UI elements, and I always pass the current activity's context to the tasks.
As I do not switch activities until after the related tasks are completed, I believe the activity context objects are still valid (am I wrong to have assumed this???) I have never found any of them to be null while debugging.
Could this be a timing issue? I have also observed that most of the times DDMS shows all tasks get completed before the activity is displayed. If I use new Handler().postDelayed(runnable_which_calls_these_tasks,10); in the onCreate(), and add delaying code in foo_X(), the activities are displayed without any delay, but the dialog will just not dismiss().
I have read through quite a number of articles on this issue but am still not able to figure out exactly where am I going wrong. I do not want to define each task as private inner class Task1 extends AsyncTask<> in all of my activity classes and I would not want to (unless this is the only solution) load my application object with all activity references either as mentioned in this discussion: Is AsyncTask really conceptually flawed or am I just missing something?.
I have spent a week on this and am absolutely clueless :( It would be great if someone can guide me, and let me know what am I missing.
Following is the class definition: [I've removed some irrelevant application specific code for clarity]
public class NetworkTask extends AsyncTask<Void, Integer, Boolean> {
private Context UIcontext;
private int operationType;
private static ProgressDialog dialog;
private static int taskCount;
private NetworkTask(int operationType Context context){
this.UIcontext = context;
this.operationType = operationType;
if (taskCount++ == 0)
dialog = ProgressDialog.show(context,"","Loading...");
}
public static Boolean executeTask(int operationType, Context context) {
return new NetworkTask(operationType, context).execute().get();
}
#Override
protected void onPreExecute(){
super.onPreExecute();
if (taskCount == 1)
dialog.show();
}
#Override
protected Boolean doInBackground(Void... arg0) {
switch(operationType){
case TYPE_1:
foo1();
break;
case TYPE_2:
foo2();
break;
case TYPE_3:
foo3();
break;
case TYPE_4:
foo4();
break;
}
#Override
protected void onPostExecute(Boolean result) {
super.onPostExecute(result);
taskCount--;
if (dialog.isShowing() && taskCount == 0){
dialog.dismiss();
}else {
Toast.makeText(UIcontext, "Task#"+ operationType+", m done, but there are "+taskCount+" more", 5).show();
}
}
}
Edited:
Mystery solved - this one was giving me a bit of trouble. There were a few problems:
The main problem why dialog was not showing was NetworkTask.get(). This is a blocking call that waits for the whole NetworkTask to finish. During that time it blocks UI thread so nothing is drawn (also other UI elements are unresponsive). Remove get():
public static Boolean executeTask(int operationType, Context context){
new NetworkTask(operationType, context).execute();
return true; // return whatever
}
The show() on ProgressDialog is called twice. This shows two dialogs, one after another. Remove show() inside onPreExecute().
ProgressDialog is modal - it prevents changing UI until it is done. Toast.makeText() are called before dialog.dismiss() but since dialog is blocking drawing to screen, they get queued and are shown after dialog is dismissed.
super.onPostExecute(result) and super.onPreExecute() are redundant so can be removed.
I can post the whole working code if you have trouble with it.