I am using
<Chronometer android:layout_width="wrap_content"
android:layout_height="wrap_content" android:id="#+id/chrono"
android:visibility="gone" />
in my one activity now my question is can I make it global for all of my activities so that I can show its value to every activity in my android app?
If yes then how to do this please give example because I am new in android??
Here is my timer code
Chronometer stopWatch;
stopWatch.setOnChronometerTickListener(new Chronometer.OnChronometerTickListener(){
#Override
public void onChronometerTick(Chronometer arg0) {
countUp = (SystemClock.elapsedRealtime() - arg0.getBase()) / 1000;
long min = countUp / 60;
long sec = countUp % 60;
String minStr = "";
String secStr="";
if(min < 10)
{
minStr = "0"+min;
}
else
{
minStr = ""+min;
}
if(sec<10)
{
secStr = "0"+sec;
}
else
{
secStr = ""+sec;
}
// String asText = (countUp / 60) + ":" + (countUp % 60);
String asText = minStr + ":" + secStr;
textGoesHere.setText(asText);
}
});
stopWatch.start();
Here is an idea. Create a separate layout for your Chronometer and <include /> it in all the layouts that require a Chronometer.
Now you can either use a Singleton pattern or SharedPreferences to store the attributes such as start time, current state (Paused, Running, Stopped, Reset) of your timer. Whenever you start a new activity get the state of the timer and show it on your Timer.
For instance if the current state is running then you may have to kick start a thread to update the timer or if the timer is stopped just get the start time and stop time from your SharedPreference or your Singleton class and show it on the timer.
For instance, consider the following scenario. For simplicity let's have 2 Activities, ActivityA and ActivityB.
Now here are some of the states for your timer, yours could be different.
Ready (00:00 - Your timer is ready to run)
Running (Timer is running)
Paused (Timer is paused and can be resumed)
Stopped (You have stopped the timer and it displays the elapsed time and the next possible state would be 1 i.e, ready.)
You would need several other parameters such as,
Timer start time (System.currentTimeInMillis() minus this time gets you elapsed)
Timer stop time (Used to calculate timer paused and stopped time)
Let's consider this case. You are starting a timer from ActivityA and want to retain the state on ActivityB. Here are the set of things you might want to do.
When you start your timer by any event - say click of a button, you have to save the start time in your SharedPreference.
Now you want to navigate to ActivityB, then you have to save the timer state to your SharedPreference in the onStop() method of your ActivityA.
Now after you start ActivityB, in the onResume() method get the start time from the SharedPreference, the System.currentTimeInMillis() minus the start time will give you the elapsed time. Next, you have to get the timer state from your SharedPreference.
If the state is running, then you have to start a thread to update the timer. If the timer is stopped, then it's enough to show the time elapsed on your timer.
This is the outline of the solution. You can learn about SharedPreferences from here.
Also, you need to be familiar with the Activity lifecycle, which you can learn from here.
No, you can't.
Activities have a life cycle in Android : they are created, started, display & do stuff, get stopped and destroyed. And all the views inside obey to this life cycle.
Don't fight against it, that's the way Android is and it's great like that, learn this life cycle.
The views of an activity don't exist outside of it. This would have no meaning. You should read on how to pass information from one activity to another.
Also, maybe your question is : how can all my activities have the same view in their layout, each one having its own instance of the view. In that case, use the include xml keyword.
yes you can do this but not by making it global. it is little tricky.
what you have to do is:
- make choronometer xml declarartion with tag in each Activity.
- make access of this chronometer in base class.
Just like an example: i required header in each of activity but i wanted to do coding only at one place. so what i do is:
/**
* Method to init Header components sets header bar title and header bar
* buttons. This method sets onClickListener to
*/
private void initHeader() throws InvalidHeaderTitleException {
try {
View headerView = findViewById(R.id.header_layout);
if (headerView != null) {
headerTextView = (TextView) headerView
.findViewById(R.id.layout_header_textview_header);
nextHeaderButton = (Button) headerView
.findViewById(R.id.layout_header_button_next);
prevHeaderButton = (Button) headerView
.findViewById(R.id.layout_header_button_previous);
if (headerTextView != null) {
String title = getHeaderText();
if (isValidString(title)) {
if (title.length() > IDryIceUIConstants.LENGTH_HEADER_TEXT)
title = title.substring(0,
IDryIceUIConstants.LENGTH_HEADER_TEXT)
+ IDryIceUIConstants.SUFFIX_HEADER_TEXT;
headerTextView.setText(title);
} else {
throw new InvalidHeaderTitleException(title);
}
}
if (nextHeaderButton != null) {
nextHeaderButton.setVisibility(getVisibility());
nextHeaderButton.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
headerNextButtonClicked();
}
});
}
if (prevHeaderButton != null) {
prevHeaderButton.setVisibility(getVisibility());
prevHeaderButton.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
headerPrevButtonClicked();
}
});
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
xml declaration in each Activity xml is
<include
android:id="#+id/header_layout"
android:layout_width="fill_parent"
android:layout_height="40dip"
layout="#layout/layout_header" />
Related
I am just starting to learn Android, Java and need help.
I have an activity with the countdowntimer, which works fine. However, I want it to be displayed in the fragment. What is the best way to do it?
I tried calling Timer.getCountdowntimer, I tried calling Timer.getUserTime (userTime is the user selected time for the countdowntimer), but the textview in my fragment doesn't display the timer.
thanks in advance!
If you are coding in Java purely, and want to use the android SDK to do it, I would recommend:-
//Create a handler that runs on main loop so we can update UX
final android.os.Handler handler = new android.os.Handler(Looper.getMainLooper());
//Get a callback in 1 second
handler.postDelayed(new Runnable() {
int timer;
#Override
public void run() {
timer += 1;
myTextView.setText(String.valueOf(timer));
//Recursively get another callback in a second
handler.postDelayed(this, 1000);
}
}, 1000);
Make sure you add some logic to stop the timer when you want, and also onPause/onResume
Novice looking for some help~
I have a CountDownTimer with start, pause, and reset buttons. When the timer is running, I'd like to be able to hit the reset button to restart it from the original value (edittext.) Currently, the only way I am able to accomplish this is to hit "pause" then "reset."
To give an example of what I'm hoping to accomplish:
If timer is set to 10s,
10-9-8-reset-10-9-8-7-6-5-reset-10-9....
Thanks in advance!
I've looked through the forums and android dev site
EDIT: Original problem solved but another has arisen. Code below shows changes made. If I hit start-pause-start too quickly, one second is added to the original countdown time. For example: 15-14-pause-start-15-pause-start-16-pause-start-17-pause-start-18
private void pauseTimer(boolean actualPause) {
mCountdowntimer.cancel();
mTimerRunning = false;
if(actualPause)
updateWatchInterface();
}
private void resetTimer() {
if(mTimerRunning)
pauseTimer(false);
mTimeLeftInMillis = mStartTimeInMillis;
updateCountDownText();
updateWatchInterface();
}
I am not sure what your exact problem is, so I will mention a couple of approaches.
Option 1: If you don't have any problems remembering the 'start time' (that's what mStartTimeInMillis denotes, right?), then you can simply change the signature of the function pauseTimer as follows:
private void pauseTimer(boolean actualPause) {
mCountdowntimer.cancel();
mTimerRunning = false;
if(actualPause)
updateWatchInterface();
}
private void resetTimer() {
if(mTimerRunning)
pauseTimer(false);
mTimeLeftInMillis = mStartTimeInMillis;
updateCountDownText();
updateWatchInterface();
}
Also modify the top portion as:
public void onClick(android.view.View view) {
if (mTimerRunning) {
pauseTimer(true);
}
//...Other code
}
This will ensure that the watch interface is not updated to show the paused interface when you press the reset button, but the actual working would be as if you had pressed pause first and then reset. Also, we put a check to ensure that the pause timer is not called if it was actually pause followed by reset.
Option 2: If you can't get the reference to mStartTimeInMillis without calling pause first, you can use SharedPreferences, and save the start time every time you start the timer, thus allowing you access to the variable as follows:
//Put
SharedPreferences.Editor editor = getSharedPreferences(MY_PREFS_NAME, MODE_PRIVATE).edit();
editor.putString("time", *Your_value* );
editor.apply();
//Get
SharedPreferences prefs = getSharedPreferences(MY_PREFS_NAME, MODE_PRIVATE);
String name = prefs.getString("time", "00:00");//"00:00" is the default value if the //entry doesn't exist.
I hope these will be helpful :)
i need a countDownTimer keep running when i swap between activities.. i have more than one activity, i put the countDownTimer in the main activity but when i swap to another activity and back to the main activity it turns back to count again from the start, i believe because the method countDownTimer is onCreate method.
So, how should I go about doing this?
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
questionTime();
}
public void updateTimer(int secondsLeft){
int minutes = (int) secondsLeft / 60;
int seconds = secondsLeft - minutes * 60;
String secondString = Integer.toString(seconds);
timerTextView.setText(Integer.toString(minutes) + ":" + secondString);
}
private void questionTime(){
new CountDownTimer(10000, 1000){
#Override
public void onTick(long millisUntilFinished) {
updateTimer((int) millisUntilFinished / 1000);
}
#Override
public void onFinish() {
timerTextView.setText("0:00");
Log.i("finished", "timer Done");
}
}.start();
}
Update: That helped me to reach my purpose How to run CountDownTimer in a Service in Android?
Maybe this is a little far fetched, but the way that I think to solve this issue and not worrying for the Activities is using an IntentService.
Even if you store some sort of value in the Bundle of the onSaveInstance() hook method this can lead to some pretty messy results if you enable the "Don't keep activities" flag in the device's settings.
What I would do is create an IntentService that when It's triggered starts the countdown, then It broadcast the changes of that countdown through EventBus/Otto/BroadcastReceiver back to the UI.
Another way of doing it is having the countdown instance in your Application class, and check it from there.
I would go with the IntentService solution because having a countdown instance running in the Application class sounds a little off.
Let me know if you want any specifics on how to implement the IntentService but a little bit of Googling should show you how to do it.
As soon as the time starts, write the time (unix timestamp) to properties file. And when the user comes back to your main activity, read the properties file and compare it the time in the properties file with current timestamp and update the timer based on that.
The following code updates a TextView till a certain condition evaluates to false and then the Handler postDelayed is not called further.
However if the activity is destroyed, it'll try to update a null TextView, what is the right way to handle this? I know I could put a defensive null check on TextView but that is still not truly thread safe.
#Override
protected void onCreate(Bundle savedInstanceState) {
Handler durationHandler = new Handler();
durationHandler.postDelayed(updateSeekBarTime, 50);
}
private Runnable updateSeekBarTime = new Runnable() {
public void run() {
timeElapsed = mediaPlayer.getCurrentPosition();
double timeRemaining = finalTime - timeElapsed;
timeLeft.setText(String.format("%d", TimeUnit.MILLISECONDS.toSeconds((long) timeRemaining)));
if (timeRemaining >= 1000)
durationHandler.postDelayed(this, 200);
}
};
In other words the updateSeekBarTime can at any execution point try to access data members of an already destroyed activity, how to prevent that?
Start your handler in onResume().
In onPause() stop the handler with
handler.removeCallbacksAndMessages(null); //null removes everything
I'm building my own Music Player app and I use
durationHandler.removeCallbacks(updateSeekBarTime);
in onStop(). It works for me.
EDIT:
The above line is helped by the fact that I prevent the Activity from being destroyed by using
#Override
public void onBackPressed() {
moveTaskToBack(true);
}
This ensures that the Activity is minimized instead of destroyed so that when opened again, it's very snappy.
EDIT 2:
private Runnable updateSeekBarTime = new MyRunnable();
private class MyRunnable extends Runnable {
private boolean dontWriteText = false;
#Override
public void run() {
timeElapsed = mediaPlayer.getCurrentPosition();
double timeRemaining = finalTime - timeElapsed;
if(!dontWriteText)
timeLeft.setText(String.format("%d", TimeUnit.MILLISECONDS.toSeconds((long) timeRemaining)));
if (timeRemaining >= 1000)
durationHandler.postDelayed(this, 200);
}
public void dontWriteText() {
dontWriteText = true;
}
};
Then call updateSeekBarTime.dontWriteText() in onDestroy() or onStop(). I'd prefer onStop().
So after some code searching and reading blogs I found the answer in sample code of Communicating with the UI Thread
Even though you can and should be removing callbacks from handler:
handler.removeCallbacksAndMessages(null)
But the above does not prevent the existing running Thread from accessing a destroyed Activity or its views.
The answer I was looking for is WeakReference.
Create a weak reference to the TextView or UI element that you'll
access. The weak reference prevents memory leaks and crashes, because
it automatically tracks the "state" of the variable it backs. If the
reference becomes invalid, the weak reference is garbage-collected.
This technique is important for referring to objects that are part of
a component lifecycle. Using a hard reference may cause memory leaks
as the value continues to change; even worse, it can cause crashes if
the underlying component is destroyed. Using a weak reference to a
View ensures that the reference is more transitory in nature.
You should still check for null reference but now the view will be set to null by the active thread/runnable so you will not face a race-condition.
I have an Activity that I want to run a Delay Function when it runs. I [i]don't[/i] want a delay in OnClick function, I want delay when activity [i]starts[/i].
I have tried the following solutions :
How to set delay in Android onClick function
How to pause/delay on Android?
Android: Timer/Delay Alternative
Android timer set delay
...and some more and none of them did what I want. I want a delay when activity starts (for my project , when The Game Starts) but with that codes, it starts the delay (e.g 10s) when I put my finger on the screen.
You should put a Thread.sleep(long) before the "setContentView(R.layout.xxxx..)" in the onCreate(..) function. In that way, it will actually delay before showing you the elements of the Activity.
If you want to delay even before the onCreate(...) is fired, the approach will need to be different, here is one suggestion:
Run a Service and check for the Foreground application using ActivityManager class (see sample code below). Keep checking for when your app is fired or brought to the 'foreground' (using code below) and then just go back to homescreen & start a timer (in the service itself). Once the timer expires, start your app.
You can run the function below inside an AsyncTask in the Service.
The two approaches are quite different and really depends on what you are looking to achieve exactly.
#SuppressWarnings("deprecation")
private void getRunningAppName() throws NameNotFoundException {
Log.v("neiltag", "Entered getRunningAppName()");
ActivityManager am = (ActivityManager) this.getSystemService(ACTIVITY_SERVICE);
// The first in the list of RunningTasks is always the foreground task.
RunningTaskInfo foregroundTaskInfo = am.getRunningTasks(1).get(0);
String foregroundTaskPackageName = foregroundTaskInfo .topActivity.getPackageName();
PackageManager pm = this.getPackageManager();
PackageInfo foregroundAppPackageInfo = pm.getPackageInfo(foregroundTaskPackageName, 0);
String foregroundTaskAppName = foregroundAppPackageInfo.applicationInfo.loadLabel(pm).toString();
String packageName = foregroundAppPackageInfo.packageName;
if(foregroundTaskAppName.matches("<NAME OF YOUR APP HERE>")) {
//If your app is fired go back to the Homescreen(i.e. the delay)
Intent startMain = new Intent(Intent.ACTION_MAIN);
startMain.addCategory(Intent.CATEGORY_HOME);
startMain.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(startMain);
handler.post(new Runnable() {
#Override
public void run() {
Toast.makeText(getApplicationContext(), "You are not allowed to open Facbeook now, sorry!", Toast.LENGTH_SHORT).show();
}
});
}
//ADD A TIMER HERE
//ONCE TIMER EXPIRES, FIRE UP YOUR APP AGAIN
}