I get an ArrayIndexOutOfBoundsException in my code - java

The output of the Android's logcat informs me that an ArrayIndexOutOfBoundsException is thown at some point in my program :
I have set up a boolean value for the button earlier, the button is for testing purposes.
This is the code in which believe the error is located :
int hour = new Date().getHours();
int min = new Date().getMinutes();
int secs = new Date().getSeconds();
String date = hour + ":" + min+ ":" + secs;
b.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
bSet = true;
}
});
while (date =="01:00:00" || bSet == true);
int randomNumber = rand.nextInt();
tv.setText(getResources().getString(ids[randomNumber]));

I think you have exception in last line.
Exactly here ids[randomNumber]
You should check random generated number, because it can be greater then ids.length.
Use rand.nextInt(ids.length); It will generate random number from 0 to ids.length.

For better practice change
while (date =="01:00:00" || bSet == true);
as
while (date.equals("01:00:00") || bSet)
And change int randomNumber = rand.nextInt(); as int randomNumber = rand.nextInt(ids.length);

Related

How can I increment the variable more than one time when sensor event changed?

As you can see that I am trying to increment the variable 'c' when the accelerometer z-axis value greater than 12. But I can do it at one time, it will change the value 0 to 1 after executing the program. But I want to collect how many times the z-axis value becomes more than 12.
#Override
public void onSensorChanged (SensorEvent event) {
textView.setText(event.values[0] + "");
textView1.setText(event.values[1] + "");
textView2.setText(event.values[2] + "");
String s = new String();
s = textView2.getText().toString().trim();
Float t = Float.parseFloat(s);
int c = 0;
if (t > 11) {
c++;
txt.setText(Integer.toString(c));
}
}
int counter = 0;
#Override
public void onSensorChanged (SensorEvent event) {
textView.setText(event.values[0] + "");
textView1.setText(event.values[1] + "");
textView2.setText(event.values[2] + "");
String s = new String();
s = textView2.getText().toString().trim();
Float t = Float.parseFloat(s);
int c = 0; // ???
if (t > 11) {
c++;
counter++;
txt.setText(Integer.toString(c));
System.out.println("I need to learn how to use global
variables.\n
also the thing has been greater than \"12\"
"+counter" times."
);
}
}
Also maybe using more meaningful variable names other than "textView#" would make it less of a pain for people to figure out what you're trying to do.
You can define the variable c as a field member like below:
public class MainActivity {
private int c = 0;
(...)
#Override
public void onSensorChanged (SensorEvent event) {
textView.setText(event.values[0] + "");
textView1.setText(event.values[1] + "");
textView2.setText(event.values[2] + "");
String s = new String();
s = textView2.getText().toString().trim();
Float t = Float.parseFloat(s);
if (t > 11) {
c++;
txt.setText(Integer.toString(c));
}
}
}

Display two number pickers on textview

I made a created two number pickers to fake as timepicker for the simple purpose of been able to rotate 0 - 30 repeatedly, which works.
But now I want to display these two number pickers to a textview.
So if the numberpickers shows what's in the image below:
enter image description here
then the timeoutput should display this:
enter image description here
Here's my code:
public void timepicker() {
mMinuteSpinner.setMinValue(0);
mMinuteSpinner.setMaxValue(3);
mMinuteSpinner.setDisplayedValues(new String[]{"00", "30", "00", "30"});
mMinuteSpinner.setOnValueChangedListener(this);
mHourSpinner.setMinValue(0);
mHourSpinner.setMaxValue(23);
String[] hours = new String[24];
for (int i = 0; i < 24; i++) {
hours[i] = String.format("%02d", i );
}
mHourSpinner.setDisplayedValues(hours);
}
#Override
public void onValueChange(NumberPicker picker, int oldVal, int newVal) {
boolean advanced = (newVal == 0 && oldVal == 3) || (newVal == 2 && oldVal == 1);
boolean regressed = (newVal == 3 && oldVal == 0) || (newVal == 1 && oldVal == 2);
if (advanced) {
mHourSpinner.setValue(mHourSpinner.getValue() + 1);
} else if (regressed) {
mHourSpinner.setValue(mHourSpinner.getValue() - 1);
}
I also tried variations of below:
timeoutput.setText("" + mHourSpinner.getValue() + "h" + mMinuteSpinner.getValue());
But it didn't work. Getvalue seems to get the position of the number instead of the actual number.
The change to display textview also seems to only happen when the user rotates the numbers on the right(minutes), when the change should also occur if they rotate the numbers on the left(hours)
This is because you did not set onValueChangeListener to mHourSpinner.
Try this instead:
public void timepicker() {
mMinuteSpinner.setMinValue(0);
mMinuteSpinner.setMaxValue(3);
mMinuteSpinner.setDisplayedValues(new String[]{"00", "30", "00", "30"});
mMinuteSpinner.setOnValueChangedListener(this);
mHourSpinner.setMinValue(0);
mHourSpinner.setMaxValue(23);
mHourSpinner.setOnValueChangedListener(this); // Add this line
String[] hours = new String[24];
for (int i = 0; i < 24; i++) {
hours[i] = String.format("%02d", i );
}
mHourSpinner.setDisplayedValues(hours);
}
And for your onValueChangeListener, instead of reading the oldVal and newVal of from any of the spinners, you get the value directly from the spinners like this:
#Override
public void onValueChange(NumberPicker picker, int oldVal, int newVal) {
//Remove the unnecessary lines and just update the value
timeoutput.setText(mHourSpinner.getDisplayedValue()[mHourSpinner.getValue()] + "h" + mMinuteSpinner.getDisplayedValue()[mMinuteSpinner.getValue()]);
}
Root cause
When you select the mHourSpinner, nothing happens because you forgot to call setOnValueChangedListener on it.
getValue() just return the value of the Picker not displayed value, you must use getDisplayedValues() to do that.
Solution: Change your code to
public void timepicker() {
mMinuteSpinner.setMinValue(0);
mMinuteSpinner.setMaxValue(3);
mMinuteSpinner.setDisplayedValues(new String[]{"00", "30", "00", "30"});
mMinuteSpinner.setOnValueChangedListener(this);
mHourSpinner.setMinValue(0);
mHourSpinner.setMaxValue(23);
String[] hours = new String[24];
for (int i = 0; i < 24; i++) {
hours[i] = String.format("%02d", i);
}
mHourSpinner.setDisplayedValues(hours);
mHourSpinner.setOnValueChangedListener(this);
displaySelectedHourAndMinute();
}
#Override
public void onValueChange(NumberPicker picker, int oldVal, int newVal) {
displaySelectedHourAndMinute();
}
private void displaySelectedHourAndMinute() {
String hour = mHourSpinner.getDisplayedValues()[mHourSpinner.getValue()];
String minute = mMinuteSpinner.getDisplayedValues()[mMinuteSpinner.getValue()];
timeoutput.setText(hour + "h" + minute);
}

Cannot use timestamp in Android Studio(Java), when the button is clicked, Simulator would shout down

long millis = System.currentTimeMillis();
ts.setText((int) millis);
Now trying to show timestamp when "buttonEqual" is clicked, but suddenly it does not work.
I tried to change long -> int and just put millis in side the setText(), but not appropriate.
buttonEqual.setOnClickListener(new View.OnClickListener() {
#RequiresApi(api = Build.VERSION_CODES.N)
#Override
public void onClick(View v) {
if (Addition || Subtract || Multiplication || Division || mRemainder) {
input2 = Float.parseFloat(edt1.getText() + "");
}
if (Addition) {
edt1.setText(input1 + "+" + input2);
Addition = false;
ans.setText(" = " + (input1 + input2) + "");
long millis = System.currentTimeMillis();
ts.setText((int) millis);
}
EditText.setText() expects either a resource id (as int value, specifying a text resource) or a string (with the text to display). Your timestamp is neither.
Assuming that you want to display the timestamp as value, you should write
ts.setText(Long.toString(millis));

Why are the integers being sent from one android app Activity to another causing my app to crash?

I've got a [DONE] button that's supposed to check 2 entries's results. One of them is an [EditText--inputType:number] and the other is a [TextView] that increments when a certain button is pressed.
What I'm trying to do is check whether the EditText has an integer or is null, and check the contents of the TextView. if they both are greater than Zero. I add them up and send the total to my main activity. Here's the code i have so far.
public void returnbtn(View view) {
// Initialize insert textView
EditText insertcountBtn = findViewById(R.id.insertPushup);
// Initialize counter textView
TextView givencountBtn = findViewById(R.id.showCount);
// get added int stuff from the insert textField
int insertcountInt =
Integer.parseInt(insertcountBtn.getText().toString());
// get string stuff from counter textView
String givencountString = givencountBtn.getText().toString();
// convert counter textView to int.
Integer givencountInt = Integer.parseInt(givencountString);
if (givencountInt <= 0 && insertcountInt <= 0){
Total = 0;
} else if (givencountInt > 0 && insertcountInt <= 0) {
Total = givencountInt;
} else if (givencountInt <= 0 && insertcountInt > 0) {
Total = insertcountInt;
} else if (givencountInt > 0 && insertcountInt > 0){
// Add Counter textView and Insert textView to an Int Total
Total = givencountInt + insertcountInt;
}
// Create an Intent to return to the mainActivity.
Intent beginPushup = new Intent(this, MainActivity.class);
// Pass the current number to the push-up Counter activity.
beginPushup.putExtra(TOTAL_DONE, Total);
// Start mainActivity.
startActivity(beginPushup);
}
The problem i'm having is with either textView or EditText i'm not sure. All i know is that if i fill them both and click done it adds them up and transfers the total to mainActivity as expected. If I add values to EditText and leave TextView with 0 it also does what it's meant to do. But if I increment TextView and leave EditText blank, it does not transfer my TextView integer and crashes app.
Could i be detecting the editText wrong, because i think that's the reason.
If so what's the right way?
----- First && Second Answer Edits -----
int insertcountInt;
String insertcountString =
String.valueOf(insertcountBtn.getText());
try {
insertcountInt =
Integer.parseInt(insertcountBtn.getText().toString());
if (insertcountInt <= 0 || insertcountString == " ") Total =
givencountInt;
if (insertcountInt > 0 ) Total = givencountInt +
insertcountInt;
} catch (NumberFormatException e) {
insertcountInt = 0;
}
Good news is no more crash, but unless I fill the EditText with something, I'm not receiving my Integer in mainActivity. This is getting interesting. * I think it's a play of the if statements which I've restructures, but no luck so far. *
----- Updated Working Code For Any Future Requests -----
public void filledChecker() {
// Initialize insert textView
EditText insertcountBtn =
findViewById(R.id.insertPushup);
// Initialize counter textView
TextView givencountBtn = findViewById(R.id.showCount);
int insertcountInt = 0;
int givencountInt = 0;
// get added int stuff from the insert textField
if (!TextUtils.isEmpty(insertcountBtn.getText()) &&
TextUtils.isDigitsOnly(insertcountBtn.getText())) {
insertcountInt =
Integer.parseInt(insertcountBtn.getText().toString());
}
// get string stuff from counter textView
String givencountString = givencountBtn.getText().toString();
if (!TextUtils.isEmpty(givencountString) &&
TextUtils.isDigitsOnly(givencountString)) {
givencountInt = Integer.parseInt(givencountString);
}
if (insertcountInt <= 0) {
Total = givencountInt;
}
if (insertcountInt > 0) {
Total = givencountInt + insertcountInt;
}
}
public void returnbtn(View view) {
// Create an Intent to return to the mainActivity.
Intent beginPushup = new Intent(this, MainActivity.class);
filledChecker();
Integer current_Id = getIntent().getIntExtra(GIVEN_ID, 0);
// Pass the current number to the push-up Counter activity.
if (current_Id == 1) beginPushup.putExtra(TOTAL_P_DONE,
Total);
if (current_Id == 2) beginPushup.putExtra(TOTAL_S_DONE,
Total);
if (current_Id == 3) beginPushup.putExtra(TOTAL_C_DONE,
Total);
if (current_Id == 4) beginPushup.putExtra(TOTAL_SQ_DONE,
Total);
beginPushup.putExtra(GIVEN_ID, current_Id);
// Start mainActivity.
startActivity(beginPushup);
}
I As you can see I ended up dividing the if-logic from the Intent to Transfer to main Activity. This way they're both simple. And using the Do Not Repeat Yourself i did the same thing to the rest of my other buttons as you can see with all the if's in [returnbtn] method. I also simplified the if statement aside from the ones i was helped with. I ended up needing 2 if statements to manage getting a total from the 2 entries. Thanks again for the help everyone. Ohh the try-except didn't seem necessary so i deprecated them. as the app gets more complex i'll add them if necessary.
As the other answer explained, the issue with your code is that when the EditText is blank then parsing "null" is causing exception. So you just have to insure that if content is null then just use 0(Zero) value. You can try this:
public void returnbtn(View view) {
// Initialize insert textView
EditText insertcountBtn = findViewById(R.id.insertPushup);
// Initialize counter textView
TextView givencountBtn = findViewById(R.id.showCount);
int insertcountInt = 0;
int givencountInt = 0;
// get added int stuff from the insert textField
if (!TextUtils.isEmpty(insertcountBtn.getText()) && TextUtils.isDigitsOnly(insertcountBtn.getText())) {
insertcountInt = Integer.parseInt(insertcountBtn.getText().toString());
}
// get string stuff from counter textView
String givencountString = givencountBtn.getText().toString();
if (!TextUtils.isEmpty(givencountString) && TextUtils.isDigitsOnly(givencountString)) {
givencountInt = Integer.parseInt(givencountString);
}
if (givencountInt <= 0 && insertcountInt <= 0){
Total = 0;
} else if (givencountInt > 0 && insertcountInt <= 0) {
Total = givencountInt;
} else if (givencountInt <= 0 && insertcountInt > 0) {
Total = insertcountInt;
} else if (givencountInt > 0 && insertcountInt > 0){
// Add Counter textView and Insert textView to an Int Total
Total = givencountInt + insertcountInt;
}
// Create an Intent to return to the mainActivity.
Intent beginPushup = new Intent(this, MainActivity.class);
// Pass the current number to the push-up Counter activity.
beginPushup.putExtra(TOTAL_DONE, Total);
// Start mainActivity.
startActivity(beginPushup);
}
TextUtils is a class provided in Android Framework.
This will check for if the content is not empty and also digits only. You can obviously omit the digit check if you are sure that only number will be the input of your edit text.
Because when your EditText is empty, it has no numerical value.
You can do
Integer.parseInt(insertcountBtn.getText().toString());
when the input is blank; there's no Integer value there, because there's nothing at all, so it's going to throw a NumberFormatException.
You can do the following to make sure it has a value (default will be 0 on failure):
int insertedcountInt;
try {
insertedCountInt = Integer.parseInt(insertcountBtn.getText().toString());
} catch (NumberFormatException e) {
insertedCountInt = 0;
}
The issue here is you are defining editText to check for only interger: you did not put the conditional statement for the cases like if String was entered, if editText is blank, it contains String. Hence, you may want to put something like;
String editTextString = String.valueOf(insertcountBtn.getText());
if (editTextString == "") {
//do something
}
Alternatively,
String editTextString = insertcountBtn.getText().toString();
if (editTextString == "") {
//do something
}

How can I make the loudness of the music playing oscillate with my timer?

I'm trying to make the second sound on this app. oscillate in volume based on a Sin curve as a function of time passing. How would you suggest I edit what I already have to make that work? Any help would be amazing!
I'm sorry If some of the code is bad, I stepped away from this for some time and I added some sections back in that I previously commented out. I wasn't sure if it was for a good reason or not, so I added it back in.
MediaPlayer beep;
MediaPlayer sound2;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); //call superclass onCreate
setContentView(R.layout.activity_main); //inflate the GUI
minutesChanged = (TextView) findViewById(R.id.minutesChanged);
secondsChanged = (TextView) findViewById(R.id.secondsChanged);
minutesTotal = (TextView) findViewById(R.id.totalMinutesEntered);
secondsTotal = (TextView) findViewById(R.id.totalSecondsEntered);
percentageFinishedAmount = (TextView) findViewById(R.id.percentageFinishedAmount);
errorMessage = (TextView) findViewById(R.id.errorMessage);
secondEditText =
(EditText) findViewById(R.id.secondEditText);
secondEditText.addTextChangedListener(secondEditTextWatcher);
minuteEditText =
(EditText) findViewById(R.id.minuteEditText);
minuteEditText.addTextChangedListener(minuteEditTextWatcher);
whichSound =
(EditText) findViewById(R.id.whichSound);
whichSound.addTextChangedListener(whichSoundTextWatcher);
seekBarSeconds =
(SeekBar) findViewById(R.id.seekBarSeconds);
seekBarSeconds.setOnSeekBarChangeListener(seekBarListener);
seekBarMinutes =
(SeekBar) findViewById(R.id.seekBarMinutes);
seekBarMinutes.setOnSeekBarChangeListener(seekBarListener);
percentSeekBar =
(SeekBar) findViewById(R.id.seekBarTotal);
beep = MediaPlayer.create(MainActivity.this, R.raw.beep);
sound2 = MediaPlayer.create(MainActivity.this, R.raw.sound);
}
private void calculate() {
totalmili = minutesT + secondsT;
new CountDownTimer(totalmili + 2000, interv) {
public void onTick(long millisUntilFinished) {
secondsEllapsed = (int) ((totalmili + 2000 - millisUntilFinished) / 1000);
minutesEllapsed = secondsEllapsed / 60;
secondsEllapsed = secondsEllapsed % 60;
totalTimeEllapsed = secondsEllapsed + (minutesEllapsed * 60);
Log.d("Lucas", "total time elapsed " + totalTimeEllapsed);
if (totalTimeEllapsed < 10) {
errorMessage.setText("Elapsed Time: " + minutesEllapsed + " : 0" + secondsEllapsed);
} else if (totalTimeEllapsed >= 10) {
errorMessage.setText("Elapsed Time: " + minutesEllapsed + " : " + secondsEllapsed);
}
//set seekBar minutes/seconds and changing minute/seconds textView
seekBarMinutes.setProgress(minutesEllapsed);
minutesChanged.setText(Integer.toString(minutesEllapsed));
seekBarSeconds.setProgress(secondsEllapsed);
secondsChanged.setText(Integer.toString(secondsEllapsed));
double t = sin((360/totalmili) *(totalTimeEllapsed*1000));
float left = (float) ((t+1.0)*0.9/2.0+0.1);
float right = (float) ((t+1.0)*0.9/2.0+0.1);
sound2.setVolume(left,right);
Log.d("Lucas", "value of left and red respectively " + left + ", " +right);
if(sound == 1){
musicPlaying = beep.isPlaying();
if(musicPlaying == true){
beep.pause();
beep.seekTo(0);
beep.start();
} else {
beep.start();
}
}else if (sound == 2){
if(start ==1) {
sound2.seekTo(19);
sound2.start();
start = 2;
float left = (float) ((sin(totalTimeEllapsed)+1.0)*0.9/2.0+0.1);
float right = (float) ((sin(totalTimeEllapsed)+1.0)*0.9/2.0+0.1);
sound2.setVolume(left, right);
Log.d("Lucas", "value of left and red respectively " + left + ", " +right);
musicPlaying = sound2.isPlaying();
}else if(start ==2){
if (totalTimeEllapsed == 11) {
sound2.pause();
sound2.seekTo(34);
sound2.start();
} else if (totalTimeEllapsed == 22) {
sound2.pause();
}
}
//calculate total percentage finished, set percentage text, set total percentage seekBar
int percentProgress = (int) Math.round(((double) totalTimeEllapsed) / ((double) (totalmili) / 1000) * 100);
percentageFinishedAmount.setText(percentProgress + "% ");
percentSeekBar.setProgress(percentProgress);
//change background and text color bassed on increasing progress
errorMessage.setBackgroundColor(Color.argb(255, (int) (percentProgress * 2.5), 0, 0));
errorMessage.setTextColor(Color.argb(255, (int) (255 - (percentProgress * 2.5)), 255, 255));
}
public void onFinish() {
//display on finish text
errorMessage.setText("Done!");
}
}.start();
}
//listener object for the EditText's text-changed events
private final TextWatcher minuteEditTextWatcher = new TextWatcher() {
#Override
public void onTextChanged(CharSequence s, int start,
int before, int count) {
// set hours Total and converts minutes to milliseconds
if (s.charAt(start + count - 1) == '\n') {
minuteEditText.getText().replace(start + count - 1, start + count, " ");
s = minuteEditText.getText();
Log.d("Lucas", "in enter key min, s = " + s);
try {
minutesT = Integer.parseInt(s.toString());
minutesTotal.setText(String.valueOf(minutesT) + " Minutes");
percentageFinishedAmount.setText(" ");
minutesT *= 60000;
} catch (NumberFormatException e) {
minutesTotal.setText("");
minutesT = 0;
}
}
}
#Override
public void afterTextChanged(Editable s) {
}
#Override
public void beforeTextChanged(
CharSequence s, int start, int count, int after) {
}
};
// listener object for the EditText's text-changed events
private final TextWatcher secondEditTextWatcher = new TextWatcher() {
#Override
public void onTextChanged(CharSequence s, int start,
int before, int count) {
// set minutes Total when text is changed, calls calculate, changes seconds to milliseconds
if (s.charAt(start + count - 1) == '\n') {
secondEditText.getText().replace(start + count - 1, start + count, " ");
s = secondEditText.getText();
Log.d("Lucas", "in enter key sec, s = " + s);
try {
secondsT = Integer.parseInt(s.toString());
secondsTotal.setText(String.valueOf(secondsT) + " Seconds");
secondsT *= 1000;
percentageFinishedAmount.setText(" ");
calculate();
} catch (NumberFormatException e) {
secondsTotal.setText("");
secondsT = 0;
}
}
}
#Override
public void afterTextChanged(Editable s) {
}
#Override
public void beforeTextChanged(
CharSequence s, int start, int count, int after) {
}
};
Yowza. I'm not really clear on what the requirements are here or what you are doing.
My approach would be radically different, and maybe missing the point of what you are attempting. It would have these elements:
1) Output via a SourceDataLine, as this gives you a handle to affect the volume of every frame.
2) Per frame, consult a pointer into a Sin LUT that has the same number of elements as needed to correspond to the desired rate. (But it could also be fine to just create an argument into a sine function that increments the correct amount each frame to get your desired rate. No need to get into a war about whether the function or the LUT performs better.)
3) Multiply the SDL frame by the Sin LUT value.
For example an LFO of 1 Hz would imply either an LUT of 44100 elements, or an argument that increments by 1/44100 per frame.
As for getting access to the individual sound frames, see the tutorial Using Files and Format Converters/Reading Sound Files and look for the point in the example with the comment "Here, do something useful with the audio data that's now in the audioBytes array". That useful thing would be to convert the bytes to PCM (there are other StackOverflow explain how), get your next sin function value and multiply, then convert back to bytes.
EDIT:
Looking into the MediaPlayer API, I'm not clear you will be able to efficiently do what you want with this class.
A player is not prepared to respond to commands quasi-immediately
until its status has transitioned to MediaPlayer.Status.READY, which
in effect generally occurs when media pre-roll completes.
Does this imply some sort of buffer-size that will limit the frequency at which you can make the volume updates? IDK. When we get into buffer-size issues that in effect enforce a maximum number of updates per second, one has to listen carefully to check that there are no clicks or zippering due to discontinuities when the volume jumps from one level to another. A lot also depends on the amount of overhead happening under the hood when you set the position for each volume change.
With a SourceDataLine output, you have clean access to each frame which pretty much eliminates the potential zippering problems. I should add disclaimer though that I haven't grappled with MediaPlayer and may be ignorant of capabilities that you can take advantage of. Regardless, SDL is low level, powerful and efficient.

Categories

Resources