Android Chronometer,保留时间状态(并在后台继续计数)

发布于 2024-12-08 17:44:01 字数 453 浏览 1 评论 0原文

我有一个计时器,从用户遇到该活动的时间开始计时,

我当前在 onCreate 期间使用天文台设置(最初仅在满足某些条件时启动)。但我需要计时器继续向上计数,直到应用程序及其所有视图都关闭(我有一个“退出”功能来做到这一点)。

问题是,每次我查看另一个选项卡并返回其活动时,计时器都会重置为零。 (这与 oncreate 有关,但我不知道解决方法)

我没有找到一种直观的方法来在后台保存计时器的状态或计数(或者也许跟踪我的计时器上的时间)拥有并在不同的时间点直观地更新天文钟)

我的一个想法是通过一项服务启动天文钟并让该服务继续计数,同时在现有活动更新中使用天文钟的当前时间计数作为文本视图 !

任何对此问题的已知方法的见解都将受到赞赏

这更加复杂,因为这是 tabhost 中的活动,并且 tabhost 在每次加载视图时都会调用 onPause 和 onResume,因此这会破坏生命周期功能。

I have a timer that counts up from the time a user encounters that activity

I am currently using a Chronometer set during onCreate (initially started only when certain conditions are met). But I need the chronometer to keep counting upward until the app and all its views are closed (I have an "Exit" function to do that).

The problem is that the Chronometer gets reset to zero on every time I look at another tab and come back to its activity. (This has to do with the oncreate, but I dont know the way around it)

I didn't find an intuitive way to save the chronometer's state or countup in the background on its own (or to perhaps keep track of the time on my own and update the chronometer visually at a different point in time)

One idea I had was to start the Chronometer with a service and let the service keep counting , while having a textview in the existing activity update using the chronometer's current time tally as a string

any insight on a known approach to this problem be appreciated!

This is further complicated because this is an activity in a tabhost, and tabhosts call both onPause and onResume every time you load a view, so this breaks lifecycle functions.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

梦一生花开无言 2024-12-15 17:44:01

有多种方法可以保持时间。我发现的最简单的方法是通过 getIntent().putExtra("START_TIME", floatvalue) 将时间存储在用于创建原始活动的 Intent 中。您可以使用 getIntent().getFloatExtra("START_TIME", 0f) 检索该值。这样做有很多好处:

  • 它不会破坏 Activity 生命周期,也不需要 Context。
  • 它可以在其他活动和应用程序之间轻松传递。
  • 它在暂停和停止之间持续存在。
  • 它不需要特殊的听众。
  • 它不会创建任何新对象(意图是第一次用于创建活动的对象)。

此解决方案非常适合在选项卡式活动中或跨对话框等进行持久化。如果将应用程序留给内存密集型应用程序,但只有当您的活动被破坏(由于内存)时,它才会有一些限制。

There are a number of ways to persist the time. The easiest one I have found is to store the time in the Intent that was used to create the original activity via getIntent().putExtra("START_TIME", floatvalue). You may retrieve the value with getIntent().getFloatExtra("START_TIME", 0f). Doing it this way has a number of benefits:

  • It doesn't break the Activity LifeCycle and does not require a Context.
  • It can be passed easily between other Activities and Applicaitons.
  • It persists among Pauses and Stops.
  • It doesn't require special listeners.
  • It doesn't create any new objects (the Intent is the one used to create the Activity the first time).

This solution is great for persisting in a Tabbed Activity, or across Dialogs, etc. It has some limitations if leaving the Application to a more memory intensive one, but only if your Activity is destroyed (due to memory).

怎樣才叫好 2024-12-15 17:44:01

由于我的 Tabhost,无法依赖生命周期功能。

我所做的是将计时器设置为中心类中的静态全局变量,并在我的 tabhost 中添加了一个 ontabchangedlistener 来检查要更改的选项卡是否是带有计时器的选项卡。如果这是真的,那么它会存储天文钟当前时间的长整型值。

 tabHost.setOnTabChangedListener(new OnTabChangeListener(){

        @Override
        public void onTabChanged(String arg0) {
            // TODO Auto-generated method stub
            if(arg0.contentEquals("homeGroup"))
            {
                //store time in centralhelper.java
                                    //stopWatch is of type Chronometer
                                    //stopWatchLastTime is of type Long and is initially set to zero. Chronometer uses milliseconds to determine time, will never be zero after set
                CentralHelper.stopWatchLastTime = CentralHelper.stopWatch.getBase();
            }
        }

    });

当我的 homeGroup 视图加载时,调用 onResume() 函数,这里有一个条件来检索计时器恢复计数的时间。尽管 tabhost 在正常生命周期函数之外的每次加载中都会调用 onPause() 和 onResume(),但它们仍然会在 onCreate() 之前被调用,

   public void onResume(){
    super.onResume();

    //update Chronometer with time stored in tabchangelistener
    if(CentralHelper.stopWatchLastTime!=0)
        CentralHelper.stopWatch.setBase(CentralHelper.stopWatchLastTime);
}

这允许我在 onCreate() 中执行类似的检查

    if(CentralHelper.stopWatchLastTime!=0)
    {

        CentralHelper.stopWatch.start(); //this is where it resumes counting from the base set in onResume()
    }
    else
    {
        CentralHelper.stopWatch.start();
        CentralHelper.stopWatch.setBase(SystemClock.elapsedRealtime());
    }

Because of my Tabhost, the lifecycle functions could not be relied on.

What I did was make the chronometer a static global in a central class, and added a ontabchangedlistener within my tabhost that checked to see if the tab being changed to was the tab with the chronometer. If this was true then it stores the Long value of the chronometer's current time.

 tabHost.setOnTabChangedListener(new OnTabChangeListener(){

        @Override
        public void onTabChanged(String arg0) {
            // TODO Auto-generated method stub
            if(arg0.contentEquals("homeGroup"))
            {
                //store time in centralhelper.java
                                    //stopWatch is of type Chronometer
                                    //stopWatchLastTime is of type Long and is initially set to zero. Chronometer uses milliseconds to determine time, will never be zero after set
                CentralHelper.stopWatchLastTime = CentralHelper.stopWatch.getBase();
            }
        }

    });

When my homeGroup view loads, the onResume() function is called, there is a condition here to retrieve the time for the chronometer to resume counting from. Despite the fact that a tabhost will call both onPause() and onResume() in EVERY load outside of normal lifecycle functions, they still get called before onCreate()

   public void onResume(){
    super.onResume();

    //update Chronometer with time stored in tabchangelistener
    if(CentralHelper.stopWatchLastTime!=0)
        CentralHelper.stopWatch.setBase(CentralHelper.stopWatchLastTime);
}

this allowed me to do a similar check in onCreate()

    if(CentralHelper.stopWatchLastTime!=0)
    {

        CentralHelper.stopWatch.start(); //this is where it resumes counting from the base set in onResume()
    }
    else
    {
        CentralHelper.stopWatch.start();
        CentralHelper.stopWatch.setBase(SystemClock.elapsedRealtime());
    }
七婞 2024-12-15 17:44:01

当您切换到不同的 Activity 时,前一个 Activity 会暂停(如附图中的 onPause 等),当您返回该 Activity 时,它会恢复,但有时当 dalvik 内存不足时,您的 Activity 对象可能会被删除显示。

如果您将应用程序数据保留在 Activity 实例中,则可能会意外丢失它,请阅读此 Activity 生命周期 http://developer.android.com/reference/android/app/Activity.html

输入图片此处描述

When you switch to a different activity the previous one is paused (onPause, asand so on, in attached image) when you came back to the activity it is resumed, but occasionaly when dalvik runs out of memory your Activity object can be deleted when ton showing.

If you keep your application data in the Activity instance you might loose it accidentally, please read this Activity Lifecycle http://developer.android.com/reference/android/app/Activity.html

enter image description here

っ左 2024-12-15 17:44:01

这种方法经过测试,效果非常好。
试试这个:

采用一个布尔易失性变量来控制您的线程(启动/停止)。采取三个文本视图,小时、分钟和秒文本视图,并完全删除计时器。使用 Handler 更新您的 UI 编写以下代码。

public void timeUpdate()
{
    timerThread = new Thread(new Runnable() {

        @Override
        public void run() {
            while(continueThread){
                Date newDate = new Date();
                if(((newDate.getTime()) - date.getTime()) > 1000){
                    secondCounter = secondCounter+1;
                    mHandlerUpdateSec.post(mUpdateSec);
                    System.out.println("Inside the Theread ..."+secondCounter);
                    if(secondCounter > 59){
                        minuteCounter = minuteCounter + 1;
                        mHandlerUpdateMinute.post(mUpdateMinute);
                        secondCounter = 0;
                        if(minuteCounter > 59){
                            hourCounter = hourCounter + 1;
                            mHandlerUpdateHour.post(mUpdateHour);
                            minuteCounter = 0;
                        }
                    }
                }
                try{
                    timerThread.sleep(1000);
                }catch (Exception e) {
                    // TODO: handle exception
                }
            }
        }
    });
    timerThread.start();
}

continueThread 是一个布尔易失性变量。将其设置为 false 将停止线程。 TimerThread 是线程的一个实例。有三个计数器,小时、分钟和秒计数器,它们将为您提供最新的时间值。处理程序更新如下。

final Handler mHandlerUpdateSec = new Handler();
final Runnable mUpdateSec = new Runnable() {
    public void run() {
        String temp = "" + secondCounter;
        System.out.println("Temp second counter length: " + temp.length());
        if(temp.length() == 1)
            secTextView.setText("0" + secondCounter);
        else
            secTextView.setText("" + secondCounter);
    }
};
final Handler mHandlerUpdateMinute = new Handler();
final Runnable mUpdateMinute= new Runnable() {
    public void run() {
        String temp = "" + minuteCounter;
        System.out.println("Temp second counter length: " + temp.length());
        if(temp.length() == 1)
            minTextView.setText("0" + minuteCounter);
        else
            minTextView.setText("" + minuteCounter);
    }
};
final Handler mHandlerUpdateHour = new Handler();
final Runnable mUpdateHour = new Runnable() {
    public void run() {
        String temp = "" + hourCounter;
        System.out.println("Temp second counter length: " + temp.length());
        if(temp.length() == 1)
            hourTextView.setText("0" + hourCounter);
        else
            hourTextView.setText("" + hourCounter);
    }
};

现在,每当您想要启动计时器时,请将 continueThread 设置为 true 并调用 timeUpdate()。要停止它,只需执行 continueThread = false 即可。要再次启动线程,请将 continueThread 设置为 true 并再次调用 timeUpdate()。确保在启动/停止计时器时相应地更新计数器。

This approach is tested and it works really well.
Try this:

Take a boolean volatile variable which will control your thread(start/stop). Take three text views, hour, min and sec text views, and remove chronometer completely. Update your UI using a Handler Write the following code.

public void timeUpdate()
{
    timerThread = new Thread(new Runnable() {

        @Override
        public void run() {
            while(continueThread){
                Date newDate = new Date();
                if(((newDate.getTime()) - date.getTime()) > 1000){
                    secondCounter = secondCounter+1;
                    mHandlerUpdateSec.post(mUpdateSec);
                    System.out.println("Inside the Theread ..."+secondCounter);
                    if(secondCounter > 59){
                        minuteCounter = minuteCounter + 1;
                        mHandlerUpdateMinute.post(mUpdateMinute);
                        secondCounter = 0;
                        if(minuteCounter > 59){
                            hourCounter = hourCounter + 1;
                            mHandlerUpdateHour.post(mUpdateHour);
                            minuteCounter = 0;
                        }
                    }
                }
                try{
                    timerThread.sleep(1000);
                }catch (Exception e) {
                    // TODO: handle exception
                }
            }
        }
    });
    timerThread.start();
}

The continueThread is a boolean volatile variable. Setting it to false will stop the thread. The timerThread is an instance of thread. There are three counters, hour, min and sec counters which will give you the latest time values. The handlers are updated as follows.

final Handler mHandlerUpdateSec = new Handler();
final Runnable mUpdateSec = new Runnable() {
    public void run() {
        String temp = "" + secondCounter;
        System.out.println("Temp second counter length: " + temp.length());
        if(temp.length() == 1)
            secTextView.setText("0" + secondCounter);
        else
            secTextView.setText("" + secondCounter);
    }
};
final Handler mHandlerUpdateMinute = new Handler();
final Runnable mUpdateMinute= new Runnable() {
    public void run() {
        String temp = "" + minuteCounter;
        System.out.println("Temp second counter length: " + temp.length());
        if(temp.length() == 1)
            minTextView.setText("0" + minuteCounter);
        else
            minTextView.setText("" + minuteCounter);
    }
};
final Handler mHandlerUpdateHour = new Handler();
final Runnable mUpdateHour = new Runnable() {
    public void run() {
        String temp = "" + hourCounter;
        System.out.println("Temp second counter length: " + temp.length());
        if(temp.length() == 1)
            hourTextView.setText("0" + hourCounter);
        else
            hourTextView.setText("" + hourCounter);
    }
};

Now, whenever you want to start the timer, set continueThread to true and call timeUpdate(). To stop it, just do continueThread = false. To start the thread again, set continueThread to true and call timeUpdate() again. Make sure you update the counters accordingly while you start/stop the timer.

唱一曲作罢 2024-12-15 17:44:01

您可以将开始时间保存在共享首选项(或文件等)中,并在 onResume() 中从此开始计数(而不是从 0 开始)。

您的 UI 可能需要进行一些更改来处理您必须重置开始时间的事实,因为理论上它可以永远计数。

You could save the start time in a sharedpreferences (or file, etc.) and establish your count-up from that (rather than starting at 0) in onResume().

Your UI may need some changes to handle the fact that you will have to reset the start time, since it could theoretically count forever.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文