I am writing a program that calculates pi with a given amount of iterations. I want to be able to time how long this takes and how much power is being used. I have another version of this application that works perfectly but, with the same code, this version won't.
Most of the code is working fine but the powerRunnable code is not executing when it is called.
any thoughts?
public class MainActivity extends AppCompatActivity {
//GUI
TextView piResultTextView, timeResultTextView,
powerResultTextView, voltageTextView, averageCurrentTextView;
EditText piEditText;
Button calculateButton, stopButton;
TextView countView;
//GLOBAL VARIABLES
Results results;
Handler powerHandler = new Handler();
Runnable powerRunnable = new Runnable() {
#Override
public void run() {
Toast.makeText(getApplicationContext(), "here", Toast.LENGTH_SHORT).show();
long millis = System.currentTimeMillis() - results.initialTime;
timeResultTextView.setText(getString(R.string.display_time, millis));
double current = getCurrent();
results.totalCurrent += current;
results.count++;
double power = current * results.voltage;
results.powerConsumption += power;
countView.setText(String.valueOf(results.count));
powerHandler.postDelayed(this, 1);
}
};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
piEditText = findViewById(R.id.PiEditText);
calculateButton = findViewById(R.id.CalculateButton);
calculateButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
if (!empty()) {
results = new Results(getVoltage());
results.initialTime = System.currentTimeMillis();
powerHandler.postDelayed(powerRunnable, 0);
calculatePi(piEditText.getText().toString());
finalizeResults();
displayResults();
}
}
});
stopButton = findViewById(R.id.StopButton);
stopButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
piResultTextView.setText("");
timeResultTextView.setText("");
powerResultTextView.setText("");
voltageTextView.setText("");
averageCurrentTextView.setText("");
powerHandler.removeCallbacks(powerRunnable);
}
});
piResultTextView = findViewById(R.id.PiResultTextView);
timeResultTextView = findViewById(R.id.TimeResultTextView);
powerResultTextView = findViewById(R.id.PowerResultTextView);
voltageTextView = findViewById(R.id.VoltageTextView);
averageCurrentTextView = findViewById(R.id.AverageCurrentTextView);
countView = findViewById(R.id.CountView);
}
#Override
public void onPause() {
super.onPause();
powerHandler.removeCallbacks(powerRunnable);
}
public void finalizeResults() {
results.endTime = System.currentTimeMillis();
powerHandler.removeCallbacks(powerRunnable);
results.powerConsumption *= 1000;
}
public void displayResults() {
piResultTextView.setText(results.pi);
timeResultTextView.setText(getString(R.string.display_time, results.getTime()));
powerResultTextView.setText(getString(R.string.display_power, results.powerConsumption));
voltageTextView.setText(getString(R.string.display_voltage, results.getVoltage()));
averageCurrentTextView.setText(getString(R.string.display_current, results.getAverageCurrent()));
}
}
I try to use your part of code in my application:
Handler powerHandler = new Handler();
Runnable powerRunnable = new Runnable() {
#Override
public void run() {
Toast.makeText(getApplicationContext(), "here", Toast.LENGTH_SHORT).show();
powerHandler.postDelayed(this, 1);
}
};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login);
ButterKnife.bind(this);
powerHandler.postDelayed(powerRunnable, 0);
}
And its working.
Related
I have a problem with my countdown and I want to play an individual sound at the end. For this I have created a list. When the corresponding picture is clicked, the selection should be saved and played in this method:
private void loadMusic() {
if (timerStatus == TimerStatus.PAUSED)
new Runnable() {
#Override
public void run() {
playSound(R.raw.sound1);
}
public void playSound(int sound1) {
MediaPlayer mp = MediaPlayer.create(getBaseContext(), (R.raw.sound2));
mp.start();
}
}.run()
}
I tried to solve this with an array in the onCreate method, but this is "void" and therefore I don't get a return:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(layout.sound);
final int[] selection = new int[1];
imageButton1 = findViewById(id.iv_bowl1);
imageButton1.setOnClickListener(v -> {
selection[0] = 1;
Toast.makeText(Sound.this, "1-click", Toast.LENGTH_SHORT).show();
});
return selection[0];
}
Thanks for help.
The way that I have my current application set up is that when you press the button then the app displays a counter on the bottom that goes up to ten then stops and then it displays a counter on the top that goes from 10 to 0. However, what I need to do is make these counters happen at the same time. I tried using threads but I think that I must not have been doing it right. Any help would be appreciated.
edit: I want to run mytask and mytask1 at the same time, they currently run after each other
edit2: I was asked for the code for publish progress
protected final void publishProgress(Progress... values) {
if (!isCancelled()) {
getHandler().obtainMessage(MESSAGE_POST_PROGRESS,
new AsyncTaskResult<Progress>(this, values)).sendToTarget();
}
}
Code:
public class MainActivity extends AppCompatActivity {
Button btn;
TextView txt;
Integer count =1;
Integer count1 =10;
TextView txt1;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//p
//p
btn = (Button) findViewById(R.id.button);
btn.setText("Start");
txt = (TextView) findViewById(R.id.textView);
txt1 = (TextView) findViewById(R.id.textView2);
View.OnClickListener listener = new View.OnClickListener(){
public void onClick(View view){
count =1;
//p
//p
switch (view.getId()){
case R.id.button:
new MyTask().execute(10);
new MyTask1().execute(0);
break;
}
}
};
btn.setOnClickListener(listener);
}
class MyTask extends AsyncTask<Integer, Integer, String> {
#Override
protected String doInBackground(Integer... params) {
for (; count <= params[0]; count++) {
try {
Thread.sleep(1000);
publishProgress(count);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
return "Task Completed.";
}
#Override
protected void onPostExecute(String result) {
txt.setText(result);
btn.setText("Restart");
}
#Override
protected void onPreExecute() {
txt.setText("Task Starting...");
}
#Override
protected void onProgressUpdate(Integer... values) {
txt.setText("BackGround Task Running..."+ values[0]);
}
}
class MyTask1 extends AsyncTask<Integer, Integer, String> {
#Override
protected String doInBackground(Integer... params) {
for (; count1 >= params[0]; count1--) {
try {
Thread.sleep(1000);
publishProgress(count1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
return "Task Completed.";
}
#Override
protected void onPostExecute(String result) {
txt1.setText(result);
btn.setText("Restart");
}
#Override
protected void onPreExecute() {
txt1.setText("Task Starting...");
}
#Override
protected void onProgressUpdate(Integer... values) {
txt1.setText("Countdown "+ values[0]);
}
}
}
AsyncTasks are executed on a single thread according to documentation, so that might be the issue.
On the first activity I want to set the number with a number picker and I have this:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_timer_settings);
NumberPicker np = (NumberPicker)findViewById(R.id.numberPicker2);
np.setMinValue(1);
np.setMaxValue(999);
np.setWrapSelectorWheel(false);
np.setOnValueChangedListener(new NumberPicker.OnValueChangeListener() {
#Override
public void onValueChange(NumberPicker picker, int oldVal, int newVal) {
Intent timer2 = new Intent(timer_settings.this, timer_2.class);
Bundle timer2extras = new Bundle();
timer2extras.putString("timer2string", newVal + "");
timer2.putExtras(timer2extras);
}
});
final Button testbutton = (Button) findViewById(R.id.testbutton);
testbutton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent testintent = new Intent(timer_settings.this, timer_2.class);
startActivity(testintent);
}
});
}
And on the second activity I want to use the number as the start time for the countdown, and I have this:
public class timer_2 extends AppCompatActivity {
ImageButton imageButton3;
private TextView timer_2_up;
private TextView timer_2_down;
private CountDownTimer timer_2_up_countdowntimer;
private CountDownTimer timer_2_down_countdowntimer;
private boolean timer_2_up_running;
private boolean timer_2_down_running;
private Bundle timer2extras = getIntent().getExtras();
private String timer2string = timer2extras.getString("timer2string");
private long starttime = Integer.parseInt(timer2string);
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_timer_2);
timer_2_up = findViewById(R.id.timer_2_up);
timer_2_down = findViewById(R.id.timer_2_down);
imageButton3 = (ImageButton)findViewById(R.id.imageButton3);
imageButton3.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
imageButton3.animate().rotation(imageButton3.getRotation()+180).start();
imageButton3.setEnabled(false);
Timer buttonTimer = new Timer();
buttonTimer.schedule(new TimerTask() {
#Override
public void run() {
runOnUiThread(new Runnable() {
#Override
public void run() {
imageButton3.setEnabled(true);
}
});
}
}, 300);
if (timer_2_up_running){
pausetimer_2_up();
starttimer_2_down();
}else {
starttimer_2_up();
if (timer_2_down_running) {
pausetimer_2_down();
}
}
}
});
}
private void starttimer_2_up() {
timer_2_up_countdowntimer = new CountDownTimer(starttime, 1000) {
#Override
public void onTick(long millisUntilFinished) {
starttime = millisUntilFinished;
update_up_text();
}
#Override
public void onFinish() {
timer_2_up_running=false;
}
}.start();
timer_2_up_running = true;
}
private void starttimer_2_down() {
timer_2_down_countdowntimer = new CountDownTimer(starttime, 1000) {
#Override
public void onTick(long millisUntilFinished) {
starttime = millisUntilFinished;
update_down_text();
}
#Override
public void onFinish() {
timer_2_down_running=false;
}
}.start();
timer_2_down_running=true;
}
private void pausetimer_2_up () {
timer_2_up_countdowntimer.cancel();
timer_2_up_running=false;
}
private void pausetimer_2_down() {
timer_2_down_countdowntimer.cancel();
timer_2_down_running=false;
}
private void update_up_text() {
int minutes_up = (int) (starttime / 1000) / 60;
int seconds_up = (int) (starttime / 1000) % 60;
String time_2_up_left_formatted = String.format(Locale.getDefault(),"%02d:%02d", minutes_up, seconds_up);
timer_2_up.setText(time_2_up_left_formatted);
}
private void update_down_text() {
int minutes_down = (int) (starttime / 1000) / 60;
int seconds_down = (int) (starttime / 1000) % 60;
String time_2_down_left_formatted = String.format(Locale.getDefault(),"%02d:%02d", minutes_down, seconds_down);
timer_2_down.setText(time_2_down_left_formatted);
}
But it does not work showing null errors that I cant find a solution to.
I don't know if this is because of the long/int difference between the NumberPicker and the countdown timer or I forgot to add some line.
Please help me.
Because you are put bundle extra to a Intent, then start another Intent. You don't have to watch for NumberPicker's value changed event. Just getValue() whenever you want to start timer activity.
In your first activity, it should be
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_timer_settings);
NumberPicker np = (NumberPicker)findViewById(R.id.numberPicker2);
np.setMinValue(1);
np.setMaxValue(999);
np.setWrapSelectorWheel(false);
final Button testbutton = (Button) findViewById(R.id.testbutton);
testbutton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent testintent = new Intent(timer_settings.this, timer_2.class);
Bundle timer2extras = new Bundle();
timer2extras.putString("timer2string", np.getValue() + "");
timer2.putExtras(timer2extras);
startActivity(testintent);
}
});
}
In the timer activity, put the code that getIntent().getExtras() inside onCreate() when everything is ready.
private Bundle timer2extras;
private String timer2string;
private long starttime;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_timer_2);
// Find views
timer2extras = getIntent().getExtras();
timer2string = timer2extras.getString("timer2string");
starttime = Integer.parseInt(timer2string);
// ...
}
I'm a student trying to create an app for my miniproject for one of my modules and I'm trying to create an app that grabs data from a server every few seconds so it's updated. I tried using java timer and timerTask to run the code repeatedly but the program only run once and the get-button doesn't work as intended (suppose to grab data instantly) after implementing the timer. Android Emulator
public class MainActivity extends AppCompatActivity implements OnClickListener{
private Button speed;
private TextView result;
Timer timer;
TimerTask timerTask;
private TextView sSpeed;
final StringBuilder builder = new StringBuilder();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
result = (TextView) findViewById(R.id.result);
sSpeed = (TextView) findViewById(R.id.sSpeed);
speed = (Button) findViewById(R.id.get_button);
speed.setOnClickListener(new View.OnClickListener(){
#Override
public void onClick(View view) {
getWebsite();
}
});
View aboutButton = this.findViewById(R.id.about_button);
aboutButton.setOnClickListener(this);
View exitButton = this.findViewById(R.id.exit_button);
exitButton.setOnClickListener(this);
}
public void onClick(View v) {
switch (v.getId()){
case R.id.get_button:
getWebsite();
break;
case R.id.about_button:
Intent i = new Intent(this, About.class);
startActivity(i);
break;
case R.id.exit_button:
finish();
break;
}
}
private void getWebsite(){
new Thread(new Runnable() {
#Override
public void run() {
try{
Document doc = Jsoup.connect("http://10.0.2.2:8080/Start_Stop_buttons_UTF8.html").get();
// Elements element = doc.getElementsByTag("p");
Elements element = doc.select("p");
//String title = doc.title();
builder.append(title).append("\n");
for (Element tag : element){
builder.append("\n\n").append(tag.text());
}
}catch(IOException e){
//e.printStackTrace();
builder.append("Error : ").append(e.getMessage()).append("\n");
}
runOnUiThread(new Runnable() {
#Override
public void run() {
String a = builder.toString(); // parse data from html into new string
a = a.substring(a.indexOf(":")+1, a.indexOf("Control")).trim();//trim string content
String b = builder.toString();
b = b.substring(11,b.indexOf(":")+1).trim();
double speed = Double.parseDouble(a);//convert string into double
if (speed<1000)
Log.i("HTML text","too slow");
else if((speed> 1500))Log.i("HTML text","too fast!");
result.setText(a);
sSpeed.setText(b);
}
});
}
}).start();
}
protected void onResume() {
super.onResume();
startTimer();
}
public void startTimer(){
timer = new Timer();
timerTask = new TimerTask() {
#Override
public void run() {
getWebsite();
}
};
timer.schedule(timerTask,1500,3000);
}
public void stopTimer(){
if(timer != null){
timer.cancel();
timer.purge();
}
}
}
Am I implementing the timer correctly to run getwebsite() repeatedly and able to get an instant update when get-button is clicked like it should have? Or is there a better way to implement these features using different method?
You are never calling the startTimer method in your ClickListener. You make one call to getWebsite. Change your call to startTimer.
speed.setOnClickListener(new View.OnClickListener(){
#Override
public void onClick(View view) {
startTimer();
}
});
You also might want to check if the timer is already running before you start a new one. To do that assign a null value on your stopTimer method e.g.
public void stopTimer(){
if(timer != null){
timer.cancel();
timer.purge();
timer = null;
}
}
And your startTimer would look like this
public void startTimer(){
if(timer != null) return; // don't start multiple timers
timer = new Timer();
timerTask = new TimerTask() {
#Override
public void run() {
getWebsite();
}
};
timer.schedule(timerTask,1500,3000);
}
I am having a problem with the Timer in my quiz Game. Essentially it's a multiple choice game and the player is timed on each question. I have the timer starting when the application starts and the player sees the first question. My issue is that if the player answers the question correctly or Incorrectly the timers starts giving random values, even though I reset the timer to 30 seconds on the onclick method. How do I get the timer to start at 30 seconds and countdown normally.
public class MainActivity extends AppCompatActivity {
//Views
TextView questionTextView;
TextView mscoreTextView;
TextView mtimerTextView;
Button mchoice1;
Button mchoice2;
Button mchoice3;
Button mchoice4;
//Constructors
private questions Question = new questions();
private Answers cAnswers = new Answers();
private choices Choices = new choices();
//Variables
private int questionNumber = 0;
private int mScore = 0;
private String correctAnswer;
public void onClick(View view) {
Button answer1 = (Button) view;
if(answer1.getText() == correctAnswer) {
mScore = mScore + 1;
Toast.makeText(getApplicationContext(), "CORRECT!!", Toast.LENGTH_SHORT).show();
mtimerTextView.setText("30s");
runTimer();
} else {
Toast.makeText(getApplicationContext(), "WRONG!!", Toast.LENGTH_SHORT).show();
mtimerTextView.setText("30s");
runTimer();
}
updateScore(mScore);
updateUI();
}
private void updateScore(int points) {
mscoreTextView.setText("" + points + "/" + Question.getLength());
}
public void runTimer() {
new CountDownTimer(30100, 1000) {
#Override
public void onTick(long millisUntilFinished) {
String tick = String.valueOf(millisUntilFinished/1000 + "s");
mtimerTextView.setText(tick);
}
#Override
public void onFinish() {
Toast.makeText(getApplicationContext(), "TIME RAN OUT!!", Toast.LENGTH_LONG).show();
mtimerTextView.setText("0s");
updateUI();
}
}.start();
}
private void updateUI () {
if (questionNumber < Question.getLength()) {
questionTextView.setText(Question.getQuestion(questionNumber));
mchoice1.setText(Choices.getChoices(questionNumber, 1));
mchoice2.setText(Choices.getChoices(questionNumber, 2));
mchoice3.setText(Choices.getChoices(questionNumber, 3));
mchoice4.setText(Choices.getChoices(questionNumber, 4));
correctAnswer = cAnswers.getAnswer(questionNumber);
questionNumber ++;
} else {
Toast.makeText(getApplicationContext(), "This is the last question", Toast.LENGTH_LONG).show();
//Intent intent = new Intent(MainActivity.this, HighScoreActivity.class);
//intent.putExtra("Score", mScore);
//startActivity(intent);
}
runTimer();
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
questionTextView = (TextView) findViewById(R.id.questionTextView);
mchoice1 = (Button) findViewById(R.id.choice1);
mchoice2 = (Button) findViewById(R.id.choice2);
mchoice3 = (Button) findViewById(R.id.choice3);
mchoice4 = (Button) findViewById(R.id.choice4);
mtimerTextView = (TextView) findViewById(R.id.timerTextView);
mscoreTextView = (TextView) findViewById(R.id.scoreTextView);
updateScore(mScore);
updateUI();
}
}
The thing is, you never really cancel a timer you've launched. Along with this, for every time you need a timer - you create a new one, which is not essential. The following must solve your problem:
You need to store CountDownTimer in a class field:
private CountDownTimer timer;
Then you can create it once on the start of app:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
...
timer = createTimer();
...
}
CreateTimer function:
public void createTimer() {
timer = new CountDownTimer(30100, 1000) {
#Override
public void onTick(long millisUntilFinished) {
...
}
#Override
public void onFinish() {
...
}
}
}
So when you need to run timer you just call:
timer.start();
And when user gives an answer, you need to cancel timer first, then start it again:
public void onClick(View view) {
...
timer.cancel();
timer.start();
...
}
Also: you have some duplicated code in your OnClick() method. Regardless of user's answer correctness you need to run timer and set a value to mtimerTextView, so basically you want to do it outside of if-else construction.
You have to define a variable inside a CountDownTimer class.
public void runTimer() {
new CountDownTimer(30100, 1000) {
private int time = 30;
#Override
public void onTick(long millisUntilFinished) {
mtimerTextView.setText(time--+"s");
}
#Override
public void onFinish() {
Toast.makeText(getApplicationContext(), "TIME RAN OUT!!", Toast.LENGTH_LONG).show();
mtimerTextView.setText("0s");
updateUI();
}
}.start();
}
Cancelable Timer
If you want your Timer cancelable you have to define it as a global variable.
private CountDownTimer timer; // global variable
start the timer by calling the below runTimer() method.
public void runTimer() {
timer = new CountDownTimer(30100, 1000) {
private int time = 30;
#Override
public void onTick(long millisUntilFinished) {
mtimerTextView.setText(time--+"s");
}
#Override
public void onFinish() {
Toast.makeText(getApplicationContext(), "TIME RAN OUT!!", Toast.LENGTH_LONG).show();
mtimerTextView.setText("0s");
updateUI();
}
}.start();
}
You can cancel the timer by calling the below method.
public void stopTimer(){
if(timer != null){
timer.cancel();
}
}
Hope this will help