How to Pass a Resource Id as a Parameter; without NullPointerException - java

Working on an Android app where each activity has its own timer. Originally I had code like this in every class
public void tTimer() {
mTextField = (TextView) findViewById(R.id.countDown_timer);
final CountDownTimer tCounter = new CountDownTimer(7000, 1000) {
#Override
public void onTick(long millisUntilFinished) {
mTextField
.setText("Time Remaining: "
+ String.format(
"%d min, %d sec",
TimeUnit.MILLISECONDS
.toMinutes(millisUntilFinished),
TimeUnit.MILLISECONDS
.toSeconds(millisUntilFinished)
- TimeUnit.MINUTES
.toSeconds(TimeUnit.MILLISECONDS
.toMinutes(millisUntilFinished))));
}
#Override
public void onFinish() {
mTextField.setText("Done!");
Intent i = new Intent (ColdActivity.this, PopUpActivity.class);
startActivity(i);
}
};
Button startButton = (Button) findViewById(R.id.timer_button_start);
/* When the Start Button is touched, the Countdown Timer will start */
startButton.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
AlertDialog.Builder builder = new AlertDialog.Builder(
ColdActivity.this);
builder.setNegativeButton("Dismiss",
new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface arg0, int arg1) {
tCounter.start();
// Once the user has been notified that they should increase
// their alarm volume, and they dismiss the notification, the timer
// will start
}
});
builder.setTitle("Notification");
builder.setMessage("It is recommended that you turn your Alarm/Ringtone volume on so that you can hear the alarm when it is finished");
AlertDialog dlg = builder.create();
dlg.show();
}
});
Button stopButton = (Button) findViewById(R.id.timer_button_cancel);
/* When the Stop Button is touched, the Countdown Timer will stop */
stopButton.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
tCounter.cancel();
}
});
}
I am now trying to create a new class that has a method called tTimer() like in the above code, so that I can instantiate a new object of that class, and then call the method in onCreate(), that way I don't have to rewrite timer code in every class, like I had previously done.
I tried to parameterize the method like this:
CustomTimerActivity cGT = new CustomTimerActivity();
cGT.tTimer(7000, ColdActivity.this, R.id.countDown_timer, R.id.timer_button_start, R.id.timer_button_cancel);
And what I keep getting is a NullPointerException, which points to my class called CustomTimerActivity
Why am I not able to pass the resource Id's as parameters? Or is the NPE coming from something else?
Here is the CustomTimerActivity I made:
public class CustomTimerActivity extends Activity {
TextView mTextField;
int mId;
public void tTimer(long millisecs, final Activity activity1, int tv, int start, int cancel) {
mTextField = (TextView) findViewById(tv);
final CountDownTimer tCounter = new CountDownTimer(millisecs, 1000) {
#Override
public void onTick(long millisUntilFinished) {
mTextField
.setText("Time Remaining: "
+ String.format(
"%d min, %d sec",
TimeUnit.MILLISECONDS
.toMinutes(millisUntilFinished),
TimeUnit.MILLISECONDS
.toSeconds(millisUntilFinished)
- TimeUnit.MINUTES
.toSeconds(TimeUnit.MILLISECONDS
.toMinutes(millisUntilFinished))));
}
#Override
public void onFinish() {
mTextField.setText("Done!");
Intent i = new Intent (activity1, PopUpActivity.class);
startActivity(i);
}
};
Button startButton = (Button) findViewById(start);
/* When the Start Button is touched, the Countdown Timer will start */
startButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
AlertDialog.Builder builder = new AlertDialog.Builder(
activity1);
builder.setNegativeButton("Dismiss",
new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface arg0, int arg1) {
tCounter.start();
// Once the user has been notified that they should increase
// their alarm volume, and they dismiss the notification, the timer
// will start
}
});
builder.setTitle("Notification");
builder.setMessage("It is recommended that you turn your Alarm/Ringtone volume on so that you can hear the alarm when your tea is finished");
AlertDialog dlg = builder.create();
dlg.show();
}
});
Button stopButton = (Button) findViewById(cancel);
/* When the Stop Button is touched, the Countdown Timer will stop */
stopButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
tCounter.cancel();
}
});
}
}
The issue must be something to do with findViewById() and the Id that is used as input, right?
Here is another NullPointerException I get when the Intent is called.

The Activity has not been initialized in the constructor. Only collect the parameters in the constructor and do the initialization in the onCreate(Bundle) method!
However, if you want to call it from a givin activity, you have to call .findViewById on that class, not on your own class

Related

Intent activity keeps popping

I set a timer to this application, so when the timer ends and boxes in Itemdata are still selected, it should call for Thanks.class activity.
However, I realised that it class the Thanks.class activity multiple times.
E.g. if there are 3 selected items, it calls the Thanks.class activity three times.
This is the timer i've declared
//Declare timer
CountDownTimer cTimer = null;
//start timer function
void startTimer() {
cTimer = new CountDownTimer(10000, 1000) {
public void onTick(long millisUntilFinished) {
}
public void onFinish() {
Intent intent = new Intent(ctx, Thanks.class);
ctx.startActivity(intent);
}
};
cTimer.start();
}
//cancel timer
void cancelTimer() {
if(cTimer!=null)
cTimer.cancel();
}
Here is how I call the function.
#Override
public View getView(final int position, final View view, ViewGroup parent) {
final GridItemData itemData = getItem(position);
inflater = (LayoutInflater) ctx.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
final View itemView = inflater.inflate(R.layout.grid_image, parent, false);
ivGallery = itemView.findViewById(R.id.grid_item_image);
ivGallery.setImageResource(getItem(position).imageUrl);
final MainActivity main = new MainActivity();
itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
ivGallery = itemView.findViewById(R.id.grid_item_image);
itemData.setSelected(!itemData.isSelected());
startTimer();
if(itemData == getItem(8)) {
AlertDialog.Builder builder = new AlertDialog.Builder(v.getContext());
customizeAlert(builder, v);
builder.show();
}
else if (itemData == getItem(0)) {
ivGallery.setImageResource(itemData.isSelected()?R.drawable.clickfloor: R.drawable.floor);
}
else if (itemData == getItem(1)) {
ivGallery.setImageResource(itemData.isSelected()?R.drawable.cb: R.drawable.wb);
}
else if (itemData == getItem(2)) {
ivGallery.setImageResource(itemData.isSelected()?R.drawable.cs: R.drawable.s);
}
else if (itemData == getItem(3)) {
ivGallery.setImageResource(itemData.isSelected()?R.drawable.clickothers: R.drawable.others);
}
}
});
return itemView;
}
Please advice me what to do, thank you!
How about starting that CountDownTimer only once?
void startTimer() {
if(cTimer == null) {
cTimer = new CountDownTimer(10000, 1000) {
public void onTick(long millisUntilFinished) {
}
public void onFinish() {
Intent intent = new Intent(ctx, Thanks.class);
ctx.startActivity(intent);
}
};
cTimer.start();
}
}
Alternatively, just stop the first CountDownTimer, when the second one is about to be started.
Thats because you start a CountdownTimer for each click but you don't check if there is already a CountDownTimer active which needs to be canceled or restarted.
If you expand this to production i would recommend to use AsyncTasks or Courotines for this, because when your CountDownTimer is finished your are maybe no longer allowed to change the UI-State and you will get an IllegalStateException or your findByView will throw a NullPointerException.
With AsyncTasks and Courotines you also don't need to worry about spawning multiple instances of your CountDownTimer.
https://developer.android.com/reference/android/os/AsyncTask

How do I make a Button which restarts a CountdownTimer, when clicked?

I have a function that has a timer that I want to "restart" every time you click the button. I tried doing this but when the button is clicked several times it appears that there are several timers still going on when I only want the one. How do I fix this?
So, onClick => Cancel last timer => Start new timer
public void startService(android.view.View view) {
final SharedPreferences sP = getSharedPreferences("com.example.safetyNet", MODE_PRIVATE);
final Button button = findViewById(R.id.button3);
final Intent transIntent = new Intent(this, CheckPinActivity.class);
CountDownTimer cdt = new CountDownTimer(sP.getInt("TiT", 10) * 1000, 1000) {
#Override
public void onTick(long millisUntilFinished) {
button.setText(String.valueOf(millisUntilFinished).substring(0,2));
}
#Override
public void onFinish() {
if(sP.getBoolean("lockedDown", false) == true){
startActivity(transIntent);
}
}
};
cdt.cancel();
cdt.start();
}
The problem is that, everytime you call the method "startService(android.view.View view) {}", a new CountDownTimer is created, so the previous CountDownTimer that you created is not the same reference as this one.
To solve that, you are going to have to create the CountDownTimer as a class member for your class:
public YourClass {
private CountDownTimer cdt;
.... (do whatever)....
public void startService(android.view.View view) {
final SharedPreferences sP = getSharedPreferences("com.example.safetyNet", MODE_PRIVATE);
final Button button = findViewById(R.id.button3);
final Intent transIntent = new Intent(this, CheckPinActivity.class);
if (cdt == null) {
cdt = new CountDownTimer(sP.getInt("TiT", 10) * 1000, 1000) {
#Override
public void onTick(long millisUntilFinished) {
button.setText(String.valueOf(millisUntilFinished).substring(0,2));
}
#Override
public void onFinish() {
if(sP.getBoolean("lockedDown", false) == true){
startActivity(transIntent);
}
}
};
} else {
cdt.cancel();
}
cdt.start();
}
Hope that helps you

android - countdown with decreasing time

In my game the user gets a point when he clicks a button within five seconds. Now I want the timer to decrease the time with every point the user gets - so e.g. with zero points the user has five seconds, and when he has one point he gets only 4.5 seconds to click it again and get the second point. Do I solve it with a for loop?
public class GameScreen extends Activity {
public int score = 0;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_game);
Button count = (Button) findViewById(R.id.button1);
text = (TextView) this.findViewById(R.id.textView3);
tvscore = (TextView) findViewById(R.id.score);
timer();
}
public void gameover() {
Intent intent = new Intent(this, GameOverScreen.class);
startActivity(intent);
}
public void onClick (View view) {
score++;
tvscore.setText(String.valueOf(score));
timer();
}
public void timer(){
new CountDownTimer(5000, 10) {
public void onTick(long millisUntilFinished) {
text.setText(""+String.format("%02d:%03d",
TimeUnit.MILLISECONDS.toSeconds(millisUntilFinished) - TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(millisUntilFinished)),
TimeUnit.MILLISECONDS.toMillis(millisUntilFinished) - TimeUnit.SECONDS.toMillis(TimeUnit.MILLISECONDS.toSeconds(millisUntilFinished))
));
if(animationRunning) {
cancel();
}
}
public void onFinish() {
text.setText("Too slow.");
gameover();
}
}.start();
}
}
What about doing this:
public void timer(float time) {
new CountDownTimer(time, 10) {
// YOUR CODE
}
}
public void onClick (View view) {
score++;
tvscore.setText(String.valueOf(score));
timer(Math.max(5000-score*500, 2000));
}
I suppose each click (score) will decrease the time with 500 millis...
Limit - Math.max(a, b) will choose the biggest value. Means when 5000-score*500 will be lower than 2000, it will choose 2000 millis instead
Only timer method:
public void timer() {
float time = Math.max(5000-score*500, 2000)
new CountDownTimer(time, 10) {
// YOUR CODE
}
}

Android Quiz Game - Countdown timer for each qstion

I have created a Quiz app for Android using the tutorial here: http://automateddeveloper.blogspot.co.uk/2011/06/getting-started-complete-android-app.html
For each question, the user will only have 20 seconds to answer it. If he/she fails to answer in 20 seconds, an AlertDialog will popup and the game will terminate.
To do this, I have added a counter in the OnCreate method of QuestionActivity class:
final TextView myCounter = (TextView) findViewById(R.id.countdown);
new CountDownTimer(20000, 1000) {
#Override
public void onFinish() {
timeUp();
}
#Override
public void onTick(long millisUntilFinished) {
myCounter.setText("Time left: "
+ String.valueOf(millisUntilFinished / 1000));
}
}.start();
public void timeUp() {
AlertDialog.Builder builder = new AlertDialog.Builder(
QuestionActivity.this);
builder.setTitle("Times up!")
.setMessage("Game over")
.setCancelable(false)
.setNeutralButton(android.R.string.ok,
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
QuestionActivity.this.finish();
}
});
AlertDialog alert = builder.create();
alert.show();
}
The counter works displays and functions on screen correctly. After answering a question, the activity moves to the next question and the counter resets itself to 20 seconds again.
The problem
The quiz has 15 questions, after answering 3 or 4 questions, the app crashes and I get the following error:
07-18 00:49:05.530: E/AndroidRuntime(4867): android.view.WindowManager$BadTokenException: Unable to add window -- token android.os.BinderProxy#41533a80 is not valid; is your activity running?
I believe this relates to the AlertDialog. I have looked up this error code on Stackoverflow and the popular solution is to pass ActivityName.this as the context when building the AlertDialog.
Unfortunately this does not solve the problem.
I believe the counter is setting a time limit of 20 seconds for the whole activity. My requirement is 20 seconds for each question.
However, the counter resets to 20 seconds when the user press the' Next button and the activity moves to the next question.
Should I be resetting the counter when the user presses the Next button? Here is the OnClickListener code for the Next button
if (currentGame.isGameOver()) {
Intent i = new Intent(this, EndgameActivity.class);
startActivity(i);
finish();
} else {
Intent i = new Intent(this, QuestionActivity.class);
startActivity(i);
SHOULD I ADD SOMETHING HERE?
finish();
Can anyone help me code a solution to my problem?
Here is all the code in QuestionActivity.class
public class QuestionActivity extends SherlockActivity implements
OnClickListener {
private Question currentQ;
private GamePlay currentGame;
private Context context;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.question);
getSupportActionBar().hide();
/**
* Configure current game and get question
*/
currentGame = ((ChuckApplication) getApplication()).getCurrentGame();
currentQ = currentGame.getNextQuestion();
Button nextBtn = (Button) findViewById(R.id.nextBtn);
nextBtn.setOnClickListener(this);
Button quitBtn = (Button) findViewById(R.id.quitBtn);
quitBtn.setOnClickListener(new OnClickListener() {
public void onClick(View arg0) {
finish();
}
});
//Update the question and answer options..
setQuestions();
final TextView myCounter = (TextView) findViewById(R.id.countdown);
new CountDownTimer(20000, 1000) {
#Override
public void onFinish() {
// myCounter.setText("Time up!");
timeUp(context);
}
#Override
public void onTick(long millisUntilFinished) {
myCounter.setText("Time left: "
+ String.valueOf(millisUntilFinished / 1000));
}
}.start();
}
public void timeUp(Context context) {
AlertDialog.Builder builder = new AlertDialog.Builder(
QuestionActivity.this);
builder.setTitle("Times up!")
.setMessage("Game over")
.setCancelable(false)
.setNeutralButton(android.R.string.ok,
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
QuestionActivity.this.finish();
}
});
AlertDialog alert = builder.create();
alert.show();
}
/**
* Method to set the text for the question and answers from the current
* games current question
*/
private void setQuestions() {
// set the question text from current question
String question = Utility.capitalise(currentQ.getQuestion()) + "?";
TextView qText = (TextView) findViewById(R.id.question);
qText.setText(question);
// set the available options
List<String> answers = currentQ.getQuestionOptions();
TextView option1 = (TextView) findViewById(R.id.answer1);
option1.setText(Utility.capitalise(answers.get(0)));
TextView option2 = (TextView) findViewById(R.id.answer2);
option2.setText(Utility.capitalise(answers.get(1)));
TextView option3 = (TextView) findViewById(R.id.answer3);
option3.setText(Utility.capitalise(answers.get(2)));
TextView option4 = (TextView) findViewById(R.id.answer4);
option4.setText(Utility.capitalise(answers.get(3)));
}
public void onClick(View arg0) {
//validate a checkbox has been selected
if (!checkAnswer())
return;
//check if end of game
if (currentGame.isGameOver()) {
Intent i = new Intent(this, EndgameActivity.class);
startActivity(i);
finish();
} else {
Intent i = new Intent(this, QuestionActivity.class);
startActivity(i);
finish();
}
}
#Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
switch (keyCode) {
case KeyEvent.KEYCODE_BACK:
return true;
}
return super.onKeyDown(keyCode, event);
}
/**
* Check if a checkbox has been selected, and if it has then check if its
* correct and update gamescore
*/
private boolean checkAnswer() {
String answer = getSelectedAnswer();
if (answer == null) {
// Log.d("Questions", "No Checkbox selection made - returning");
return false;
} else {
// Log.d("Questions",
// "Valid Checkbox selection made - check if correct");
if (currentQ.getAnswer().equalsIgnoreCase(answer)) {
// Log.d("Questions", "Correct Answer!");
currentGame.incrementRightAnswers();
} else {
// Log.d("Questions", "Incorrect Answer!");
currentGame.incrementWrongAnswers();
}
return true;
}
}
private String getSelectedAnswer() {
RadioButton c1 = (RadioButton) findViewById(R.id.answer1);
RadioButton c2 = (RadioButton) findViewById(R.id.answer2);
RadioButton c3 = (RadioButton) findViewById(R.id.answer3);
RadioButton c4 = (RadioButton) findViewById(R.id.answer4);
if (c1.isChecked()) {
return c1.getText().toString();
}
if (c2.isChecked()) {
return c2.getText().toString();
}
if (c3.isChecked()) {
return c3.getText().toString();
}
if (c4.isChecked()) {
return c4.getText().toString();
}
return null;
}
I think the activity doesn't exist anymore at a certain point when you try to make the dialog(probably when the CountDownTimer is near the end?!?).
Anyway I think finishing and starting the same activity for each question isn't such a good idea, instead you could use the current activity and simply restart the timer. For example:
public class QuestionActivity extends SherlockActivity implements
OnClickListener {
private CountDownTimer mCountDown;
#Override
public void onCreate(Bundle savedInstanceState) {
// ...
mCountDown = new CountDownTimer(20000, 1000) {
#Override
public void onFinish() {
// myCounter.setText("Time up!");
timeUp(context);
}
#Override
public void onTick(long millisUntilFinished) {
myCounter.setText("Time left: "
+ String.valueOf(millisUntilFinished / 1000));
}
}.start();
// ...
and in the onClick callback do the same to setup a new question, stop the old timer and restart the new timer:
//check if end of game
if (currentGame.isGameOver()) {
Intent i = new Intent(this, EndgameActivity.class);
startActivity(i);
finish();
} else {
if (mCountDown != null) {
mCountDown.cancel();
}
currentQ = currentGame.getNextQuestion();
setQuestions();
mCountDown = new CountDownTimer(20000, 1000) {
#Override
public void onFinish() {
// myCounter.setText("Time up!");
timeUp(context);
}
#Override
public void onTick(long millisUntilFinished) {
myCounter.setText("Time left: "
+ String.valueOf(millisUntilFinished / 1000));
}
}.start();
}
Also, in the callback for the Dialog's Button I would first close the Dialog before finishing the Activity:
((AlertDialog) dialog).dismiss();
QuestionActivity.this.finish();

countdown timer on alert box in android

How do i display a countdown timer in my alert box .i want to notify the user that the session will end in 5 minutes and show a timer running in the alert pop up box in android
The following code creates a prompt as you described. It adds a count down timer to a default action button.
Dialog Listener Class
private static class DialogTimeoutListener
implements DialogInterface.OnShowListener, DialogInterface.OnDismissListener {
private static final int AUTO_DISMISS_MILLIS = 5 * 60 * 1000;
private CountDownTimer mCountDownTimer;
#Override
public void onShow(final DialogInterface dialog) {
final Button defaultButton = ((AlertDialog) dialog).getButton(AlertDialog.BUTTON_NEGATIVE);
final CharSequence positiveButtonText = defaultButton.getText();
mCountDownTimer = new CountDownTimer(AUTO_DISMISS_MILLIS, 100) {
#Override
public void onTick(long millisUntilFinished) {
if (millisUntilFinished > 60000) {
defaultButton.setText(String.format(
Locale.getDefault(), "%s (%d:%02d)",
positiveButtonText,
TimeUnit.MILLISECONDS.toMinutes(millisUntilFinished),
TimeUnit.MILLISECONDS.toSeconds(millisUntilFinished % 60000)
));
} else {
defaultButton.setText(String.format(
Locale.getDefault(), "%s (%d)",
positiveButtonText,
TimeUnit.MILLISECONDS.toSeconds(millisUntilFinished) + 1 //add one so it never displays zero
));
}
}
#Override
public void onFinish() {
if (((AlertDialog) dialog).isShowing()) {
// TODO: call your logout method
dialog.dismiss();
}
}
};
mCountDownTimer.start();
}
#Override
public void onDismiss(DialogInterface dialog) {
mCountDownTimer.cancel();
}
Alert Dialog
AlertDialog dialog = new AlertDialog.Builder(this)
.setTitle("Session Timeout")
.setMessage("Due to inactivity, you will soon be logged out.")
.setPositiveButton("Extend Session", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
// TODO: call your log out method
}
})
.setNegativeButton("Log Out Now", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
// TODO: call method to extend session
}
})
.create();
DialogTimeoutListener listener = new DialogTimeoutListener();
dialog.setOnShowListener(listener);
dialog.setOnDismissListener(listener);
dialog.show();
Create a Custom dialog with a TextView on it.
and update that code with the help of CountDownTimer class like this.
new CountDownTimer(300000, 1000) {
public void onTick(long millisUntilFinished) {
mTextField.setText("seconds remaining: " + millisUntilFinished / 1000);
}
public void onFinish() {
mTextField.setText("done!");
}
}.start();
you can dismiss your dialog in onFinish().
for more detail you can follow this link

Categories

Resources