Issue
Context
I have an activity where a user clicks hit or miss for three turns and then it is the computers turn, to click hit or miss.
The problem
The problem is when it is the computers turn the program hangs the recycler view and makes multiple clicking sounds before eventually displaying the a result. You can see this here:
What I've tried
Through some troubleshooting I seen that I should preform the computers task in a background thread and any UI changes should be preformed in the runOnUiThread
. So I have this (this is the onClickEvent):
AsyncTask.execute(new Runnable() {
@Override
public void run() {
playerHit(whosThrowing);
runOnUiThread(new Runnable() {
@Override
public void run() {
setAdapterToDisplayStats(whosThrowing);
tv_numberToHit.setText(numToHit.get(whosThrowing));
if(amountThrownThisRound == 3 && (!opponent.equals("SINGLE"))) {
nextPlayerTurn(whosThrowing);
}
}
});
}
});
break;
case R.id.btn_miss:
AsyncTask.execute(new Runnable() {
@Override
public void run() {
playerMissed(whosThrowing);
runOnUiThread(new Runnable() {
@Override
public void run() {
setAdapterToDisplayStats(whosThrowing);
//Player threw their three darts. Change player.
if(amountThrownThisRound == 3 && (!opponent.equals("SINGLE"))) {
nextPlayerTurn(whosThrowing);
}
}
});
}
});
break;
However this didn't solve the problem and the GIF above actually shows the result of this code. I designed this first for a Human v Human scenario and then started implementing a Human V Computer scenario. I thought this would have been straight forward get a result for the computer either hit or miss and perfomClick()
on the relevant button.
As you can see in the above code block, the majority of the methods are in the runOnUiThread
this is because these methods contain at least one bit of code that changes the UI but parts that doesn't mess with the UI. I can't imagine I have to go through and wrap each line of code in a run in background or run in UI thread, surely? Just when it is the computers turn.
The setAdapterToDisplayStats(whosThrowing);
calls onBindViewHolder
in a separate class which updates the recylerview. Does having just setAdapterToDisplayStats(whosThrowing)
ensure that anything after it even if it is in a separate class runsOnTheUi thread?
Code that may be having an effect
Computers throw
if(opponent.equals("COMPUTER") && confirmedPlayers.get(0).equals("A.I") && Integer.parseInt(amountThrown.get(0)) % 3 == 0){
btn_hit.setEnabled(false);
btn_miss.setEnabled(false);
for (int i = 0; i < 3; i++) {
takeCompThrow();
}
btn_hit.setEnabled(true);
btn_miss.setEnabled(true);
}
return whosThrowing;
Computers performClick
The preformClick was what I had originally wrapped in a runnable block, thinking anything I called after it would be done in the background thread. Although this is where I first ran into the problem and moved it to the onClick() as I read the UI should be done separately but still no joy.
private void takeCompThrow() {
boolean hitOrMiss = computerThrow.computerHitOrMiss(compLevel);
if(hitOrMiss) {
btn_hit.performClick();
} else {
btn_miss.performClick();
Here's how it preforms Human V Human in case that's important:
The main question
Where am I going wrong?
Solution
In my opinion the problem is related with this code block, because you are trying to update recyclerview for multiple times in a really short period.
for (int i = 0; i < 3; i++) {
takeCompThrow();
}
Since you are the owner of the calculation logic, you can directly play turns and update the result directly without performing clicks. In this regard, there is no need to use any async task, unless there is a huge calculation cost. My first suggestion, you can do sth like this:
if this is computer turn
for 1..3
calculate result for the computer turn
update recyclerview
There is a second option, but I'd go definitely with the above . Even though it will be a quick solution but won't be the best. You just need to put delay between computer clicks in order to let Recyclerview to calculate and redraw elements. So it will be like with the existing code :
for (int i = 0; i < 3; i++) {
takeCompThrow();
someDelay();
}
Answered By - Erdem
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.