I am developing an app that needs to process acceleration values continuously for some time (approx. an hour) - yes, I would really like to do it that way. The processing involves doing some calculations and updating the UI from time to time. The acceleration is collected inside a (foreground) service - collecting acceleration should happen if the user minimizes the app as well.
My question is: what would be the most appropriate pattern to implement this? I don't want the processing to make the app UI unresponsive.
Right now I'm collecting acceleration data in the UI thread (in the Service). The collected data is than passed to a class that does some calculations and based on them broadcasts an Intent, which is registered in the Main activity to update the UI.
Should I be collecting acceleration data in a worker thread in a service? (Is this even possible)?
Or should I do the processing in another thread? (How would be the best way to do this without starving either the UI/acceleration collection thread or the processing thread)?
Thanks!
You certainly should be doing any non-trivial processing in a background thread. The easiest way sounds like it'd just be putting it into an AsyncTask called from your existing Service. You can move your processing to doInBackground. Another option would be to create a separate IntentService to handle your processing, but I think AsyncTask should be sufficient.
Try an AsyncTask
public class AsyncTaskTestActivity extends Activity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
new PostTask().execute();
}
// The definition of our task class
private class PostTask extends AsyncTask<String, Integer, String> {
#Override
protected void onPreExecute() {
super.onPreExecute();
displayProgressBar("Working...");
}
#Override
protected String doInBackground(String... params) {
do_background_Stuff();
// call this method whenever you want to run something in the UI thread and then get back to processing
publishProgress(i);
}
return "All Done!";
}
#Override
protected void onProgressUpdate(Integer... values) {
super.onProgressUpdate(values);
updateProgressBar(values[0]);
}
#Override
protected void onPostExecute(String result) {
super.onPostExecute(result);
dismissProgressBar();
}
}
}
Related
I need to perform a very simple operation that involve network. I know that this must be done with an Async Task, because run a task that involves Network operations on main thread is bad.
Since is pretty verbose using the classic way
private class LongOperation extends AsyncTask<String, Void, String> {
#Override
protected String doInBackground(String... params) {
//to do
return "Executed";
}
#Override
protected void onPostExecute(String result) {
//to do
}
#Override
protected void onPreExecute() {}
#Override
protected void onProgressUpdate(Void... values) {}
}
for a method static method invocation that must download only few bits
I'm wondering if there is some more concise form or alternative that I could use.
You don't need an AsyncTask. It is just a convenience to use because it already has callback methods.
You can create a new Thread and execute your network call there.
There are many ways to create a worker thread. It depends on what are you doing with network.
If you just want to do simple network operations such as download some JSON data then get it back to update UI: use AsyncTask.
If you want to do long network operations which involve moderate to large amounts of data (either uploading or downloading): use Thread.
If you want to continuously send/receive message to/from the Internet, use HandlerThread.
So in conclusion: AsyncTask is already the simplest and easiest to use. Beside, you don't need to override all methods, just override doInBackGround() and onPostExecute() if you want to receive data.
See: Asynctask vs Thread in android
You can always use AsyncTask.execute(() -> { /* network operations */ });, the downside is you don't get any of the callbacks so I tend to only use this when prototyping or with very simple tasks.
Use an anonymous class inside a method:
public void asyncOperation () {
new AsyncTask<Task, Void, Boolean>() {
#Override
protected Boolean doInBackground(String... params) {
// Your background operation, network, database, etc
return true;
}
}.execute();
}
so I am coming across a weird problem I cant find an explaination for. I have an async task in which in its doBackground method does a wait until a certain variable is set then the "wait" is notified
private class TestAsyncTask extends AsyncTask<Void, Object, Boolean> {
#Override
protected void onPreExecute() {
Log.d("Test1");
}
#Override
protected Boolean doInBackground(Void... params) {
Log.d("Test2");
while (nextCardToPlay == null) {
wait();
}
Log.d("Test3");
}
}
Activity A:
protected void onCreate(){
a = new TestAsyncTask().execute();
}
protected void onPause(){
a.cancel()
}
So as you can see when the activity starts, the asyncTask is started. When activity is closed the asyncTask is supposed to be cancelled.
What I noticed is that if I open the activity, close it, and reopen it again then the asynctask is created and in wait mode (never cancelled). No problem. Whats confusing is that when I start the activity (while the stale asyncTask is there), then it seems a new asyncTask is started ( because the logs from OnPreExecute are called) however the doInBackground in the nextAsyncTask is not executed because the Test2 log is not showing.
Any idea why?
This behavior is not at all weird if you look at the documentation, which states the AsyncTasks run on a single background thread, i.e. sequentially. If you really want your tasks to run on parallel worker threads, then use the executeOnExecutor() method instead of a simple execute() and pass it the AsyncTask.THREAD_POOL_EXECUTOR parameter.
Any suggestions for this kind of error which occurs when a UI thread is loaded with lots of loops and logical operations?
get the error message through data/anr/trace.txt from File explorer. And, also put all logical operations and loops into separate threads.
That ANR error happens when you are doing intensive work on UI thread and do not allow the user interface to refresh. Your description is a perfect match for this case.
To fix it run those operations on a different thread. You can also use AsyncTask if that's convenient in your situation. See http://developer.android.com/reference/android/os/AsyncTask.html
private class LongWork extends AsyncTask<Void, Integer, Void>
{
#Override
protected Void doInBackground(Void... arg0) {
//Do a long Task here
return null;
}
#Override
protected void onPostExecute(Void result) {
//Do what you have to do on the UI Thread
}
}
Then
LongWork work=new LongWork();
work.execute();
I have several AsyncTasks doing network operations. I was recently asked to add, after each of these operations, another network call that invokes a remote service sending some statistics. I'd like this statistics call not to delay 'main' network calls, and so I was thinking of executing them in a thread created and started inside the AsyncTask's doInBackground(). This thread would most probably end after the doInBackground() and possibly the whole AsyncTask has ended. I tried this and it works, but I was wondering if there are side effects, such as memory leaks or similar?
Thanks ;)
Try starting a second AsyncTask in the first AsyncTasks 'onPostExecute' Method.
For me this worked without any issues.
If you want to start thread in doInBackground method, you can start it in onProgressUpdate() method
Example:
protected class MyTask extends AsyncTask<Void,Integer,Void> {
public static final int START_THREAD = -1;
#Override
protected void onProgressUpdate(Integer... values) {
if(values[0] == START_THREAD){
startThread();
}
}
#Override
protected Void doInBackground(Void... params) {
publishProgress(START_THREAD);
return null;
}
}
I need my Android app to periodically fetch data from a server using AJAX calls, and update the UI accordingly (just a bunch of TextViews that need to be updated with setText()). Note that this involves 2 tasks:
Making an AJAX call, and updating the UI once I receive a response - I use a simple AsyncTask for this.
Doing the above repeatedly, at regular intervals.
I haven't figured out an elegant way to achieve Point 2 above. Currently, I am simply executing the task itself from OnPostExecute(). I read on this thread at SO that I need not worry about garbage collection as far as the AsyncTask objects are concerned.
But I'm still unsure as to how I set up a timer that will fire my AsyncTask after it expires. Any pointers will be appreciated. Here is my code:
public class MyActivity extends Activity {
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
new AjaxRequestTask().execute(MY_REST_API_URL);
}
private void updateReadings(String newReadings) {
//Update the UI
}
class AjaxRequestTask extends AsyncTask<String, Integer, String> {
#Override
protected String doInBackground(String... restApiUrl) {
//Do AJAX Request
}
#Override
protected void onPostExecute(String result) {
updateReadings(result);
/*Is there a more elegant way to achieve this than create a new AsyncTask object every 10 seconds? Also, How can I update the UI if I create a timer here? */
new AjaxRequestTask().execute(MY_REST_API_URL);
}
}
}
Thanks in advance
EDIT:
I tried posting an answer but couldn't do it since I don't have the reputation to answer within 8 hours.
Well, so I found a solution. I'm not convinced however.
protected void onPostExecute(String result) {
updateReadings(result);
// super.onPostExecute(result);
new Timer().schedule(
new TimerTask() {
#Override
public void run() {
new AjaxRequestTask().execute(MY_REST_API_URL);
}
},
TIMER_ONE_TIME_EXECUTION_DELAY
);
}
Are there any flip sides that I should be aware of when I use this? In particular, I am seeing lots of GCs happening in the LogCat. Also, I am wondering how an AsyncTask can be candidate for GC unless the onPostExecute() completes?
How can I "stop" the updates? One way I thought of was to make the very first AsyncTask instance as a member variable of the Activity. That way, I can invoke cancel(true) on it and hope that this will "stop" the tasks.
SOLUTION:
In case anyone is looking for something similar - none of the solutions I mentioned here work satisfactorily. They all suffer from OutOfMemory issues. I did not debug into the details of the OOM, but I suspect it could either be because of the recursion, or because of having HTTP-related objects as member variables in the AsyncTask rather than as members of the Activity (basically because of NOT reusing HTTP and other objects).
I discarded this approach for a different one - making my Ajax Calls endlessly in the doInBackground() of my AsyncTask; and updating the UI in onProgressUpdate(). That way I also avoid the overhead of maintaining too many threads or Handlers for updating the UI (remember UI can be updated in onProgressUpdate() ).
This approach also eliminates the need for Timers and TimerTasks, favoring the use of Thread.sleep() instead. This thread on SO has more details and a code snippet too.
Call postDelayed() on any View to schedule a hunk of code to be run on the main application thread after a certain delay. Do this in onPostExecute() of the AsyncTask to create and execute another AsyncTask.
You could use AlarmManager, as others have cited, but I would agree with you that it feels a bit like overkill for timing that occurs purely within an activity.
That being said, if the AJAX calls should be occurring regardless of whether the activity exists, definitely consider switching to AlarmManager and an IntentService.
I think the android way to do this is using AlarmManager. Or you can user a basic java Timer as well. I'd recommend AlarmManager.
Set it up to send some intent with a custom Action, and register a broadcastreceiver for it.
If the ajax calls are only executed in the activity you can just use a timer in the activity which starts the tasks.
Otherwise use a service which uses the AlarmManager and which connects to the gui via a broadcast.
The recommended way to do a repeated task, is via AlarmManager, as alluded to by Scythe. Basically it involves setting up a broadcast listener, and having AlarmManager fire off an intent to that listener at whatever interval you choose. You then would have your broadcast listener call out to the activity to run the AsyncTask. If you need a very tight timer (less than 5s calls I'd say), then you're better off using a Timer within a Service, and using AIDL to call back to the activity.
Instead of talking directly from the broadcast intent, you could also setup an IntentService which you can poke, and use AIDL to update the activity.
This is how I achieved it finally. Note that the AsyncTask cancel(true) method is useless in my scenario because of the recursion. I used what #CommonsWare suggested - used a flag to indicate whether any more tasks should be executed.
public class MyActivity extends Activity {
/*Flag which indicates whether the execution should be halted or not.*/
private boolean mCancelFlag = false;
private AjaxRequestTask mAjaxTask;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
if(mAjaxTask == null){
mAjaxTask = new AjaxRequestTask();
}
mAjaxTask.execute(MY_REST_API_URL);
}
#Override
protected void onResume() {
super.onResume();
mCancelFlag = false; /*when we resume, we want the tasks to restart. Unset cancel flag*/
/* If the main task is Finished, create a new task and execute it.*/
if(mAjaxTask == null || mAjaxTask.getStatus().equals(AsyncTask.Status.FINISHED)){
new AjaxRequestTask().execute(TLS_REST_API_URL);
}
}
#Override
protected void onPause() {
mCancelFlag = true; /*We want the execution to stop on pause. Set the cancel flag to true*/
super.onPause();
}
#Override
protected void onDestroy() {
mCancelFlag = true;/*We want the execution to stop on destroy. Set the cancel flag to true*/
super.onDestroy();
}
private void updateReadings(String result) {
//Update the UI using the new readings.
}
class AjaxRequestTask extends AsyncTask<String, Integer, String> {
private AjaxRequestTask mChainAjaxRequest;
private Timer mTimer;
private TimerTask mTimerTask;
#Override
protected String doInBackground(String... restApiUrl) {
//Do AJAX call and get the response
return ajaxResponse;
}
#Override
protected void onPostExecute(String result) {
Log.d(TAG, "Updating readings");
updateReadings(result);
// super.onPostExecute(result);
if(mTimer == null){
mTimer = new Timer();
}
if(!mCancelFlag){/*Check if the task has been cancelled prior to creating a new TimerTask*/
if(mTimerTask == null){
mTimerTask = new TimerTask() {
#Override
public void run() {
if(!mCancelFlag){/*One additional level of checking*/
if(mChainAjaxRequest == null){
mChainAjaxRequest = new AjaxRequestTask();
}
mChainAjaxRequest.execute(MY_REST_API_URL);
}
}
};
}
mTimer.schedule(mTimerTask,TIMER_ONE_TIME_EXECUTION_DELAY);
}
}
}
}