I'm trying to execute some code parallel with threads using async task.
But for some reason in android 4.2.2 doesn't work.
I have this code which is in main class:
new XmlDownloader();
task=new SendTask().execute("");
and the following classes:
private class SendTask extends AsyncTask<String,String,String>{
#Override
protected void onPreExecute(){
}
#Override
protected String doInBackground(String...strings){
while(true){
Log.w("outside", "hello");
}
}
return strings[0];
}
#Override
protected void onPostExecute(String country){
}
}
and
public class XmlDownloader extends Activity {
public XmlDownloader(int pos) {
DownloaderTask task = new DownloaderTask();
task.execute("");
}
private String downloadXml(String s,int pos1) {
return null;
}
private class DownloaderTask extends AsyncTask<String, Void, String> {
public DownloaderTask() {
}
#Override
// Actual download method, run in the task thread
protected String doInBackground(String... params) {
while(true){
Log.w("down", "asdasdasssasdasdasdasd");
if(isCancelled())
return null;
};
return null;
}
#Override
// Once the image is downloaded, associates it to the imageView
protected void onPostExecute(String bitmap) {
}
}
}
In android 2.3.3 the logcat shows this sequence
Log.w("down", "asdasdasssasdasdasdasd");
Log.w("down", "asdasdasssasdasdasdasd");
Log.w("down", "asdasdasssasdasdasdasd");
Log.w("outside", "hello");
Log.w("outside", "hello");
Log.w("down", "asdasdasssasdasdasdasd");
but in android 4.2.2 only shows
Log.w("down", "asdasdasssasdasdasdasd");
Log.w("down", "asdasdasssasdasdasdasd");
Log.w("down", "asdasdasssasdasdasdasd");
Log.w("down", "asdasdasssasdasdasdasd");
Log.w("down", "asdasdasssasdasdasdasd");
Any ideas why threads don't work?
Using AsyncTask may not give you the true parallelism that you need. Across different versions of Android, the number of AsyncTasks that can run simultaneously has been changed from 1 to 5 and then back to 1 (If I'm not wrong).
https://github.com/android/platform_frameworks_base/commits/master/core/java/android/os/AsyncTask.java
https://groups.google.com/forum/?fromgroups#!topic/android-developers/8M0RTFfO7-M
AsyncTasks are backed by a ThreadPool over which you have no control. If AsyncTask doesn't fit your needs, is to use Services or Loopers or build your own ThreadPoolExecutor. AsyncTask is not designed to loop idefinitely, that is to be a server or a service.
So what is happening is that in your Android version only the first enqueued thread from the pool is executed and since it doesn't terminate (they will be run sequentially), the second one never starts.
This has to do with the way AsyncTasks have evolved since their conception in API 3. In API 3, AsyncTasks(plural) were executed serially. This was changed to a pool of threads, allowing multiple AsyncTasks to run in parallel (API 4(DONUT)). But, starting HONEYCOMB(API 11), AsyncTasks are back to being executed serially.
Looking at the output you have provided, both SendTask & DownloaderTask execute in parallel in case of 2.3.3 which is > DONUT and < HONEYCOMB. But, in case of 4.2.2, serial execution of AsyncTasks takes place. Since DownloaderTask is executed first, SendTask waits for it to finish execution(which won't happen thanks to while(true)) --> hence, no output.
Since API 11, you have a choice over whether your AsyncTasks run serially or in parallel. For serial execution, use execute(Params... params). For parallel execution, look into executeOnExecutor(Executor exec, Params... params).
Related
I'm new to Android and Java. I'm trying to download 1000 plus images. I don't want to do that serially in a UI thread as that will be slow. Hence, I implemented multi-threading using thread and runnable in the below manner.
The for-loop will be called 1000 plus times. So is it an efficient way of achieving it? Will the OS manage the thread pool by its own?
private void syncS3Data() {
tStart = System.currentTimeMillis();
try {
for (final AWSSyncFile f : awsSyncData.getFiles()) {
new Thread(new Runnable() {
#Override
public void run() {
beginDownload(f);
}
}).start();
}
} catch (Exception ex) {
progressDialog.dismiss();
showMessage("Error:" + ex.getStackTrace().toString());
}
}
for Sure you can't do that in MainThread (UI Thread) because if you did, the application will not be responding.. and then it will be killed by system, you can use AsyncTask class in order to do what do you need but i prefer to use intentservice
However you have to use Intentservice it's a worker thread (long operation) but be noted intentservice will not execute anything until it finish the current task, if you need to download it in parallel then you have to use Service it works with UI Thread so you need asyncTask in order to perform the action but make sure of calling stopSelf() unlike intentService it will be stopped once it finish
Instead of creating threads for each download, create one thread and use that for downloading all images.
You can use AsyncTask Refer: https://developer.android.com/reference/android/os/AsyncTask.html
private class DownloadFilesTask extends AsyncTask<SomeObject, Integer, Long> {
protected Long doInBackground(SomeObject... objs) {
for (final AWSSyncFile f : obj.getFiles()) {
beginDownload(f);
}
}
protected void onPostExecute(Long result) {
//Task Completed
}
new DownloadFilesTask().execute(someObj);
I had developed an e-commerce app before and have encountered a similar problem in which I had to download some 200+ images for each category.The way I did it was using a loop within an AsyncTask and after each download was completed the image was displayed at the relevant place using the onProgessUpdate() function.I can't share the actual code,so i will give a skeleton example.
public class DownloadImages extends AsyncTask<String,String,String>
{
File image;
protected String doInBackground(String... params)
{
//download the image here and lets say its stored in the variable file
//call publishProgress() to run onProgressUpdate()
}
protected void onProgressUpdate(String... values)
{
//use the image in variable file to update the UI
}
}
So i use this code to call my AsyncTask
Log.d("before","make_connection");
new Make_Connection().execute();
Log.d("after","make_connection");
My class
private class Make_Connection extends AsyncTask<Void,Void,String>{
final int port = 4445;
#Override
protected void onPreExecute() {
Toast.makeText(KeyboardActivity.this,"This runs",Toast.LENGTH_LONG).show();
}
#Override
protected String doInBackground(Void... params) {
Log.d("Connection","Started");
Log.e("Connec","this runs");
try {
socket = new Socket(IP,port);
//dout = new DataOutputStream(socket.getOutputStream());
//dout.writeUTF("Connection Formed");
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
protected void onPostExecute(String result) {
Toast.makeText(KeyboardActivity.this,"Connection Made",Toast.LENGTH_SHORT).show();
}
}
Now i can see in the android monitor that these two are always execute
Log.d("before","make_connection");
Log.d("after","make_connection");
But half of the time i cannot see the output produced by
Log.d("Connection","Started");
Log.e("Connec","this runs");
Even though onPreExecute() runs properly everytime.
I have tested on two diffent mobilies running 7.1 and 7.0
Can someone please tell me why this is happening
Try:
new Make_Connection().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
instead of only
new Make_Connection().execute();
This is needed, because in Android SDK 13 or higher they run serially by default. So if you want to run more than one AsyncTask simultaneously, use executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR)
For more details, see explanation under order of execution from This docs
AsyncTasks are run sequentially by default. They all execute on the same executor. Taken from here https://developer.android.com/reference/android/os/AsyncTask.html
If you truly want parallel execution, you can invoke
executeOnExecutor(java.util.concurrent.Executor, Object[]) with
THREAD_POOL_EXECUTOR.
At application launch time I am making network call (resttemplate Get call) to fetch data.
Scenario is something like this,
1)Parent call which returns list of tokens(Id's)
2)Once I got list of tokens(Id's),I iterate through it make network call for each token(Id) to get Data.
What I have done so for:
1)I have used Intent service to make parent network call to get list tokens(ID's).
2)Once I got list token(Id's) I started my AsyncTask executeOnExecutor,Passing list of tokens(ID's) to asynctask through constructor and starting AsyncTask executor.
Something like this,
MyAsyncExecutorTask executorTask = new MyAsyncExecutorTask(List<Integer> of tokens);
executorTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR,(Void[]) null);
And In MyAsyncExecutorTask this is what I am doing.
protected Void doInBackground(Void...params) {
//Settimg max priority
Thread.currentThread().setPriority(Thread.MAX_PRIORITY);
for (int i = 0; i < scheduleList.size(); i++) {
ScheduleImpl scheduleImpl = new ScheduleImpl();
//Making network call to get data using token
scheduleImpl.getData(scheduleList(i));
}
}
Its working as it should be.
My doubts or Questions are:
1)Am I using Async executeOnExecuter() in right way(I want to make parallel network calls).I don't see any huge performance improvement after switching from AsyncTask execute() to Async executeOnExecuter().
2)How to check how many number worker threads running.
You can make it like this:
AsyncTaskGetTokens.java
public class AsyncTaskGetTokens extends AsyncTask<Void,Integer, List<Integer>> {
private ProgressDialog pd;
private Context context;
private String dataURL;
public AsyncTaskGetTokens (Context context, Integer token)
{
this.act = act;
this.token = token;
}
protected void onPreExecute()
{
this.pd = ProgressDialog.show(context, "", "");
}
protected Integer doInBackground(Void... arg0) {
List<Integer> tokenList = new List<Integer>();
//get token list from URL here
return tokenList;
}
protected void onPostExecute(List<Integer> tokenList)
{
this.pd.dismiss();
AsyncTaskGetData.tokensDownloading = new List<AsyncTaskGetData>();
foreach(Integer token : tokenList)
{
AsyncTaskGetData.tokensDownloading.add(new AsyncTaskGetData(context, token); // here you create a list with all the tokens that will be downloaded
}
foreach(AsyncTaskGetData asynctask : AsyncTaskGetData.tokensDownloading)
{
asynctask.execute(); // here you will start downloading the data from each token
}
}
}
AsyncTaskGetData.java
public class AsyncTaskGetData extends AsyncTask<Void,Integer, Data> {
public static List<AsyncTaskGetData> tokensDownloading;
private ProgressDialog pd;
private Context context;
private Integer token;
public AsyncTaskGetData (Context context, Integer token)
{
this.context = context;
this.token = token;
}
protected void onPreExecute()
{
this.pd = ProgressDialog.show(context, "", "");
}
protected Data doInBackground(Void... arg0) {
Data data = getDataFromURL(token);
return data;
}
protected void onPostExecute(Data data)
{
//show data here
this.pd.dismiss();
}
}
1)Am I using Async executeOnExecuter() in right way(I want to make parallel network calls).I don't see any huge performance improvement after switching from AsyncTask execute() to Async executeOnExecuter().
From Android Documentation
execute:
Executes the task with the specified parameters. The task returns itself (this) so that the caller can keep a reference to it.
Note: this function schedules the task on a queue for a single background thread or pool of threads depending on the platform version. 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 HONEYCOMB, tasks are back to being executed on a single thread to avoid common application errors caused by parallel execution
executeOnExecuter
Executes the task with the specified parameters. The task returns itself (this) so that the caller can keep a reference to it.
This method is typically used with THREAD_POOL_EXECUTOR to allow multiple tasks to run in parallel on a pool of threads managed by AsyncTask, however you can also use your own Executor for custom behavior.
Warning: Allowing multiple tasks to run in parallel from a thread pool is generally not what one wants, because the order of their operation is not defined. For example, if these tasks are used to modify any state in common (such as writing a file due to a button click), there are no guarantees on the order of the modifications. Without careful work it is possible in rare cases for the newer version of the data to be over-written by an older one, leading to obscure data loss and stability issues. Such changes are best executed in serial; to guarantee such work is serialized regardless of platform version you can use this function with SERIAL_EXECUTOR.
The question isn't about the performance improvement necessarily. When you run as executeOnExecuter, there is no guarantee that the calls will return in the order you made them. An execute method will schedule the task in a queue for a single background thread.
2)How to check how many number worker threads running.
You have the ability to define your own work queue, so if the question is how many threads can you run, then refer to this post Android AsyncTask threads limits?
I'm not sure if there is an easy way to check the count of current running. If there is I'm sure someone will be comment on that. But you can keep references to each task and check its status.
Is it possible to get a list of all threads currently running on an Android device?
I am using Android studio and I have created two Android projects.
In the first app I created a dummy threads.
#Override
protected void onCreate(Bundle icicle) {
Thread t = new Thread("DummyTHREAD")
{
public void run() {
while(true) {
// yield();
}
}
};
t.start();
In the second app I want a thread list including the dummy thread from App one. I have tried already the following:
java.util.Map<Thread, StackTraceElement[]> myMap = Thread.getAllStackTraces();
Then I started the first app and debugged the second app afterwards, but this just show me the system threads and the main thread of my second application.
Can anybody help me?
This could be a duplicate question but I did not find what I was looking for.
I am calling an AsyncTask in the UI activity new LoadData().execute(); and in doInBackground I call a method which takes time. I want to interrupt this thread if the data is not return after some time.
Below is the code how I tried to do this.
class LoadData extends AsyncTask<String, String, String>
{
#Override
protected void onPreExecute() {
super.onPreExecute();
startTime = System.currentTimeMillis();
}
protected String doInBackground(String... args)
{
DataCollector dc = new DataCollector();
data = dc.collectData(query);
//Here I check if the time is greater than 30 seconds then cancel
if(((System.currentTimeMillis()-startTime)/1000)>30)
{
cancel(true);
}
return null;
}
}
But this does not stop the task after 30 seconds, in fact it is taking more time.
I have tried get(long timeout, TimeUnit unit); as well but that does not work either.
Can anyone show me how can I do it or how do I use isCancelled() in doInBackground.
Thanks.
You need a thread that cancels your task after a certain amount of time. That Thread could look like this:
public class TaskCanceler implements Runnable{
private AsyncTask task;
public TaskCanceler(AsyncTask task) {
this.task = task;
}
#Override
public void run() {
if (task.getStatus() == AsyncTask.Status.RUNNING )
task.cancel(true);
}
}
And when you call your AsyncTask, you need to run the cancle task after a certain amount of time (=the timeout, in this case 20 sec)
private Handler handler = new Handler();
private TaskCanceler taskCanceler;
...
LoadData task = new LoadData();
taskCanceler = new TaskCanceler(task);
handler.postDelayed(taskCanceler, 20*1000);
task.execute(...)
It's a good idea if you clean this up on cancel or finish with
if(taskCanceler != null && handler != null) {
handler.removeCallbacks(taskCanceler);
}
You can of course wrap this in an custom implementation of AsyncTask. I've used this pattern many times and it works like a charm. One thing to note, in rare cases the handler would not start, I suspect if you create it in the wrong context it will not survive in certain instances, so I forced the handler to be an the UI Thread with handler= new Handler(Looper.getMainLooper());
You have to do the Time check on a different thread.
What you currently do is: executing the dc.collectData(query) (in background) and once it is ready you check if you should cancel. So if the query takes 1 minute, you will do the cancel check after 1 minute, which is already too late.
What you could do is schedule a TimerTask that should run 30 seconds after the LoadData().execute() and if the timer Task is run, you can cancel the AsyncTask (if it is still running)
I would translate this into an async/await problem making all the expensive methods as async methods.
First, Modify DataCollector's collectData(query) to collectDataAsync(query). (If you can't modify DataCollector, there are work arounds to wrap it in a lambda function or something similar).
Second, change doInBackground as an async task, something like this:
protected async Task<String> doInBackgroundAsync(String... args)
{
DataCollector dc = new DataCollector();
int timeout = 1000;
var task = dc.collectDataAsync(query);
if (await Task.WhenAny(task, Task.Delay(timeout)) == task) {
// task completed within timeout
data = task.Result;
} else {
// timeout logic
}
}
Basically, you have two tasks inside doInBackgroundAsync: collectDataAsync and a delay task.
Your code waits for the faster one. Then you know which one was and you can react accordingly.
If you also need to cancel collectDataAsync task, then you want to used a cancellationToken.
I use this to solve your problem https://stackoverflow.com/a/11191070/3307066.
Note that now doInBackgroundAsync is a async, so it changes a bit the way of using it.
Hope it helps.
Short answer is you CAN'T cancel an AsyncTask once its started. What you can do, is insert a loop inside doInBackGround() which will check for isCancelled() and if it is set to true sometime in the future - return a value from the function (which will in turn call onPostExecute() if you have defined it);
Note that just because you can't stop an AsyncTask doesn't mean that the OS won't cancel it if it's low on memory. You should have this in mind if you are doing essential tasks in the AsyncTask (ones that you want executed 100%). If so, it is better to use a Service - a component that is automatically killed and restarted by the OS as need.
try this :
public class MyTask extends AsyncTask<Void, Void, Void> {
private volatile boolean running = true;
private final ProgressDialog progressDialog;
public MyTask(Context ctx) {
progressDialog = gimmeOne(ctx);
progressDialog.setCancelable(true);
progressDialog.setOnCancelListener(new OnCancelListener() {
#Override
public void onCancel(DialogInterface dialog) {
// actually could set running = false; right here, but I'll
// stick to contract.
cancel(true);
}
});
}
#Override
protected void onPreExecute() {
progressDialog.show();
}
#Override
protected void onCancelled() {
running = false;
}
#Override
protected Void doInBackground(Void... params) {
while (running) {
// does the hard work
}
return null;
}
// ...
}
Courtesy and for more details see this answer.