How to call a method when Countdown OnFinish from another activity? - java

I have a class that has a CountDownTimer, which will be use throughout my project and I want to call different methods upon the Countdown onFinish() from different activities.
Here's my CountDownTimer class;
public class CountDownTimer {
private static final long START_TIME_IN_MILLIS = 10000;
private long timeLeftInMillis = START_TIME_IN_MILLIS;
private final TextView textViewCountDown;
private CountDownTimer countDownTimer;
private boolean timerRunning;
public CountDownTimer(TextView textView) {
this.textViewCountDown = textView;
startTimer();
}
public void startTimer() {
countDownTimer = new android.os.CountDownTimer(timeLeftInMillis, 1000) {
#Override
public void onTick(long millisUntilFinished) {
timeLeftInMillis = millisUntilFinished;
updateCountDownText();
}
#Override
public void onFinish() {
timerRunning = false;
}
}.start();
timerRunning = true;
}
public void resetTimer() {
timeLeftInMillis = START_TIME_IN_MILLIS;
updateCountDownText();
}
public void pauseTimer() {
countDownTimer.cancel();
timerRunning = false;
}
}
Example Scenario - Once a specific activity prompted, countdown will start and user has 10s to do whatever he wants otherwise it will automatically collect data and validate. So, once the 10s is over validating and data collecting methods should call from the activity.
I am a newbie to Android Dev and Thanks in advance!

There is multiple ways to achive this, each of them with different preferences. For your usecase i guess you could look into Broadcasts. Have all Activities that need to perform an action after the countdown implement a BroadcastReceiver which reacts to the Broadcast sent by your CountDownTimer.
Another option would be to implement some way of eventhandling. Android doesn't provide a event API, but you could look into the EventBus lib. Alternatively you could also just write your own event framework. For a simple case like yours it shouldn't be to complex.

In cases where I have to call methods/functions from other places in the application I make use of interfaces.
For example:
Here is an activity:
public class SomeActivity extends AppCompatActivity implements RemoteRunner.RemoteRunnerCallback{
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_about_us);
RemoteRunner remoteRunnerObject = new RemoteRunner(this);
remoteRunnerObject.runExternalMethod(); // <--- This part calls the showMessage() function
}
private void showMessage(String message){
Toast.makeText(this, message,Toast.LENGTH_LONG).show();
}
#Override
public void onRemoteCalled(String message)
}
I want to run a method in SomeActivity from this class:
public class RemoteRunner{
public interface RemoteRunnerCallback{
void onRemoteCalled(String message);
}
private RemoteRunnerCallback remoteRunnerListener;
public RemoteRunner(RemoteRunnerCallback remoteRunnerListener){
this.remoteRunnerListener = remoteRunnerListener;
}
public void runExternalMethod(){
remoteRunnerListener.onRemoteCalled("This message is from RemoteRunner");
}
}

Related

Updating TextView with timer onTick after leaving and returning to activity

I'm writing a workout app and am trying to implement a rest timer in the Train activity. CountDownTimer located within Train and is called when the user presses a start button.
public CountDownTimer createTimer(long timerDuration) {
Log.d("new timer duration:", "value: " + timerDuration);
return new CountDownTimer(timerDuration, 1000) {
#Override
public void onTick(long millisUntilFinished) {
int progress = (int) (millisUntilFinished / 1000);
secondsLeftOnTimer = progress; // update variable for rest of app to access
// Update the output text
breakTimerOutput.setText(secondsToString(progress));
}
#Override
public void onFinish() { // Play a beep on timer finish
breakTimerOutput.setText(secondsToString(timerDurationSeconds));
playAlertSound(); // TODO: Fix the delay before playing beep.
}
}.start();
}
The timer works, as long as the user stays in the Train activity. If you switch to another activity, the timer continues to run in the background (the beep still occurs), which is what I want. If you go back to the Train activity, however, the breakTimerOutput TextView is no longer updated by onTick.
How can I "reconnect" breakTimerOutput to onTick when the user re-enters the Train activity?
Here is the full code for the activity, just in case.
I would like to suggest to keep the timer inside a Service and use BroadcastReceiver to receive the tick to update the TextView in your TrainActivity.
You need to start the CountDownTimer from the Service. So in the onCreate method of your Service you need to initialize a LocalBroadcastManager.
broadcastManager = LocalBroadcastManager.getInstance(this);
So on each tick on your timer (i.e. onTick method), you might consider calling a function like this.
static final public String UPDATE_TIME = "UPDATE_TIME";
static final public String UPDATED_TIME = "UPDATED_TIME";
public void updateTextView(String time) {
Intent intent = new Intent(UPDATE_TIME);
if(time != null)
intent.putExtra(UPDATED_TIME, time);
broadcastManager.sendBroadcast(intent);
}
Now in your TrainActivity create a BroadcastReceiver.
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
super.setContentView(R.layout.copa);
receiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
String time = intent.getStringExtra(YourService.UPDATED_TIME);
// Update your TextView here.
}
};
}
And additionally you need to register and unregister the BroadcastReceiver.
#Override
protected void onStart() {
super.onStart();
LocalBroadcastManager.getInstance(this).registerReceiver((receiver),
new IntentFilter(YourService.UPDATE_TIME)
);
}
#Override
protected void onStop() {
LocalBroadcastManager.getInstance(this).unregisterReceiver(receiver);
super.onStop();
}

Get variable from dialog fragment to return to the activity which calls it

I'm using TimeDurationPicker for a dialog in an Android app I'm writing. I want the user to enter a duration for a timer, and have that duration passed back to the activity which calls it. I know there are already answered questions on SO regarding this issue, but I haven't been able to get anything to work.
Here's the activity:
public class train extends AppCompatActivity {
public Integer customTimerlength = null;
public Integer timerDurationSeconds = 180; // 3 minutes is a good default value
public boolean timerIsPaused;
public long millisLeftOnTimer;
Button startBreakTimerButton;
Button stopBreakTimerButton;
Button pauseBreakTimerButton;
TextView breakTimerOutput;
CountDownTimer countdowntimer;
private CountDownTimer mCountDownTimer;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_train);
startBreakTimerButton = (Button) findViewById(R.id.startBreakTimer);
stopBreakTimerButton = (Button) findViewById(R.id.stopBreakButton);
pauseBreakTimerButton = (Button) findViewById(R.id.pauseBreakButton);
breakTimerOutput = (TextView) findViewById(R.id.breakTimerOutput);
// Break timer long-click set time
breakTimerOutput.setOnLongClickListener(new OnLongClickListener() {
#Override
public boolean onLongClick(View v) {
//customTimerlength = timerLengthInputAlert();
new RestDurationPicker().show(getFragmentManager(), "Session break length");
and here is the fragment:
import android.widget.Toast;
import mobi.upod.timedurationpicker.TimeDurationPicker;
import mobi.upod.timedurationpicker.TimeDurationPickerDialogFragment;
public class RestDurationPicker extends TimeDurationPickerDialogFragment {
#Override
protected long getInitialDuration() {
return 0; // Default to empty
}
#Override
protected int setTimeUnits() {
return TimeDurationPicker.MM_SS;
}
#Override
public void onDurationSet(TimeDurationPicker view, long duration) {
Toast.makeText(getContext(), "New break duration set", Toast.LENGTH_LONG).show();
}
}
I've found quite a few answers here on SO mentioning intents and interfaces, but I haven't been able to get anything to work and I'm at a loss. This is my first attempt at an Android app so I'm not sure what else to do.
I really appreciate your help in advance!
Figured it out!
I added this to my activity:
// Break timer long-click set time
#Override
public void onDurationSet(long duration) {
Integer i = (int) (long) duration; // get integer i from duration (long)
customTimerlength = i / 1000; // convert millis to seconds
// Set the timer duration in seconds
timerDurationSeconds = customTimerlength;
// Assign the new custom timer duration to the timerduration variable
breakTimerOutput.setText(Integer.toString(timerDurationSeconds));
Log.d("NewTimer", "New Timer Duration: " + timerDurationSeconds);
}
public interface DurationListener {
void onDurationSet(long duration);
}
The fragment now passes the duration to the activity as desired.
In order for your Activity to receive the duration from your DialogFragment, you need to create an interface. Here is an example
public interface DurationListener {
void onDurationSet(long duration);
}
Your activity should then implement this interface. In other words, the activity will have to follow the terms of the interface contract by implementing the onDurationSet() method.
public class TrainActivity extends AppCompatActivity implements DurationListener {
//skipping most of your code
#Override
public void onDurationSet(long duration) {
//Do something with the duration
}
}
Now in your DialogFragment, you need to change your constructor to accept a DurationListener and you need to call onDurationSet() on the listener when the duration is changed by the user.
public class RestDurationPicker extends TimeDurationPickerDialogFragment {
private final DurationListener mListener;
public RestDurationPicker() {}
//The modified constructor, which accepts a listener as a parameter
public RestDurationPicker(DurationListener listener) {
mListener = listener;
}
//Most of your code goes here
#Override
public void onDurationSet(TimeDurationPicker view, long duration) {
//When the duration is set by the user, notify the listener
listener.onDurationSet(duration);
}
}
Now when you create the DialogFragment, just pass the Activity to the Fragment and you are done!
//This code is in your onCreate method in your activity
breakTimerOutput.setOnLongClickListener(new OnLongClickListener() {
#Override
public boolean onLongClick(View v) {
//customTimerlength = timerLengthInputAlert();
new RestDurationPicker(this).show(getFragmentManager(), "Session break length");
}
});
SIDENOTE: You should make sure your code follows the Java and Android coding guidelines, namely by using the correct naming conventions for classes and methods and by keeping class fields private or protected unless you have a reason to make them public. This link can help you with this: https://source.android.com/source/code-style.html

onTick method of Countdown timer keeps getting called even after calling cancel

I am trying to load some data. Id data is loaded in 20 seconds than i start new activity else i will finish by giving some relevant message. I have started a countdownTimer to keep track of time. Once data is loaded, I want to stop the timer. I have Following class :
public class SplashActivity extends AppCompatActivity {
private Context mContext;
private Boolean mDataLoadedFromServer = false;
private String mJSONData;
private SplashTimerForLoadingMasterDataForAllChannels mTimer;
private void stopTimer(){
mTimer.cancel();
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mContext = this;
setContentView(R.layout.activity_splash);
mTimer = new SplashTimerForLoadingMasterDataForAllChannels(20000,1000);
mTimer.start();
}
class SplashTimerForLoadingMasterDataForAllChannels extends CountDownTimer {
public SplashTimerForLoadingMasterDataForAllChannels(long millisInFuture, long countDownInterval) {
super(millisInFuture, countDownInterval);
Log.d("testTimer", "SplashTimerForLoadingMasterDataForAllChannels");
//SomE AsyncTAsk
LoadData loaddata = new LoadData();
loaddata.execute();
//SomE AsyncTAsk
}
#Override
public void onTick(long millisUntilFinished) {
Log.d("testTimer", "onTick millisUntilFinished = " + millisUntilFinished + " mDataLoadedFromServer = " + mDataLoadedFromServer);
//mDataLoadedFromServer is modified once Data is loaded in AsyncTask
if(mDataLoadedFromServer) {
stopTimer();
}
}
#Override
public void onFinish() {
Log.d("testTimer", "onFinish");
if(mDataLoadedFromServer) {
mDataSavedAndNextActivityLaunched = true;
if (Utils.checkIfUserLoggedIn()) {
mContext.startActivity(new Intent(mContext, ABCACtivity.class));
} else {
mContext.startActivity(new Intent(mContext, XYZActivity.class));
}
finish();
}
}
}
}
I cancel it in a local method call but onTick still keeps getting called. Can someone please help?
Basically counter does not simply stop if I cancle it from onTick() or from onFinish() ie FROM INSIDE TIMER.
However it stops very easily if I do it from any point outside of timer.
So the point at which my data is fully loaded...I called timer.cancle() and it did the trick.
However I still dont understand why it does not work if we do same from inside timer methods.
I tried this code snippet, since most answers are saying you cannot cancel the timer inside its implementation, thus i tried using a handler inside onFinish. Old post but if anyone comes across this its helpful.
new Handler().post(new Runnable() {
#Override
public void run() {
timerTextView.setText("00:" + String.format("%02d", counter));
cancel();
}
});
you need to call stopTimer() outside of the CountDownTimer's onTick(),
something like this
#Override
public void onFinish() {
Log.d("testTimer", "onFinish");
if(mDataLoadedFromServer) {
mDataSavedAndNextActivityLaunched = true;
if (Utils.checkIfUserLoggedIn()) {
mContext.startActivity(new Intent(mContext, ABCACtivity.class));
} else {
mContext.startActivity(new Intent(mContext, XYZActivity.class));
}
finish();
stopTimer();
}
}

Base Activity with runnable

Intro: I have made a Base Activity to extend my other activities to. I have overriden several methods with runnables in the function bodies, for example:
#Override
protected void onStop(){
new Handler().postDelayed(new Runnable()
{
#Override
public void run()
{
BaseActivity.super.onStop();
}
}, Fade.fadeDuration);
}
However, I get a SuperNotCalledException when I try to run the app. If I take the super.onStop() out of the runnable, I get no exception whatsoever.
Question: How do I call the super.onStop from a runnable in a base activity without causing a SuperNotCalledException?
Additional info: I am trying to add a fadeoutanimation which only fades out certain views. This takes about 700ms so I need to delay the onStop for 700ms as well. The problem is that this is a hassle to code in every activity. I want to make a base activity so I don't have to worry about the fading in every single activity.
If you are trying to simply delay execution of the super.onStop I would use a CountDownLatch.
Maybe something like this :
private void CountDownLatch latch;
private void long latchWait = 10L; // seconds
private void TimeUnit latchWaitUnit = SECONDS;
#Override
protected void onStop(){
try{
this.latch.await(this.latchWait, this.latchWaitUnit);
catch(InterruptedException e){
// Handle
}finally{
super.onStop();
}
}
public void startLatch(long wait){
this.latch = new CountDownLatch(1);
this.latchWait = wait;
}
public void releaseLatch(){
this.latch.countDown()
}
I did not test this code.

Re executing a code after a certain period of time in android

I am in a google map project and here is my code in oncreate:
mapView = (MapView)findViewById(R.id.mapView);
mapView.setBuiltInZoomControls(true);
mapView.setSatellite(false);
mapView.setStreetView(true);
mapController = mapView.getController();
mapController.setZoom(19);
getLastLocation();
drawCurrPositionOverlay();
drawMalls();
animateToCurrentLocation();
but now i want to call this DrawMalls(); method after some seconds and unless the user closes this application this method will be being called after that time? Is there any way to do this?
You can use Handler and Runnable combination to execute statements after a period of time.
You can delay a Runnable using postDelayed() method of Handler.
Runnable mRunnable;
Handler mHandler=new Handler();
mRunnable=new Runnable() {
#Override
public void run() {
// TODO Auto-generated method stub
drawMalls();
//If you want to re call this method at a gap of x seconds then you can schedule handler again
mHandler.postDelayed(mRunnable,2*1000);
}
};
mHandler.postDelayed(mRunnable,10*1000);//Execute after 10 Seconds
If you want to cancel this then you have to use removeCallback() method of Handler like mHandler.removeCallbacks(mRunnable);
Or You can use Timer. You can refer an example here http://thedevelopersinfo.wordpress.com/2009/10/18/scheduling-a-timer-task-to-run-repeatedly/
You can follow the instructions for using a ScheduledExecutorService here I've had bugs before where timer's wouldn't be stopped and started properly on 2.1, the scheduling scheme described worked perfectly for me though.
There are two ways
1) using Handler
2)Using Timer
//using Timer//
public void OnCreate(Bundle SaveInstanceState())
{
------------
-----------------
PreferedTime pTime=new preferedTime();
Timer t=new Timer(false);
t.Schedule(pTime,2000);
}
class PreferedTime extends TimerTask
{
public void run()
{
drawMalls();
}
}
//method 2//
public void OnCreate(Bundle SaveInstanceState())
{
-----------------
-----------------
Handler handler=new handler(new Runnable()
{
public void run()
{
drawMalls();
}
},2000);
You could use a java.util.Timer's schedule() method to arrange future execution of drawMalls():
Timer t = new Timer();
t.schedule(
new TimerTask()
{
public void run()
{
System.out.println("hello\n");
}
},
2000); // Milliseconds: 2 * 1000
I am unsure if drawMalls() is a static or non-static method. If it is static then it is straightforward to call in the TimerTask.run() method. Otherwise, you will need to arrange for the class instance to which drawMalls() belongs is available to the run() method of TimerTask:
class DrawMallsTask extends TimerTask
{
public DrawMallsTask(YourClass a_build) { _instance = a_instance; }
public void run() { _instance.DrawMalls(); }
private YourClass _instance;
};
Timer t = new Timer();
t.schedule(new DrawMallsTask(this), 2000);
EDIT:
To repeatedly run the task after every two seconds you can use:
t.scheduleAtFixedRate(new DrawMallsTask(this), 2000, 2000);
MyCount counter;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
counter= new MyCount(60000,1000);
counter.start();
}
public class MyCount extends CountDownTimer{
public MyCount(long millisInFuture, long countDownInterval) {
super(millisInFuture, countDownInterval);
}
#Override
public void onFinish() {
counter= new MyCount(60000,1000);
}
#Override
public void onTick(long millisUntilFinished) {
s1=millisUntilFinished/1000;
if(s1%2==0)
{
drawMalls();
}
}
}
this one calls drawMalls() for every 2 seconds..u can change it as required..
If re-executing code is not bound to state of application, but only to time period, look at Timer class
http://developer.android.com/reference/java/util/Timer.html
Timer timer;
function myCallerFunction(){
timer = new Timer();
timer.schedule(seconds * 1000); //must be in milliseconds
}
private class MyTask extends TimerTask {
public void run() {
drawMalls();
}
}

Categories