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?
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();
}
Related
I am using a Thread to do some calculations related to the app that need to be done simultaneously but this Thread causes the FPS to drop (logically) and I wanted to know how to resolve the issue as the Thread is not doing any heavy calculations at all. Here is the code where I implement the Thread and the Thread itself.
incrementMass = new IncrementMass();
incrementMass.start();
// I added some extra functionality to the InputProcessor but I assume that is irrelevant
if(InputProcessor.isButtonUp() && InputProcessor.getButtonLetGo() == RIGHT && !isJustPressed) {
isJustPressed = true;
try {
incrementMass.join();
} catch(InterruptedException e) {
e.printStackTrace();
}
planets.add(new Planet(10, m, mouseOnWorld2.x, mouseOnWorld2.y));
} else if(Gdx.input.isButtonJustPressed(RIGHT)) {
isJustPressed = false;
incrementMass.restart();
}
The Thread:
/**
* Thread to increment the mass in a while loop.
*/
public class IncrementMass extends Thread {
/**
* Increments the mass when started.
*/
#Override
public void run() {
super.run();
while(Gdx.input.isButtonPressed(Input.Buttons.RIGHT)) {
MainScreen.m += 100;
System.out.println(MainScreen.m);
}
}
/**
* Resets the mass so the whole thing starts over (for the creation of a new planet)
*/
public void restart() {
MainScreen.m = 100000;
}
}
All this is called in the render() function of my Screen by the way.
I have one idea as to what is causing this: Every frame I create a new Thread which is not optimal but everything else I tried failed to actually perform my calculations correctly. It definitely solves the FPS problem to have the initiation of the Thread and the ´start()´ function in the constructor of my Screen but that for some reason messes with the incrementing of the mass and makes it a fixed value: the value I reset it to in ´restart()´
I've been trying to solve this but I'm baffled so here I am.
As said in the comment, there was no function for isButtonJustUp() which made it not be able to run sequentially. Therefore I made a Thread so that it was sequential which is not a good implementation of Threads. I've come up with a solution:
if(Gdx.input.isButtonPressed(RIGHT)) {
m += 100;
} else if(InputProcessor.isButtonJustUp() && InputProcessor.getButtonLetGo() == RIGHT) {
planets.add(new Planet(10, m, mouseOnWorld2.x, mouseOnWorld2.y));
m=0;
}
I haven't made isButtonJustUp() yet but it is the best way rather than implementing an unnecessary Thread.
I have this code sample
public static class BlinkMe extends Thread {
int counter = 0;
protected boolean stop = true;
public void run() {
while (stop) {
counter++;
if (counter % 2 == 0) {
jLabel4.setVisible(true);
jLabel7.setVisible(true);
jLabel8.setVisible(true);
counter = 0;
} else {
jLabel4.setVisible(false);
jLabel7.setVisible(false);
jLabel8.setVisible(false);
if (jButton4.isEnabled() == false) {
stop = false;
jLabel4.setVisible(true);
jLabel7.setVisible(true);
jLabel8.setVisible(true);
if (jButton2.isEnabled() == false) {
stop = true;
jButton2.setEnabled(false);
}
}
}
}
}
}
I need to stop this Thread when I press my Stop Button...
Here's the code I'm using for the Button's function but it is not working. ***The Thread is not working at ll*
Here is the Button's function
private void jButton4ActionPerformed(java.awt.event.ActionEvent evt) {
BlinkMe b=new BlinkMe();
b.stop(); //here I have even used b.interrupt(); but doesn't stop the
}
There are many, many things wrong in this code.
you're accessing Swing components from a background thread. That's forbidden. Only the event dispatch thread is allowed to access Swing components
You're trying to stop() a thread, although this method is deprecaed and should never, ever be used, as the documentation explains
Instead of stopping the actual thread, you create a new instance of that thread class, and call stop() on that new instance.
You "blink" without any delay between the blink.
Your thread uses a stop variable, but this variable is never modified anywhere. Even if it was, it's not volatile, so you have a big chance of not seeing the modification, and thus not stopping the thread.
Read the Swing tutorial abount concurrency. And use a Swing Timer, which is designed to do that kind of thing, safely.
You are creating a new thread in actionPerformed and trying to stop the same, which was not started so far. Try calling stop in actual thread.
The initial value of your stop is "true". This means that when the thread starts, the run method executes but will not execute the while block because the condition will result to false right away.
First, you need to change your while loop into like this:
while(!stop) { /* the rest of your code */ }
Next, you need to create a method in your BlinkMe thread that would allow other objects in your program that would make it stop. The method would look something like this:
public void stopBlinking() {
stop = true;
}
Calling the above method will stop the infinite loop in the run method.
I don't think you will see a blinking effect when you run your program. It is because the loop executes very fast. I suggest you put a Thread.sleep(1000) somewhere in the loop so that there is time to reflect the blink effect visually.
I am using Bukkit API 1.8 with Java 7.
I have a repeating task that loops through all the players on the server and sets their armor randomly to either leather, chainmail, etc...
When I use the method setHelmet,setChestplate, etc... I update their inventory like usual, but since this task is running every 6 ticks, it runs fast. Therefore, when a player tries to fire a bow, the bow resets its power every time this task runs.
Since I knew it was a problem with updating the inventory, I tried removing the updateInventory method.
After doing this the armor still got put on and changed, but the bow was still being reset every time the task was ran.
How would I keep the bow from resetting while still keeping the task running?
My code:
#SuppressWarnings("deprecation")
public static void repeatEffect()
{
main.getServer().getScheduler().scheduleAsyncRepeatingTask(main, new Runnable()
{
#Override
public void run()
{
for(Player o : Bukkit.getOnlinePlayers())
{
Material M1 = Material.WOOL;
int num = rainbow.get(o.getName());
if(num==1)
{
M1 = Material.LEATHER_HELMET;
}
else if(num==2)
{
M1 = Material.CHAINMAIL_HELMET;
}
else if(num==3)
{
M1 = Material.GOLD_HELMET;
}
else if(num==4)
{
M1 = Material.IRON_HELMET;
}
else if(num==5)
{
M1 = Material.DIAMOND_HELMET;
}
rainbow.put(o.getName(), num+1);
if(rainbow.get(o.getName())>5)
{
rainbow.put(o.getName(), 1);
}
ItemStack rrhelm = createItemStack(M1, 1, "§a§lR§b§la§c§li§d§ln§e§lb§f§lo§a§lw §c§lH§d§le§e§ll§f§lm§a§le§b§lt", "§7Very special piece of armor");
o.getInventory().setHelmet(rrhelm);
}
}
}
, 6, 6);
}
If changing armour resets the players bow, you could work around it by only changing the armour of players who are joining, not wielding a bow or just after an EntityShootBowEvent.
To see if the player is wielding a bow, use:
org.bukkit.Bukkit.entity.Player player = ...;
boolean hasBowEquiped = player.getEquipment().getItemInHand().getData().getItemType().equals(Material.BOW);
After testing this some more, the only way I was able to reproduce the bow complication was by calling the deprecated updateInventory() method which you said you removed. I'm fairly certain that you still have this method somewhere in your code because I can't find anything else that would cause the bow to act this way (I was still able to fire the bow but the animation looks glitchy and the power of the arrow is sometimes incorrect).
The only difference between my code is that I used new ItemStack(M1) instead of your createItemStack() method to instantiate the helmet (also tried changing name, lore and amount). I was still able to shoot a bow just fine. Could the resetting of the bow/inventory have something to do with your createItemStack method?
There's no reason why you should be running this task asynchronously. You're accessing the Bukkit API from an asynchronous task or different thread which is a big no-no and can cause all kinds of tricky problems. Use the scheduleSyncRepeatingTask method to run the task in the same thread.
For simplicity's sake I randomly set a single armor slot (also tried all four) to either leather or iron every 6 ticks. Didn't seem to interfere with the bow. Could we see your code? Here is mine:
public void onEnable() {
this.getServer().getScheduler().scheduleSyncRepeatingTask(this, new Runnable() {
public void run() {
for (World world : Bukkit.getWorlds()) {
for (Player player : world.getPlayers()) {
if (Math.random() < 0.5) {
player.getInventory().setBoots(new ItemStack(Material.IRON_BOOTS));
} else {
player.getInventory().setBoots(new ItemStack(Material.LEATHER_BOOTS));
}
}
}
}
}, 0, 6);
}
Learning Android development.
Code has to wait for few seconds/minutes/hours before going to the next statement in a for Loop.
for( i=0; i<number; i++) {
// Do Something
// Then Wait for x hours, y minutes, and z seconds. Then proceed to next command.
// Do some more things.
} //End for loop.
I searched for this but found many answers like thread.Sleep, Sleep, try{wait(); } Catch{ }, etc...
Also, found out about Handler. Can I use a Handler inside a for loop??
Rather, is there a simple command like wait(x hours, x minutes, x seconds); something like this??
Please help!!
It depends on where do you have the loop. If you run the loop in main thread, you can't "simply insert a delay" into it, because it will block execution, and Java doesn't have anything like C#'s async&await to "easily" solve this. So, the easiest way to do this is: first, move the entire loop to a background thread. Then, you can just use Thread.sleep(…) where you need a delay. But then, if you need to update UI, you can't do this directly from background thread, you will need to use a Handler, call post(Runnable) method (the passed Runnable will run on main thread), and inside that Runnable you must check if the UI is still alive (because user could "close" the application, so your Activity/Fragment/View/whatever can be finished or be in a "bad" state)
In Android there is a class that can do all what you are saying, AsyncTask.
private class YourTaskClassName extends AsyncTask<Void, Integer, Long> {
protected Long doInBackground(Void.. values) {
//Here is where you do the loop
for (int i = 0; i < number; i++) {
...
publishProgress(yourProgress); //Value passed to onProgressUpdate
}
return totalSize; //Value for onPostExecute
}
protected void onProgressUpdate(Integer... progress) {
//Here is what you wanna show while your loop is running in background
setProgressPercent(progress[0]);
}
protected void onPostExecute(Long result) {
//Here is what you wanna do when your loop has finished
}
}
You can call it like this new YourTaskClassName().execute();
Thread.sleep(time_in_miliseconds)
looks like the simplest solution. It's a static method, so you need no instances of Thread class.
Wait is a monitor method which means you can call the method from synchronized block or method.
Use sleep for your case.
I've done Android programming in the past but not recently though. I have done lots of Java though and think that I will still be of help.
With respect to the Handler, it appears that you would be able to do this. Having looked at the documentation, http://developer.android.com/reference/android/os/Handler.html#handleMessage(android.os.Message), essentially you're posting messages or runnables from one thread and handling messages in a different thread. Your for-loop won't stop though since you're starting a new thread when using a handler.
When creating a handler, you need to override the handleMessage(Message msg) method if it's a message or post a runnable you're sending as this is the method that's called after a suitable time has ellapsed. To send your message at a specific time or after a delayed amount of time, you have postAtTime, postDelayed, sendMessageAtTime and sendMessageDelayed methods, whichever one is needed.
new Handler() {
public void handleMessage(Message msg) {
// Your code here.
}
}.sendMessageDelayed(yourMessage, theAmountOfTimeInMilles);
Also, after your message is handled, if you want to do any user-interface updating (in other words, changing anything graphical, such as updating a label or changing the background), you need to use the runOnUiThread method, otherwise it will throw an exception:
runOnUiThread(new Runnable() {
public void run() {
// Code including UI code here.
}
});
I am working on a game using the thread-per-client model. The game operates so that every half a second all of the players need to be updated. The updates all have to happen within the half a second interval, so they need to all be executed at the same time. My idea is to have a class that keeps track of when the "global update" needs to happen and then when the time comes, go through all of the players and tell it to update:
for(Player p : currentPlayers) {
p.update();
}
The problem is that since every player has their own thread, I want the player to take advantage of that fact since it is already there. If I go through the updates from a different class, then there is one thread executing what a couple hundred threads could be doing individually. How can I design it so that if a thread calls method 'update()' in class Player, a different thread than the one that called it executes it, or perhaps a different approach that can achieve the same goal?
If you need any clarification, please ask! Thanks a lot!
UPDATE: What do you guys think of this (I can't figure out how to format long amounts of code in posts!):
UPDATE 2: Just realized I would need to know when all of the players finish updating to reset the last time...
public class PseudoExample implements Runnable
{
// Assume 'players' is full of active players.
private Player[] players = new Player[100];
private long lastUpdate = System.currentTimeMillis();
public void run()
{
while (true)
{
if (System.currentTimeMillis() - lastUpdate >= 500)
{
for (Player p : players)
{
p.update = true;
}
}
try
{
Thread.sleep(10);
} catch (InterruptedException e)
{
}
}
}
private class Player implements Runnable
{
private boolean update = false;
public void run()
{
while (true)
{
if (update)
{
// Do updating here ...
}
try
{
Thread.sleep(10);
} catch (InterruptedException e)
{
}
}
}
}
}
I think the best way to handle this would be instead of calling p.update(), you could send an asynchronous message to p. This would use the Handler functionality. This is probably the cleanest way, although I believe some (likely trivial) overhead will occur from the message passing.
So, in your ticking thread (i.e. the one that calls the global update), you would have a reference to a Handler object for each client thread. Then, you look would look like
for (Player p : currentPlayers) {
p.handler().sendMessage(); // this isn't exactly the syntax
}
and in your Player, you would have a PlayerHandler object that extends Handler and overrides handleMessage(Message).
EDIT: the comments on the question are good ones - don't use more threads than you need to. They might seem to be the "right" abstraction, but they introduce a ton of potentially tricky issues. If all of your computation needs to be done in between ticks, it might not matter whether it's done sequentially or not.