How to repeat an Asynchronous task periodically? - java

I have an asynchronous task that i will like to repeat every 10 secs allowing focus to move back to the user interface in my Android application.
I have tried using java.util.Timer & TimerTask but the app crashes. It works within a for loop as you can see but i need to have this repeated every 10 secs.
do ...while loop also doesn't work even if i include a Thread.Sleep(10000), delay.
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.*;
import android.os.AsyncTask;
public class MainActivity extends AppCompatActivity {
TextView statusDisplay,display;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
display=(TextView)findViewById(R.id.display);
display.setText("display");
statusDisplay=(TextView)findViewById(R.id.statusDisplay);
statusDisplay.setText("status");
//I need to make this call every 10 secs
new MyAsyncTask().execute("start");//Works fine as a single execution
}
//Our AsynTask
// Specify your own types <params,progress,result>
private class MyAsyncTask extends AsyncTask<String,Integer,Integer>
{
String status="Task being setup";
int counter=0;
//Step 1 that is executed for setting up our Asynchronous task
#Override
protected void onPreExecute()
{
super.onPreExecute();
display.setText(status);
statusDisplay.setText(String.valueOf(counter));
}
//Step 2 runs in the background and is only executed once
//So put whatever computations including access to the Network inside this method
//Do not make any calls to the UI from inside this method as its running in the background
#Override
protected Integer doInBackground(String[] params)
{
try{
status=params[0];
for(int i = 0;i<10;i++){
counter++;
status = "Task Running" + " " + String.valueOf(counter) + " " + "of" + " " + "10";
publishProgress(counter);//Calls onProgressUpdate
Thread.sleep(1000);
}
}
catch(InterruptedException ex){
}
status = "Task completed";
return counter;
}
//Step 3 called when we make a call to publishProgress in doInBackground
#Override
protected void onProgressUpdate(Integer[] values)
{
super.onProgressUpdate(values);
display.setText(String.valueOf(values[0]));
statusDisplay.setText(status);
}
//Step 4 Called after completion of doInBackground. Its return value is passed on to this method
//Make final update changes to your UI at this step
#Override
protected void onPostExecute(Integer result)
{
super.onPostExecute(result);
display.setText(String.valueOf(result));
statusDisplay.setText(status);
}
}
}

You could use ScheduledExecutorService:
private ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
Runnable yourTaskRunner = new Runnable() {
public void run() { new MyAsyncTask().execute("start"); }
}
scheduler.scheduleAtFixedRate(yourTaskRunner, 0, 10, TimeUnits.SECONDS);
Which is one of the four ways described here.

This is what ive tried but not seeing the delay. It only reruns periodically
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.*;
import android.os.AsyncTask;
import android.os.Handler;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
public class MainActivity extends AppCompatActivity {
TextView statusDisplay,display;
int x=0;
Handler handler = new Handler();
int stopcondition=0;
ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
display=(TextView)findViewById(R.id.display);
display.setText("display");
statusDisplay=(TextView)findViewById(R.id.statusDisplay);
statusDisplay.setText("status");
//new MonitorSecurityStatus().execute("start");//This works fine
//handler.post(rerunCode);//A)Runs periodically and terminates when stop-condition occurs but we don't see the 5 sec delay
//handler.postDelayed(rerunCode,5000);//B) Executes rerunCode after 5 sec delay we don't need this
scheduler.scheduleWithFixedDelay(rerunCode,0,5000, TimeUnit.MILLISECONDS);//C) Behaves same as A)
}
private Runnable rerunCode = new Runnable() {
#Override
public void run()
{
//handler.postDelayed(this,5000);//A) We dont see the 5 secs delay behaves same as if this declaration was inside else-if
stopcondition++;
if(stopcondition==10){
handler.removeCallbacks(this);
}
else if(stopcondition<10)
{
new MonitorSecurityStatus().execute("start");
handler.postDelayed(this,5000);//A) We dont see the 5 secs delay
}
}
};

Related

.setText() being called but screen not updateing while in a while(true) loop

I've been running into this bug and I can't seem to figure out how to fix it as I'm fairly new to java and android development so I would really appreciate any help I could get with this!
The bug I'm running into is that when I'm using .setText() to update a TextView element periodically the text displayed on screen never actually changes.
I believe this is due to the while(true) loop in the startCrunching() method I'm using to run the main calculation process as before I start that method the screen updates fine with the test data I'm feeding it.
I also know that when the while loop starts the updateScreen() method is only being called from the while loop and not the repeating handler I have as the handler stops posting logs to the logcat when the method starts but then the while loop logs start being posted.
What I want to achieve is the while(true) loop running as quickly as possible while every so often (as a variable of time and not cycles of the while loop) updating the screen with information regarding the process in the while loop.
I know the while loop is running and the updateScreen() method is being called.
Full source below:
package com.example.android.collatzconjecturepathcruncher;
import android.os.Handler;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.EditText;
import android.widget.TextView;
import java.math.BigInteger;
import java.util.concurrent.TimeUnit;
public class MainActivity extends AppCompatActivity {
TextView longestPathDisplay;
TextView longestPathSeedDisplay;
TextView currentSeedDisplay;
EditText startingNumberDisplay;
BigInteger longestPathSeed= BigInteger.ONE;
int longestPath=0;
BigInteger currentSeed=BigInteger.ZERO;
int currentPath=0;
BigInteger workingSeed=BigInteger.ONE;
boolean run;
int temp =0;
private Handler mHandler;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
longestPathDisplay = findViewById(R.id.longest_path);
longestPathSeedDisplay = findViewById(R.id.longest_path_seed);
currentSeedDisplay = findViewById(R.id.current_seed_display);
startingNumberDisplay = findViewById(R.id.starting_number_display);
longestPathDisplay.setText(getString(R.string.longest_path_display,longestPath));
longestPathSeedDisplay.setText(getString(R.string.longest_path_seed_display,longestPathSeed));
currentSeedDisplay.setText(getString(R.string.current_seed_display,currentSeed));
mHandler = new Handler();
startRepeatingTask();
}
#Override
public void onDestroy(){
super.onDestroy();
stopRepeatingTask();
}
public void startCrunching(View view){
String value = startingNumberDisplay.getText().toString();
currentSeed = new BigInteger(value);
workingSeed=currentSeed;
run=true;
while(run){
if(workingSeed.compareTo(BigInteger.ONE)==0){
if(currentPath>longestPath){
longestPath=currentPath;
longestPathSeed=currentSeed;
}
currentSeed= currentSeed.add(BigInteger.ONE);
workingSeed=currentSeed;
Log.d("end", "startCrunching: Finished "+(currentSeed.subtract(BigInteger.ONE))+" at "+currentPath+". Starting "+currentSeed);
currentPath=0;
updateScreen();
}
if (workingSeed.mod(new BigInteger("2")).compareTo(BigInteger.ZERO)==0){
workingSeed=workingSeed.divide(new BigInteger("2"));
}else{
workingSeed=(workingSeed.multiply(new BigInteger("3"))).add(BigInteger.ONE);
}
currentPath++;
}
}
public void updateScreen() {
//longestPathDisplay.setText(getString(R.string.longest_path_display, longestPath));
//longestPathSeedDisplay.setText(getString(R.string.longest_path_seed_display, longestPathSeed));
//currentSeedDisplay.setText(getString(R.string.current_seed_display, currentSeed));
longestPathDisplay.setText(getString(R.string.longest_path_display, temp));
longestPathSeedDisplay.setText(getString(R.string.longest_path_seed_display, temp));
currentSeedDisplay.setText(getString(R.string.current_seed_display, temp));
Log.d("update","requested screen update. Temp currently: "+temp);
temp++;
}
Runnable mStatusChecker = new Runnable() {
#Override
public void run() {
try{
updateScreen();
Log.d("repeat","Tried Updating Screen");
}finally {
mHandler.postDelayed(mStatusChecker,5000);
}
}
};
void startRepeatingTask(){
mStatusChecker.run();
}
void stopRepeatingTask() {
mHandler.removeCallbacks(mStatusChecker);
}
}
Thanks in advance!
-Michael
Maybe I missed it, but I Don't see where you actual call your crunchnumber method.
startCrunching() this method is never called. I guess you need to change you execution sequence

I am trying to create a Stopwatch app and am having problems adding a lap button and continue button that work

As the title suggests I am trying to create a Stopwatch app and am having problems adding a lap button and continue button that work. I have added the buttons to the layout.xml file but am having trouble with the java code that gets them to function.
I need to display the "stopped/paused" time when the lap button is clicked, the internal clock needs to keep running however and no longer be displayed, or the stopped/paused time needs to be shown in a new display whichever is easier to accomplish. When the lap timer is clicked subsequently it should display the current time (internal clock)
I need the continue button to then resume the paused/stopped time.
Could somebody help me with the code, I'm relatively inexperienced in java, so any help would be appreciated
here's the code of my main java file:
package com.hfad.stopwatch;
import android.os.Bundle;
import android.os.Handler;
import android.app.Activity;
import android.os.SystemClock;
import android.view.View;
import android.widget.Button;
import android.widget.Chronometer;
import android.widget.TextView;
public class StopwatchActivity extends Activity implements View.OnClickListener {
Button Continue;
Button lapChrono;
Chronometer chrono;
long time =0;
//Number of seconds displayed on the stopwatch.
private int seconds = 0;
//Is the stopwatch running?
private boolean running;
private boolean wasRunning;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_stopwatch);
Continue=(Button)findViewById(R.id.Continue_button);
lapChrono=(Button)findViewById(R.id.lap_button);
lapChrono.setOnClickListener(this);
Continue.setOnClickListener(this);
chrono=(Chronometer)findViewById(R.id.chronometer);
if (savedInstanceState != null) {
seconds = savedInstanceState.getInt("seconds");
running = savedInstanceState.getBoolean("running");
wasRunning = savedInstanceState.getBoolean("wasRunning");
}
runTimer();
}
#Override
protected void onPause() {
super.onPause();
wasRunning = running;
running = false;
}
#Override
protected void onResume() {
super.onResume();
if (wasRunning) {
running = true;
}
}
public void onClick(View arg0) {
switch (arg0.getId()){
case R.id.Continue_button:
chrono.setBase(SystemClock.elapsedRealtime()+time);
chrono.setBase(time);
break;
case R.id.lap_button:
time = chrono.getBase()+SystemClock.elapsedRealtime();
break;
}
}
#Override
public void onSaveInstanceState(Bundle savedInstanceState) {
savedInstanceState.putInt("seconds", seconds);
savedInstanceState.putBoolean("running", running);
savedInstanceState.putBoolean("wasRunning", wasRunning);
}
//Start the stopwatch running when the Start button is clicked.
public void onClickStart(View view) {
running = true;
}
//Stop the stopwatch running when the Stop button is clicked.
public void onClickStop(View view) {
running = false;
}
//Reset the stopwatch when the Reset button is clicked.
public void onClickReset(View view) {
running = false;
seconds = 0;
}
//Sets the number of seconds on the timer.
private void runTimer() {
final TextView timeView = (TextView)findViewById(R.id.time_view);
final Handler handler = new Handler();
handler.post(new Runnable() {
#Override
public void run() {
int hours = seconds/3600;
int minutes = (seconds%3600)/60;
int secs = seconds%60;
String time = String.format("%d:%02d:%02d",
hours, minutes, secs);
timeView.setText(time);
if (running) {
seconds++;
}
handler.postDelayed(this, 1000);
}
});
}
}
I am just having problems getting things to run smoothly as I'm not too fluent in my Java, apologies, that is why help is needed. The logic isn't quite there. The continue button doesn't function properly nor does the lap, I'm needing it to function as described above.
chrono object is not initialized and used in onClick(). Hence NPE occurs.
Try to initialise it in onCreate().

How to delay spawned thread when a Runnable run on UI thread isn't an option?

I had issues with a previous question where I was unsure whether my code had a memory leak. A few answers were concerned with it being run on the UI thread and so blocking. It is true, it runs on the UI thread and doesn't spawn a new one..
So to solve it I use Thread instead of Handler to spawn a new thread outside of UI. The problem now is that I can't manage to delay it like I did with the one ran in the UI thread.
This is my previous question where my original UI thread code is: Is this Runnable safe from memory leak? and the following is the updated code which spawns a new thread:
package com.example.helloworld;
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.widget.TextView;
import android.util.Log;
import java.lang.ref.WeakReference;
public class HelloWorldActivity extends Activity
{
private static TextView txtview;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
txtview = (TextView) findViewById(R.id.mainview);
Thread t = new Thread(new WeakRunnable(txtview));
t.start();
}
private static final class WeakRunnable implements Runnable {
private final WeakReference<TextView> mtextview;
protected WeakRunnable(TextView textview){
mtextview = new WeakReference<TextView>(textview);
}
#Override
public void run() {
TextView textview = mtextview.get();
if (textview != null) {
try {
Thread.sleep(1500);
} catch (InterruptedException e) {
e.printStackTrace();
}
int test = 5*5;
txtview.setText("Hola Mundo"+test);
}
Log.d("com.example.helloworld", "" + Thread.currentThread().getName()); // Outputs "Thread-<num>" if not running on UI thread
}
}
}
It just sets the view text and appends the result of 5*5.
As soon as I start the app it quits itself and I don't get why. Something tells me I'm delaying it the wrong way or using runOnUiThread wrong. Even changing txtview.setText("Hola Mundo"+test); to runOnUiThread( txtview.setText("Hola Mundo"+test) ); doesn't compile giving error: 'void' type not allowed here.
In a nutshell: Computation (5*5 in this case) should be done on a separate thread to avoid blocking the main (UI) thread, and the text should be set on the UI taking the computated item from the separate thread. A simple example of your own would be fine too.
UPDATE
I have posted an answer to my own question implementing AsyncTask.
Use postDelayed method found in the Handler class and Views
change,
Thread t = new Thread(new WeakRunnable(txtview));
t.start();
to :
txtview.postDelayed(new WeakRunnable(txtview), 1500);
Then remove the following sleep clause in your runnable as it is no longer needed
try {
Thread.sleep(1500);
} catch (InterruptedException e) {
e.printStackTrace();
}
You can use condition until it is met instead of using thread.sleep();
Condition.wait(new Callable<Boolean>() {
#Override
public Boolean call() throws Exception {
return textview != null;
}
});
As #Axxiss said, this case is better suited to AsyncTask. I updated my code to use AsyncTask with a WeakReference to avoid memory leaks:
package com.example.helloworld;
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.AsyncTask;
import android.widget.TextView;
import android.util.Log;
import java.lang.ref.WeakReference;
public class HelloWorldActivity extends Activity
{
private static TextView txtview;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
txtview = (TextView) findViewById(R.id.mainview);
SimpleTask objSimpleTask=new SimpleTask();
objSimpleTask.execute();
}
private static class SimpleTask extends AsyncTask<Void,Void,String> {
private WeakReference<TextView> mtextview = new WeakReference<TextView>(txtview);
#Override
protected String doInBackground(Void... params) {
Log.d("com.example.helloworld", "" + Thread.currentThread().getName());
try{
Thread.sleep(1500);
} catch(InterruptedException ex) {
Thread.currentThread().interrupt();
}
return "Hola Mundo";
}
#Override
protected void onPostExecute(String result) {
TextView mtxtview = mtextview.get();
mtxtview.setText(result);
}
}
}
doInBackground executes the code in a separate thread, while you can later catch the result with onPostExecute and execute it in the main (UI) thread without any frills.

How to run a background application in countdowntimer using threading concept?

I want to make a background application in countdowntimer, that is if i am starting
the timer and comes out of that application, and going to another application then
coming back to that same countdowntimer application. i want that timer to be
running until i stop. I know about the methods involved in it, but i am not sure
about the threading concepts used in it.
//MyActivity.class
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
public class MyappActivity extends Activity
{
private static final String Tag = "Background_Timer";
private Button start;
private Button stop;
private TextView tv;
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
start = (Button) findViewById(R.id.button);
stop = (Button) findViewById(R.id.button1);
tv = (TextView) findViewById(R.id.text1);
this.runOnUiThread(new Runnable()
{
public void run()
{
tv.setText(MyAppService.seconds + " Seconds Left");
}
});
}
public void onClick(View src)
{
switch (src.getId())
{
case R.id.button:
Log.e(Tag, "onClick: starting service");
startService(new Intent(this, MyAppService.class));
break;
case R.id.button1:
Log.e(Tag, "onClick: stopping service");
stopService(new Intent(this, MyAppService.class));
break;
}
}
}
//MyService.class
import android.app.Service;
import android.content.Intent;
import android.os.CountDownTimer;
import android.os.IBinder;
import android.util.Log;
import android.widget.TextView;
public class MyAppService extends Service
{
private static final String TAG = "My Service";
private static boolean state;
private static TextView TextTimer;
public static String seconds;
MyThread mt = new MyThread();
#Override
public void onCreate()
{
CountDownTimer Myapp = new CountDownTimer(50000, 1000)
{
public void onTick(long millisUntilFinished)
{
TextTimer.setText("Seconds left: " + (millisUntilFinished)
/ 1000);
}
public void onFinish()
{
TextTimer.setText("Finished!");
}
};
}
public void onStart(Intent intent, int startid)
{
Log.d(TAG, "on-Start");
mt.start();
}
public void onDestroy()
{
Log.d(TAG, "on-Stop");
mt.stop();
}
public static class MyThread extends Thread
{
public void run()
{
try
{
while (state = true)
{
MyThread.sleep(500);
}
}
catch (InterruptedException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
};
}
}
#Override
public IBinder onBind(Intent intent)
{
// TODO Auto-generated method stub
return null;
}
}
Have a static Handler in Your Activity which receives your Message of Tick and Finish
In the Service have a Thread which start the CountDown So that your CountDown will be working at your Thread not in the Main Thread.
You can use TimerTask Class for such purpose. It is same as thread , but allows you to perform a task based on Time Interval. you can also perform repeatable task in its run method.
Please check simple example here.
First off: You shouldn't run the CountDownTimer in the applications UI thread, since that could cause ANRs (Application not responding) issues.
You can use the SheduledThreadPoolExecutor with your custom Runnable or use a Bound Service. To call back the actual activity (if it's running, you could use different methods like subscribing via the Observer Pattern or send around Intents using the LocalBroadcastManager and then update the UI in it's own thread.
You may also use TimerTask as Lucifer has pointed out, but make sure the Runnable calls runOnUiThread when updating views.

struggling with timer in android

All I am looking to do is run some function 5 seconds after the app starts. However i keep getting a "force close" after 5 sec. Is timerTask even the correct function to be using in a situation like this? How about if i want to press a button later in the program, and have an event occur 5 seconds after user presses the button?
package com.timertest;
import java.util.Timer;
import java.util.TimerTask;
import android.app.Activity;
import android.os.Bundle;
import android.widget.TextView;
public class timerTest extends Activity {
Timer timer = new Timer();
TextView test;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
test = (TextView)findViewById(R.id.test);
timer.schedule(task, 5000);
}
TimerTask task = new TimerTask() {
#Override
public void run() {
test.setText("task function run");
}
};
}
A TimerTask will run on a background thread but you're trying to change UI. You want to run your operation on the UI thread instead. Android traditionally uses messages posted to a Handler to do this. A Handler will not create a new thread, when used as shown below it will simply attach to the same message queue that your app uses to process other incoming UI events.
public class Test extends Activity {
private final Handler mHandler = new Handler();
private TextView mTest;
private Runnable mTask = new Runnable() {
public void run() {
mTest.setText("task function run");
}
};
/** Called when the activity is first created. */
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
mTest = (TextView) findViewById(R.id.test);
mHandler.postDelayed(mTask, 5000);
}
#Override
protected void onDestroy() {
super.onDestroy();
mHandler.removeCallbacks(mTask);
}
}
If you want to execute some code after 5 secs try the following...
new CountDownTimer(5000,5000)
{
#Override
public void onTick(long millisUntilFinished) {
}
#Override
public void onFinish() {
// DO YOUR OPERATION
}
}.start();

Categories

Resources