This is the first time I am posting something on StackOverflow and that it only because I felt like this is one of those times I was not able to find what I needed from the vast Internet!
I am currently making an Android Application that is a game where I have an ball that is an imageview and each time I click on the ball, it moves to a random location with this method I've built:
private void changePos() {
RelativeLayout gameLayout = findViewById(R.id.gameFrame);
int frameHeight = gameLayout.getHeight();
int frameWidth = gameLayout.getWidth();
Random ballLocationY = new Random();
int ballY = ballLocationY.nextInt(frameHeight);
Random ballLocationX = new Random();
int ballX = ballLocationX.nextInt(frameWidth);
gameLayout.setY(ballY);
gameLayout.setX(ballX);
}
So what I am struggling with is to reduce the timer with each click.
What I am trying to do is to reduce the timer with each click on the ball by a certain percentage.
Basically each time the user clicks on the ball, the timer starts off from 0 and counting upwards in seconds and milliseconds, and at 3 second mark the game is over.
This is the approach I am playing around with:
Runnable updateThreadTimer = new Runnable() {
#Override
public void run() {
timeInMilliseconds = System.Clock.uptimeMillis() - startTime();
updateTime = timeSwapBuff + timeInMilliseconds;
int secs = (int) (updateTime / 1000);
countDownText.setText("" + String.format("%2d", secs) + ":"
+ String.format("%3d", timeInMilliseconds));
mHandler.postDelayed(this, 0);
if (secs == 3 && timeInMilliseconds >= 3000) {
timeSwapBuff += timeInMilliseconds;
mHandler.removeCallbacks(updateThreadTimer);
}
}
}
Variables necessary:
long startTime = 0L, timeInMilliseconds = 0L, timeSwapBuff = 0L, updateTime = 0L;
Handler mHandler = new Handler();
And then I have this in the Overridden onCreate method:
ball.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View view, MotionEvent motionEvent) {
if (motionEvent.getAction() == MotionEvent.ACTION_DOWN) {
changePos();
startTime = SystemClock.uptimeMillis();
mHandler.postDelayed(updateThreadTimer, 0);
}
return true;
}
}
So what I get is a timer that gets reset to 0 with each click on the button and starts again. And the timer displays in seconds and milliseconds: 0:0000, which is what I wanted, but I wanna reduce a certain percentage with each click and update the time.
So let's say the counter starts with 3 seconds limit, after clicking on the ball couple of times, the timer should eventually come down and the game should fail if the timer goes above that time.
Obviously I have simplified the code quite a lot to get straight to the point.
I was wondering if anyone has any suggestions on how I could approach the problem I have.
I also want to apologize if the question is not asked properly, being the first time posting, leave suggestions if theres any hatin' going on!
And I also want to mention it one more time, I've looked around for a solution like this, and the code I have put together is from lots of different sources, so I feel like I've done my research, and not being able to find something, hence I am turning to StackOverflow!
So I guess I am going to answer my own question as I have solved it now and also in hope that this may solve problems for some.
I redid some parts of the code and scratched the Runnable way, instead I took an approach that uses CountDownTimer class.
private long currentTime;
private long maxTimer = 3000;
private double fivePercent = .05;
private CountDownTimer myTimer = null;
protected void onCreate(Bundle savedInstanceState) {
// Some code...
// Assign 3000 to currentTime
currentTime = maxTimer;
ball.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View view, MotionEvent motionEvent) {
if (motionEvent.getAction() == MotionEvent.ACTION_DOWN) {
if (myTimer != null) {
// Cancel timer
myTimer.cancel();
// Calculating 5 % from maxTimer
long a = (long) (maxTimer * fivePercent);
maxTimer -= a;
// Storing new maxTimer in currentTime
currentTime = maxTimer;
}
myTimer = new CountDownTimer(currentTime, 1) {
#Override
public void onTick(long millisUntilFinished) {
countDownText.setText("Time: " + String.valueOf(millisUntilFinished));
currentTime = millisUntilFinished;
}
#Override
public void onFinish() {
Intent intent = new Intent(getApplicationContext(), ResultsActivity.class);
GameActivity.this.startActivity(intent);
}
}.start();
changePos();
scoreLabel.setText("Score: " + score++ + "");
}
return true;
}
});
}
I have simplified the code for demonstration purpose, but basically what I did was to create a CountDownTimer, and whenever I click on the ball, the CountDownTimer will get cancelled, and invoke a new one, before creating a new CountDownTimer it will calculate off 5 % and put the result into the new CountDownTimer.
Related
I'm looking for some solution which will be faster than mine. I get a time difference between current time and my saved, next step is to put the time in TextView. This solution works but it makes my app very slowly. Does anyone know faster solution?
Thread counter = new Thread(){
public void run()
{
long saved
long difference;
while(true)
{
saved = Long.parseLong(getString(c, "0", "saved"));// sharedPreferences
difference = System.currentTimeMillis() - saved;
seconds = (int) (difference / 1000) % 60;
difference-=seconds;
minutes= (int)((difference/ 60000 ) % 60);
difference=minutes;
hours = (int) ((difference/ 3600000) % 24);
days = (int) ((difference/86400000) % 30);
difference-=days;
months= (int) ((difference/2592000)/1000);
runOnUiThread(new Runnable() {
#Override
public void run() {
myTextView5.setText(Integer.toString(seconds));
myTextView4.setText(Integer.toString(minutes));
myTextView3.setText(Integer.toString(hours));
myTextView2.setText(Integer.toString(days));
myTextView1.setText(Integer.toString(months));
}
});
Your precision is 1s - so you can Thread.sleep (1000) in the while without missing a beat.
I would recommend the use of JodaTime library.
DateTime saved = //getSaved;
DateTime diff = DateTime.now().minus(saved);
//update TextView
txtView.setText(diff.getSecondsOfMinute().toString());
According to my understanding you are using runOnUiThread that created temporary shortlife objects that is the main reason your code is running slow because in each iteration it does it created a new instance of Runnable class and then updates your UI.
Read this topic to get a good understanding of Communication with Ui Thread
http://developer.android.com/training/multiple-threads/communicate-ui.html
You can use Handlers to overcome this issue all you need to do is pass message to handler and it will do the job for you.
This is how you do it.
First of all create a custom handler class
public class CustomMessageHandler extends Handler {
private IUpdateAudioProgressListView iUpdateRef;
public void setOnProgressUpdatedListner(IUpdateAudioProgressListView ref) {
this.iUpdateRef = ref;
}
#Override
public void handleMessage(Message msg) {
// TODO Auto-generated method stub
super.handleMessage(msg);
YOUR HANDLING CODE HERE ......................
}
}
then in order to send message to UI thread from a custom thread you need to do following things
initialize a class level variable in your thread class like
public class Test {
CustomMessageHandler handler;
public Test() {
handler = new CustomMessageHandler();
Thread counter = new Thread() {
public void run() {
long saved
long difference;
while (true) {
saved = Long.parseLong(getString(c, "0", "saved"));// sharedPreferences
difference = System.currentTimeMillis() - saved;
seconds = (int) (difference / 1000) % 60;
difference -= seconds;
minutes = (int) ((difference / 60000) % 60);
difference = minutes;
hours = (int) ((difference / 3600000) % 24);
days = (int) ((difference / 86400000) % 30);
difference -= days;
months = (int) ((difference / 2592000) / 1000);
Message msg = handler.obtainMessage();
msg.obj = // send all your variables via a class or whatever logic you use
handler.sendMessage(msg);
}
}
};
}
}
If you don't want to use an external library, I would suggest the use of java.util.Calendar (Don't forget to import that!). For your solution, every time your value in SharedPreferences is changed, just run the code below.
Code to calc diff
Calendar c = Calendar.getInstance();
c.setTimeInMillis(difference);
int months = c.get(Calendar.MONTH);
int days = c.get(Calendar.DAY_OF_MONTH);
int hours = c.get(Calendar.HOUR_OF_DAY);
int minutes = c.get(Calendar.MINUTE);
int seconds = c.get(Calendar.SECOND);
myTextView5.setText(Integer.toString(seconds));
myTextView4.setText(Integer.toString(minutes));
myTextView3.setText(Integer.toString(hours));
myTextView2.setText(Integer.toString(days));
myTextView1.setText(Integer.toString(months));
Detect change in preferences
public class MyPreferences extends PreferenceActivity implements SharedPreferences.OnSharedPreferenceChangeListener {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.preferences);
PreferenceManager.getDefaultSharedPreferences(this).registerOnSharedPreferenceChangeListener(this);
}
#Override
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
// handle the preference change here
}
}
I am new to Android and Java and I have been trying to solve an issue on timers.Please help
I have an App where the user can create multiple countdown timers and multiple stopwatches.
Example code of countdown timer is given below .(Stop watch is also implemented in a similar fashion using handler). I want the timers and stopwatches to run in the background even when the user leaves the app.And the current state of timers should be shown when the user comes back to the app again,rather than showing the initial state.
The problem is my timers and stopwatches are running when I leave the app,but the results are not published into the UI when the user comes back to the app. A new instance is created and the fresh timers with 00:00:00 are shown again,while the old timers keep running in the background and goes on without being able to stop.Also in the following code I have a listener which publishes the result into the UI in its callback.This interface is implemented in my activity. So can anyone please suggest a solution for this ?
public class CountDownTimerService {
public interface CounterTimeChangeListener {
public void onCounterTimeChange(String time,Boolean counterFinished);
}
CounterTimeChangeListener listener;
MyCountDownTimer myCountDownTimer;
String output;
int length;
long startTime = 0;
long currentTime = 0;
long timeElapsed = 0;
long timeRemaining = 0;
long prevTimeRemaining = 0;
public CountDownTimerService(int countDownFutureTime)
{
myCountDownTimer= new MyCountDownTimer(countDownFutureTime,1000);
length=countDownFutureTime;
}
// code for countdown timer
// this function format the time to hours seconds and minutes format
public String formatTime(long mills)
{
output = "";
long seconds = mills / 1000;
long minutes = seconds / 60;
long hours = minutes / 60;
seconds = seconds % 60;
minutes = minutes % 60;
hours = hours % 60;
String secondsD = String.valueOf(seconds);
String minutesD = String.valueOf(minutes);
String hoursD = String.valueOf(hours);
if (seconds < 10)
secondsD = "0" + seconds;
if (minutes < 10)
minutesD = "0" + minutes;
if (hours < 10)
hoursD = "0" + hours;
output = hoursD +":" +minutesD +":"+ secondsD;
return output;
}
// this function is called on start button click
public void CountDownControl(int state) {
if(state==0)
{
startTime = System.currentTimeMillis();
myCountDownTimer.start();
}
else if(state==1)
{
// when the pause is clicked
myCountDownTimer.cancel();
currentTime = System.currentTimeMillis();
timeElapsed = currentTime - startTime;
if (prevTimeRemaining == 0)
timeRemaining = length - timeElapsed;
else
timeRemaining = prevTimeRemaining - timeElapsed;
prevTimeRemaining = timeRemaining;
myCountDownTimer= new MyCountDownTimer(timeRemaining,1000);
if (listener!=null) {
listener.onCounterTimeChange(formatTime(timeRemaining), false);
}
}
}
// this function is called on reset button click
public void resetInitial()
{
prevTimeRemaining = 0;
myCountDownTimer.cancel();
if (listener!=null) {
listener.onCounterTimeChange(formatTime(length),false);
}
myCountDownTimer= new MyCountDownTimer(length,1000);
}
public class MyCountDownTimer extends CountDownTimer {
public MyCountDownTimer(long millisInFuture, long countDownInterval) {
super(millisInFuture, countDownInterval);
}
public void onTick (long millisUntilFinished) {
// calls the fragment's callback function passing the time value
Log.e("in counter","1");
if (listener!=null) {
Log.e("in counter","2");
listener.onCounterTimeChange(formatTime(millisUntilFinished), false);
}
}
public void onFinish() {
/*
* write code for an alarm when timer times out
*
* */
prevTimeRemaining = 0;
if (listener!=null) {
listener.onCounterTimeChange(formatTime(length),true);
}
myCountDownTimer= new MyCountDownTimer(length,1000);
}
}
public void setCounterTimeChangeListener(CounterTimeChangeListener listener) {
this.listener = listener;
}
}
I'm trying to make a count down time loop.
I want it to make it loop till "int x" reaches 100.
I've tried adding a do/while and a for loop but I think I'm doing it wrong.
Any suggestions?
Thanks for looking. :-) `
public class MainActivity extends Activity{
Button buttonStartTime;
// clicking this button will start time count down
TextView textViewShowTime; // will show the time
TextView shots;
CountDownTimer countDownTimer; // built in android class CountDownTimer
long totalTimeCountInMilliseconds; // total count down time in milliseconds
long timeBlinkInMilliseconds; // start time of start blinking
boolean blink; // controls the blinking .. on and off
static int x = 3;
int whole = 100;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
getReferenceOfViews (); // get all views
setActionListeners (); // set action listerns
totalTimeCountInMilliseconds = 60 * 1000; // time count for 3 minutes = 180 seconds
timeBlinkInMilliseconds = 10 * 1000; // blink starts at 1 minutes = 60 seconds
}
private void setActionListeners() {
buttonStartTime.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
textViewShowTime.setTextAppearance(getApplicationContext(), R.style.normalText);
countDownTimer = new CountDownTimer(totalTimeCountInMilliseconds, 500) {
// 500 means, onTick function will be called at every 500 milliseconds
#Override
public void onTick(long leftTimeInMilliseconds) {
long seconds = leftTimeInMilliseconds / 1000;
if ( leftTimeInMilliseconds < timeBlinkInMilliseconds ) {
textViewShowTime.setTextAppearance(getApplicationContext(), R.style.blinkText);
// change the style of the textview .. giving a red alert style
if ( blink ) {
textViewShowTime.setVisibility(View.VISIBLE);
// if blink is true, textview will be visible
} else {
textViewShowTime.setVisibility(View.INVISIBLE);
}
blink = !blink; // toggle the value of blink
}
textViewShowTime.setText(String.format("%02d", seconds / 60) + ":" + String.format("%02d", seconds % 60));
// format the textview to show the easily readable format
}
#Override
public void onFinish() {
x++;
// this function will be called when the timecount is finished
textViewShowTime.setText("SHOT!!!");
textViewShowTime.setVisibility(View.VISIBLE);
}
}
.start();
}
});
}
private void getReferenceOfViews() {
buttonStartTime = (Button) findViewById(R.id.btnStartTime);
textViewShowTime = (TextView) findViewById(R.id.tvTimeCount);
}
}`
totalTimeCountInMilliseconds =1000 * 1000; // time count for 3 minutes = 180 seconds
timeBlinkInMilliseconds = 10 * 1000; // blink starts at 1 minutes = 60 seconds
new CountDownTimer(totalTimeCountInMilliseconds , timeBlinkInMilliseconds )
above will call onTick 100 times
I am trying to get a ValueAnimator to repeat once it has ended. I am using it with a SeekBar in a ListView. For some reason, the ValueAnimator will finish, trigger the onAnimationEnd() go again, but then when it reaches the end the onAnimationEnd() is never called a second time.
#Override
public View getContentView(int position, View convertView, ViewGroup parent) {
...
setupTimerBar(t);
...
}
private AnimatorListenerAdapter generateNewAnimatorListenerAdapter(final TylersContainer t) {
return new AnimatorListenerAdapter() {
#Override
public void onAnimationEnd(Animator animation) {
setupTimerBar(t);
}
};
}
private void setupTimerBar(TylersContainer t)
{
View view = t.getView();
BusTime arrivalTime = t.getBusTime();
int minutes = BusTime.differenceInMiuntes(arrivalTime, BusTime.now());
long milliseconds = minutes * 60 * 1000;
final TimerBar seekBar = (TimerBar) view.findViewById(R.id.SeekBar);
int progress = Utility.setProgress(arrivalTime, seekBar.getMax());
long duration = Utility.setAnimationDuration(progress);
seekBar.setProgress(progress);
seekBar.setAnimationDuration(duration);
seekBar.setAnimationStartDelay(milliseconds);
seekBar.setAnimatorListenerAdapter(generateNewAnimatorListenerAdapter(t));
}
The seekBar object is actually an custom object which contains a SeekBar and a ValueAnimator, here are the relevant bits:
//Constructor
public TimerBar(Context context) {
super(context);
startTime = Calendar.getInstance();
valueAnimator = ValueAnimator.ofInt(0, getMax());
//Override the update to set this object progress to the animation's value
valueAnimator.addUpdateListener(new AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(ValueAnimator animation) {
int animProgress = (Integer) animation.getAnimatedValue();
setProgress(animProgress);
}
});
}
//Specify the start time by passing a long, representing the delay in milliseconds
public void setAnimationStartDelay(long milliseconds){
//Set the delay (if need be) and start the counter
if(milliseconds > 0)
valueAnimator.setStartDelay(milliseconds);
valueAnimator.setIntValues(this.getProgress(), this.getMax());
valueAnimator.start();
}
//Set the duration of the animation
public void setAnimationDuration(long duration){
valueAnimator.setDuration(duration);
}
public void setAnimatorListenerAdapter(AnimatorListenerAdapter ala){
valueAnimator.addListener(ala);
}
I can't figure out why it isn't repeating more than twice.
I've tried using the Repeat attribute and setting that to INIFINITI but that didn't help either.
Edit: To be clear, what I am trying to get is an animation that repeats itself indefinitely, each time with a different duration.
I have made the error of setting the RepeatMode to infinite which did not work, this must be set as the RepeatCount:
valueAnimator.setRepeatCount(ValueAnimator.INFINITE);
In case you are using Animator, and then bind it with Animator.AnimatorListener
The function AnimatorListener.onAnimationEnd() is used in case your animation repeats for finite times, and is only called once
In case your animation is repeating, for number of times, you should be using the function AnimatorListener.onAnimationRepeat() instead, which will apply everytime your animation repeats after the end of each repeatance
From what I understand, what you need is onAnimationRepeat(), so if you just move the code that you want to be executed after each repeat from onAnimationEnd() to onAnimationRepeat(), this should fix it
Reference: http://developer.android.com/reference/android/animation/Animator.AnimatorListener.html
I am new to android and I need help.
I want my image which is falling from the top of screen to get invisible when I click a button on the keyboard which has the same tag as the image. Although I have implemented the above points a problem arises when I want to show the next animation again immediately after the previous image gets invisible. This is my code for animation.
public void startAnimation(final ImageView aniView)
{
animator= ValueAnimator.ofFloat(0 ,.85f);
animator.setDuration(Constants.ANIM_DURATION);
animator.setInterpolator(null);
//generation of random values
Random rand = new Random();
index = rand.nextInt((int) metrics.widthPixels);
//for debugging
i = Integer.toString(index);
Log.e(" index is :", i);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener()
{
#Override
public void onAnimationUpdate(ValueAnimator animation)
{
float value = ((Float) (animation.getAnimatedValue())).floatValue();
aniView.setTranslationX(index);
aniView.setTranslationY((height+ (50*mScale))*value);
//aniView.setTranslationY(height);
}
});
animator.start();
}
//keyboard methods goes here
#Override
public void onClick(View v)
{
gettext(v);
}
private void gettext(View v)
{
try
{
String b = "";
b = (String) v.getTag();
String img_val = map.get(b);
int imgid = (Integer) imageView.getTag();
Log.e("img values=:", img_val+" "+imgid);
if(img_val.equals(ALPHABETS[imgid]))
{
imageView.setVisibility(View.INVISIBLE);
animator.start();
//trying to start the animation again
}
I am using the animation.addupdateListener to call the animation again and again but it only calls when the .ofFloat finishes on the value. When I click on the appropriate button the animation gets invisible but the next animation starts again after the same time. I want to start it immediately.
Basically calling start() again won't work. you need to "reset" the animation somehow, did you try calling end() before ?
animator.end();
animator.start();