Can someone help me to understand what is happening here? Have been trying to debug, but feel like stuck!
I am trying to animate some online images in my Android app using the following method.
private void animateImages() {
// URL loading
// int i = 1; (initialized earlier)
// ArrayList<String> myImages = new ArrayList<>(); (initialized earlier)
myImages.clear();
While (i < 11) {
// Adds ten images using web link
myImages.add("My_web_url");
i++;
}
AccelerateInterpolator adi = new AccelerateInterpolator();
try {
Field mScroller = ViewPager.class.getDeclaredField("mScroller");
mScroller.setAccessible(true);
mScroller.set(viewPager, new MyScroller(getApplicationContext(), adi, 1));
}
catch (NoSuchFieldException e) {
e.printStackTrace();
}
catch (IllegalAccessException e) {
e.printStackTrace();
}
if (viewPager != null) {
viewPager.setAdapter(new MyPageAdapter(getApplicationContext(), myImages));
}
final Handler handler = new Handler();
final Runnable Update = new Runnable() {
// Printing variables for debugging
System.out.println("The page number is=" + currentPage);
System.out.println("The myImages size is=" + myImages.size());
public void run() {
if (currentPage == myImages.size() - 1) {
currentPage = 0;
}
viewPager.setCurrentItem(currentPage++, true);
}
};
timer = new Timer();
timer.schedule(new TimerTask() {
#Override
public void run() {
handler.post(Update);
}
// delay and period can be initialized as desired
}, delay, period);
}
}
When I call this method in OnCreate, animation works fine. However, when I call this method in OnClickButton Listener, variable myImages size (before public void run()) become zero and due to this animation doesn't work.
In the above, MySCroller and MyPageAdapeter are java classes. But, most likely, the issue is related to button click, and I don't understand why it resets the myImages size which halts the animation!
This is how button click listener is called. What am I doing wrong?
MyButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
animateImages();
}
});
Edit 1:
Thanks to all the comments, I made a little progress.
I moved all these variables from MainActivity to animateImages() method. The animation runs with button click as well but there is a bump in animation, where too images moves too fast then bump and so on..
// Added just before while loop
DELAY_MS = 1000;
PERIOD_MS = 1000;
i = 1;
currentPage = 0;
I notice the same animation bump if I move the URL loading while loop to OnCreate().
The second time you call animateImages it clears myImages but then doesn't loop because i is not reset so it remains empty. Move creation of that list to onCreate instead to avoid that issue.
Related
I have a soundboard with multiple buttons (approx 17), each linked to a .mp3 sound.
The issue is that when a sound is playing and I press another button, both are then playing in the background.
I would like to be able to stop the playing sound and start the new one when a different button is pressed. Also, is there the ability to stop the current playing sound by pressing on its button again?
Also, I don't really like the section of code that states: private MediaPlayer[] mPlayers = new MediaPlayer[17];
The number (in this case 17), determines the amount of times sounds can be played. After that, no further sounds can be played it seems. Is there a way of making this indefinite?
Rather than paste all of the code from my activity, I have attached the salient code and numbered it in the order in which it appears on my main activity .java file.
Thanks for your help all.
private int mNextPlayer = 0;
2) a.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
v.startAnimation(animAlpha);
startSound(R.raw.likethebattle);
}
});
3) public void onDestroy() {
super.onDestroy(); // <---------------------- This needed to be there
for (int i = 0; i < mPlayers.length; ++i)
if (mPlayers[i] != null)
try {
mPlayers[i].release();
mPlayers[i] = null;
} catch (Exception ex) {
// handle...
}
}
4) private void startSound(int id) {
try {
if (mPlayers[mNextPlayer] != null) {
mPlayers[mNextPlayer].reset();
mPlayers[mNextPlayer].prepare();
mPlayers[mNextPlayer].stop();
mPlayers[mNextPlayer].release();
mPlayers[mNextPlayer] = null;
}
mPlayers[mNextPlayer] = MediaPlayer.create(this, id);
mPlayers[mNextPlayer].start();
} catch (Exception ex) {
// handle
} finally {
++mNextPlayer;
mNextPlayer %= mPlayers.length;
}
}
It looks like you are not stoping currently playing MediaPlayer. startSound(id) does not stop currently playing sound. In
finally {
++mNextPlayer;
mNextPlayer %= mPlayers.length;
}
you move you counter to next player in array and next time you enter startSound() method your counter does not point to previously started player so it can not stop it.
i am trying to make a button that when its clicked , it changes its color image and starts a countdowntimer in a method activeDelay() as here:
piscaAutoButton = (Button) rootView.findViewById(R.id.piscaAutoButton);
piscaAutoButton.setOnClickListener(new Button.OnClickListener() {
#Override
public void onClick(final View view) {
if (sessionManager.getPisca()) {
sessionManager.setPisca(false);
trigger = false;
piscaAutoButton.setBackgroundResource(R.drawable.button_bg_round);
} else {
sessionManager.setPisca(true);
piscaAutoButton.setBackgroundResource(R.drawable.button_add_round);
trigger = true;
activeDelay(trigger);
}
here is my activeDelay method:
private boolean activeDelay(boolean trigger) {
while (trigger) { // LOOP WHILE BUTTON IS TRUE CLICKED
int timerDelay = manualControl.getDelayPisca(); //input for timer
//delay manual
new CountDownTimer(timerDelay * 1000, 1000) {
public void onFinish() {
System.out.println("sent");
try {
System.out.println("blink button " + manualControl.getBlinkButton());
if (!manualControl.getBlinkButton().isEmpty()) {
MenuActivity.mOut.write(manualControl.getBlinkButton().getBytes());
}
} catch (IOException e) {
e.printStackTrace();
}
}
public void onTick(long millisUntilFinished) {
}
}.start();
}
return trigger;
}
My problem is that i need the counter keeps going after finished, stopping just when the user clicks again in the button (trigger = false). I am having problems to program that, if someone could help,i know the return inside activeDelay ejects from the method, how can we solve that ,tks
I would suggest you to don't use CountDownTimer(this runs for some specific time period) , instead of this you should use Handler(this run infinitely) . i am sending you handler code.
private Handler handler = new Handler();
//call this when you want to start the timer .
handler.postDelayed(runnable, startTime);
Runnable runnable = new Runnable() {
#Override
public void run() {
// Do here , whatever you want to do(show updated time e.t.c.) .
handler.postDelayed(this, xyz); //xyz is time interval(in your case it is 1000)
}
};
//Stop handler when you want(In your case , when user click the button)
handler.removeCallbacks(runnable);
I am creating a simple click game that spawns enemies on screen and when the user clicks them, they get points and the enemies are destroyed. I do this with making imageboxs visible and invisible when the user clicks on them. They run on a timer and have a constant loop of spawning.
Currently I want to implement a way the user will start to loose health. So I would like to check if the enemy imagebox is visible, if it is, the player will slowly loose health.
I am confused with creating a timer task that can refresh the UI for this job. I want to be able to check the UI constantly if some images are visible or not. I have made a start on this from my own research but the game crashes when loaded if this is implemented.
Timer to refresh UI:
private Timer mTimer1;
private TimerTask mTt1;
private Handler mTimerHandler = new Handler();
public void onStart() {
mTimer1 = new Timer();
mTt1 = new TimerTask() {
public void run() {
mTimerHandler.post(new Runnable() {
public void run() {
//TODO
final TextView health = (TextView) findViewById(R.id.Health);
health.setText("Health: " + health2);
//Enemy ImageViews
final ImageView enemy1 = (ImageView) findViewById(R.id.enemy1);
final ImageView enemy2 = (ImageView) findViewById(R.id.enemy2);
final ImageView enemy3 = (ImageView) findViewById(R.id.enemy3);
final ImageView enemy4 = (ImageView) findViewById(R.id.enemy4);
//sets imageViews into array
final ImageView[] enemies = new ImageView[4];
enemies[0] = enemy1;
enemies[1] = enemy2;
enemies[2] = enemy3;
enemies[3] = enemy4;
boolean running = true;
while (running) {
if (enemy1.getVisibility() == View.VISIBLE) {
int damage = 1;
health2 = health2 - damage;
health.setText("Health:" + health2);
} else {
// Either gone or invisible
}
if (enemy2.getVisibility() == View.VISIBLE) {
int damage = 1;
health2 = health2 - damage;
health.setText("Health:" + health2);
} else {
// Either gone or invisible
}
if (enemy3.getVisibility() == View.VISIBLE) {
int damage = 1;
health2 = health2 - damage;
health.setText("Health:" + health2);
} else {
// Either gone or invisible
}
if (enemy4.getVisibility() == View.VISIBLE) {
int damage = 1;
health2 = health2 - damage;
health.setText("Health:" + health2);
} else {
// Either gone or invisible
}
}
}
});
}
};
mTimer1.schedule(mTt1, 1, 5000);
}
}
This is the timer task I have created. I would like some clarity to why this crashes my game and how to fix this issue. I have never used timer in this way before so if the problem is obvious that is why I have not noticed it.
I have a lot more code inside the onCreate method and can post if needed. Thank you for all the help and advice for this begineer.
Crash:
Based on the error message you need to call super.onStart()
so you need to add that here:
public void onStart() {
super.onStart();
//your code
}
I assume you know, but just in case super is class you extend, the parent. if you override it's onStart function the normal onStart procedure isn't done, if you don't call the super function.
EDIT: as for your other question, i (as a beginner with java, so i'm not claiming this is the best way to go) would be thinking along the lines of doing something like:
First create a handler and make runnables for the enemies:
Handler handler = new Handler();
Runnable[] eRunnables = new Runnable[enemies.length-1];
for(int i = 0; i < eRunnables.length; i++){
eRunnables[i] = new Runnable(){
public void run(){
if(enemies[i].getVisibility() == View.VISIBLE){
health2--;
health.setText("Health:" + health2);
handler.postDelayed(eRunnables[i], 1000);
}
}
};
}
And then where you initially make the enemies visible (besides setting them to visible) do something like
handler.postDelayed(eRunnable[enemyNr], 1000);
ofcourse replace the 1000 with however many milliseconds you want.
Again i'm not saying this is the best way, just what i thought up.
I have a major problem about changing the value from a constructor
This is an app for flashlights. It will connect to a site to check the interval value (ex. 500 ms) and it will store it to an variable named frum_timer every 2 seconds.
Here's a object for that.
(also it will update a boolean if there's a new value)
FlashActivity = new CountDownTimer(40000, frum_timer) {
#Override
public void onTick(long millisUntilFinished) {
stats_of_run = true;
if (bool) {
final_form.setText("\\Flash ON//");
// CAMERA INSTRUCTIONS FOR OPENING FLASH
bool = false;
frumtimer_stats.setText("Speed:" + frum_timer);
} else {
stats_of_run = true;
final_form.setText("->Flash OFF-<");
// CAMERA INSTRUCTIONS FOR CLOSING FLASH
bool = true;
}
}
#Override
public void onFinish() {
}
}.start();
I made another CountDownTimer object with a refresh rate of 200 seconds to make sure the frum_timer from FlashActivity object will take change.
and using this
frumtimer_stats.setText("Speed:" + frum_timer);
in FlashActivity for displaying the variable.
However, after the variable frum_timer is changed, the FlashLight keep going again and again at the same old speed even if a made an FlashActivity.cancel() followed by FlashActivity.start()
Can someone give me some help?
Full link of code:
https://mycodestock.com/public/snippet/14395
Summary:
1.You start the app.
2. Refresh countdown starts in 2 sec
3. When there is a frum_timer the FlashActivity will start. After 2 sec, if there is another value stored on frum_timer, the actual FlashActivity will be canceled and will start a new one.
4.The problem is the new FlashActivity start but with the old frum_timer
I used:
public void startProgress(View view) {
// do something long
Runnable runnable = new Runnable() {
#Override
public void run() {
for (int i = 0; i <= 20; i++) {
final int value = i;
doFakeWork();
progress.post(new Runnable() {
#Override
public void run() {
// text.setText("Updating");
progress.setMax(20);
progress.setProgress(value);
}
});
}
}
};
new Thread(runnable).start();
}
private void doFakeWork() {
try {
Thread.sleep(800);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
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.