I have a Countdown timer and I want to return value when i call the class here is my class CountdownTimer
public class CountDownTimerActivity extends CountDownTimer {
public boolean finish = false;
public CountDownTimerActivity(long startTime, long interval) {
super(startTime, interval);
}
#Override
public void onFinish()
{
finishTime(true);
}
#Override
public void onTick(long millisUntilFinished) {
finishTime(false);
Log.e("TESTINg","" + millisUntilFinished/1000);
}
public boolean finishTime(boolean finish) {
return finish;
}
}
Here is my calling countdown timer
CountDownTimerActivity countdowntimer = new CountDownTimerActivity(5000,1000);
countdowntimer.start();
if(// I DONT KNOW WHAT WILL I PUT HERE)
{
Log.e("Testing", "OK na");
}
Anyone can help me? Thank you
I think what you are trying to accomplish is a callback when the timer expires? If so, you have to think about the timer running by itself and then calling another method when finished. For instance:
public class Main extends Activity
{
private MyCountDownTimer myCountDownTimer;
#Override
public void onCreate(Bundle savedInstanceState){
myCountDownTimer = new MyCountDownTimer(5000, 1000);
myCountDownTimer.start();
}
public void finished(){
Log.e("Testing", "OK na");
}
public class MyCountDownTimer extends CountDownTimer {
public MyCountDownTimer(long startTime, long interval) {
super(startTime, interval);
}
#Override
public void onFinish() {
finished();
}
#Override
public void onTick(long millisUntilFinished) {
Log.e("TESTINg","" + millisUntilFinished/1000);
}
}
}
See this link for more details/example:
https://androidcookbook.com/Recipe.seam;?recipeId=1205
EDIT to make a universal class that can be used in other activities, I would do something like this.
Create a MyCountDownTimer class that looks like this in its own file:
public class MyCountDownTimer extends CountDownTimer {
private MyCallback myCallback;
public MyCountDownTimer(long startTime, long interval) {
super(startTime, interval);
}
public Interface MyCallBack{
void callback();
}
#Override
public void onFinish() {
myCallback.callback();
}
#Override
public void onTick(long millisUntilFinished) {
Log.e("TESTINg","" + millisUntilFinished/1000);
}
public void setMyCallback(MyCallback myCallback){
this.myCallback = myCallback;
}
}
Then, in each of your activities, you would implement the new interface like so:
public class Main extends Activity implements MyCountDownTimer.MyCallback
{
private MyCountDownTimer myCountDownTimer;
#Override
public void callback(){
Log.e("Testing", "OK na");
}
#Override
public void onCreate(Bundle savedInstanceState){
myCountDownTimer = new MyCountDownTimer(5000, 1000);
myCountDownTimer.setMyCallback(this); //will use the callback method in this class which can be different for each activity
myCountDownTimer.start();
}
}
CountDownTimer is a very simple class, you don't need to make an entire class for it, you could create it on your caller class and in that way you could call the callback function on finish.
public class MyActivity extends Activity{
//Other methods and variables
CountDownTimer countdowntimer = new CountDownTimer(5000,1000){
#Override
public void onFinish() {
//Call the callback from your activity
}
#Override
public void onTick(long millisUntilFinished) {
Log.e("TESTINg","" + millisUntilFinished/1000);
}
};
}
If for some reason you must to make it in a different class then in that class you must create an interface that your activity must implement and in your finish method call the method of the interface listener.
Like in fragments: https://stackoverflow.com/a/34192088/2367237
I don't think you can return a value from CountDownTimer.
Ideally you should start the timer and implement what you have to do in the call back methods -
abstract void onFinish()
//Callback fired when the time is up.
abstract void onTick(long millisUntilFinished)
//Callback fired on regular interval.
sample implementation
https://androidcookbook.com/Recipe.seam;jsessionid=DF53064E03C7505C4EBF727E56E0728E?recipeId=1205
I think it's not working because you never set the variable finish to true on your code. You have to change your code in onFinish method to finish = true then put a logic inside onTick method to check if it's already finished then call onFinish() method;
Related
I have a ScrollView which englobes some TextView.
When I press on a textView there's a "MotionEvent.ACTION_UP/DOWN" method which make a textSize change, then after 2s the size text change again.
Handler handler5 = new Handler();
handler5.postDelayed(new Runnable() {
#Override
public void run() {
Presence.setTextSize(TypedValue.COMPLEX_UNIT_PX, 60);
}
}, 2000);
With the ScrollView, the text doesn't change again after 2 seconds, any ideas?
You can use CountDownTimer Class like this:
public class MyCountDownTimer extends CountDownTimer {
public MyCountDownTimer(long startTime, long interval) {
super(startTime, interval);
}
#Override
public void onFinish() {
Presence.setTextSize(TypedValue.COMPLEX_UNIT_PX, 30);
}
#Override
public void onTick(long millisUntilFinished) {
Presence.setTextSize(TypedValue.COMPLEX_UNIT_PX, 60);
}
}
Then call that class like this:
private CountDownTimer countDownTimer = new MyCountDownTimer(startTime, interval);
In my app I have a countdown which counts from five to one. At the moment, the counter starts as soon as the activity is started. What I want is to stay at 5 seconds and wait to count down until the screen is touched. So the countdown timer should be started which a touch event.
public class MainActivity extends Activity implements OnGestureListener {
private static final String FORMAT = "%02d:%02d";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_game);
new CountDownTimer(5000, 10) {
public void onTick(long millisUntilFinished) {
text.setText("" + String.format("%02d:%03d",
TimeUnit.MILLISECONDS.toSeconds(millisUntilFinished) - TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(millisUntilFinished)),
TimeUnit.MILLISECONDS.toMillis(millisUntilFinished) - TimeUnit.SECONDS.toMillis(TimeUnit.MILLISECONDS.toSeconds(millisUntilFinished))
));
if (animationRunning) {
cancel();
}
}
public void onFinish() {
text.setText("done!");
}
}.start();
}
#Override
public boolean onTouchEvent(MotionEvent touchevent) {
}
}
Place your count down timer inside onTouch like below
public class MainActivity extends Activity implements OnGestureListener {
private static final String FORMAT = "%02d:%02d";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_game);
}
#Override
public boolean onTouchEvent(MotionEvent touchevent) {
new CountDownTimer(5000, 10) {
public void onTick(long millisUntilFinished) {
text.setText("" + String.format("%02d:%03d",
TimeUnit.MILLISECONDS.toSeconds(millisUntilFinished) - TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(millisUntilFinished)),
TimeUnit.MILLISECONDS.toMillis(millisUntilFinished) - TimeUnit.SECONDS.toMillis(TimeUnit.MILLISECONDS.toSeconds(millisUntilFinished))
));
if (animationRunning) {
cancel();
}
}
public void onFinish() {
text.setText("done!");
}
}.start();
}
}
Move this section of code to your onTouchEvent, because it's on activity create that is why its starting when your activity starts
new CountDownTimer(5000, 10) {
public void onTick(long millisUntilFinished) {
text.setText("" + String.format("%02d:%03d",
TimeUnit.MILLISECONDS.toSeconds(millisUntilFinished) - TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(millisUntilFinished)),
TimeUnit.MILLISECONDS.toMillis(millisUntilFinished) - TimeUnit.SECONDS.toMillis(TimeUnit.MILLISECONDS.toSeconds(millisUntilFinished))
));
if (animationRunning) {
cancel();
}
}
public void onFinish() {
text.setText("done!");
}
}.start();
you should be fine
I am implementing an inactivity timer based on this answer: https://stackoverflow.com/a/12481918/6298161
I need the timer to work across multiple activities, so as the comments suggest from the original post I have change the Handler and Runnable to be static.
How do I now redirect to a new activity in the runnable where I have put the comment? Any help is greatly appreciated
public class InactivityTimerActivity extends AppCompatActivity {
public static final long DISCONNECT_TIMEOUT = 300000; // 5 min = 5 * 60 * 1000 ms
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_inactivity_timer);
}
private static Handler disconnectHandler = new Handler() {
public void handleMessage(Message msg) {
}
};
private static Runnable disconnectCallback = new Runnable() {
#Override
public void run() {
// I want to redirect here
}
};
public void resetDisconnectTimer() {
disconnectHandler.removeCallbacks(disconnectCallback);
disconnectHandler.postDelayed(disconnectCallback, DISCONNECT_TIMEOUT);
}
public void stopDisconnectTimer() {
disconnectHandler.removeCallbacks(disconnectCallback);
}
#Override
public void onUserInteraction() {
resetDisconnectTimer();
}
#Override
public void onResume() {
super.onResume();
resetDisconnectTimer();
}
#Override
public void onStop() {
super.onStop();
stopDisconnectTimer();
}
}
I think you shouldn't make it static. Just keep that protected, and then when start new activity, putting an integer variable inside the intent (the remaining time or the time that the timer has run). Then when on create new activity, you get that value out and set your timer base on that value.
in this below simple code i want to set unlimited interval for CountDownTimer. i can not find any document for this action.
public class MyCountDownTimer extends CountDownTimer {
public MyCountDownTimer(long startTime, long interval) {
super(startTime, interval);
}
#Override
public void onFinish() {
countDownTimer.cancel();
timerHasStarted = false;
}
#Override
public void onTick(long millisUntilFinished) {
Random rand = new Random();
int rnd = rand.nextInt(1000000000);
text.setText("" + rnd);
}
}
i want to stop that by click on button to finish.
In order to make the CountDownTimer infinite you can restart it onFinish method
like this
public void onFinish() {
if (!finishBtnPressed) {
countDownTimer.start();
} else {
//your logic
}
}
CountDownTimer has a method cancel() and you can call it when finish button is clicked (Note that cancel() call onFinish() so that's why i added the boolean variable finishBtnPressed). If you want to have some alternative then look into TimerTask
In my DataTrak activity I defined the following method:
public void updateTotal(IAmount totalAmount, int transactionType) {
switch (transactionType) {
case AccountTotals.VALUE_CANCELS:
txtView_cancels_value.setText("" + (Long.parseLong(txtView_cancels_value.getText().toString()) + totalAmount.getValue()));
break;
case AccountTotals.VALUE_PAYS:
txtView_pays_value.setText("" + (Long.parseLong(txtView_pays_value.getText().toString()) + totalAmount.getValue()));
break;
case AccountTotals.VALUE_SALES:
txtView_sales_value.setText("" + (Long.parseLong(txtView_sales_value.getText().toString()) + totalAmount.getValue()));
break;
default:
break;
}
btn_total.setBackgroundResource(R.drawable.button_green );
}
The method computes and updates some TextViews and changes the color of a button. Then I need to call this method from a Java abstract class. The method call appears in a method that runs on a non-UI thread. Here's how I call the method:
new Thread()
{
public void run()
{
new DataTrak().runOnUiThread(new Runnable()
{
public void run()
{
new DataTrak().updateTotal(totalAmount,transactionType);
}
});
}
}.start();
The problem is that I get a run time exception. Here's the LogCat output:
05-13 16:52:13.325: E/AndroidRuntime(22101): FATAL EXCEPTION: Thread-1577
05-13 16:52:13.325: E/AndroidRuntime(22101): Process: com.ilts.lct, PID: 22101
05-13 16:52:13.325: E/AndroidRuntime(22101): java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
05-13 16:52:13.325: E/AndroidRuntime(22101): at android.os.Handler.<init> (Handler.java:200)
05-13 16:52:13.325: E/AndroidRuntime(22101): at android.os.Handler.<init>(Handler.java:114)
05-13 16:52:13.325: E/AndroidRuntime(22101): at android.app.Activity.<init>(Activity.java:786)
05-13 16:52:13.325: E/AndroidRuntime(22101): at com.ilts.lct.ap.mainframe.DataTrak.<init>(DataTrak.java:37)
05-13 16:52:13.325: E/AndroidRuntime(22101): at com.ilts.lct.ap.customerfunctions.CustomerTransaction$2.run(CustomerTransaction.java:736)
In fact, initially I had just the line with the method call but I got the same run time exception. I searched for "Can't create handler inside thread that has not called Looper.prepare()" and I found several posts on this issue. One of them made me put the method call inside a new Thread, as shown above. But I still get the same run time exception. What should I change? Could you help me understand what's the problem actually and how to fix it? Thanks in advance.
After I read the answer by #Metero here's the code in the Java abstract class:
public abstract class CustomerTransaction extends Transaction {
...................................................
public interface CallBack {
public void updateTotal(IAmount a,int n);
}
private static CallBack callback;
public static void registerCallback(CallBack callback1){
callback = callback1;
}
/**
* Method to update the transaction state
*
* #param state The new transaction state
**/
public void setState(final int state) {
this.state = state;
/*
* Update the status
*/
if (state == TRANSACTION_COMPLETE) {
new Thread()
{
public void run() {
Looper.prepare();
new DataTrak().runOnUiThread(new Runnable()
{
public void run() {
Log.i("HERE", "HERE");
Looper.prepare();
callback.updateTotal(totalAmount,transactionType);
Looper.loop();
}
});
}
}.start();
}
}
....................
}
The very nature of this question suggests a MVC violation. Instead of your model calling methods in an Activity, it should call a method on some callback that the Activity has registered on the model. This callback should be queued in the UI thread.
You should never instantiate an Activity by yourself, if you do that, it won't be a normal activity, it will be just a problematic plan Java object.
So what you can maybe to to solve your problem is use the Observer pattern where you can define an interface with the 'callback' method and you let the Activity implement it and make it subscribe to the 'provider' of the notification. So basically, when this update Thread is running, you will run thru the list of subscribed listeners and dispatch the call, it will be just like a normal method call.
Just keep in mind to: 'subscribe' and 'unsubscribe' respecting the Activity lifecycles..like subscribe on onCreate() and unsubscribe on onDestroy().
Activity:
public class YourActivity extends Activity implements ControlListener {
public void onCreate(...) {
....
control.registerListener(this);
control.performOperation();
}
public void onDestroy(...) {
....
control.unregisterListener(this);
}
public void updateTotal(String newValue) {
runOnUiThread(new Runnable() {
public void run() {
textView.setText(newValue);
}
});
}
}
Control class:
public class Control {
private Set<ControlListener> listeners = new HashSet<ControlListener>();
public synchronized void registerListener(ControlListener listener) {
listeners.add(listener);
}
public synchronized void unRegisterListener(ControlListener listener) {
listeners.remove(listener);
}
public synchronized void notifyListeners(String newValue) {
for(ControlListener listener : listeners) {
listener.updateTotal(newValue);
}
}
public void performOperation() {
new Thread() {
public void run() {
String newValue= service.performBackgroundOperationToGetNewValue();
notifyListeners(newValue);
}
}.start();
}
}
Control listener:
public interface ControlListener {
public void updateTotal(String newValue);
}
Alternatively, you can use a very HANDY library to apply the Observer pattern on your project, it's the Otto: http://square.github.io/otto/ With the Otto, you wouldn't need to have the register/unregister/notifylisteners methods in your control, it would be placed somewhere else automatically.
This is not the best choice.
new Thread()
{
public void run()
{
new DataTrak().runOnUiThread(new Runnable()
{
public void run()
{
Looper.prepare();//This is not the best choice.
new DataTrak().updateTotal(totalAmount,transactionType);
}
});
}
}.start();
I recommend use AsyncTask, like this.
class SampleTask extends AsyncTask<Boolean, Boolean, Boolean> {
private int totalAmount;
private yourActivity activity;
//passing parameters
public void SampleTask(yourActivity activity){
this.activity = activity;
}
#Override
protected Boolean doInBackground(Boolean... params) {
while (totalAmount < 10){
totalAmount++;
}
}
#Override
protected void onPostExecute(Boolean result) {
super.onPostExecute(result);
// this is not the best choice
// because you are creating two instances.
new DataTrak().updateTotal(totalAmount,transactionType);
//If you pass a parameter, this for me is the best option.
activity.updateTotal(totalAmount,transactionType);
}
}
I agree #Alécio, please use a callback to do this. Add a callback interface in the non-activity class:
class yourclass{
public interface callBack{
public void updateTotal(...);
}
private callBack callback;
public void registerCallback(callBack callback){
this.callback = callback;
}
//somewhere call the updateTotal(...)
callback.updateTotal(...);
}
In the Activity
//the activity implement the callback and then register it, and call the callback when neccesary
class yourActivity extends Activity implement callBack{
#Override
onCreate(...){
...
yourclass.registerCallback(this);
}
#Override
public void updateTotal(...){
.......
}
}
The sample code for multiple class comunicating.
public class Controller {
callBack callBack;
public void registerCallBack(callBack back){
this.callBack = back;
}
public void show(){
callBack.update(1, "my name");
}
public interface callBack{
public void update(int type, String message);
}
public callBack getCallBack(){
return callBack;
}
}
public class AnotherClass {
Controller controller = new Controller();
public void registerCallBack(callBack back){
controller.registerCallBack(back);
}
public void show(){
controller.getCallBack().update(1, "show me!");
}
}
public class MyActivity extends Activity implements callBack {
AnotherClass myclass = new AnotherClass();
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.d("TAG", "This is message!");
setContentView(R.layout.main);
myclass.registerCallBack(this);
}
#Override
protected void onResume() {
super.onResume();
myclass.show();
}
#Override
public void update(int type, String message) {
((TextView) findViewById(R.id.display)).setText(message);
}
}