Android Threading (AsyncTasks) acting a little weird - android

From my main thread, I start an AsyncTask which will go through a list of images and for each image, it will do some processing on it. So basically, there's a for loop and inside it, another AsyncTask is called. I use an instance of a class which holds the boolean value for checking if each image is done with its processing, its called a dummyStructure.
Code of the main thread:
new BatchProcessor().execute()
the doInBackground of the BatchProcessor:
protected Void doInBackground(Void... params){
while(dummyStructure.isWorking())
{
//Try loop
thread.sleep(1000);
}
dummyStructure.setIsWorking(true); //basically sets the flag to true
for(String s: pictureList)
{
RunTheProcessingLoop().execute();
}
The Problem:
I tried debugging, and here's what the problem is imo, if I remove the line just outside the while loop dummyStrucutre.setIsWorking(true) then there are multiple asyncTasks called even before it finishes, and basically everything gets screwed up. However, if I don't remove that line, then the BatchProcessor AsyncTask gets caught in the while loop, while as the RunTheProcessingLoop AsyncTask never executes beyond its onPreExecute()(debugged to know that, I used Log.e() in every method of that asyncTask).
Definitely I'm missing something, any help? Thanks a lot! :)

What you are encountering is asynctasks getting piled up because you are starting one from another and not exiting the first. This is because the asynctasks are handled serially by a single thread by default. If you want to use multiple threads in parallel, you'd need to use your own thread executor. See the AsyncTask documentation for more details.

So after 2 days of posting this question and finding out more about what people posted, I figured this:
My main thread called for an AsyncTask and I wanted to wait for that AsyncTask to finish. So I used a boolean flag which the AsyncTask sets to false once it is done and I can queue another task. Here's the code:
class mExecutor implements Executor {
public void execute(Runnable r) {
new Thread(r).start();
}}
Now, all you need to do is, whatever task/method/etc you want to run Asynchronously, simply create a thread and push it in that class, example:
Thread t = new Thread(new Runnable() {
public void run() {
new someshit().execute();
}
});
new mExecutor().execute(t);
and Tada! Now they both won't be queued/synchronized but would run in parallel.
If I am wrong, please correct me! Thanks! :)

Related

Why Android myActivity.runOnUiThread and uihandler.post hangs my UI?

I have a method invoked by onClickListener
#Override
public Object getData() {
Thread t = new Thread(new testThread());
t.start();
return false;
}
it start the new Thread well, but when I am trying to do both:
private class testThread implements Runnable{
#Override
public void run() {
OuterClass.this.myActivity.runOnUiThread(new Runnable(){ ... });
OuterClass.this.myActivity.uiHandler.post(new Runnable(){ ... });
...
nothing happens. UI hang up and no Runnable never run (I see it during careful debugging).
Why? Everything should work or even if it fail, why the UI hangs??
Please help!
SOLVED!!! The problem was in method which invokes getData (outside the scope), it never finished failing into infinite loop. Since that scheduled Runnables never started as I think. Now everything works .
AsyncTask is better. It is easier to use, you don't have to manually manage so many threads, and it keeps your code clean.
The doInBackground() method will do your lengthy task on an alternate thread. If you want to update your UI when the task is running, use the publishProgress() method, and if you want to update the UI after the work is done, use onPostExecute().
As to your question on why the UI hangs, see if you are using any method that takes very long or blocks for some reason in the runOnUiThread() method. If any code takes time, remove it from this method.

Multiple AsyncTasks with sequential execution

I know that Similar questions have been asked before but the solution to those questions will not work for me. The situation is that I have an Array of objects that are each getting sent to uploaded to the server via an asynctask. I need to send each one separately but each object in the list uses the same asynctask so calling task.execute in the onPostExecute() is not an option since that would cause it to infinitely call itself. I have tried something like so
for(each item in list){
task.execute();
while(task.getStatus() != android.os.AsyncTask.Status.FINISHED){
//spin here and wait
}
}
But when doing this it just spins for ever and never leaves the while loop.
Any suggestions are greatly appreciated
From AsyncTask docs:
Starting with HONEYCOMB, tasks are executed on a single thread to avoid common application errors caused by parallel execution.
so if you are not >= HONEYCOMB, then maybe switch to use ExecutorService:
ExecutorService executor = Executors.newSingleThreadExecutor();
Why don't you change your architecture: Make the uploading async task take an array of files to upload and just loop through them?
If you really want to stay this way, just use a lock object.
Something like:
class MyAsyncClass extends AsyncTask{
static Object lock = new Object();
.......
void doWork(){
synchronized(lock) {
//do stuff
}
}
}
EDIT: I should point out that this does not ensure you, that the doWork() methods are executed in the order, they were called.
I suggest you should switch to Thread and Executor service to do this. This will give you greater grip on switching between sequential and parallel execution of tasks.
With the help of ExecutorService(Actually a Threadpool manager).
You can pass in the Tasks as runnable to executor service.
You can define the number of threads to be used by executor Service (For your case, make it as 1).
Example :
ExecutorService service = Executors.newFixedThreadPool(1);
service.submit(new Runnable() {
#Override
public void run() {
// TODO Auto-generated method stub
}
});
You can submit as many runnables to this and since the thread count is 1, it will get executed sequentially.
For communicating with UI, you can user Handler.
public void onPostExecute(){if(blahblah){
task.execute();
}
}
AKA put an if statement on task.execute so you have control..
You could look into using an IntentService, instead of an AsyncTask -- since launching multiple intents to the same IntentServicewill queue up the operations, so the Intent launched before will have to complete before the second onHandleIntent(Intent) will run.

Android runOnUiThread/AsyncTask cannot resolve CalledFromWrongThreadException

I'm working for an Android app and implementing a ProgressBar by using AsyncTask class.
The problem is that on some devices, it causes "CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views." in onPostExecute. On those devices, the problem occurs 100%. On other devices, it works fine.
public final class MyAsyncTask extends AsyncTask<String, Integer, String>
{
private ProgressBar progress;
private ListActivity activity;
public MyAsyncTask(ListActivity activity, ProgressBar progress)
{
this.progress = progress;
this.activity = activity;
}
protected void onPreExecute()
{
this.progress.setVisibility(view.VISIBLE);
}
protected String doInBackground(String[] arg0)
{
// getting xml via httpClient
return string;
}
protected void onPostExecute(String result)
{
this.progress.setVisibility(view.GONE);
}
I don't understand why onPostExecute does not run on the UI thread, on those certain devices.
Next, I tried to call it with runOnUiThread, to make absolutely sure that it runs on the UI thread.
runOnUiThread(new Runnable() {
#Override
public void run() {
ProgressBar progress = (ProgressBar)findViewById(R.id.some_view_progressbar);
MyAsyncTask task = new MyAsyncTask(activity, progress);
task.execute();
}
} );
Even this did not solve the problem. The same exception still occurs.
From Log, I confirmed that Thread.currentThread().getId() is certainly different from the app's main activity's thread inside the handler.
I'm stuck. Any advice will be appreciated.
NOTE:I edited the sample code (not a real code) above to fix the wrong method name and missing "return string".
I will add more information later.
I don't see anything wrong with MyAsyncTask itself, but there are still other things that can go wrong.
Starting the AsyncTask
From the Android Docs
Threading rules
There are a few threading rules that must be followed for this class
to work properly:
The AsyncTask class must be loaded on the UI thread. This is done automatically as of JELLY_BEAN.
The task instance must be created on the UI thread.
execute(Params...) must be invoked on the UI thread.
Do not call onPreExecute(), onPostExecute(Result), doInBackground(Params...), onProgressUpdate(Progress...) manually.
The task can be executed only once (an exception will be thrown if a second execution is attempted.)
You don't show where you normally instantiate, and execute the task, so make sure that you do this in code that's already on the UI/main thread. Note that the first bullet point above might explain why this works for you on some devices, and not on others.
Creating the View Hierarchy
The message tells you
Only the original thread that created a view hierarchy can touch its views.
and you're assuming that this is because your async task is (strangely) trying to modify the UI on a background thread. However, it is possible that you get this error because the async task modifies the UI on the main thread, but the UI (ProgressBar) was not created correctly in the first place.
See this question for an example of how you can erroneously create the view on the wrong thread (anything other than the main thread), and get this same error.
More
I would, however, like to see exactly where you are logging the thread ID, and what value(s) you're getting. If you check out my first two suggestions, and they don't solve your problem, then we may need more information.
You also mention a Handler (?), but don't show how or where you use that. Normally, using AsyncTask removes the need to use Handler, so I'm a little worried about how you might be using that.
Update
Per the discussion in comments below, it looks like the issue here is the one discussed in this question. Some code, probably running on a background thread, is first to cause the AsyncTask class to be loaded. The original (pre-Jelly Bean) implementation of AsyncTask required class loading to occur on the main thread (as mentioned in the Threading Rules above). The simple workaround is to add code on the main thread (e.g. in Application#onCreate()) that forces early, deterministic class loading of AsyncTask:
Class.forName("android.os.AsyncTask");
Make sure you are invoking aysnctask.execute() from the main thread only.
Write a handler in UI thread and call the handler from onPostExecute. It will solve the problem.
Something like this. Have a handler in UI thread (main thread):
handler = new Handler(){
#Override
public void handleMessage(Message msg) {
//run on UI Thread
}
};
and call in onPostExecute() like this:
handler.sendEmptyMessage(MSG);

Executing a runnable in Asynctask

I have a class AsycnIntegerCounter which extends AsyncTask, with doInBackground() and onPostExecute() overridden in the same.
From my main thread, I am able to create a runnable object and execute it using the
AsycnIntegerCounter's static execute method. AsycnIntegerCounter.execute(Runnable)
Can anyone help me in understanding what exactly happens when we execute a runnable using AsycnIntegerCounter (i.e) using AsycnTask object.
When this can be used ? and what is the advantage rather than running using a Thread object?
Code Sample:
AsycnIntegerCounter integerCounter1 = new AsycnIntegerCounter(next,0);
AsycnIntegerCounter.execute(new Runnable() {
#Override
public void run() {
int i = 100;
while(i<=105){
i++;
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
});
There are a couple of fundamental differences between
static void execute(Runnable)
and
AsyncTask execute(Params...)
Background task is defined in Runnable instead of implementing doInBackground
The Runnable-task is not using the internal thread communication mechanism of the AsyncTask. Hence, neither onPreExecute nor onPostExecute are called.
The latter is available on all platforms, whereas the first was added in API level 11.
The advantage of using execute(Runnable) is that the task can be executed on a worker thread of the internal thread pool, i.e. no new thread has to be created.
It's the same as execute() but it will run your Runnable in the background instead of running the doInBackround function. It can be useful when you have the same onPreExecute and onPostExecute but several runnables.
I guess the advantage over Thread.execute or an Executor is exactly calling onPreExecute and onPostExecute before and after.
#Alex makes a very good point. Suppose the you have a lot of methods, M1(), M2(), and so on that you wish to execute. Suppose that before executing any of them you need to execute method Before() and after you need to execute method After().
ie, the sequence of methods goes:
Before();
M1();
After();
Or
Before();
M2();
After();
By putting Before() in onPreExecute and After() in onPostExecute you can achieve that sequence. By making M a runnable, you can then achieve:
Before();
WhateverRunnableYouWant();
After();
With the Runnable in a background, non-UI, thread, as per your code.
As far as i figure it's like AsyncTask class but AsynchTask only runs once, but with this class it provides two things-:
It loops so it benefits, if you want a task to run multiple time
like checking for continuous data on a web service.
It fixed the running time of a task with Thread.sleep, so if a task finished
earlier it will fix the time of this task by Thread.wait().

Android Looper.prepare() and AsyncTask

Hi I have some questions regarding Looper.prepare() and AsyncTasks.
In my app I have an AsyncTask that's starting other AsyncTasks. I had 2 AsyncTasks Search and GetImage. The GetImage task is executed several times within the Search task. It works fine.
However recently I implemented image caching as described here:
http://android-developers.blogspot.com/2010/07/multithreading-for-performance.html
After I implemented this I started getting intermittent crashes
02-09 17:40:43.334: W/System.err(25652): java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
I'm not sure where I should call prepare(). Here's a rough outline of the code
Search extends AsyncTask{
#Override
protected void doInBackground(){
ArrayList<Object> objs = getDataFromServer();
ArrayList<View> views = new ArrayList<View>();
for(Object o: objs){
//multiple AsyncTasks may be started while creating views
views.add(createView(o));
}
for(View v: views){
publishProgess(v);
}
}
}
public View createView(Object o){
//create a view
ImageView iv = .....;
ImageDownloader.getInstance().download(url,iv);
}
The ImageDownloader can be seen in the link above, in it is another AsyncTask to download the image aswell. It also contains a Handler and Runnable for purging the cache which is reset every time a download occurs. I did make one change to the ImageDownloader, I made it a singleton.
public static ImageDownloader getInstance(){
if(instance == null){
//tried adding it here but it results in occasional
//cannot create more than one looper per thread error
Looper.prepare();
instance= new ImageDownloader();
}
return instance;
}
The ImageDownloader download method may be called 10's of times, which is creating an AysncTask for each of the downloads. So I've been scratching my head for the last few days, Hope you guys can help.
What is really going on is you are attempting to perform something on a background thread that requires the UI thread to run.
The Looper is a part of the system that ensures that transactions are done in order, and the device is responding as it should.
95% of the time when you get the Looper error, what it really means is you need to move part of your code to the UI thread, in Asynctask this means moving it to either onPostExecute or onProgressUpdate.
In your case it appears as if you are adding views, which is part of the UI and therefor would cause a problem. If that is not in fact what is causing the problem, an examination of the stacktrace should give you some clues.
As a side note, if you MUST call Looper.prepare() I would call it at the beginning of your thread. However, this is generally recommended to avoid the need to call it.

Categories

Resources