Welcome!

Welcome to the official BlackBerry Support Community Forums.

This is your resource to discuss support topics with your peers, and learn from each other.

inside custom component

Java Development

Reply
Developer
Posts: 489
Registered: ‎05-31-2009
My Device: Not Specified
Accepted Solution

How to reference one global non-static Timer var from a static context

Hello. I need to have one global Timer for my application, which can be cancelled, and re-scheduled for a different date, from within a few different static methods in the app.

 

I confess I don't fully understand how static works. I am currently declaring my Timer as static at class level (so it could be accessed from static methods), but it doesn't seem to hold its value and is null when it should have a value. To be exact, I set my Timer variable = new Timer() from within a static method, and schedule, then come back to cancel it and reschedule, only to find the Timer variable is null.


What I want is to have one and only one global Timer, so some code runs when it gets to zero (I don't want to declare a local Timer var in my static methods and schedule, because then I would have several timers). And I want to cancel the countdown and reschedule at will. (There is another Timer for another purpose, but I want just one for Reset purposes).


I noticed my class-level static Timer variable (I didn't think a Timer could be static) was able to be assigned to = new Timer() - it compiled fine. My limited understanding is that static variables have no instances, so I am grappling with this. From reading I gather that in a static context you can't reference a non-static var because Java doesn't know which object instance you want. 

 

I found that if you want to access a non-static var from a static context, you must first instantiate the containing Class and say classname.globalvar within the static context. Trouble is, when I tried this I found that I already had an instance of the app running, as I instantiate my UIApp in main() just before I entereventdispatcher- so an exception was thrown. My app was created using JDE 4.6 and it is a UIApplication.


How do you have one class-level Timer, referenced from a few static methods, cancelled and rescheduled? Or am I going about this the wrong way? Ideas appreciated as ever.

 

Justin.

 

Developer
Posts: 71
Registered: ‎06-26-2009
My Device: Curve 8310

Re: How to reference one global non-static Timer var from a static context

Hi

 

How about finding the instance of your class? That way you could reference a non-static? If a class isn't instantiated, the variable doesn't exist anyway.

 

Something like:

 

 

private static MyClass m_instance = null;

public static MyClass getInstance()
{
    if (m_instance == null)
        m_instance = new MyClass();
    return m_instance;
}

 

 

Then, instead of instantiating your class as normal:

 

 

MyClass instance = new MyClass();

 

 

Do this instead:

 

 

MyClass instance = MyClass.getInstance();

 

 

That way you'll never have two instances of the class, the same one will always be re-used.

 

Although I don't quite see the problem with the Timer being static either, it should work, I've done that before.

 

Regards

 

Lionel

Give kudos if somebody helps you, also mark accepted if it solves your problem. Search first, then post. Please respect RFC-1855 when posting on forums.

Developer
Posts: 19,623
Registered: ‎07-14-2008
My Device: Not Specified

Re: How to reference one global non-static Timer var from a static context

A static is not a Singleton, except in the (rare) circumstances that it is only used with in one Application Process.  So icefrost1, the mechanism you have suggested will not work as you expect it to, if the SIngleton was being used by an ApplicationMenuItem and an Application for example - they would see different Objects. 

 

I'd rather not go into the detail here, it has been covered a number of times on this forum.

 

The solution to this problem is to create a real SIngleton you can rely on.  To do this, use RuntimeStore, here is a KB article to help:

 

How to - Create a singleton using the RuntimeStore
Article Number: DB-00686
http://www.blackberry.com/knowledgecenterpublic/livelink.exe/fetch/2000/348583/800332/832062/How_to_...

Developer
Posts: 71
Registered: ‎06-26-2009
My Device: Curve 8310

Re: How to reference one global non-static Timer var from a static context

Absolutely, I agree with you, but from I understood of the original post, a Singleton may not be required. I might be wrong though, in that case your solution is definitely better.

Give kudos if somebody helps you, also mark accepted if it solves your problem. Search first, then post. Please respect RFC-1855 when posting on forums.

Developer
Posts: 19,623
Registered: ‎07-14-2008
My Device: Not Specified

Re: How to reference one global non-static Timer var from a static context

@icefrost1.  We could argue the point, but from the Original Post, I think the easiest solution is to use a Singleton. 

 

But in fact, we must be clear about what the Singleton actually is.  In this case, I would code this so that the Singleton contains a reference to a Timer, i.e. it is not the Timer itself.  The process can update the reference to the Timer, so that other processing will see the updated Timer.  At least that is how I would do it.

Developer
Posts: 489
Registered: ‎05-31-2009
My Device: Not Specified

Re: How to reference one global non-static Timer var from a static context

Thanks so far Peter. I am doing this a step at a time, so I have not yet made a reference to the Timer- I use a Timer itself.

 

 

Strange behaviour: the Singleton seems to be working, because I successfully set and retrieve x (a string) from it, time and again. 
However, doing a timer.schedule isn't working. On the .schedule line, I get an 'unknown Exception' (I was also sometimes getting the schedule line to work, only to have it fail to Reset). 
Code is below, help greatly appreciated...

                        
                        // We only want one monthly reset timer, so cancel any existing one
                        if (gort == null)           // This if statement always succeeds, i.e. gort is always null. Weird
                                gort = new GlobalOnlyResetTimer();
                        
                        Timer tempTimer = gort.getInstance().timer;	// And yet, tempTimer always has a value after this line executes
                        if (tempTimer == null)
                              gort.getInstance().timer = new Timer();
                        else {
                         
                            try {
                                gort.getInstance().timer.cancel();
                            }
                            catch (Exception e) {
                                    String logMessage = "Cancelled Timer when it wasn't scheduled anyway";
                                    if ( EventLogger.logEvent( 0x4c9d3452d87922f2L, logMessage.getBytes(), EventLogger.ALWAYS_LOG ) ) {
                                        System.out.println("Log Successful!");
                                    }
                            }
                        }
                        
                        gort.getInstance().timer.schedule(new ResetTotalAtStartOfBillingCycle(), 20000);   // cal.getTime());    // ##### This is the problem- Unknown Exception
                        String y = gort.getInstance().x;   // this is for testing, and y always has the correct value i.e. firstDate as entered last time
                        gort.getInstance().x = "Singleton x = " + String.valueOf(firstDate);

... later on ...

class GlobalOnlyResetTimer {
    
   private static GlobalOnlyResetTimer _instance;
   private static final long GUID = 0xab4dd61c5d004c18L;
   public Timer timer;
   public String x;   // x used for testing
   
   GlobalOnlyResetTimer() {}

   public static GlobalOnlyResetTimer getInstance() {

     if (_instance == null) {
         
         _instance = (GlobalOnlyResetTimer)RuntimeStore.getRuntimeStore().get(GUID);
      
         if (_instance == null) {   // If it is still null, i.e. null in the RuntimeStore
    
            GlobalOnlyResetTimer singleton = new GlobalOnlyResetTimer();
    
            RuntimeStore.getRuntimeStore().put(GUID, singleton);
            _instance = singleton;        
         }      // inner if
    }           // outer if
    
            String tx = _instance.x;        // for testing
            int y = 5;

    return _instance;
    
  }             // getInst    
}               // class

 

 

Developer
Posts: 489
Registered: ‎05-31-2009
My Device: Not Specified

Re: How to reference one global non-static Timer var from a static context

[ Edited ]

Update, Peter- it's not the Singleton! :smileyhappy: I added the following code, and it fell over the same way.

 

 

     Timer qwert = new Timer();
     qwert.schedule(new ResetTotalAtStartOfBillingCycle(), 20000000);
     qwert.cancel();
     qwert.schedule(new ResetTotalAtStartOfBillingCycle(), 200000000);
                        

 

 

It's just that you can't reschedule after you cancel- working on the right way now...

 

J

Developer
Posts: 19,623
Registered: ‎07-14-2008
My Device: Not Specified

Re: How to reference one global non-static Timer var from a static context

Here is a variation on your Singleton Code, review it, might be useful to you.

 

Only coded as a sample, might not even compile.

 

                        // We only want one monthly reset timer, so cancel any existing one
                        GlobalOnlyResetTimer gort = GlobalOnlyResetTimer.getInstance();
                        Timer tempTimer = new Timer();
                        gort.setTimer(tempTimer); // Will cnacel any existing Timer
                        tempTimer.schedule(new ResetTotalAtStartOfBillingCycle(), 20000);   // cal.getTime());    // ##### This is the problem- Unknown Exception
                        String y = gort.getID.x;
                        gort.setID("Singleton x = " + String.valueOf(firstDate));


class GlobalOnlyResetTimer {
    
   private static GlobalOnlyResetTimer _instance = null;
   private static final long GUID = 0xab4dd61c5d004c18L;
   private Timer _timer = null;;
   private String _id = null;
   
   GlobalOnlyResetTimer() {}

   public static GlobalOnlyResetTimer getInstance() {

      if (_instance == null) {
         _instance = (GlobalOnlyResetTimer)RuntimeStore.getRuntimeStore().get(GUID);
         if (_instance == null) {   // If it is still null, i.e. null in the RuntimeStore
            GlobalOnlyResetTimer singleton = new GlobalOnlyResetTimer();
            RuntimeStore.getRuntimeStore().put(GUID, singleton);
            _instance = singleton;        
         } // inner if
      } // outer if
      return _instance;
   } // getInst    

   public Timer getTimer() {
      return _timer;
   }
   public void setTimer(Timer newTimer) {
      if ( _timer != null ) {
         try {
            _timer.cancel();
         }
         catch (Exception e) {
             String logMessage = "Cancelled Timer when it wasn't scheduled anyway";
             if ( EventLogger.logEvent( 0x4c9d3452d87922f2L, logMessage.getBytes(), EventLogger.ALWAYS_LOG ) ) {
                System.out.println("Log Successful!");
             }
         }
         _timer = null;

      }
      _timer = newTimer;
   }

   public String getID() {
      return _id;
   }
   public void setID(String newID) {
      _id = newID;
   }

}

 

Developer
Posts: 489
Registered: ‎05-31-2009
My Device: Not Specified

Re: How to reference one global non-static Timer var from a static context

[ Edited ]

You need to instantiate a Timer again after cancelling it, before scheduling again.

Tks Peter for the Singleton, which did it, though I didn't need a reference, just the Timer itself.

 

Justin

 

New Contributor
Posts: 6
Registered: ‎10-06-2010
My Device: 9800 Torch
My Carrier: AT&T

Re: How to reference one global non-static Timer var from a static context

Sorry to dig up and old thread, but do you mind explaining how you got it working. 

 

I already know about re-instaniating a timer after it has been canceled. i.e.

 

_timer.cancel();

Timer _timer = new Timer();

_timer.scheduleAtFixedRate(new mytimertask(), dateON, delay);

 my issue seems to lie with the Singleton.  I used the code provided by peter with the modificaiton for re-instaniating.  I can get an instance but it doesn't seem to work.  For example if I get an instance like so:

GlobalOnlyResetTimer gort = GlobalOnlyResetTimer.getInstance();
Timer tempTimer = new Timer();
tempTimer.schedule(new mytimertask(), 20000);
gort.setTimer(tempTimer);

I added a new method to GlobalOnlyResetTimer to just cancel the timer and nothing else

 

public void killTimer()
{
  _timer.cancel();
}

 So in theory I should be able get an instace to the timer and cancel with the following statement:

 

 

GlobalOnlyResetTimer gort = GlobalOnlyResetTimer.getInstance();
gort.killTimer();

 However, _timer is always null?  I have to be missing something here?  Anyhelp would be appreciated.