ListView onScroll being called multiple times - java

I know that this question has been asked before but I think I am really close to my solution and therefore I wish to do this way.
I am using a ListView and populating it with some data. Now, I am trying to populate it with some more data when the user reaches the bottom. This should continue as long as there are less than 100 items in the ListView. But the code below add all the data at once when I scroll it to the bottom for the first time. I guess there are tens of calls to my async method that loads more data.
#Override
public void onScroll(AbsListView absListView, int firstVisibleItem,
int visibleItemCount, int totalItemCount) {
scrollTask myscrolltask = new scrollTask();
int lastVisibleIndex = absListView.getLastVisiblePosition();
if(lastVisibleIndex != totalItemCount - 1)
{
System.out.print("lastVisibleIndex "+lastVisibleIndex);
System.out.print("totalItemCount-1 " + (totalItemCount-1));
myscrolltask.cancel(true);
return;
}
if(moreNewsAvailable == 0)
return;
if(totalItemCount > 75)
return;
Log.v("Total Item Count", String.valueOf(totalItemCount));
int lastItem = firstVisibleItem + visibleItemCount;
if(lastItem == totalItemCount && totalItemCount<=75 && moreNewsAvailable==1 && lastVisibleIndex != -1 && totalItemCount!=0) //Means that you have reached the bottom
{
Log.v("LastVisibleItemPosition", String.valueOf(lastVisibleIndex));
setProgressBarIndeterminateVisibility(true);
myscrolltask.execute("");
}
}
Is there anyway around? How can I make sure that only one call to the async is made when reaching bottom?

create a Boolean variable and set that variable to true in task execution and again set that Boolean to true on task completion.
Check if task is in progress than dont execute on scroll method.
if(!isLoading){
if(lastVisibleIndex != totalItemCount - 1)
{
System.out.print("lastVisibleIndex "+lastVisibleIndex);
System.out.print("totalItemCount-1 " + (totalItemCount-1));
myscrolltask.cancel(true);
return;
}
if(moreNewsAvailable == 0)
return;
if(totalItemCount > 75)
return;
}

Related

Collision detection not working with my brick breaker program?

My program has been experiencing an odd bug i just cannot seem to fix. In summary, whenever I switch two if statements, only the one coming afte tthe first one will work.
Example: (The ball will successfully collide with the top, but won't with the bottom.)
public void update()
{
if(enemies != null)
{
for(Enemy e : enemies)
if(c.getBall().getHitbox().intersects(e.getHitbox()))
{
if(e.collidedBottom())
c.getBall().setSpeedY((c.getBall().ballSpeed));
if(e.collidedTop())
c.getBall().setSpeedY(-(c.getBall().ballSpeed));
deadEnemies.add(e);
}
enemies.removeAll(deadEnemies);
}
Now if i switched the positions of the two if statements like so;
if(e.collidedTop())
c.getBall().setSpeedY(-(c.getBall().ballSpeed));
if(e.collidedBottom())
c.getBall().setSpeedY((c.getBall().ballSpeed));
The ball will successfully react the way it should when colliding with the bottom, but not with the top. Here is the two collision methods:
public boolean collidedBottom()
{
if(c.getBall().getBallY() <= enemy.y + enemy.height &&
c.getBall().getBallX() + c.getBall().getHitbox().width >= enemy.x
&& c.getBall().getBallX() <= enemy.x + enemy.width)
return true;
return false;
}
public boolean collidedTop()
{
if(c.getBall().getBallY() + c.getBall().getHitbox().height >= enemy.y &&
c.getBall().getBallX() + c.getBall().getHitbox().width >= enemy.x
&& c.getBall().getBallX() <= enemy.x + enemy.width)
return true;
return false;
}
Enemy refers to the current focused block in the loop.

Changing image on imageView in android via java

I have a imageView, button inside an activity, 10 pictures that are named from stage1 to stage9.
I need you help to solve some problem
I would like to use a button click to change picture that is on imageView to the next one.
I mean, I want to press on the button, and image view shows stage2 image, I press the button again and stage3 picture will be shown.
I have done this using counter var which count number of clicks and then running if statment to see which picture should go next, but it is too long and it is not possible to have more or less pictures.
I would like to know is there a way to do this, and if possible please show me how.
Thanks
code
private void changeImage(int counter) {
if (counter == 1) {
image.setImageResource(R.drawable.stage2);
} else if (counter == 2) {
image.setImageResource(R.drawable.stage3);
} else if (counter == 3) {
image.setImageResource(R.drawable.stage4);
} else if (counter == 4) {
image.setImageResource(R.drawable.stage5);
} else if (counter == 5) {
image.setImageResource(R.drawable.stage6);
} else if (counter == 6) {
image.setImageResource(R.drawable.stage7);
} else if (counter == 7) {
image.setImageResource(R.drawable.stage8);
} else if (counter == 8) {
image.setImageResource(R.drawable.stage9);
}
}
bassically this is the code that I am using right now.
It works, but if I want to do it to be more dynamic.
You'll need to tell the vm to update -> 'invalide()'.
Or use Picasso,
Picasso.with(Statics.context).load(R.drawable.stageX).error(R.drawable.error_img).resize(width, height).priority(Priority.HIGH).into(image);
Just get resource id by name, use like,
private void changeImage(int counter) {
if(counter >= 1 && counter <= 9) // Always check counter value before accessing as resource id
{
int counterValue = counter+1;
int resourceId = Resources.getSystem().getIdentifier("stage"+counterValue, "drawable", this.getPackageName()); // Use application context to get package name
image.setImageResource(resourceId);
}
}

if there a better way to write this if statment in java

So is there a way to simplify this to make is smaller in anyway?
else if(selectedCards.size() == 3
&& cardAt(selectedCards.get(0)).pointValue() + cardAt(selectedCards.get(1)).pointValue() + cardAt(selectedCards.get(2)).pointValue() == 0
&& !cardAt(selectedCards.get(0)).rank().equals(cardAt(selectedCards.get(1)).rank())
&& !cardAt(selectedCards.get(0)).rank().equals(cardAt(selectedCards.get(2)).rank())
&& !cardAt(selectedCards.get(1)).rank().equals(cardAt(selectedCards.get(2)).rank()))
From what I can see you're trying to test if the 3 cards have different ranks. An easier way to test this is to put them into a Set and see if the set size is same as selected set. This scales to any number of selected cards...
public boolean differentRanks(List<Integer> selectedCards) {
Set<Integer> ranks = new HashSet<Integer>();
for (int card : selectedCards) {
ranks.add(cardAt(card).rank());
}
return ranks.size() == selectedCards.size();
}
I'd also create a method to total the points for the selected cards...
public int sum(List<Integer> selectedCards) {
int total;
for (int card : selectedCards) {
total += cardAt(card).pointValue();
}
return total;
}
So the condition would end up
} else if (selectedCards.size() == 3 && sum(selectedCards) == 0 &&
differentRanks(selectedCards) {
This would be one option:
else if(selectedCards.size() == 3
&& cardAt(selectedCards.get(0)).pointValue() + cardAt(selectedCards.get(1)).pointValue() + cardAt(selectedCards.get(2)).pointValue() == 0
&& !(cardAt(selectedCards.get(0)).rank().equals(cardAt(selectedCards.get(1)).rank())).equals(cardAt(selectedCards.get(2)).rank()) )
To make more readable this condition you could do something like this:
//here you extract the values you need only once and use them in your condition block below
int cardsSize = selectedCards.size();
int pointValue0 = cardsSize == 3 ? cardAt(selectedCards.get(0)).pointValue() : 0;
int pointValue1 = cardsSize == 3 ? cardAt(selectedCards.get(1)).pointValue() : 0;
int pointValue2 = cardsSize == 3 ? cardAt(selectedCards.get(2)).pointValue() : 0;
bool rankEquals = CompareRanks(cardAt(selectedCards.get(0)),cardAt(selectedCards.get(1)),cardAt(selectedCards.get(2));
if (<condition>) {
//block of sentences
} else if (cardsSize == 3 && (pointValue0 + pointValue1 + pointValue2) == 0 && !rankEquals )
I'm suggesting the creation of a function called "CompareRanks" where you receive 3 different objects (result of "cardAt") and you get the rank in there and compare if the values are the same or not.
This option leads you to more lines of code but is cleaner and more readable for any person besides you.
In my opinion most readable:
else if(selectedCards.size() == 3 && checkRanks(selectedCards))
{
//...
}
//...
private boolean checkRanks(List<Card> cards)
{
Card zeroCard = cardAt(selectedCards.get(0));
Card firstCard = cardAt(selectedCards.get(1));
Card secondCard = cardAt(selectedCards.get(2));
boolean isZero = zeroCard.pointValue() + firstCard.pointValue() + secondCard.pointValue() == 0;
boolean zeroCardRankNotEqualFirst = !zeroCard.rank().equals(firstCard.rank())
boolean zeroCardRankNotEqualSecond = !zeroCard.rank().equals(secondCard.rank())
boolean firstCardRankNotEqualsSecond = !firstCard.rank().equals(secondCard.rank());
return isZero && zeroCardRankNotEqualFirst && zeroCardRankNotEqualSecond && firstCardRankNotEqualsSecond;
}

Only trigger proximity detector when object enters the range, not when he moves within range

I'm making a text-based radar for Minecraft. If a player comes within 20 blocks of you, it will say in chat. As of now, it spams the chat. How can I get it to only write to chat about that player ONCE? Even if you don't play the game, it should be easy to understand.
if (Camb.radar)
{
for (Entity e: (List < Entity > ) mc.theWorld.loadedEntityList)
{
if (e instanceof EntityPlayer)
{
EntityPlayer player = (EntityPlayer) e;
if (player == mc.thePlayer || mc.thePlayer.getDistanceToEntity(e) > 20.0)
continue;
mc.thePlayer.addChatMessage("\2479[CAMB] \247e" + player.getEntityName() + " has entered your 20 block radius!"); //Write to chat, only want this line done once for every player
}
}
}
You'll need to keep track of when the player leaves the range and set a flag, so you'll know when they're transitioning from "out of range" to "in range". Might also want to add a timer so that you can only alert once every N seconds.
You could try creating a List or Array of nearby players, and add them to that list when they are within 20 blocks. When you find an entity within range, check to see if its in your list. If not, notify and add it to the list, if so, game on :)
For removing items from your list, check the entities in your list and compare them to the players position. If they are out of range, remove them. This may need to happen in a separate loop.
If you make a class PlayerData, it can contain a hashmap of playernames mapped to booleans. You give each player a PlayerData object and then when somebody enters the radius of that player, you toggle his/her boolean.
public class PlayerData {
public Player thePlayer;
public HashMap<String,boolean> inRadius = new HashMap<String,boolean>();
public PlayerData(Player thePlayer) {
this.thePlayer = thePlayer;
}
public void checkRadius(P Entity player) {
/**function that checks radius and if a new player is there, notify thePlayer*/
if(inRadius.get(player.getEntityName()) == true || thePlayer == player || thePlayer.getDistanceToEntity(player) > 20.0) return;
else {
thePlayer.addChatMessage("whatever you want to say");
inRadius.put(player.getEntityName(), true);
}
for(Iterator<String> key=inRadius.keySet().Iterator();key.hasNext()) {
String name = key.next();
/**Check to see if that player is still within 20 meters. If not, set value to false*/
/** also be careful to check if player is online*/
}
}
}
Add a boolean flag to EntityPlayer detected with getter/setter methods.
Inside your loop:
if (Camb.radar) {
for (....) {
if (e instanceof EntityPlayer) {
EntityPlayer player = (EntityPlayer) e;
if (player.isDetected() || player == mc.thePlayer || mc.thePlayer.getDistanceToEntity(e) > 20.0) {
continue;
}
if (!player.isDetected()) {
mc.thePlayer.addChatMessage(....);
player.setDetected(true); // reset this flag when player goes out of radar
}
}
}
}
You need to store outside of that method that you have alerted the player already.
A Map is perfect for this. Even better a WeakHashMap in case you don't want to leak those Entities
private final Set<EntityPlayer> playersInRange = Collections
.newSetFromMap(new WeakHashMap<EntityPlayer, Boolean>());
void onMove() {
if (Camb.radar) {
for (Entity e : (List<Entity>) mc.theWorld.loadedEntityList) {
if (e instanceof EntityPlayer) {
EntityPlayer player = (EntityPlayer) e;
if (player == mc.thePlayer || mc.thePlayer.getDistanceToEntity(e) > 20.0) {
// make sure player is (no longer) in set
playersInRange.remove(player);
continue;
}
if (!playersInRange.contains(player)) {
playersInRange.add(player);
mc.thePlayer.addChatMessage("\2479[CAMB] \247e" + player.getEntityName()
+ " has entered your 20 block radius!");
}
}
}
}
}
You could also store a time along with them to re-alert every X time.
private static final long WAIT_BETWEEN_ALERTS = 30000;
private final WeakHashMap<EntityPlayer, Long> map = new WeakHashMap<EntityPlayer, Long>();
void onMove() {
if (Camb.radar) {
for (Entity e : (List<Entity>) mc.theWorld.loadedEntityList) {
if (e instanceof EntityPlayer) {
EntityPlayer player = (EntityPlayer) e;
if (player == mc.thePlayer || mc.thePlayer.getDistanceToEntity(e) > 20.0) {
// clear alerts
map.remove(player);
continue;
}
Long lastTimeAlerted = map.get(player);
long minimumLastAlert = System.currentTimeMillis() - WAIT_BETWEEN_ALERTS;
if (lastTimeAlerted == null || lastTimeAlerted < minimumLastAlert) {
map.put(player, System.currentTimeMillis());
mc.thePlayer.addChatMessage("\2479[CAMB] \247e" + player.getEntityName()
+ " has entered your 20 block radius!");
} // else, already alerted recently.
}
}
}
}
I suggest doing as following:
int radius = 0;
if (Camb.radar) for (Entity e : (List <Entity>) mc.theWorld.loadedEntityList)
if (e instanceof EntityPlayer) {
EntityPlayer player = (EntityPlayer) e;
if (player == mc.thePlayer || mc.thePlayer.getDistanceToEntity(e) > 20.0)
continue;
while (radius < 1) {
mc.thePlayer.addChatMessage("\2479[CAMB] \247e" + player.getEntityName() + " has
entered your 20 block radius!");
}
}

Release on TouchEvent not working

Here is my method code I use in onTouchEvent:
public void touch(MotionEvent event) {
// starta = "klicka för att börja";
if (event.getAction() == MotionEvent.ACTION_DOWN) {
starta = "Click to start";
fN.aktivitetNer.start();
if (event.getAction() == MotionEvent.ACTION_CANCEL) {
if (y == -300) {
touch(event);
}
else if (y > -300) {
fN.aktivitetNer.interrupt();
fU.aktivitetUpp.start();
p++;
}
}
else if (y2 <= y + xMax) {
fN.aktivitetNer.interrupt();
fU.aktivitetUpp.start();
p = 0;
}
}
}
What should happening is a knife coming down very fast with help of a Thread(fN.aktivitetNer) and if the knife slice the finger(y2) you loose, if you're fast enough you score one point(p), when you loose or win the knife will go up again with another Thread(fU.aktivitetUpp)
I know it's not perfect but it's now working at all!
ps. if you click two times on the screen the programm will crash.
Well it certainly won't work in it's current form, because the code will never enter your second if statement.
Your first if statement asserts that event.getAction() == MotionEvent.ACTION_DOWN. If this is true, then atevent.getAction() cannot possibly be equal to MotionEvent.ACTION_CANCEL and you will never enter that block of code.
Since I don't know what your thread does I can't be certain, but you probably want something more like this:
public void touch(MotionEvent event)
{
// starta = "klicka för att börja";
int actionCode = event.getAction();
if (actionCode == MotionEvent.ACTION_DOWN)
{
//Start to drop knife
}
else if (actionCode == MotionEvent.ACTION_CANCEL || actionCode == MotionEvent.ACTION_UP)
{
if (Knife is falling, and touch point is below knife)
{
//Add one to score
}
else if (Knife is falling, and touch point is above knife)
{
//Reset score to 0
}
}
else if (Knife has already fallen and still touching screen)
{
//Reset score to 0
}
}

Categories

Resources