Retrieving TextView.getText() to set a CountDownTimer with a Start Button - java

I am in the dawn of my Android programming adventure and have just become able to communicate between on-screen views. So the next step for me is to successfully pull text from a TextView (set by a Dialog) and use a Start Button to run a Timer based on the user selected Dialog (default to the current minute value of the clock).
Here is what you see on screen.
A TextView that displays the selection from the Dialog.
A Selector Button that launches the Dialog TimePicker Dialog and resets the Start Button.
A Start Button that (should) read the TextView, disable itself, and begin a CountDownTimer based on a Long extracted from the TextView string.
A debug TextView that displays to me what is actually seen by the system.
The entire activity consists of a single Java File with two Classes declared and of course an XML. Every time I click my start button, despite the Debug TextView showing that I properly extracted the Long value for the seconds the timer instantly completes. I can see from my debug TextView that when I select say.. 08:26, the pSecondsLeft=26 as it should.. but the timer still doesn't count down from 26. I can't see my mistake.
Here is the XML first.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:orientation="vertical">
<TextView android:id="#+id/timeDisplay"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:text="Time will appear here after being selected"
android:textSize="30sp"/>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal">
<Button android:id="#+id/pickTime"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="Change the time"/>
<Button android:id="#+id/startTimer"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="Start the time"
/>
</LinearLayout>
<TextView android:id="#+id/timeRemaining"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:layout_gravity="center_horizontal"
android:textSize="30sp"
android:text="Time Remaining"
/>
</LinearLayout>
And here is my Main Activity.
package com.stembo.android.botskooltimepickertutorial;
import java.util.Calendar;
import java.util.StringTokenizer;
import android.app.Activity;
import android.app.Dialog;
import android.app.TimePickerDialog;
import android.os.Bundle;
import android.os.CountDownTimer;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.widget.TimePicker;
import android.widget.Toast;
public class TimePickerActivity extends Activity {
/** Private members of the class */
private TextView displayTime;
private Button pickTime;
private Button startTimer;
private TextView timeRemaining;
private int pMinutesLeft;
private int pSecondsLeft;
/** This integer will uniquely define the
* dialog to be used for displaying time picker.*/
static final int TIME_DIALOG_ID = 0;
/** Callback received when the user "picks" a time in the dialog */
private TimePickerDialog.OnTimeSetListener mTimeSetListener =
new TimePickerDialog.OnTimeSetListener() {
public void onTimeSet(TimePicker view, int minLeft, int secLeft) {
pMinutesLeft = minLeft;
pSecondsLeft = secLeft;
updateDisplay();
displayToast();
}
};
/** Updates the time in the TextView */
private void updateDisplay() {
displayTime.setText(
new StringBuilder()
.append(pad(pMinutesLeft)).append(":")
.append(pad(pSecondsLeft)));
}
/** Displays a notification when the time is updated */
private void displayToast() {
Toast.makeText(this, new StringBuilder().append("Time choosen is ")
.append(displayTime.getText()), Toast.LENGTH_SHORT).show();
}
/** Add padding to numbers less than ten */
private static String pad(int c) {
if (c >= 10)
return String.valueOf(c);
else
return "0" + String.valueOf(c);
}
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
/** Capture our View elements */
displayTime = (TextView) findViewById(R.id.timeDisplay);
pickTime = (Button) findViewById(R.id.pickTime);
startTimer = (Button) findViewById(R.id.startTimer);
timeRemaining = (TextView) findViewById(R.id.timeRemaining);
/** Listener for click event of the pick button */
pickTime.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
startTimer.setEnabled(true);
showDialog(TIME_DIALOG_ID);
}
});
/**Listener for click event of the start button */
startTimer.setOnClickListener(new View.OnClickListener(){
public void onClick(View v){
startTimer.setEnabled(false);
StringTokenizer st = new StringTokenizer(displayTime.getText().toString(), ":");
while (st.hasMoreElements()){
st.nextElement();
long pSecondsTimer = Long.parseLong(st.nextToken());
}
timeRemaining.setText(displayTime.getText()+" Token="+ pSecondsLeft);
long oneSecondInterval = 1000;
MyCount counter = new MyCount(pSecondsLeft, oneSecondInterval);
counter.start();
}
});
/** Get the current time */
final Calendar cal = Calendar.getInstance();
pMinutesLeft = cal.get(Calendar.HOUR_OF_DAY);
pSecondsLeft = cal.get(Calendar.MINUTE);
/** Display the current time in the TextView */
updateDisplay();
}
/** Create a new dialog for time picker */
#Override
protected Dialog onCreateDialog(int id) {
switch (id) {
case TIME_DIALOG_ID:
return new TimePickerDialog(this,
mTimeSetListener, pMinutesLeft, pSecondsLeft, true);
}
return null;
}
public class MyCount extends CountDownTimer {
public MyCount(long pSecondsLeft, long countDownInterval){
super(pSecondsLeft, countDownInterval);
}
#Override
public void onTick(long pSecondsTimer){
displayTime.setText("Time remaining: " + pSecondsLeft);
}
#Override
public void onFinish(){
displayTime.setText("Countdown Complete!");
}
}
}
Here is the Start Button code which I am having trouble with, its in the Main Activity but may be easier to see excluded.
/**Listener for click event of the start button */
startTimer.setOnClickListener(new View.OnClickListener(){
public void onClick(View v){
startTimer.setEnabled(false);
StringTokenizer st = new StringTokenizer(displayTime.getText().toString(), ":");
while (st.hasMoreElements()){
st.nextElement();
long pSecondsTimer = Long.parseLong(st.nextToken());
}
timeRemaining.setText(displayTime.getText()+" Token="+ pSecondsLeft);
long oneSecondInterval = 1000;
MyCount counter = new MyCount(pSecondsLeft, oneSecondInterval);
counter.start();
}
});

It appears there is a misunderstanding about the values you get back from TimePickerDialog.OnTimeSetListener. It gives you hours and minutes, but you're expecting minutes and seconds. Same for the values coming out of the Calendar you're using on onCreate.
That said, if you are still trying to use a TimePickerDialog to get minutes and seconds with a full understanding that you're reinterpreting the values, you will need to multiply the number of "seconds" you receive from the picker by 1000 to get a unit in milliseconds that you can feed to the CountDownTimer.
MyCount counter = new MyCount(pSecondsLeft * 1000, oneSecondInterval);

I think it's because you're not subtracting from the pSecondsLeft variable on each tick
public class MyCount extends CountDownTimer {
public MyCount(long pSecondsLeft, long countDownInterval){
super(pSecondsLeft, countDownInterval);
}
#Override
public void onTick(long pSecondsTimer){
displayTime.setText("Time remaining: " + pSecondsLeft);
pSecondsLeft --;
}
#Override
public void onFinish(){
displayTime.setText("Countdown Complete!");
}
}

Related

Transition between decimal or double numbers

Imagine a number 10, then after user clicks a button it changes to 100. But how to make an efficient transition
10 -> 100,
that will display values like
12, 15, 18, ..., 97, 100 over 1 second.
I've seen something like that in "Cookie clicker" but couldn't find anything about that kind of transition in the source code.
I had an idea of a loop (for number1 < number2, do number1++), it will work fine for small numbers, but if 10 changes to 1 billion, then the loop will probably freeze the whole app.
Second idea is to get added value (100-10=90) and divide by 30 or 60 frames, and add this value with each frame. But what will happen if frame is dropped? - Probably value will not be added. What if user makes double click or the system adds values automatically?
Hope it gives an idea of what kind of number transition I need.
Maybe I overlooked and there is a simple approach? Any help is appreciated.
Hope this little demo using a ValueAnimator will inspire you to find an appropriate solution.
You can specify the duration of the animation (see code) and even adjust the frame-rate by saying mAnimator.setFrameDelay(frameDelay);.
By using animator.isRunning() or animator.isStarted() you can prevent double-click malfunction or other unwanted behaviour while the current animation is runnning.
The Main Activity:
/** ValueAnimator demo */
public class MainActivity extends Activity {
ValueAnimator mAnimator;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final TextView tv = (TextView) findViewById(R.id.textview);
mAnimator = ValueAnimator.ofInt(1, 100).setDuration(1000);
mAnimator.setInterpolator(new AccelerateDecelerateInterpolator());
mAnimator.addUpdateListener(new AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(final ValueAnimator animator) {
final Integer value = (Integer) animator.getAnimatedValue();
tv.setText(String.format("%04d", value));
}
});
mAnimator.addListener(new AnimatorListenerAdapter() {
#Override
public void onAnimationEnd(Animator animator) {
super.onAnimationEnd(animator);
final int endValue = Integer.parseInt((String) tv.getText());
mAnimator.setIntValues(endValue, endValue + 100);
}
});
}
/** Button callback */
public void onClick(final View view) {
if (!mAnimator.isStarted() && !mAnimator.isRunning()) {
mAnimator.start();
}
}
}
Simple demo layout:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<TextView
android:id="#+id/textview"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="25sp"
android:typeface="monospace"
android:text="0001" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Gimme +100"
android:onClick="onClick">
</Button>
Here's another demo (hope this answers your 2. question), which implements different behaviour dependent on single click or double-click on the button. Just experiment with it, you now have the basic building blocks to construct own behavour ...
/** ValueAnimator demo */
public class MainActivity extends Activity {
ValueAnimator mAnimator;
TextView mTv;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mTv = (TextView) findViewById(R.id.textview);
mAnimator = ValueAnimator.ofInt(1, 100).setDuration(1000);
mAnimator.setInterpolator(new AccelerateDecelerateInterpolator());
mAnimator.addUpdateListener(new AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(final ValueAnimator animator) {
final Integer value = (Integer) animator.getAnimatedValue();
mTv.setText(String.format("%04d", value));
}
});
final Button button = (Button) findViewById(R.id.button);
final GestureDetector gestureDetector = new GestureDetector(this,
new GestureDetector.SimpleOnGestureListener() {
#Override
public boolean onDoubleTap(MotionEvent e) {
performAnimation(100);
return true;
}
#Override
public boolean onSingleTapConfirmed(MotionEvent e) {
performAnimation(0);
return true;
}
});
button.setOnTouchListener(new OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
return gestureDetector.onTouchEvent(event);
}
});
}
/** starts animation */
private void performAnimation(final int offset) {
if (!mAnimator.isStarted() && !mAnimator.isRunning()) {
final int endValue = Integer.parseInt((String) mTv.getText());
mAnimator.setIntValues(endValue + offset, endValue + 100 + offset);
mAnimator.start();
}
}
}
Don't forget to replace your layout file, since the click-attribute of the button has been removed:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<TextView
android:id="#+id/textview"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="25sp"
android:typeface="monospace"
android:text="0001" />
<Button
android:id="#+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Gimme +100" >
</Button>
</LinearLayout>
I guess you can do it by using different threads. Only main thread works with UI so you can divide the interval into small intervals and make a transitions in different threads.After send them to main thread and print. Hope it will help.

Java/Android - Hide a link as text

Hey guys I have been trying to figure this out and have looked over a number of questions here but can't seem to find the answer to my problem. I am making an app that displays dinners at random from an array. I would like these dinners to be clickable and take the user to a web page but I have no idea how to make that happen so at the moment I have just added the link below the dinner which looks pretty ugly.
Here is the class that contains the recipes:
package me.oak.dinnertime;
import java.util.Random;
public class CookBook {
public String[] mfood =
{
"Chicago Deep Dish Pizza \n \n http://www.taste.com.au/recipes/28896/chicago+deep+dish+pizza?ref=collections,pizza-recipes",
"Spaghetti Bolognese \n \n http://www.bbcgoodfood.com/recipes/1502640/the-best-spaghetti-bolognese",
"Bourbon Chicken \n \n http://www.food.com/recipe/bourbon-chicken-45809",
};
public String getFood() {
String food = "";
//Randomly select a dinner
Random randomGenerator = new Random(); //Construct a new Random number generator
int randomNumber = randomGenerator.nextInt(mfood.length);
//Convert random number to text
food = mfood[randomNumber];
return food;
}
}
And here is the main activity:
package me.oak.dinnertime;
import android.app.Activity;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.RelativeLayout;
import android.widget.TextView;
public class DinnerTimeActivity extends Activity {
private CookBook mCookBook = new CookBook();
private ColourWheel mColourWheel = new ColourWheel();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_dinner_time);
final TextView dinnerLabel = (TextView) findViewById(R.id.DinnerTextView);
final Button showDinnerButton = (Button) findViewById(R.id.showDinnerButton);
final RelativeLayout relativelayout = (RelativeLayout) findViewById(R.id.relativeLayout);
View.OnClickListener listener = new View.OnClickListener() {
#Override
public void onClick(View view) {
String food = mCookBook.getFood();
//Update the label with the dinner
dinnerLabel.setText(food);
int colour = mColourWheel.getColour();
relativelayout.setBackgroundColor(colour);
showDinnerButton.setTextColor(colour);
}
};
showDinnerButton.setOnClickListener(listener);
}
}
And here is the XML file:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingLeft="#dimen/activity_horizontal_margin"
android:paddingRight="#dimen/activity_horizontal_margin"
android:paddingTop="#dimen/activity_vertical_margin"
android:paddingBottom="#dimen/activity_vertical_margin" tools:context=".DinnerTimeActivity"
android:background="#ff51b46d"
android:id="#+id/relativeLayout">
<TextView android:text="What&apos;s for dinner?" android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="24sp"
android:textColor="#80ffffff" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/DinnerTextView"
android:layout_centerVertical="true"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:textSize="24sp"
android:textColor="#android:color/white"
android:text="Click the button to find out!"
android:autoLink="web" />
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Dinner Time"
android:id="#+id/showDinnerButton"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:background="#android:color/white"
android:textColor="#ff51b46d" />
</RelativeLayout>
Sorry to give you so much, I just hope someone can help me out.
To use the LinkMovementMethod, try following:
change your array list content from:
Chicago Deep Dish Pizza \n \n http://www.taste.com.au/recipes/28896/chicago+deep+dish+pizza?ref=collections,pizza-recipes
to:
Chicago Deep Dish Pizza
And when set this text to your TextView, do it as:
(Updated: remove the underline and change text color, source: Remove underline from links in TextView - Android)
Spannable s = (Spannable) Html.fromHtml(foodString);
for (URLSpan u: s.getSpans(0, s.length(), URLSpan.class)) {
s.setSpan(new UnderlineSpan() {
public void updateDrawState(TextPaint tp) {
//remove the underline
tp.setUnderlineText(false);
//set text color
tp.setColor(getResources().getColor(R.color.orange));
}
}, s.getSpanStart(u), s.getSpanEnd(u), 0);
}
dinnerLabel.setText(s);
dinnerLabel.setMovementMethod(LinkMovementMethod.getInstance());
Also remove the
android:autoLink="web"
in the xml.
As I have tested, "Chicago Deep Dish Pizza" will appear as a clickable link in the testview.
just use something like this in your string file and refrence it in the textview
<string name="links">Google shalom is a boyGoogle 2 </string>
you can also use this in an array in the strings file
to make it actually work do this
terms = findViewById(R.id.terms);
terms.setMovementMethod(LinkMovementMethod.getInstance());
I answered this on Hackforums for you.
Store the links in a separate array make sure the indexes of the links line up with the location in the other array. So:
public class CookBook {
public String[] mfood =
{
"Chicago Deep Dish Pizza",
"Spaghetti Bolognese",
"Bourbon Chicken",
};
public String[] mLinks =
{
"http://www.taste.com.au/recipes/28896/chicago+deep+dish+pizza?ref=collections,pizza-recipes",
"http://www.bbcgoodfood.com/recipes/1502640/the-best-spaghetti-bolognese",
"http://www.food.com/recipe/bourbon-chicken-45809",
};
public int getRandomFoodIndex() {
//Randomly select a dinner
Random randomGenerator = new Random(); //Construct a new Random number generator
int randomNumber = randomGenerator.nextInt(mfood.length);
//Convert random number to text
return randomNumber;
}
public String getFood(int index) {
return mfood[index];
}
public String getLink(int index) {
return mLinks[index];
}
}
and then
public class DinnerTimeActivity extends Activity {
private CookBook mCookBook = new CookBook();
private ColourWheel mColourWheel = new ColourWheel();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_dinner_time);
final TextView dinnerLabel = (TextView) findViewById(R.id.DinnerTextView);
final Button showDinnerButton = (Button) findViewById(R.id.showDinnerButton);
final RelativeLayout relativelayout = (RelativeLayout) findViewById(R.id.relativeLayout);
View.OnClickListener listener = new View.OnClickListener() {
#Override
public void onClick(View view) {
int index = mCookBook.getRandomFoodIndex();
String food = mCookBook.getFood(index);
String link = mCookBook.getLink(index);
//Update the label with the dinner
dinnerLabel.setText(food);
/** open link with the link variable */
int colour = mColourWheel.getColour();
relativelayout.setBackgroundColor(colour);
showDinnerButton.setTextColor(colour);
}
};
showDinnerButton.setOnClickListener(listener);
}
}

How to set maximum and minimum date for datepicker in android

I am using a tutorial i found on the net for datepicker.But i want to set the maximum and minimum date for the datepicker.Also i have heard that there is an issue for API level less than 11.
My code:
package com.androidexample.datepicker;
import java.util.Calendar;
import android.app.Activity;
import android.app.DatePickerDialog;
import android.app.Dialog;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.DatePicker;
import android.widget.TextView;
public class DatePickerExample extends Activity {
private TextView Output;
private Button changeDate;
private int year;
private int month;
private int day;
static final int DATE_PICKER_ID = 1111;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Output = (TextView) findViewById(R.id.Output);
changeDate = (Button) findViewById(R.id.changeDate);
// Get current date by calender
final Calendar c = Calendar.getInstance();
year = c.get(Calendar.YEAR);
month = c.get(Calendar.MONTH);
day = c.get(Calendar.DAY_OF_MONTH);
// Show current date
Output.setText(new StringBuilder()
// Month is 0 based, just add 1
.append(month + 1).append("-").append(day).append("-")
.append(year).append(" "));
// Button listener to show date picker dialog
changeDate.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
// On button click show datepicker dialog
showDialog(DATE_PICKER_ID);
}
});
}
#Override
protected Dialog onCreateDialog(int id) {
switch (id) {
case DATE_PICKER_ID:
// open datepicker dialog.
// set date picker for current date
// add pickerListener listner to date picker
return new DatePickerDialog(this, pickerListener, year, month,day);
}
return null;
}
private DatePickerDialog.OnDateSetListener pickerListener = new DatePickerDialog.OnDateSetListener() {
// when dialog box is closed, below method will be called.
#Override
public void onDateSet(DatePicker view, int selectedYear,
int selectedMonth, int selectedDay) {
year = selectedYear;
month = selectedMonth;
day = selectedDay;
// Show selected date
Output.setText(new StringBuilder().append(month + 1)
.append("-").append(day).append("-").append(year)
.append(" "));
}
};
}
The xml code:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<Button
android:id="#+id/changeDate"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Click To Change Date" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Current/Selected Date (M-D-YYYY): "
android:textAppearance="?android:attr/textAppearanceLarge" />
<TextView
android:id="#+id/Output"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text=""
android:textAppearance="?android:attr/textAppearanceLarge" />
</LinearLayout>
The problem with the above code is that there is no upper limit on the year part.I also need a lower limit on the year part.Can someone tell me as how to modify the code to set the upper and lower limit on the year part?
In DatePickerDialog.OnDateSetListener() you can compare the month, year , date with your specified min and max dates.
You can obtain DatePicker using DatePickerDialog.
DatePickerDialog dialog = new DatePickerDialog(this, pickerListener, year, month,day);
//calculate min and max dates (you can use, Calender API or Joda Time, just search for it.
dialog.getDatePicker().setMaxDate(maxDate.getTime());
dialog.getDatePicker().setMinDate(minDate.getTime());
return dialog;
You can get the underlying DatePicker from a DatePickerDialog by simply calling getDatePicker() and set its bounds using:
setMinDate(long minDate)
setMaxDate(long maxDate)
This works only for API level 11 and above.

Wrong updating TextView in Android app

I create simple Android app (https://www.linux.com/learn/docs/683628-android-programming-for-beginners-part-1) with latest Android Studio. Code:
public class test_act extends Activity {
private static final int MILLIS_PER_SECOND = 1000;
private static final int SECONDS_TO_COUNTDOWN = 30;
private android.widget.TextView countdownDisplay;
private android.os.CountDownTimer timer;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.full_act);
countdownDisplay = (android.widget.TextView) findViewById(R.id.time_display_box);
android.widget.Button startButton = (android.widget.Button) findViewById(R.id.startbutton);
startButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View view) {
try {
showTimer(SECONDS_TO_COUNTDOWN * MILLIS_PER_SECOND);
} catch (NumberFormatException e) {
// method ignores invalid (non-integer) input and waits
// for something it can use
}
}
});
}
private void showTimer(int countdownMillis) {
if(timer != null) { timer.cancel(); }
timer = new android.os.CountDownTimer(countdownMillis, MILLIS_PER_SECOND) {
#Override
public void onTick(long millisUntilFinished) {
countdownDisplay.setText("counting down: " +
millisUntilFinished / MILLIS_PER_SECOND);
}
#Override
public void onFinish() {
countdownDisplay.setText("KABOOM!");
}
}.start();
}
}
My XML:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<TextView
android:id="#+id/time_display_box"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_centerHorizontal="true"
android:layout_marginTop="60dp"
android:text="#string/_00_30"
android:textAppearance="?android:attr/textAppearanceLarge"/>
<Button
android:id="#+id/startbutton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="#+id/time_display_box"
android:layout_centerHorizontal="true"
android:layout_marginTop="41dp"
android:text="#string/start" />
</RelativeLayout>
In emulator it's good working. But on my Galaxy S2 with CyanogenMod10.1(Android 4.2.2) app wrong updating TextView. Screenshot:
How I can resolve this problem?
upd: after screen rotate TextView is updating once.
You might want to try invalidating your layout every time it is updated. I am guessing with how often the text is being updated the phone is not having enough time to redraw the layout. This would also explain why it works when you rotate your phone, because then the layout is forced to update.
countdownDisplay.invalidate();
Let me know if that does not work.
It commonly happens when you put UI updates inside try blocks, try to avoid it or wrap with runOnUiThread.
EDIT:
Another reason - you update it to fast - you code does 1000 updates per second i dont think it can handle it.

Android App Clicking Button Calls Incorrect OnClick Listener

I uploaded my app yesterday to Google Play and this morning I've wanted to make just a layout tweak as some of the text was overlapping buttons on smaller screens, basically I just want to move the buttons further down the screen. I thought this would be as easy as using eclipse's graphical editor... Nope.
I have no idea why but the small edit I've done to the position of the buttons on my "view_fact" layout has registered the buttons with the wrong OnClick listeners, there's only two buttons on the view and they're using eachothers event listeners and I have no idea why. I didn't touch the event listener code that was working perfectly on the old layout.
Here is my view_fact layout:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<TextView
android:id="#+id/viewFactTitleText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_centerHorizontal="true"
android:layout_marginTop="18dp"
android:text="#string/factTitleText"
android:textSize="22dp"
tools:context=".MainActivity" />
<ImageView
android:id="#+id/randomFactImage"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="#+id/viewFactTitleText"
android:layout_centerHorizontal="true"
android:layout_marginTop="18dp"
android:contentDescription="Fact Image"
android:src="#drawable/canadaflag" />
<TextView
android:id="#+id/factData"
android:layout_width="300dp"
android:layout_height="wrap_content"
android:layout_below="#+id/randomFactImage"
android:layout_centerHorizontal="true"
android:layout_marginTop="14dp"
android:text="TextView" />
<Button
android:id="#+id/anotherFactButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_above="#+id/backToHomeButton"
android:layout_alignLeft="#+id/backToHomeButton"
android:layout_alignRight="#+id/backToHomeButton"
android:text="#string/anotherFactButtonText" />
<Button
android:id="#+id/backToHomeButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignLeft="#+id/factData"
android:layout_alignParentBottom="true"
android:layout_alignRight="#+id/factData"
android:text="#string/backToHomeButtonText" />
</RelativeLayout>
Listener and startup code:
public class MainActivity extends Activity {
/* Declaration of global variables */
private boolean debugMode = true; // Whether debugging is enabled or not
private static String logtag = "CanadianFacts"; // For use as the tag when logging
private TextView factData;
private int totalFacts = 72;
private String[][] facts = new String[totalFacts][5];
private int lastFact = 0;
/* Buttons */
/* Home page */
private Button randomFactButton;
/* View Fact page */
private Button anotherRandomFactButton;
private Button backToHomeButton;
/* About page */
private Button backToHomeFromAboutButton;
/* Image Views */
private ImageView randomFactImage;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
/* Home Page Objects */
randomFactButton = (Button)findViewById(R.id.randomFactButton);
randomFactButton.setOnClickListener(randomFactListener); // Register the onClick listener with the implementation above
/* View Fact Page Objects */
/* Build Up Fact Array */
buildFactArray();
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.menu_about:
loadAboutPage(); // Call the loadAboutPage method
return true;
}
return false;
}
public void loadAboutPage() {
setContentView(R.layout.about);
/* Set up home page button listener */
backToHomeFromAboutButton = (Button)findViewById(R.id.backToHomeFromAboutButton);
backToHomeFromAboutButton.setOnClickListener(backToHomeListener); // We can reuse the backToHomeListener
}
/* Home Page Listeners */
//Create an anonymous implementation of OnClickListener, this needs to be done for each button, a new listener is created with an onClick method
private OnClickListener randomFactListener = new OnClickListener() {
public void onClick(View v) {
if (debugMode) {
Log.d(logtag,"onClick() called - randomFact button");
Toast.makeText(MainActivity.this, "The random fact button was clicked.", Toast.LENGTH_LONG).show();
}
setContentView(R.layout.view_fact); // Load the view fact page
/* We're now on the View Fact page, so elements on the page are now in our scope, instantiate them */
/* Another Random Fact Button */
anotherRandomFactButton = (Button)findViewById(R.id.anotherFactButton);
anotherRandomFactButton.setOnClickListener(anotherRandomFactListener); // Register the onClick listener with the implementation above
/* Back to Home Button */
backToHomeButton = (Button)findViewById(R.id.backToHomeButton);
backToHomeButton.setOnClickListener(backToHomeListener); // Register the onClick listener with the implementation above
// Get a random fact
String[] fact = getRandomFact();
if (fact[2] == null) { // If this fact doesn't have an image associated with it
fact[2] = getRandomImage();
}
int imageID = getDrawable(MainActivity.this, fact[2]);
/* See if this fact has an image available, if it doesn't select a random generic image */
randomFactImage = (ImageView) findViewById(R.id.randomFactImage);
randomFactImage.setImageResource(imageID);
factData = (TextView) findViewById(R.id.factData);
factData.setText(fact[1]);
if (debugMode) {
Log.d(logtag,"onClick() ended - randomFact button");
}
}
};
/* View Fact Page Listeners */
private OnClickListener anotherRandomFactListener = new OnClickListener() {
public void onClick(View v) {
if (debugMode) {
Log.d(logtag,"onClick() called - anotherRandomFact button");
Toast.makeText(MainActivity.this, "The another random fact button was clicked.", Toast.LENGTH_LONG).show();
}
// Get a random fact
String[] fact = getRandomFact();
if (fact[2] == null) { // If this fact doesn't have an image associated with it
fact[2] = getRandomImage();
}
int imageID = getDrawable(MainActivity.this, fact[2]); // Get the ID of the image
/* See if this fact has an image available, if it doesn't select a random generic image */
randomFactImage = (ImageView) findViewById(R.id.randomFactImage);
randomFactImage.setImageResource(imageID);
factData = (TextView) findViewById(R.id.factData);
factData.setText(fact[1]);
if (debugMode) {
Log.d(logtag,"onClick() ended - anotherRandomFact button");
}
}
};
private OnClickListener backToHomeListener = new OnClickListener() {
public void onClick(View v) {
if (debugMode) {
Log.d(logtag,"onClick() called - backToHome button");
Toast.makeText(MainActivity.this, "The back to home button was clicked.", Toast.LENGTH_LONG).show();
}
// Set content view back to the home page
setContentView(R.layout.main); // Load the home page
/* Reinstantiate home page buttons and listeners */
randomFactButton = (Button)findViewById(R.id.randomFactButton);
randomFactButton.setOnClickListener(randomFactListener); // Register the onClick listener with the implementation above
if (debugMode) {
Log.d(logtag,"onClick() ended - backToHome button");
}
}
};
Thank you.
I've managed to fix this, by moving the buttons around, changing the IDs a few times and then changing them back. And removing all of the align settings and resetting it's position.
A very strange problem, probably due to eclipse's graphical editor.

Categories

Resources