I'm using timer in my application and I'd like to stop it from another class. So I have an Activity and two classes: MainActivity,Timer,Pause.
MainActivity calls a method from Timer class to start the countdown. I have a button which calls a method from Pause class to stop the timer. It's seems like pretty easy but I always got NullPointerException error message.
MainActivity:
public TextView txt;
public TextView szamlalo;
Timer i;
Pause p;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
txt = (TextView)findViewById(R.id.hello);
szamlalo = (TextView)findViewById(R.id.szam);
Button b = (Button)findViewById(R.id.button);
p = new Pause(szamlalo,txt,this);
i = new Timer(szamlalo,this,txt);
i.startTimerbig();
b.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
p.stopminden();
}
});
}
Timer class:
public Timer bigtimer;
public TimerTask bigtimerTask;
public final Handler bighandler = new Handler();
int ido = 10;
TextView szamlalo;
TextView txt;
Context context;
Over over;
public Timer(TextView szamlalo,Context context,TextView txt){
this.szamlalo = szamlalo;
this.context = context;
this.txt = txt;
}
public void startTimerbig() {
bigtimer = new Timer();
biginitializeTimerTask();
bigtimer.schedule(bigtimerTask, 3000, 1000);
}
public void bigstoptimertask(){
bigtimer.cancel();
}
public void biginitializeTimerTask() {
bigtimerTask = new TimerTask() {
#Override
public void run() {
bighandler.post(new Runnable() {
#Override
public void run() {
ido--;
szamlalo.setText("" + ido + "s");
}
});
}
};
}
Pause class:
TextView szamlalo;
TextView txt;
Context context;
Timer i;
public Pause(TextView szamlalo,TextView txt,Context context){
this.szamlalo = szamlalo;
this.txt = txt;
this.context = context;
this.i = new Timer(szamlalo,context,txt);
}
public void stopminden(){
i.bigstoptimertask();
}
The error message also says that this line is the guilty one:
bigtimer.cancel();
If anyone has an idea how to do that please response!
public Pause(TextView szamlalo,TextView txt,Context context){
this.szamlalo = szamlalo;
this.txt = txt;
this.context = context;
this.i = new Timer(szamlalo,context,txt);//HERE!!
}
You create a new object of Timer in the last line, it's not the same object with field 'i' of class 'MainActivity' and it's field 'bigtimer' not inited because it's startTimerbig() never been called;
Related
first of all excuse me if my title doesn't describe my question very well but i couldn't find a better one .
there is a simple stopWatch app that has three button start,stop,reset and a textview to display time . app has just one activity like this:
public class StopwatchActivity extends AppCompatActivity {
private int mNumberOfSeconds = 0;
private boolean mRunning = false;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_stopwatch);
//if if uncomment this runner method and delete the runner inside onClickStart everything will work find
//runner()
}
public void onClickStart(View view){
mRunning = true;
runner();
}
public void onClickStop(View view){
mRunning = false;
}
public void onClickReset(View view){
mRunning = false;
mNumberOfSeconds = 0;
}
public void runner(){
final TextView timeView = (TextView) findViewById(R.id.time_view);
final Handler handler = new Handler();
handler.post(new Runnable() {
#Override
public void run() {
int hours = mNumberOfSeconds/3600;
int minutes = (mNumberOfSeconds%3600)/60;
int second = mNumberOfSeconds%60;
String time = String.format("%d:%02d:%02d" , hours , minutes , second );
timeView.setText(time);
if (mRunning){
mNumberOfSeconds++;
}
handler.postDelayed(this , 1000);
}
});
}
}
my problem is when i comment the runner() in onClickStart method and put it in the onCreate method everything is ok . but when i change the code like above the code is still running but after i press stop button and then press start again the second will increment by 4 or 5 very fast.
can anyone explain me what is the difference between this two modes?
declare your handler globally
public void runner(){
timeView = (TextView) findViewById(R.id.time_view);
handler = new Handler();
runnable = new Runnable() {
#Override
public void run() {
int hours = mNumberOfSeconds/3600;
int minutes = (mNumberOfSeconds%3600)/60;
int second = mNumberOfSeconds%60;
String time = String.format("%d:%02d:%02d" , hours , minutes , second );
timeView.setText(time);
if (mRunning){
mNumberOfSeconds++;
}
handler.postDelayed(this , 1000);
}
}
handler.post(runnable);
}
in button function
public void onClickStart(View view){
if(handler != null) {
//restart the handler to avoid duplicate runnable
handler.removeCallbacks(runnable);//or this handler.removeCallbacksAndMessages(null);
}
mRunning = true;
runner();
}
public void onClickStop(View view){
mRunning = false;
handler.removeCallbacks(runnable); // this will stop the handler from working
}
How to do sample counter in Activity? This is not working.
public class MainActivity extends AppCompatActivity implements Runnable {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
run();
}
#Override
public void run() {
while (true) {
updateTv();
try {
Thread.sleep(17);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public void updateTv() {
int counter = 100;
final TextView tv = (TextView) findViewById(R.id.tv);
tv.setText(String.valueOf(counter));
counter--;
}
}
In onCreate() you're starting an infinite loop inside of the UI thread, blocking it completely. Alternatively you could use a Handler for periodic updates. Maybe using a bigger delay and stop it sometime.
public class MainActivity extends AppCompatActivity implements Runnable {
private final Handler mHandler = new Handler();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
run();
}
#Override
public void run() {
updateTv();
mHandler.postDelayed(this, 17);
}
public void updateTv() {
int counter = 100;
final TextView tv = (TextView) findViewById(R.id.tv);
tv.setText(String.valueOf(counter));
counter--;
}
}
Anyway you should read What is the Android UiThread (UI thread) for sure.
Consider using Timer class which allows you to define a callback method that will be invoked at specified rate.
An example that fits your needs:
public class CounterActivity extends AppCompatActivity {
private TextView mCounterTextView;
private Timer mTimer;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_counter);
mCounterTextView = (TextView) findViewById(R.id.counterTextView);
mTimer = new Timer();
mTimer.scheduleAtFixedRate(
new CounterTask(100), 0, TimeUnit.SECONDS.toMillis(1));
}
protected class CounterTask extends TimerTask {
protected int mCounter;
CounterTask(int initial) {
mCounter = initial;
}
#Override
public void run() {
runOnUiThread(new Runnable() {
#Override
public void run() {
mCounterTextView.setText(String.valueOf(mCounter));
}
});
--mCounter;
}
}
}
One more thing that should be noticed. As Timer executes it's own thread - it prevents you from updating your UI from outside of the main thread. In that case
you have to register a Runnable using runOnUiThread method.
Also, calling findViewById in a loop is not the best idea.
I have a CountDownTimer that dismisses a dialog popup window. I would like for this timer to restart if the user touches the screen. Here is what I have so far,
public class dataCapture extends Fragment implements OnClickListener {
...
MotionEvent event;
View.OnTouchListener touchListener;
#Override
public void onCreate(Bundle savedDataEntryInstanceState) {
super.onCreate(savedDataEntryInstanceState);
setRetainInstance(true);
}
...
#Override
public View onCreateView
#Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.btnHelpFilexml:
openHelpDialog();
break;
...
}
private void openHelpDialog() {
Button btnCloseWindow;
final Dialog helpDialog;
TextView tvHelpDialogTitle, tvHelpDialogBody;
helpDialog = new Dialog(getActivity(), android.R.style.Theme_Translucent);
helpDialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
helpDialog.setCancelable(true);
helpDialog.setContentView(R.layout.help_dialog);
tvHelpDialogTitle = (TextView) helpDialog.findViewById(R.id.tvHelpDialogTitle);
tvHelpDialogTitle.setText("DataCapture Help");
tvHelpDialogBody = (TextView) helpDialog.findViewById(R.id.tvHelpDialogBody);
tvHelpDialogBody.setText("Start of help text\n" +
"This is help text\n" +
"\n" +
"Here we go...\n" +
...
"This is the end.");
btnCloseWindow = (Button) helpDialog.findViewById(R.id.btnCloseWindow);
btnCloseWindow.setText("Close");
btnCloseWindow.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
helpDialog.dismiss();
}
});
CountDownTimer countDownTimer = new CountDownTimer(30000, 1000) {
// new countDownTimer(30000, 1000) {//makes popup go away after 30 secs
#Override
public void onTick(long millisUntilFinished) {//Do something every second...
}
#Override
public void onFinish() {//action at end of specified time
helpDialog.dismiss();
}
}.start();
#Override
public boolean onTouchEvent(MotionEvent event) {
if (event.getAction()==MotionEvent.ACTION_DOWN) {
countDownTimer.cancel();
countDownTimer.start();
}
return super.onTouchEvent(event);
}
helpDialog.show();
}
}
Any suggestions regarding how best to implement this function would be highly appreciated. Copious TIA.
UPDATE Got it. Solution below. Thanks.
public class dataCapture extends Fragment implements OnClickListener {
...
private static final int COUNTDOWN_TIME_MS = 30000;
Handler handlerHelpDialogTimer;
Runnable runnableHelpDialogDismissCountdown;
Dialog helpDialog;
private Dialog getHelpDialog() {
Button btnCloseWindow;
final Dialog helpDialog;
TextView tvHelpDialogTitle, tvHelpDialogBody;
helpDialog = new Dialog(getActivity(), android.R.style.Theme_Translucent);
helpDialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
helpDialog.setCancelable(true);
helpDialog.setContentView(R.layout.help_dialog);
tvHelpDialogTitle = (TextView) helpDialog.findViewById(R.id.tvHelpDialogTitle);
tvHelpDialogTitle.setText("DataCapture Help");
tvHelpDialogBody.setText("Start of help text\n" +
"This is help text\n" +
"\n" +
"Wheee, here we go\n" +
...
"this is the end.");
btnCloseWindow = (Button) helpDialog.findViewById(R.id.btnCloseWindow);
btnCloseWindow.setText("Close");
btnCloseWindow.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
helpDialog.dismiss();
}
});
tvHelpDialogBody.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View tvHelpDialogBody, MotionEvent event) {
cancelCountdown();
startCountdown();
return false;
}
});
helpDialog.show();
return (helpDialog);
}
private void showHelpDialog() {
helpDialog = getHelpDialog();
helpDialog.show();
startCountdown();
}
synchronized private void startCountdown() {
handlerHelpDialogTimer.postDelayed(getCountdownTask(), COUNTDOWN_TIME_MS);
}
synchronized private void cancelCountdown() {
handlerHelpDialogTimer.removeCallbacks(runnableHelpDialogDismissCountdown);
runnableHelpDialogDismissCountdown = null;
}
private Runnable getCountdownTask() {
Runnable task = new Runnable() {
#Override
public void run() {
if (helpDialog != null) helpDialog.dismiss();
}
};
runnableHelpDialogDismissCountdown = task;
return task;
}
Ditch the countdown timer. Instead use a handler, for example:
public class AwesomeActivity extends Activity {
private static final int COUNTDOWN_TIME_MS = 300000;
Handler handler;
Runnable countDown;
Dialog helpDialog;
#Override public void onCreate(Bundle b) {
super.onCreate(b);
handler = new Handler();
}
/* call cancelCountdown() in onPause* */
private Dialog getHelpDialog() { return /* fill in the details */ }
private void showHelpDialog() {
helpDialog = getHelpDialog();
helpDialog.show();
startCountDown();
}
synchronized private void startCountDown() {
handler.postDelayed(getCountdownTask(), COUNTDOWN_TIME_MS);
}
synchronized private void cancelCountdown() {
handler.removeCallbacks(countdown);
countdown = null;
}
private Runnable getCountdownTask() {
Runnable task = new Runnable() {
#Override public void run() {
if (helpDialog != null) helpDialog.dismiss();
}
};
countDown = task;
return task;
}
}
Now in onTouch(MotionEvent e) you can cancel and start the countdown.
I'll leave it to you to figure out how to handle onPause and onResume :)
Furthermore, if you really wanted to, you could override a Dialog and put the Handler timer countdown logic inside that class, overriding show() to start the countdown and then add a method such as, restartTimer() you can call after a TOUCH_DOWN. If you do, you can then also override onSaveInstanceState and onRestoreInstanceState in the Dialog subclass, to cancel the callback, stash the time remaining, then pull out the time remaining and re-postdelay the countdown runnable with the remaining time.
I´m trying to create a fullscreen clock. I managed to set text for hours, minutes and seconds. Well, but when I start the app, it shows the time but the UI is not updating... I dont know how to do it, I read this tutorial but i dont understand it... any one can explain me how to consantly update the UI?
public class Clock1Activity extends Activity {
/** Called when the activity is first created. */
private Timer timer;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
final TextView txtHour = (TextView)findViewById(R.id.TxtHour);
final TextView txtMinutes = (TextView)findViewById(R.id.TxtMinute);
final TextView txtSeconds = (TextView)findViewById(R.id.TxtSeconds);
final TextView txtMilliseconds = (TextView)findViewById(R.id.TxtMilliseconds);
final Integer hora = new Integer(Calendar.HOUR_OF_DAY);
final Integer minutos = new Integer(Calendar.MINUTE);
final Integer segundos = new Integer(Calendar.SECOND);
final Long milisegundos = new Long (System.currentTimeMillis());
timer = new Timer("DigitalClock");
Calendar calendar = Calendar.getInstance();
// Get the Current Time
final Runnable updateTask = new Runnable() {
public void run() {
/** txtHour.setText(hora.toString());
txtMinutes.setText(minutos.toString());
txtSeconds.setText(segundos.toString()); */
txtMilliseconds.setText(milisegundos.toString());
Toast toast1 = Toast.makeText(getApplicationContext(), milisegundos.toString(), Toast.LENGTH_SHORT);
toast1.show();
}
};
timer.scheduleAtFixedRate(new TimerTask() {
#Override
public void run() {
runOnUiThread(updateTask);
}
}, 1, 1000);
}
}
Just tell me how to complete it to update UI,please...
You didn't mention which tutorial you're working on, so just in case, you'll probably want to use AsyncTask.
see this example for Create a Apps to Show Digital Time in Android .And in your case use
runOnUiThread for Upadting time on UI.as
CurrentActivity.this.runOnUiThread(new Runnable() {
public void run() {
//UPDATE TIME HERE
}
});
and your code look like:
public class Clock1Activity extends Activity {
/** Called when the activity is first created. */
private Timer timer;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
final TextView txtHour = (TextView)findViewById(R.id.TxtHour);
final TextView txtMinutes = (TextView)findViewById(R.id.TxtMinute);
final TextView txtSeconds = (TextView)findViewById(R.id.TxtSeconds);
final TextView txtMilliseconds = (TextView)findViewById(R.id.TxtMilliseconds);
timer = new Timer("DigitalClock");
Calendar calendar = Calendar.getInstance();
// Get the Current Time
final Runnable updateTask = new Runnable() {
public void run() {
final Integer hora = new Integer(Calendar.HOUR_OF_DAY);
final Integer minutos = new Integer(Calendar.MINUTE);
final Integer segundos = new Integer(Calendar.SECOND);
final Integer milisegundos = new Integer(Calendar.MILLISECOND);
txtHour.setText(hora.toString());
txtMinutes.setText(minutos.toString());
txtSeconds.setText(segundos.toString());
txtMilliseconds.setText(milisegundos.toString());
}
};
timer.scheduleAtFixedRate(new TimerTask() {
#Override
public void run() {
runOnUiThread(updateTask);
}
}, 1, 1000);
}
}
public class Talk extends Activity {
private ProgressDialog progDialog;
int typeBar;
TextView text1;
EditText edit;
Button respond;
private String name;
private String textAtView;
private String savedName;
public void onCreate (Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.dorothydialog);
text1 = (TextView)findViewById(R.id.dialog);
edit = (EditText)findViewById(R.id.repsond);
respond = (Button)findViewById(R.id.button01);
respond.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
text1.setText("Welcome! Enter your name!");
respond.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
name = edit.getText().toString();
text1.setText("Cool! your name is "+name);
}
});
}
});
}
}
Okay so i want to figure out how i would save the state of this activity. this is just a small snippet from my code to show you guys an example. So i want to save the state so when the activity is destroyed the user will come back where they left off.
Second thing, I would like to show a quick 5 second Progress dialog spinner between each button click.
For the second thing
This should work:
public class TestActivity extends Activity implements Runnable, OnClickListener {
private TextView tv;
private ProgressDialog pd;
private Button btn;
#Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
setContentView(R.layout.main);
tv = (TextView) this.findViewById(R.id.tv);
btn = (Button)findViewById(R.id.btn);
tv.setText("initial text");
btn.setOnClickListener(this);
}
public void onClick(View v) {
pd = ProgressDialog.show(TestActivity.this, "Please wait...", "Details here", true, false);
Thread thread = new Thread(TestActivity.this);
thread.start();
}
public void run() {
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
handler.sendEmptyMessage(0);
}
private Handler handler = new Handler() {
#Override
public void handleMessage(Message msg) {
pd.dismiss();
tv.setText("text after 5 sec passed");
}
};
}