I thought I'd figured out this problem, by making a function showMessage, which can take a Runnable as an argument and run that piece of code if that particular button has been pressed.
Now I find the problem that I need to wait on several inputs before running the code. I essentially go through a bunch of questions which are added dynamically, so I don't know how many there'll be. When the users presses "Submit", it checks if any that are "soft" required and if there's no answer pops up with the message "There isn't an answer, would you like to continue anyway?".
The way I thought I could handle this is by counting the amount of questions which are like that, assigning them an Enumerator with a boolean variable to say if they're INPROGRESS or COMPLETE. I then had the Runnable to set that particular question's Progress state to COMPLETE and if they click "No", then to set the boolean variable to false.
Since the the dialogs are launched asynchronously, I can't just do an if statement, so I did a while any were still in progress. Buuuuuut! When I click submit now, it just freezes. I'm guessing because it's stuck at the while loop, whilst also not launching the dialogs asynchronously. I think it has to "complete" the code before launching them?
My code for reference to the points made above, this is all in the onClick of the submit button:
//Prep work
final ArrayList<Result> results = new ArrayList<Result>();
for (BaseQuestion q : questionViews)
{
if (q.requiredSoft)
{
results.add(Result.INPROGRESS);
}
}
final int[] i = {0};
//Validation checks
Boolean allOk = true;
for (BaseQuestion questionView : questionViews)
{
if (questionView.isRequiredHard())
{
if (questionView.getResponse().isEmpty())
{
Utils.showMessage("You have to fill in '" + questionView.getQuestionText() + "'", v.getContext());
allOk = false;
break;
}
}
else if (questionView.isRequiredSoft())
{
if (questionView.getResponse().isEmpty())
{
Runnable isOk = new Runnable()
{
#Override
public void run()
{
results.get(i[0]).value = 1;
results.get(i[0]).result = true;
i[0]++;
}
};
Runnable isNotOk = new Runnable() {
#Override
public void run() {
results.get(i[0]).value = 1;
i[0]++;
}
};
Utils.showMessage("You've not filled in '" + questionView.getQuestionText() + "'. Do you wish to continue?", v.getContext() , isOk, "Yes", isNotOk, "No");
}
}
else
{
}
}
if (allOk)
{
for (Result result : results)
{
while (result == Result.INPROGRESS)
{
}
if (!result.result)
{
allOk = false;
}
}
if (allOk)
{
submitQuestionnaire();
}
}
you can put all soft check into a runnable linkļ¼ and do the submit action at the last runnable. I not have a IDE now, see following logic
on submit button clicked{
allOk = true;
foreach(question in questions){
if(question require hard && question is empty){
allOk = false;
break;
}
}
if(allOk){
boolean needMoreConfirm = false;
for(int i = 0; i < questions.length; i++){
if(question require soft && question is empty){
Runnable isOk = new MyRunnable(i + 1, questions);/*begin check from next question*/
Utils.showMessage("your question",
new MyRunnable(i + 1)/* check next soft */,
null/*do nothing, wait another submit click*/);
needMoreConfirm = true;
break;
}
}
if(!needMoreConfirm){
do real submit here
}
}
}
class MyRunnable extends Runnable{
protected int mIdx;
Question[] mQuestions;
public MyOkRunnalbe(int idx, Question[] qs){mIdx = idx; mQuestions = qs;}
public void run(){
boolean needMoreConfirm = false;
for(int i = mIdx; i < questions.length; i++){
if(mQuestions[i] is empty && mQuestions[i] is soft){
Utils.showMessage("your question",
new MyRunnable(i + 1)/* begin to check from next soft */,
null/*do nothing, wait another submit click*/);
needMoreCOnfirm = true;
break;
}
}
if(!needMoreConfirm){
do real submit here
}
}
}
SOLVED
If I gave myself another half an hour to tinker, would've been fine! I whacked the checking code in a separate thread, this means it wasn't hanging.
But then I had the problem of the result not changing state. So instead of doing my for loop as a for each item loop, I did it as an index, as it wasn't changing the state when it kept checking.
As shown below:
new Thread(new Runnable() {
#Override
public void run() {
if (allOk[0])
{
for (int i=0; i<results.size(); i++)
{
while (results.get(i) == Result.INPROGRESS)
{
}
if (!results.get(i).result)
{
allOk[0] = false;
}
}
if (allOk[0])
{
submitQuestionnaire();
}
}
}
}).start();
Related
My ticTacToe Assigment picture
In onClickListener, I have line button00.setImageResource(R.drawable.x_sign);
but it will be executed only when listener is finished.
How can I force this command to execute immediately?
Condition in onClickListener for imageButton is:
if ((opField[x][y] == 0) && covekNext){ // field is empty and man have turn
button00.setImageResource(R.drawable.x_sign);
} else return;
When In this situation I play field 21 ( second row, first column).
button00.setImageResource(R.drawable.x_sign);
Images wouldnt be swaped! blank field stay blank, not X.
Bug or my coding error.
Thanks.
final ImageButton button00 = findViewById(R.id.imageButton00);
button00.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
x=0;
y=0;
if ((opField[x][y] == 0) && covekNext){
button00.setImageResource(R.drawable.x_sign);
} else return;
covekNext = false;
opField[x][y]= 1;
if(++opWinLines[0]==3|++opWinLines[3]==3|++opWinLines[6]==3){
covekWin(); //button00.setImageResource(R.drawable.x_sign); //command not executed
return;
}
if (++zauzeto<9) {
computerMove(); //button00.setImageResource(R.drawable.x_sign); //command not executed
} else {
nereseno(); //button00.setImageResource(R.drawable.x_sign); //command not executed
}
}
}); // button00.setImageResource(R.drawable.x_sign); executed
I think you are looking for something like this :
final ImageButton button00 = findViewById(R.id.imageButton00);
button00.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
x=0;
y=0;
if ((opField[x][y] == 0) && covekNext){
button00.setImageResource(R.drawable.x_sign);
} else return;
covekNext = false;
opField[x][y]= 1;
if(++opWinLines[0]==3|++opWinLines[3]==3|++opWinLines[6]==3){
button00.setImageResource(R.drawable.x_sign);
covekWin();
return;
}
if (++zauzeto<9) {
button00.setImageResource(R.drawable.x_sign);
computerMove();
} else {
button00.setImageResource(R.drawable.x_sign);
nereseno();
}
}
});
its because u use returnin your code
clicklisteners suppose to listen to clicks while user works with activity's ui
It works in most of cases but not always
You are only swapped the imageResource in first if condition. So when first else part is executed, image is not being swapped. If you want this line to execute every time, place it as first line in onClickListener as follows.
final ImageButton button00 = findViewById(R.id.imageButton00);
button00.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
x=0;
y=0;
//Set the imageResource here
button00.setImageResource(R.drawable.x_sign);
if ((opField[x][y] == 0) && covekNext){
} else return;
covekNext = false;
opField[x][y]= 1;
if(++opWinLines[0]==3|++opWinLines[3]==3|++opWinLines[6]==3){
covekWin();
return;
}
if (++zauzeto<9) {
computerMove();
} else {
nereseno();
}
}
});
Cheers :)
Everybody, thanks a lot!!!!
Everything about this question was my mistake made within some false call in methods: covekWin(); computerWin(); nereseno().
So this part of code is correct, and this question can be erased!
Thanks again!
I started learning Android Development. I was building a basic addition game, where user has to click on button which shows the addition of two number. There are four Textviews. First one give the time limit for each question to answer. Second gives the question for the user. Third one gives the current score of the user and the last one gives whether the chosen open is correct or incorrect.
Everything is working except the First Button. Every time when the button is pressed the the counting takes very fast.
// When First button is pressed
public void onClickButton1(View view) {
correctIncorrect.setVisibility(View.VISIBLE);
if (Integer.parseInt(button1.getText().toString())==sum) {
correctIncorrect.setText("Correct");
correctUpdater();
}
else {
correctIncorrect.setText("Incorrect");
inCorrectUpdater();
}
}
//Similar to all the buttons
//To Update the score
public void correctUpdater() {
n++;
yourScore++;
score.setText(Integer.toString(yourScore) + "/" + Integer.toString(n));
update();
}
public void inCorrectUpdater() {
n++;
score.setText(Integer.toString(yourScore) + "/" + Integer.toString(n));
update();
}
// To update the timer
//=======================================================================//
public void resetTimer() {
timer.setText(Integer.toString(temp)+"s");
if (temp == 0) {
inCorrectUpdater();
update();
}
else {
timeUpdater();
}
}
public void timeUpdater() {
Handler timeHandler = new Handler();
Runnable timeRunnable = new Runnable() {
#Override
public void run() {
temp--;
resetTimer();
}
};
timeHandler.postDelayed(timeRunnable,1000);
}
//=================================================================//
// Updater function
public void update() {
correctIncorrect.setVisibility(View.INVISIBLE);
Random random = new Random();
int a = random.nextInt(21);
int b = random.nextInt(21);
question.setText(Integer.toString(a) + " + " + Integer.toString(b));
Log.i("info", "onCreate: a = " + a);
Log.i("info", "onCreate: b = " + b);
sum = a+b;
Log.i("info", "onCreate: sum = " + sum);
int whichButton = random.nextInt(4);
Log.i("info", "onCreate: random button is " + whichButton);
values.clear();
for (int i = 0; i< 4; i++) {
if (i == whichButton) {
values.add(sum);
}
else {
values.add(random.nextInt(50));
}
Log.i("info", "onCreate: value[" + i + "] = " + values.get(i));
}
button1.setText(Integer.toString(values.get(0)));
button2.setText(Integer.toString(values.get(1)));
button3.setText(Integer.toString(values.get(2)));
button4.setText(Integer.toString(values.get(3)));
temp = 10;
resetTimer();
}
Am I using the Handler incorrectly? What can I do?
Am I using the Handler incorrectly? What can I do?
A better way to do this is CountDownTimer, by using this you won't have to deal with Handler youself and you also have a provision to cancel a running CountDownTimer.
Everything is working except the First Button
Not really sure what can cause different behaviours on click of buttons with the same code in onClick(). But you can consider using the same onClickListener for all the 4 buttons, in this way :
View.OnClickListener myListener = new View.OnClickListener() {
#Override
public void onClick(View button) {
correctIncorrect.setVisibility(View.VISIBLE);
if (Integer.parseInt(button.getText().toString())==sum) {
correctIncorrect.setText("Correct");
correctUpdater();
}
else {
correctIncorrect.setText("Incorrect");
inCorrectUpdater();
}
}
};
button1.setOnClickListener(myListener);
button2.setOnClickListener(myListener);
button3.setOnClickListener(myListener);
button4.setOnClickListener(myListener);
This will ensure that clicking any of the 4 buttons will have a same behavior (depending on the answer of course)
In case you get confused with the onTick() method on CountDownTimer, you can use modified CountDownTimer which will ensure that the timer doesn't miss any ticks.
I have a problem related click count. The problem is, I can't stop click when a number a click is given.
For example, I allow users to click a button 3 times, if clicks reached 3 times, then stop count, and do what I want.
This is my code I have used.
private int clickcount = 3;
#Override
public void onClick(View v) {
// Do button click handling here
if ( posisi2==getAdapterPosition() ) {
clickcount--;
tombolbaca.setText("Baca " + clickcount + "x");
// try to stop count but it can't, computer still counting
if (clickcount == 3)
{
mTitle.setVisibility(View.GONE);
rl2.setVisibility(View.GONE);
}
} // adapter
} // onClick
I think the trigger to do something might be when the click count is zero, not three:
if (clickcount == 0) {
mTitle.setVisibility(View.GONE);
rl2.setVisibility(View.GONE);
}
It isn't clear whether the above if statement belongs nested inside the outer if, or if it should be at the method level of onClick().
Note: We could have written if (clickCount <= 0), but there may not be a need to do this (nor may it be desirable), since after you have changed the visibility of those elements to GONE once, you don't need to do it again.
Make this Change,
private int clickcount = 3;
#Override
public void onClick(View v) {
// Do button click handling here
if ( posisi2==getAdapterPosition() ) {
clickcount--;
tombolbaca.setText("Baca " + clickcount + "x");
// try to stop count but it can't
if (clickcount <=0) <== make this change
{
mTitle.setVisibility(View.GONE);
rl2.setVisibility(View.GONE);
}
} // adapter
}
try this
private int clickcount = 3;
#Override
public void onClick(View v) {
// Do button click handling here
if ( posisi2==getAdapterPosition() ) {
clickcount--;
tombolbaca.setText("Baca " + clickcount + "x");
// try to stop count but it can't, computer still counting
if (clickcount == 0)
{
mTitle.setVisibility(View.GONE);
rl2.setVisibility(View.GONE);
}
} // adapter
} // onClick
private int clickcount = 0;
#Override
public void onClick(View v) {
// Do button click handling here
if ( clickcount<3 ) {
clickcount++;
tombolbaca.setText("Baca " + clickcount + "x");
}
//Count stops here..
else
{
mTitle.setVisibility(View.GONE);
rl2.setVisibility(View.GONE);
}
}
}
so i have a button that when i click on, it add a new object to my ArrayList.
private List<Object> addObject = new ArrayList<>();
when i click, it does this
Object object = new object;
object.setTitle("stuff");
object.isLast = false;
addObject.add(object);
This works as it should and then my ArrayList and attached to the adapter...Yada yada yada
At some point in my code, object is going to be true. How i prevent adding to the ArrayList since its the last one.
i tried running a loop
for (int i = 1; i < addObject.size(); i++ {
Object newboject = addObject.get(i);
if(newobject.getIsLast)){
//Then i kinda need to stop adding to the list on further clicks.
}
}
I think the problem may be with how my code is structed, any assistance is appreciated...
it would be better to see your whole code to show you the right places, but the flag-solution by Kevin could look like this:
private boolean isAtEnd = false;
if (object.getIsLast()) {
isAtEnd = true;
}
if (!isAtEnd) {
addobject.add(object);
}
public class TestRing extends Activity
{
boolean isLastObj = false;
Button add;
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.testring);
add = (Button) findViewById(R.id.btnAdd);
add.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view)
{
if(!isLastObj)
{
for (int i = 1; i < addObject.size(); i++ )
{
Object newboject = addObject.get(i);
newboject.setTitle("stuff");
newboject.isLast = false;
newboject.add(object);
if(newboject.getIsLast)
{
isLastObj = true; // this will prevent furtheradding of objects
}
}
}
}
});
}
}
You can create a fixed-size list from your list that already contains all the items (and the last one) and pass it to the adapter as:
List<Object> finalObjectList = Arrays.asList(addObject);
Please be advised that adding an element to this list will throw an java.lang.UnsupportedOperationException
Logic(Works with Ordered collections only): Check 'isLast' field of the last element in your list.
if(addObject.size() > 0 && !addObject.get(addObject.size()).getIsLast()){
Object object = new object;
object.setTitle("stuff");
object.isLast = false;
addObject.add(object);
}
Though the solution is bit clumsy, but it is a contained logic and won't depend on external flag.
SEE REVISION AT BOTTOM This is a fight card, so it has two people fighting one another, a red vs blue. It has to be a dynamic list that is populated information from parse.com. The first Query is fightOrder. This is a class on Parse.com that has two objectId's on a row. The redCorner and blueCorner find this information in my database (also on parse.com) and display the information accordingly. My problem, is my progressDialog box appears, and it never goes away. My list is never populated. I tried doing it without the dialog box, and populating my list with ever query and had same results.
NOTE: the list is working properly. This is a list I have used successfully before when I would load my information differently. I am just changing the way I load information because I need to have a database of all fighters, and load my fight card from that list.
NOTE: GetCallBack and FindCallBack are asynchronous, that is why this is an odd loop. I have to wait for the done().
Here is the java
public class databaseFightCard extends Activity {
int I;
int size;
private HomeListAdapter HomeListAdapter;
private ArrayList<HomeItem> HomeItemList;
private SeparatedListAdapter adapter;
//this int is to test for main and coMain events. If one is TRUE, It will assign the array position to main or coMain.
int main, coMain;
ParseQuery<ParseObject> blueCorner = ParseQuery.getQuery("FightersDB");
ParseQuery<ParseObject> redCorner = ParseQuery.getQuery("FightersDB");
String name1, name2;
List<String> red = new ArrayList<String>();
List<String> blue = new ArrayList<String>();
private ListView listView;
ProgressDialog progressDialog;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main_list);
progressDialog = ProgressDialog.show(this, "", "Loading bout...", true);
initialization();
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
HomeItem homeItem = (HomeItem) adapter.getItem(position);
AlertDialog.Builder showFighter = new AlertDialog.Builder(databaseFightCard.this, android.R.style.Theme_DeviceDefault_Dialog);
showFighter.setTitle(homeItem.getHomeItemLeft().toString() + " and " + homeItem.getHomeItemRight().toString());
showFighter.setMessage("166 - 165\nLogan Utah - Richmond Utah");
showFighter.setPositiveButton("DONE", null);
showFighter.setNegativeButton("Cancel", null);
AlertDialog dialog = showFighter.show();
TextView messageView = (TextView) dialog.findViewById(android.R.id.message);
messageView.setGravity(Gravity.CENTER);
Toast.makeText(getBaseContext(), homeItem.getHomeItemLeft().toString() + " " + homeItem.getHomeItemRight().toString(), Toast.LENGTH_LONG).show();
System.out.println("Selected Item : " + homeItem.getHomeItemID());
}
});
HomeListAdapter = new HomeListAdapter(getApplicationContext(), 0, HomeItemList);
//find the fight card, and read the ids
ParseQuery<ParseObject> fightOrder = ParseQuery.getQuery("FightCard");
fightOrder.findInBackground(new FindCallback<ParseObject>() {
#Override
public void done(List<ParseObject> parseObjects, ParseException e) {
if (e == null) {
size = parseObjects.size();
int i = 0;
while (i < size) {
if (parseObjects.get(i).getBoolean("main")) {
main = i;
}
if (parseObjects.get(i).getBoolean("coMain")) {
coMain = i;
}
red.add(i, parseObjects.get(i).getString("redCorner"));
blue.add(i, parseObjects.get(i).getString("blueCorner"));
i++;
}
displayRed();
} else {
e.printStackTrace();
}
}
});
}
private void displayRed() {
adapter = new SeparatedListAdapter(this);
//find one fighter at a time. in the done() method, start the second fighter.
redCorner.getInBackground(red.get(I), new GetCallback<ParseObject>() {
#Override
public void done(ParseObject parseObject, ParseException e) {
if (e == null) {
HomeItemList = new ArrayList<HomeItem>();
HomeItem homeItem = new HomeItem();
homeItem.setHomeItemID(I);
name1 = parseObject.getString("Name");
homeItem.setHomeItemLeft(name1);
HomeItemList.add(homeItem);
if (HomeListAdapter != null) {
if (I == main) {
adapter.addSection(" MAIN EVENT ", HomeListAdapter);
} else if (I == coMain) {
adapter.addSection(" Co-MAIN EVENT ", HomeListAdapter);
} else {
adapter.addSection(" FIGHT CARD ", HomeListAdapter);
}
}
displayBlue();
} else {
e.printStackTrace();
}
I++;
while (I < size){
displayRed();
}
if (size == I) {
listView.setAdapter(adapter);
progressDialog.dismiss();
}
}
});
}
private void displayBlue() {
//find the red fighters then call the dismiss();
blueCorner.getInBackground(blue.get(I), new GetCallback<ParseObject>() {
#Override
public void done(ParseObject parseObject, ParseException e) {
if (e == null) {
HomeItemList = new ArrayList<HomeItem>();
HomeItem homeItem = new HomeItem();
homeItem.setHomeItemID(I);
name2 = parseObject.getString("Name");
homeItem.setHomeItemLeft(name2);
HomeItemList.add(homeItem);
if (HomeListAdapter != null) {
if (I == main) {
adapter.addSection(" MAIN EVENT ", HomeListAdapter);
} else if (I == coMain) {
adapter.addSection(" Co-MAIN EVENT", HomeListAdapter);
} else {
adapter.addSection(" FIGHT CARD ", HomeListAdapter);
}
}
} else {
e.printStackTrace();
}
//if it is done running through all the IDS, set the listView, and dismiss the dialog.
I++;
while (I < size){
displayRed();
}
if (size == I) {
listView.setAdapter(adapter);
progressDialog.dismiss();
}
}
});
}
private void initialization() {
listView = (ListView) findViewById(R.id.Listview);
}
LogCat
java.lang.RuntimeException: This query has an outstanding network
connection. You have to wait until it's done.
That is pointing to this line:
while (I < size){
displayRed();
}
EDIT
I believe that it is the async tasks that are causing this.
On a previous build: I would call for one line item at a time, add it to my list, repeat until finished, then display list.
On the this build: I want to call for redCorner add it to my list, call blueCorner add it to the same line, repeat until finished, then display the list. Here is what it would look like (previous build):
Revised My question is still unanswered. Maybe I need to simplify it. I will have +-20 objectId's from one class. I took out all the code that is irrelevant. Still getting unexpected results with this code.
redCorner.getInBackground(red.get(i), new GetCallback<ParseObject>() {
#Override
public void done(ParseObject parseObject, ParseException e) {
if (e == null) {
Log.d("NAME " + i, name1 + " ");
i++;
while (i < size) {
redCorner.cancel();
displayRed();
}
if (i == size) {
progressDialog.dismiss();
}
} else {
e.printStackTrace();
}
}
});
This is yet another case of not understanding the nature of Async coding (I've seen a lot of questions with the same issue).
In your case you are calling the displayRed() method that fires off some async code, then returns.
Here's how your code might run:
First call to displayRed() (dr1)
(dr1) Async redCorner.getInBackground(..) (async1) started
(dr1) returns
.. some time passes ..
(async1) getInBackground(..) call returns with data, runs code block
calls displayBlue() (db1)
(db1) blueCorner.getInBackground(..) (async2) started
(db1) returns
begins the while loop
calls displayRed() (dr2)
(dr2) Async redCorner.getInBackground(..) (async3) started
(dr2) nothing has touched I yet, tries to start another async redCorner.getInBackgroud(..) (async4)
ERROR
You're writing your code as if the async blocks are running sync instead. Keep in mind that getInBackground means "make a web call to get this data, and when something happens (error or success) run this block of code I'm giving you, possibly on another thread".
Think about the order you want to achieve things, realise that you're asking it to start a process that takes some time, and adjust your code accordingly.