Making a Simple Recurring Text Update Continue Indefinitely - android

I have a very function function inside the activity that takes a static date in the past, formats it to a relative string using DateUtils.getRelativeDateTimeString (so it becomes something like "3 minutes ago" and sets it to a TextView. However, I want this TextView to keep updated so long as the activity stays open.
How do I make a continuous task that will either run continuously (infinite loop) or run within short intervals - like every second. How to accomplish this without getting into background services and such?

Here is an example using AsyncTask
private class BackgroundCoversionTask extends AsyncTask< String, String, Void >{
#Override
protected Void doInBackground( String... params ) {
while( !isCancelled() ){
try {
Thread.sleep( 1000 );
} catch ( InterruptedException e ) {
break;
}
//DateUtils.getRelativeDateTimeString( MainActivity.this, time, minResolution, transitionResolution, flags )
// Do something right here
publishProgress( Long.toString( System.currentTimeMillis() ) );
}
return null;
}
#Override
protected void onProgressUpdate( String... values ) {
super.onProgressUpdate( values );
mTextView.setText( values[0] );
}
}
Then if you want to cancel the task, call cancel()

Just run it on a separate thread.
Thread thread = new Thread()
{
#Override
public void run() {
try {
while(true) {
sleep(1000);
//Do your date update here
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
thread.start();
See: How to run a Runnable thread in Android?
With threads please make sure that when the app is paused or resumed you appropriately pause or resume your thread. Also it is a good idea to end them yourself at the end of the activity lifecycle for the sake of handling any data you might want

Related

Execute AsyncTask loop after previous one

I want to check unread messages after 30 seconds of previous check, means when the first check (AsyncTask) is complete and I have the result then I want to wait 30 seconds, then I want to check for unread messages again and so on. Here is my code:
TimerTask timerTask = new CheckUnreadMessages(menuItem);
Timer timer = new Timer();
timer.schedule(timerTask, Constants.CHECK_UNREAD_COUNT_INTERVAL);
Here is my TimerTask:
class CheckUnreadMessages extends TimerTask{
MenuItem menuItem;
public CheckUnreadMessages(MenuItem menuItem) {
this.menuItem = menuItem;
}
#Override
public void run() {
Log.i("PrivateHome", "Checking for unread message...");
new CheckUnreadMessagesTask(menuItem, PrivateHome.this).execute(LocalDBSP.init().getID(PrivateHome.this));
}
}
Here goes my AsyncTask:
public class CheckUnreadMessagesTask extends AsyncTask <String, String, Boolean> {
Activity activity;
JSONObject result;
MenuItem menuItem;
public CheckUnreadMessagesTask(MenuItem menuItem, Activity activity){
this.menuItem = menuItem;
this.activity = activity;
}
#Override
protected Boolean doInBackground(String... params) {
try {
//now update to server
result = getResponse(URLManager.getUnreadCount(params[0]));
return JSONHelper.isResultOK(result);
}catch (Exception e){
e.printStackTrace();
}
return false;
}
#Override
protected void onPreExecute() {
super.onPreExecute();
}
#Override
protected void onPostExecute(Boolean resultOK) {
super.onPostExecute(resultOK);
if(resultOK){
try {
String count = result.getString(JSONKeys.RESULT);
menuItem.setTitle(Constants.NAV_SEE_MESSAGES_TITLE+" ("+count+")");
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
But it's being executed for the first time only, it's not repeating.
Dont use a AsyncTask to do this, they have a lot of problems with activity lifecycle.
You should use a periodic service or use the AlarmManager. Even a Java Thread with a while true with a sleep of 30 seconds is more safe than an async task.
Basically you are not re-scheduling the CheckUnreadMessages, so it gets executed only once, and therefore it triggers the CheckUnreadMessagesTask only once.
One solution is to use timer.scheduleAtFixedRate() instead, but this has a fixed rate and may not be what you want (often it is, though).
If you want to have the next check running 30s after the last task executed, you need to do rescheduling in CheckUnreadMessagesTask instead:
#Override
protected void onPostExecute(Boolean resultOK) {
super.onPostExecute(resultOK);
TimerTask timerTask = new CheckUnreadMessages(menuItem);
timer.schedule(timerTask, Constants.CHECK_UNREAD_COUNT_INTERVAL);
// ...
}
You'll need to pass a reference to the timer to the tasks, though. I'd avoid re-creating a new timer every time, but you could do that.
Additionally, I find the name confusing, since both look similar, at least name CheckUnreadMessages as CheckUnreadMessagesTimerTask so that it is more obvious which is which.

Repeat task while activity is open

i want to repeat task while the activity is open.
For example repeat foo() every minute while the activity is open.
I tought about Timer, handler and runable.
I tought about this code:
Maybe there is some better way?
public void setRefreshRate()
{
newTimer = true
while(true)
{
if(newTimer)
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
if(isNetworkAvailable() && movedToAnotherActivity== false)
new GetWorkouts().execute();
newTimer = true;
}
}, Integer.getInteger(data.getWallRefresh()));
newTimer = false;
}
}
There may be a better way but I like AsyncTask so I would probably use that and call sleep() in doInBackground() then you can call cancel() on your task object and set it to null when the Activity finishes.
public void doInBackground(Void...params)
{
boolean flag = false;
while (!flag)
{
// do some work
Thread.sleep(6000);
}
}
then overide and set flag to true in onBackPressed() and finish(). You can then use any of the other AsyncTask methods to update the UI if necessary.
AsyncTask
Thanks to codeMagic's answer for starting me down the right path, but AsyncTask isn't really designed for this. From the docs:
AsyncTasks should ideally be used for short operations (a few seconds at the most.)
The problem is that AsyncTasks, at least by default, run sequentially on the same worker thread, so if you try to launch another AsyncTask, it won't be able to run, since the timer loop never finishes.
To work around this, I just used a raw Thread and it's working fine.
apiUpdateTimerThread = new Thread(new Runnable() {
#Override
public void run() {
while(true) {
try {
Log.i(TAG, "UPDATE FROM THE API!!!!");
doSomeStuff();
Thread.sleep(5 * 1000);
} catch(InterruptedException e) {
Log.e(TAG, "API Update AsyncTask Interrupted", e);
}
}
}
});
To stop it, just call
apiUpdateTimerThread.interrupt();

Android async task to wait for other task to complete

I have two asyc task both perform separate network operation.I want one async task to wait for other task to finish for a single variable..I thought of doing it like perform other asyc operation onPostexecute of first one but for a single variable i have to make other task to wait first one to finish...is there any to achieve efficently
Referring to this, you can not use .execute() so;
First you have to start your tasks like this:
// Start first task
new Task1().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, "");
// Start second task
new Task2().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, "");
and then you can make a static variable so the both of tasks can access to it:
public static boolean task1Finished = false;
Then simple example of the tasks:
First task
private class Task1 extends AsyncTask<String, Void, String> {
#Override
protected String doInBackground(String... params) {
Log.d("myApp", "Task1 started");
for(int x = 0; x < 10; ++x)
{
try
{
Thread.sleep(1000);
//Log.d("myApp", "sleeped 1000 ms");
}
catch (InterruptedException e)
{
e.printStackTrace();
}
}
return "";
}
#Override
protected void onPreExecute() {
}
#Override
protected void onPostExecute(String result) {
// Lets the second task to know that first has finished
task1Finished = true;
}
}
Second task
private class Task2 extends AsyncTask<String, Void, String> {
#Override
protected String doInBackground(String... params) {
Log.d("myApp", "Task2 started");
while( task1Finished == false )
{
try
{
Log.d("myApp", "Waiting for Task1");
Thread.sleep(1000);
}
catch (InterruptedException e)
{
e.printStackTrace();
}
}
Log.d("myApp", "Task1 finished");
// Do what ever you like
// ...
return "";
}
#Override
protected void onPreExecute() {
}
#Override
protected void onPostExecute(String result) {
Log.d("myApp", "All done here (Task2)");
}
}
Maybe asynctask is not the best tool? There are some interesting classes in the android api that can help doing specifically the synchronizing job :
Quote from android developper : "Four classes aid common special-purpose synchronization idioms.
Semaphore is a classic concurrency tool.
CountDownLatch is a very simple yet very common utility for blocking until a given number of signals, events, or conditions hold.
A CyclicBarrier is a resettable multiway synchronization point useful in some styles of parallel programming.
An Exchanger allows two threads to exchange objects at a rendezvous point, and is useful in several pipeline designs."
So I suggest looking into :
Cyclic Barrier
http://developer.android.com/reference/java/util/concurrent/CyclicBarrier.html
Exchanger
http://developer.android.com/reference/java/util/concurrent/Exchanger.html
You need to create another async in OnpostExecute of first one if you need to call the other synchronously.

How to handle button click while using AsyncTask?

I am developing alarm app.
I used broadcast receiver to receive alarm time.
When alarm times up, I show a activity which starts ringtone & vibrate using AsyncTask for 2 minutes.
In this activity I have two buttons named
Plus
Minus
When I press any of these buttons its click event is delaying to fire, means not getting clicked as I press button due to asyncTask running in backgroung(playing ringtone).
I read that asyncTask runs on seperate thread,
Than my button click event should fire as it pressed but in this case its not doing same.If any body had this situation and got solution then please suggest me!
Below is my code.
called using :
new RingtonePlay ().execute("");
following is implementation.
public class RingtonePlay extends AsyncTask<String,Void, String>
{
#Override
protected void onPreExecute()
{
super.onPreExecute();
try
{
audioManager = (AudioManager)mContext.getSystemService(Context.AUDIO_SERVICE);
originalVolume = audioManager.getStreamMaxVolume(AudioManager.STREAM_RING);
vibratorObj = (Vibrator)mContext.getSystemService(Context.VIBRATOR_SERVICE);
volume = originalVolume;
listObjs.clear();
listObjs.add(audioManager);
listObjs.add(originalVolume);
listObjs.add(vibratorObj);
}
catch (Exception e)
{
e.printStackTrace();
}
}
#Override
protected String doInBackground(String... params)
{
try
{
Cursor cursorSettings = dbHelper.getAllRecords(Info.SETTINGS);
if(cursorSettings!=null && cursorSettings.getCount()>0)
{
cursorSettings.moveToFirst();
durationInMilliSeconds = cursorSettings.getString(cursorSettings.getColumnIndex(Info.DEFAULT_DURATION));
vibrate = cursorSettings.getInt(cursorSettings.getColumnIndex(Info.DEFAULT_VIBRATE));
if(toneName.equals(""))
{
toneName = cursorSettings.getString(cursorSettings.getColumnIndex(Info.DEFAULT_TONE_NAME));
tonePath = cursorSettings.getString(cursorSettings.getColumnIndex(Info.DEFAULT_TONE_PATH));
}
listObjs.add(vibrate); // For vibration [ YES = 1, NO = 0]
}
else
{
listObjs.add(0); // For vibration [ YES = 1, NO = 0]
}
if(cursorSettings!=null)
cursorSettings.close();
durationInMilliSeconds = 5000;
ringTone = RingtoneManager.getRingtone(mContext, tonePathURI);
if(ringTone!=null)
{
ringTone.play();
}
if(ringTone==null && vibrate==0)
{
// No need to start any counter...
}
else
{
timer = new MyCountDownTimer(durationInMilliSeconds, 1000, ringTone, mContext, listObjs);
timer.start();
}
}
catch (Exception e)
{
e.printStackTrace();
}
return "";
}
#Override
protected void onPostExecute(String result)
{
super.onPostExecute(result);
}
}
Of the 4 functions in AsyncTask, only doInBackground() is running in its own Thread off of the main UI Thread. Therefore, make sure that you are playing your ringtone from within doInBackground() and that you are starting the AsyncTask with its execute() function.
AsyncTask.doInBackground() will not stop your Button presses from firing unless you have called it directly instead of executing the AsyncTask.
Presumably, you have a short sound file which you are playing over and over for 2 minutes.
Each time the sound finishes playing, you should check for several things to decide if you should play again. A while() loop within doInBackground() will work well for this.
If two minutes have elapsed, don't play the sound again.
Your "Plus" and "Minus" Button presses can modify the two minute time.
You can add a "Stop" button to zero out the time and stop the
AsyncTask at the next cycle.

How to kill a thread running in a new activity

So activity starts and I create a Thread which checks when to go to the next activity. But sometimes I need this activity to kill itself. onPause does this, but after that Thread is still alive and after time runs out it start a new activity. Is it possible to kill this Thread and stop goToFinals intent?
public class Questions extends Activity {
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
String in = getIntent().getStringExtra("time");
long tmp = Long.parseLong(in);
endTime = (long) System.currentTimeMillis() + tmp;
Thread progress = new Thread(new Runnable() {
public void run() {
while(endTime > System.currentTimeMillis()) {
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
Intent goToFinals = new Intent(Questions.this,End.class);
startActivity(goToFinals);
}
});
progress.start();
}
#Override
protected void onPause() {
super.onPause();
finish();
}
}
There are a couple of ways you can stop your thread. If you store your Thread object then you can call interrupt() on it:
progress.interrupt();
This would cause the sleep() to throw an InterruptedException which you should return from, not just print the stack trace. You should also do the loop like:
while(endTime > System.currentTimeMillis()
&& !Thread.currentThread().isInterrupted()) {
You could also set some sort of shutdown flag:
// it must be volatile if used in multiple threads
private volatile boolean shutdown;
// in your thread loop you do:
while (!shutdown && endTime > System.currentTimeMillis()) {
...
}
// when you want the thread to stop:
shutdown = true;
In order to safely quit the thread you must first call thread_instance.interrupt() and then you can check if it is interrupted or not.
Refer this LINK
see this post for kill java thread.The way they recomend is to use a shared variable as a flag which asks the background thread to stop. This variable can then be set by a different object requesting the thread terminate.

Categories

Resources