Cancel AsyncTasks from collection - android

Let's say I have TasksManager which has static List tasks (not sure list is good solution) and there are static methods addTaskToList(MyTask task){tasks.add(task);},
removeTaskFromList(MyTask task){tasks.remove(task);}
Each task in doInBackground() calls first method, and in onPostExecute() there is second method call with "this".
MyTask has String field "method".
I want to cancel tasks of this list where task.getMethod().contains("url")..
not sure this code is good enough for stable working.. looks like onCancelled() of task not always called, multitreading can be dangerous for such methods I think.
for (MyTask task : tasks) {
if (task.getMethod().contains("url")) {
task.cancel(true);
break;
}
}
Is it normal practice to store tasks in this way or you can suggest me more elegant?

Cancelling an AsyncTask isn't always an immediate/obvious thing. If you are using cancel, you also need to make sure doInBackground is aware of isCancelled and you have to stop what you were doing yourself (see the docs for isCancelled).
I wouldn't recommended storing a list of AsyncTask objects and iterating them for doing sequential background work anyway. That sounds like it might get very messy very quickly. Each AsyncTask creates a new Thread, and that doesn't sound like what you want. Rather, you may just want one background thread you can do stuff on?
For one background thread you can use a HandlerThread and your own Looper, as follows:
HandlerThread backThread = new HandlerThread("BackLooper", Thread.NORM_PRIORITY);
backThread.start();
Looper backLooper = backThread.getLooper();
private synchronized void runOnBackThread(Runnable r) {
new Handler(backLooper).post(r);
}
Then each item you want to run in sequence you can post on the back thread by submitting a Runnable. And, you can also use the other Handler post variants too, postDelayed, postAt, and so on.
And, depending on what you're doing you may find IntentService very helpful. IntentService is provided specifically for a "work queue" type pattern. It has one background thread, does whatever you tell it to do ONE AT A TIME when you invoke it, and goes away on its own when it's not needed.
Lastly, if you're looking for a really nice general "task" type library for Android check out Square's Tape. That's not directly related to your question, but I find Tape super handy for more robust "queue it up" task type situations.

Related

What constitutes "UI interactions" for AsyncTask?

AsyncTask is a standard way to perform long running operations asynchronously on a background thread without holding up the UI thread. One should not perform any UI interactions from the doInBackground() method.
My question: What are examples of UI interactions that are forbidden? Would it be any of the following:
LayoutInflater.inflate()
View.findViewById()
TextView.setText()
I'm inclined to say yes, but we have some code right now that does all of these (and more) and is called from the doInBackground() method, and yet the code is working. I've seen other people indicate they receive an exception when attempting to perform UI activity from doInBackground(), but that is not our experience.
Our code is generating an on-screen report that is not visible until the entire operation is complete. On rare occasion (hard to reproduce) when attempting to cancel the operation very quickly, we will see the application get into a weird state, but it doesn't crash.
Before changing our code in hopes of finding this rare condition, I wanted to see if anyone had some thoughts on why our code is "working" as-is.
The only other tidbit of information that might be helpful is that our doInBackground method has the following code template:
protected Boolean doInBackground(Void... voids) {
if (null == Looper.myLooper()) {
Looper.prepare();
}
publishProgress(0.0);
// Perform ui/non-ui logic here
Looper myLooper = Looper.myLooper();
if (null != myLooper && Looper.getMainLooper() != myLooper) {
myLooper.quit();
}
return true;
}
The Looper is needed for some of the report generating code (omitted) that uses a new Handler() to generate data. I'm not sure if creating the Looper is somehow making our ui interactions legal.
(I do have a stack trace that clearly shows our UI activity being called from doInBackground, in case you thought we might be spinning off some separate threads to update our UI)
AsyncTask is not meant for really long running work, it should complete within a few seconds. It is a one-shot completely managed thread context, which should not have its own Looper attached to it. That actually will break the backing AsyncTask functionality - starving off other future AsyncTask operations you may be starting. If you have something which requires a Looper, you should be using your own Thread or ThreadPool rather than an AsyncTask. You'll also want to make sure you retain a reference to your AsyncTask so it can be cancelled appropriately - this is a source of many memory leaks and/or exceptions due to invalid state when onPostExecute() is called.
The intent of the publishProgress() method is to give your app the ability to get updates it can reflect on the UX. You are correct, setText(), etc. should not be run in the doInBackground() callback. That callback is executed in arbitrary thread context in which you do not control and cannot make UI updates.
You may be able to use inflateLayout() and findViewById(), but this is not a good practice to do this outside of initialization as these are potentially expensive operations. Inflation has to parse the binary layout and create view objects on the fly. Finding by ID walks the entire view hierarchy to find the component you desire. A better practice would be to cache these at creation (for an Activity or Fragment) or when creating a view as part of an adapter (such as a ViewHolder in RecyclerView.

Is there a callBack to SetContentView in Android?

Is there any callBack to setContentView in Android, since i'm doing a heavy operation right after setContentView line, and it seems to skip that setContentView.
So i was thinking of moving the heavyOperation to the callBack of setContentView.
Thanks
EDIT:
Pseudo Code:
AudioRecord Finishes
SetContentView(1) //To show a "Processing" screen with no buttons
FFT analysis
SetContentView(2) //On FFT analysis DONE.
In my case "SetContentView(1)" NEVER occurs.
EDIT # 2:
I did the heavy operation in another Thread, and used Handler to send a Message after heavy operation finishes to treat it as a callBack.
Thanks for all the help guys
Short answer: No callback for the setContentView.
If you are doing network operation then you can use the AsyncTask for this.
If you are doing any more heavy operation and want to update the UI then you can do that using the Service and BroadCastReceiver.
For this you have to make your own callback using the interface.
heavy work should be done in asynk tasks or as a service or on other threads
Don't do any heavy calculations on the main UI thread where onCreate() and such are run.
What happens that the first setContentView() posts a "layout and draw" message to the UI thread message queue. Then your calculation blocks the UI thread, preventing messages in the queue from being processed. The second setContentView() posts another message to the queue. When the control eventually returns to the message loop, both messages are processed and you'll get the layout set up by the last call to setContentView().
For heavy computations, use a separate thread. For example, an IntentService or an AsyncTask make threading easier.
My hack.
final Handler handler = new Handler();
setContentView(layoutResID); // This posts some messages to message queue.
handler.post(new Runnable() { // Post another message at the end.
#Override
public void run()
{
// Called after layout has changed.
// If you want to skip some more works (like transitions),
// call another handler.post() here.
}
});
To see what happens, set a break point at the line Message msg = queue.next(); in Looper.loop() may help.
I was facing a quite similar problem a day ago, but I figured it out. (I know your problem is solved, just offering a different approach which doesn't require a handler or callback.
Most Suitable for running U.I. functions :
If you need to do something like this :runTask() then
setContentView() (or any other ui function) you can run the task on different thread by using AsyncTask or you can set a timer for when the task is completed (if your task takes a certain time), the User Interface functions will be called.
But since the Timer class, runs the functions on a different thread, you can not run the setContentView() inside it. So you can use a runOnUiThread(Runnable action) method inside the overloaded run() function of Timer class. You just need to define a function that returns a runnable. Define your Ui operations in the runnable action.
Hope it helps someone.

Implementing a cyclic executive in android?

I am writing an android app and I need to be able to do certain things periodically/continuously. I am coming from a C/C++ embedded firmware background and this new-fangled way of doing things is going to take some getting used to. It seems that there is no such thing as a "main loop" in Android, that everything is event-driven... I also understand that by default all code you write operates on the GUI thread, and I should probably make a new thread to execute the equivalent of a "main loop"...
So far what I have is an implementation of the AsyncTask class who's "doInBackground" method contains an infinite loop (my main loop), I create an instance of this class and run it immediately when my app starts. The problem I am having is in the interaction between this thread and the user interface... when something occurs in my main loop thread and I want to update the GUI understand that I must call "publishProgress", which is executed on the GUI thread. There are a few problems with this, primarily that many things I have tried to do in this "onProgressUpdate" method do not work, or do not occur in a predictable amount of time.
My question, is there a better way to accomplish what I am trying to do? In general, what do most people do when they have code that they want to run periodically and/or continuously while their application is running, code that must interact with the user interface in a timely manner (by timely I mean with zero delay).
Thank you.
public class MainLoopThread extends AsyncTask<Void, Void, Void>
{
#Override
protected Void doInBackground(Void... arg0)
{
while(true)
{
//Do stuff
//Update GUI
publishProgress();
}
}
protected void onProgressUpdate(Void...voids)
{
//Update GUI
}
}
It is unclear what you are trying to do, however just let me say using AsyncTask in this way may have negative consequences.
AsyncTask internally uses a thread pool pattern for running the stuff from doInBackground(). On Android OS before 1.6 and starting from 3.0 the pool size is just 1, meaning no parallel computations for a bunch of AsyncTasks. More details on this here.
So, this may result that only this current AsyncTask is running, while others even if started will have to wait untill the current one is done.
Depending on your needs for things to be done periodically Android exposes:
AlarmManager
Handler - it allows to post a runnable on UI thread with a delay or periodically
Timer + Activity.runOnUiThread(Runnable action) inside of TimerTask
UPDATE: basing on your comments it looks like you need a Service, that starts a thread that periodically sends broadcasts with the data for UI. Then your UI (Activity) registers broadcast receivers to catch those broadcasts, extract the data and use for UI updates.
So your saying that onProgessUpdate() isn't working? That seems weird because it should.
Another option that you have is just to make a Thread that loops.
The trick is that if you want to update the UI thread you will have to make a call to view.post() and give it a runnable that will actually perform the update. The idea here is that you must schedule an update on the UI thread, you can't just take it and say NOW!

Android thread queue

I'd like to have a queue of work/tasks to be done on a separate thread, but can only process one work at a time. So not simultaneously.
Is there something built-in android for this?
Thanks,
EDIT:
The work = get information from Database. Once done, update the UI with the fetched information.
Have you checked out java.util.concurrent.Executors ? You could do something like this:
final static ExecutorService tpe = Executors.newSingleThreadExecutor();
...
tpe.submit(new Runnable() {
#Override
public void run() {
// your work
}
}):
It's not android specific, it is part of the jdk5.
From the doc:
Creates an Executor that uses a single worker thread operating off an
unbounded queue. (Note however that if this single thread terminates
due to a failure during execution prior to shutdown, a new one will
take its place if needed to execute subsequent tasks.) Tasks are
guaranteed to execute sequentially, and no more than one task will be
active at any given time. Unlike the otherwise equivalent
newFixedThreadPool(1) the returned executor is guaranteed not to be
reconfigurable to use additional threads.
If you want something can do work independently from the activity lifecycle that can do queued work, you should take a look at IntentService. It can spin up, do discrete blocks of work asynchronously then finish itself when all its tasks are completed.
If you don't need anything that can live without any activities, Java has ExecutorService along with several different implementations.
In Android You can also consider about Loader framework.
http://developer.android.com/guide/components/loaders.html

some kind of queue for asynctask

Hello
I have ListView with list of files. i click item and start to download this file in asynctask.
then i click another one and it must be put in queue, wait for that file and start ot download after it finishes. i can make some class that will hold all clicked links, and pass it to asynctask downloading part? and than somehow process them. but want to know is it the right way?
any links of sugestions? thanks
If you're set on using AsyncTask then, yeah, hold your clicked links and kick off new tasks when appropriate. You should note that AsyncTask is like the 'pocket knife' for threading in Android apps.
If you really need to manage a bunch of background tasks, and it sounds like you do, take a look at ThreadPoolExecutor. You get a lot of flexibility.
BlockingQueue
ThreadPoolExecutor
More Info
Example
Take a look at HandlerThread and the Handler class. You need one handler to pass tasks to the background HandlerThread and another for the UI thread to pass results back to the UI
Even though old, got here from Google: consider an IntentService.

Categories

Resources