Android - User input at specific point in method - java

I am programming a darts counter app and at the moment I am trying to get an user input (which field on the dart board they hit) by pressing on a specific button.
Each button press will return an int which will be used to update list values that are used by my adapter to then update the views.
The method that should happen in looks like this:
private void startRound(MatchActivityPlayerAdapter adapter) {
for (int playerIndex = 0; playerIndex < getMatchParticipants().size(); playerIndex++) {
for (int currentDart = 1; currentDart <= maximumDartsToThrow; currentDart++) {
// Here I want the activity to "wait" until the user presses a button
if (pointsButtonClicked) {
setDartValue(playerIndex, currentDart);
setDartsCombinedValues(playerIndex, currentDart);
setRemainingPointsValues(playerIndex, currentDart);
adapter.notifyDataSetChanged();
}
}
}
setCurrentRound(getCurrentRound() + 1);
}
Since I cant really stop the activity at the point mentioned above until user has made an input I'll propably have to include a while loop. But in order to do this I think I'll have to create a second thread and handle things differently. That actually overwhelmed me, even though I've been reading through this.
Can anyone please explain to me how I have to design my code in order to achieve what i want?
Edit: Actually pointsButtonClicked is a boolean.
I have over 20 buttons in the global OnClick method and whenever one of them is clicked pointsButtonClicked will be set to true.
Button button1 = findViewById(R.id.btn1);
button1.setOnClickListener(v -> {
outputInt = 1;
pointsButtonClicked = true;
});
Button button2 = findViewById(R.id.btn2);
button2.setOnClickListener(v -> {
outputInt = 2;
pointsButtonClicked = true;
});
// [...]

I think that there should be a better way to this without the while-wait loop.
First of all I suppose that you used an android.widget.Button to implement that pointsButtonClicked
Here's what I would do:
//Global in your activity
int playerIndex = 0;
int currentDart = 1;
Then
private void startRound(MatchActivityPlayerAdapter adapter)
{
pointsButtonClicked.setOnClickListener(new View.OnClickListener()
{
#Override
public void onClick(View v)
{
setDartValue(playerIndex, currentDart);
setDartsCombinedValues(playerIndex, currentDart);
setRemainingPointsValues(playerIndex, currentDart);
adapter.notifyDataSetChanged();
nextThrow();
}
});
}
And finally
//Also in your activity
private void nextThrow()
{
if (currentDart == maximumDartsToThrow)
{
currentDart = 1;
if (playerIndex == getMatchParticipants().size()-1)
{
playerIndex = 0;
setCurrentRound(getCurrentRound() + 1);
}
else
{
++playerIndex;
}
}
else
{
++currentDart;
}
}
It can be better
You can use private variables and access them with getter and setter
Explained
Using this approach you do not create a thread that waits for every single button pressed. You simply create a button that listen for every click event that it receives and then you apply the logic to cycle the players and the darts for every players.
I hope this could be helpful.
[EDIT]
In this case I would apply the same OnClickListener to every button you use.
First of all I would create an inner class that implements OnClickListener and allows you to manage outputInt variable.
//Also in Activity (it is an inner class)
public class MyOnClickListener implements View.OnClickListener
{
private int myOutputInt;
public MyOnClickListener (int outputInt)
{
this.myOutputInt = outputInt;
}
#Override
public void onClick(View v)
{
pointsButtonClicked = true;
outputInt = myOutputInt;
setDartValue(playerIndex, currentDart);
setDartsCombinedValues(playerIndex, currentDart);
setRemainingPointsValues(playerIndex, currentDart);
nextThrow();
}
}
And then you create 20 MyOnClickListener passing only the int you want to assign. For example:
button1.setOnClickListener(new MyOnClickListener(1));
button2.setOnClickListener(new MyOnClickListener(2));
button3.setOnClickListener(new MyOnClickListener(3));
etc etc...

Related

I get an error when clicking the buttons repeatedly. How can I fix it?

I have a question and answer application. I take the questions from the arraylist. but when moving on to the next question my application gets an error. There is an animation when moving to the next question in my application, and during this animation, the buttons of the previous question get an error when clicked again while moving. My guess is that when clicked again, he wants to check whether the previous question is true or false, but he cannot find the previous question because the code goes to the next question. but I couldn't find how to fix it. my mistake is attached below
logcat:
java.lang.NullPointerException: Attempt to invoke virtual method 'void android.widget.Button.setBackgroundTintList(android.content.res.ColorStateList)' on a null object reference
at com.haktansoft.tytayt.islamidevir.checkAns(islamidevir.java:427)
at com.haktansoft.tytayt.islamidevir.access$000(islamidevir.java:41)
at com.haktansoft.tytayt.islamidevir$1.onClick(islamidevir.java:264)
Here is the line of errors I get in Logcat
java:427 = correctOption.setBackgroundTintList(ColorStateList.valueOf(Color.parseColor("#14E39A")));
java:41 = public class islamidevir extends AppCompatActivity implements NavigationView.OnNavigationItemSelectedListener {
java:264 = checkAns((Button) v);
java code :
for (int i = 0; i < 4; i++) {
linearLayout1.getChildAt(i).setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
checkAns((Button) v);
}
});
}
Random randomizer = new Random();
sira = (randomizer.nextInt(list.size()));
txtnumberIndicator.setText(position + 1 + "/" + list.size());
playAnim(txtQuestions, 0, list.get(sira).getQuestions());
Next_btn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Next_btn.setEnabled(false);
Next_btn.setAlpha(0.7f);
enableOptions(true);
position++;
sira = (randomizer.nextInt(list.size()));
}
});
navigationDrawer();
}
private void checkAns(Button selectedOptions) {
enableOptions(false);
Next_btn.setEnabled(true);
Next_btn.setAlpha(1);
if (selectedOptions.getText().toString().equals(list.get(sira).getCorrectAnswer())) {
//correct Answer
score++;
final MediaPlayer mp = MediaPlayer.create(this, R.raw.ding);
selectedOptions.setBackgroundTintList(ColorStateList.valueOf(Color.parseColor("#14E39A")));
mp.start();
} else {
//wrong Answer
final MediaPlayer mp = MediaPlayer.create(this, R.raw.wrong_buzzer);
selectedOptions.setBackgroundTintList(ColorStateList.valueOf(Color.parseColor("#FF2B55")));
Button correctOption = linearLayout1.findViewWithTag(list.get(sira).getCorrectAnswer());
correctOption.setBackgroundTintList(ColorStateList.valueOf(Color.parseColor("#14E39A")));
mp.start();
}
}
The problem is that when you click multiple times you are moving to the next context, so the actual which is becoming the previous button doesn't exist anymore.
I think you can add a verification inside your method checkAns(p pParamater) something like this :
checkAns(P pParameter) {
if(pParameter.notNullOrEmpty() {
then ...
}
}
Or having a state : isMoving and check on this state.

Instanciate an object on button click and use incremented name for reference variable ? (android studio, java)

In order to learn java and android app building, I am creating an app that will store players’ scores (for a real card game for example). So the number of players is not fixed.
First, I have created a class “Player”, containing an id, a name and the score.
public class Player {
int idj;
String namej;
int scorej;
public Player(int idj, String namej, int scorej) {
this.idj = idj;
this.namej = namej;
this.scorej = scorej;
}
public int getIdj() {
return idj;
}
public void setIdj(int idj) {
this.idj = idj;
}
public String getNamej() {
return namej;
}
public void setNamej(String namej) {
this.namej = namej;
}
public int getScorej() {
return scorej;
}
public void setScorej(int scorej) {
this.scorej = scorej;
}
}
Then I would like to create a new player each time I click a button on the UI. Here is my button that call the “newPlayer” method on click:
Button bT1 = (Button) findViewById(R.id.bT1);
bT1.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
newPlayer();
}
});
Here is the “newPlayer” method called by each button click. But this method doesn’t work. This method has to instanciate a player object and increment the reference variable name according to the “nbrPlayer” variable.
This var is counting the number of players :
public int nbrPlayer = 1;
And this is the "newPlayer" method :
private void newPlayer(){
player(nbrPlayer) = new Player(nbrPlayer,"var1FromEditText"," var2FromEditText ");
nbrPlayer ++;
}
Thanks for your help. (I am eventually looking for a good tutorial for that but for now I did not find one).
Each time when a new player hits the button, you should create instance of a player by passing id, name and score. Like this
Player newPlayer = new Player(nbrPlayer,"playerName",0);
But in your code you are not storing nbrPlayer value, so you cannot retrieve the value when that instance is dead. So you should store it in any storage to retrieve it back. I used shared preference to store that value. Check my code
private void newPlayer(){
SharedPreferences prefs = this.getSharedPreferences(
"MY_DATA", Context.MODE_PRIVATE);
int nbrPlayer = prefs.getInt("idj", 0);
if(nbrPlayer==0){
nbrPlayer = 1;
}
Player newPlayer = new Player(nbrPlayer,"playerName",0);
nbrPlayer ++;
SharedPreferences.Editor editor = getSharedPreferences("MY_DATA", MODE_PRIVATE).edit();
editor.putInt("idj", nbrPlayer);
editor.apply();
Log.d(TAG,"Player:"+nbrPlayer);
}
in your activty where you have the button you must have a counter
your code will be like this:
int counter = 1;
Button bT1 = (Button) findViewById(R.id.bT1);
bT1.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
new Player(counter++,"var1FromEditText"," var2FromEditText ");
}
});
there is no reason to have a method newPlayer since you are not returing the player so it will die after creation.
your question is not clear where you are planning to show this players at all. so even in my solution the player is created in the button click but nothing happens with it...
you must add it to a list or set or show somewhere

How to take inputs in multiple textviews?

i am new to development. i am creating an android calculator app with advanced functionality.The thing is i am using text view for taking and displaying inputs/outputs. My question is, how can i take Multiple inputs in multiple Textviews.
For example i have 3 text views,when user will enter 1st input in first textview(by default) and when user press the specific button it moves automatically to next textview . In some cases i want to take 2 inputs and in some cases i want to take 3 ,
How can i achieve this
Note: I dont want to use edit text , coz all buttons of already available in my app.Using Edit text will make softkeyboard to appear, and then for hiding the softkeyboard, i need to use hiding code lines in every class
You can do something like following:
private TextView[] textViews;
private TextView tvCurrentEditing;
private Button btnNext;
private Button btnPrev;
private Button btnSetText;
private int index = 0;
#Override
protected void onCreate(Bundle savedInstanceState) {
textViews = new TextView[3];
//Initialize all your textviews like textViews[0] = findViewById(<textview-id1>);
//textViews[1] = findViewById(<textview-id2>);
//textViews[2] = findViewById(<textview-id3>);
tvCurrentEditing = textViews[index];// I am assuming this is your first
//initialzie btnSettext
btnSettext.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
tvCurrentEditing.setText("<what ever you want");
}
});
//initialize next buton
btnNext.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if(index < textViews.length) {
index++;
}
tvCurrentEditing = textViews[index];
}
});
//Initialize previous button
btnPrev.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if(index > 0) {
index--;
}
tvCurrentEditing = textViews[index];
}
});
}
The names of the views could be different. The point is always use tvCurrentEditing whenever you want to change data of TextView. And update tvCurrentEditing whenever needed.

Is there a way to pass a member function into a method by reference? [JAVA]

I'm trying to implement a counter in my app that increases every time the button is clicked. I then want to take the whatever the final value of the counter is and have it displayed in a dialog.
The problem is that when I call the variable, it returns the value that it initially had, not the one modified by the onClick method (This is weird to explain but I commented in my code to show what I mean).
final TextView points = (TextView) findViewById(R.id.points);
points.setText("Points = 0");
class ButtonClick implements View.OnClickListener {
int value = 0;
public void onClick(View v) {
value++;
changeLocation(theButton);
points.setText("Points = " + value); // This value increases
}
public int getValue() {
return value;
} // This returns 0.
}
final ButtonClick buttonClicked = new ButtonClick();
theButton.setOnClickListener(buttonClicked);
final int finalValue = buttonClicked.getValue(); // This still equals zero.
Code is executed synchronously line by line:
// define and instantiate button listener
1) final ButtonClick buttonClicked = new ButtonClick();
// attach listener to button
2) theButton.setOnClickListener(buttonClicked);
<------ here you still didn't executed onClick :)
// trying get value
3) final int finalValue = buttonClicked.getValue(); // This still equals zero.
When you hit line 3, you are getting value 0 because value is zero.
Try clicking (perform click -> do event or whatsoever ) then get value.
To see if it works, you need a second asynchronous method example:
new Thread(new Runnable() {
#Override
public void run() {
while(buttonClicked.getValue() ==0) {
// you didn't click
Thread.sleep(10000);
}
};
}).start();
There are couple of issues that I can see,
1) onClick is not the overridden method, so try #Override annotation like this:
#Override
public void onClick(View v) { ... }
2) When a variable has to be used across, try to declare it in class level with getters and setters also at class level.
Hope these tips will help.

Automated button clicking happens simultaneously

I've tried a hundred different methods to implement a delay between automated button clicks, including thread.sleep, Handler.postDelayed, and so on… It could be I have used it incorrectly somehow. My most recent attempt was with a simple boolean toggle. It seems that no matter how I try, all the buttons that are to be automatically clicked happen at the same time after the delay, INSTEAD of being delayed between clicks.
my code as it stands now:
setting up button onClickListener:
for (int i = 0; i < mDifficulty; i++) {
ButtonsOCLArray[i].setOnClickListener(new OnClickListener() {
public void onClick(final View v) {
animating = true;
while (animating) {
animateButtons(v);
}
}
});
}
animation of buttons:
public static void animateButtons(View v) {
AlphaAnimation fadeInAnimation = new AlphaAnimation(0F, 1F);
fadeInAnimation.setDuration(1500);
fadeInAnimation.setFillAfter(true);
v.startAnimation(fadeInAnimation);
animating = false;
}
and finally, from a separate class, the automatic button setup:
public void pushAiButton(final View [] v){
mWhichButton = (mGameAi.getRandomNumber(MainActivity.mDifficulty)); // get random number for random button to press
mListOfAiButtonsToPress.add(mWhichButton); // add random number to mLOABTP
mListOfAiButtonsTemp.addAll(mListOfAiButtonsToPress); // add all elements of mLOABTP to mLOABT
boolean empty = false;
while (!empty) {
if (empty) {
break;
}
tempArrayIndex = mListOfAiButtonsTemp.get(0); // tempArray given value in first slot of mLOABT
mListOfAiButtonsTemp.remove(mListOfAiButtonsTemp.get(0)); // first slot of MLOABT removed
if (mListOfAiButtonsTemp.isEmpty()) {
// looped through whole list, empty now
empty = true;
} // end if
v[tempArrayIndex].performClick(); // click button at index *button*[*index*]
} // end !empty while
} // end pushAiButton()
any ideas HIGHLY appreciated! thanks!
UPDATE
This got it working:
mButtonStart.setOnClickListener(new OnClickListener() {
#Override
public void onClick(final View v) {
Log.d(TAG, "START BUTTON CLICKED!");
if (firstRun) {
mGameAi.setupAiButtons();
firstRun = false;
}
v.setVisibility(View.INVISIBLE);
animateButtons(ButtonsOCLArray[mGameAi.getFirstButtonInList()]);
mGameAi.deleteFirstButtonInList();
v.postDelayed(new Runnable() {
public void run() {
if (!mGameAi.buttonsListIsEmpty()) {
v.performClick();
}
else {
v.setVisibility(View.VISIBLE);
firstRun = true;
}
}
}, 500);
System.out.println("end of mButtonStart's onclicklistener");
}
});
You have coded it so that they all click nearly simultaneously. The automatic button setup does a "while" loop that iterates through all the buttons - removing them one at a time nearly simultaneously.
In other words, your while loop iterating through the buttons needs to pause (or not queue another click) until the animation is complete.
Here is the problem said another way; when each "onClick" occurs, the boolean "animateButtons" is true and they all enter into the animateButtons method.
You need to have a thread with a wait call on in pushAiButton and wait for each button to finish its animation.

Categories