Cancel a timer in BlackBerry - Java - blackberry

I am working with a BlackBerry App that has a number of timers in it to schedule sending reports to the server platform. It is all working fine until I changed the logic to prioritize reports. Therefore, now I am checking if, for instance, Report A is switched on and the user activates Report B as well, then only Report B should go through and Report A should halt UNTIL B is activated. Once B is deactivated (timer cancelled), Report A should resume. However, even when the code loops in the cancel timer task code, Report A continues to go through while B is still activated.
FieldChangeListener reportingListener = new FieldChangeListener() {
public void fieldChanged(Field field, int context)
{
try {
if (field == slider) {
int i = slider.getValue();
if(i==0)
lblInterval.setText(1+" minute");
if(i==1)
lblInterval.setText(2+" minutes");
if(i==2)
lblInterval.setText(5+" minutes");
if(i==3)
lblInterval.setText(10+" minutes");
if(i==4)
lblInterval.setText(15+" minutes");
if(i==5)
lblInterval.setText(30+" minutes");
if(i==6)
lblInterval.setText(1+" hour");
if(i==7)
lblInterval.setText(2+" hours");
if(i==8)
lblInterval.setText(6+" hours");
if(i==9)
lblInterval.setText(12+" hours");
if(i==10)
lblInterval.setText(24+" hours");
setSliderPosition(i);
value=setLblIntervalValue(i);
value2=setGpsTimerIntervalValue(i);
gpsReportValue=lblInterval.getText();
gpsIntervalValue1=setGpsTimerIntervalValue(i);
}
if (PersistentStoreHelper.persistentHashtable.containsKey("image"))
{
boolean trackONOFFImage = ((Boolean) PersistentStoreHelper.persistentHashtable.get("image")).booleanValue();
if(trackONOFFImage==true)
{
if (PersistentStoreHelper.persistentHashtable.containsKey("panic"))
{
boolean panicImage = ((Boolean)PersistentStoreHelper.persistentHashtable.get("panic")).booleanValue();
if(panicImage==true)
{
MyScreen.currentlyReporting.setText("PANIC ALARM TRIGGERED");
if (PersistentStoreHelper.persistentHashtable.containsKey("tabTrackValid"))
{
boolean trackingTab = ((Boolean)PersistentStoreHelper.persistentHashtable.get("tabTrackValid")).booleanValue();
if(trackingTab==false)
{
trackSlider.cancel();
}
PersistentStoreHelper.persistentHashtable.put("tabTrackValid", Boolean.TRUE);
}
}
else
{
//int gpsIntervalValue1=setGpsTimerIntervalValue(i);
if (PersistentStoreHelper.persistentHashtable.containsKey("gpsTimerIntervalValue"))
{
String intervalValue=((String)PersistentStoreHelper.persistentHashtable.get("gpsTimerIntervalValue"));
if(gpsIntervalValue1==Integer.parseInt(intervalValue))
{
//do nothing
}
else
{
trackSlider = new TimerTask() {
public void run() {
try {
UiApplication.getUiApplication().invokeLater(new Runnable()
{
public void run() {
//Dialog.alert("Invalid login details");
}
});
sendTrackingReport();
} catch (Exception e) {
Dialog.alert("Unable to track at the new interval set");
}
}
};
//trackSlider.run();
trackingTimerSlider.scheduleAtFixedRate(trackSlider , 0, gpsIntervalValue1);
PersistentStoreHelper.persistentHashtable.put("tabTrackValid", Boolean.FALSE);
}
}
}
}
}//this
}
} catch (IllegalStateException e) {
//Dialog.alert("CANCEL TRACK1");
e.printStackTrace();
} catch (NullPointerException e) {
//Dialog.alert("CANCEL TRACK2");
e.printStackTrace();
}
}
};
NOTE: Report A = Tracking. Report B = Panic. Panic has priority over Tracking. Slider is changing the timer interval value.
I debugged my code and while it goes into the loop and cancels the timer task of the requested report, I still see those reports going through. Am I not cancelling the timer correctly? Please advice.

From the TimerTask.cancel javadoc:
... If the task has been scheduled for repeated execution, it will never run again. (If the task is running when this call occurs, the task will run to completion, but will never run again.) ...
So to begin with, calling cancel from a thread does not immediatly stop the Timer thread as you can see.
Also you are creating a new Timer each time in your screen:
trackSlider = new TimerTask()
Thus it might be possible that if you create several instances of your screen during the app running, several timers of the same type will be created.

Related

Is Orleans reminder execution interleaved?

If there are two different reminders on the same grain activation to be fired at the same point, given that grain execution context is single-threaded, will both reminders be executed and interleaved at the same time?
Also, is the reminder execution limited by the default 30s timeout ?
Reminders are invoked using regular grain method calls: the IRemindable interface is a regular grain interface. IRemindable.ReceiveReminder(...) is not marked as [AlwaysInterleave], so it will only be interleaved if your grain class is marked as [Reentrant].
In short: no, reminder calls are not interleaved by default.
Reminders do not override the SiloMessagingOptions.ResponseTimeout value, so the default execution time will be 30s.
If you have a reminder that might need a very long time to execute, you can follow a pattern of starting the long-running work in a background task and ensuring that it is still running (not completed or faulted) whenever the relevant reminder fires.
Here is an example of using that pattern:
public class MyGrain : Grain, IMyGrain
{
private readonly CancellationTokenSource _deactivating = new CancellationTokenSource();
private Task _processQueueTask;
private IGrainReminder _reminder = null;
public Task ReceiveReminder(string reminderName, TickStatus status)
{
// Ensure that the reminder task is running.
if (_processQueueTask is null || _processQueueTask.IsCompleted)
{
if (_processQueueTask?.Exception is Exception exception)
{
// Log that an error occurred.
}
_processQueueTask = DoLongRunningWork();
_processQueueTask.Ignore();
}
return Task.CompletedTask;
}
public override async Task OnActivateAsync()
{
if (_reminder != null)
{
return;
}
_reminder = await RegisterOrUpdateReminder(
"long-running-work",
TimeSpan.FromMinutes(1),
TimeSpan.FromMinutes(1)
);
}
public override async Task OnDeactivateAsync()
{
_deactivating.Cancel(throwOnFirstException: false);
Task processQueueTask = _processQueueTask;
if (processQueueTask != null)
{
// Optionally add some max deactivation timeout here to stop waiting after (eg) 45 seconds
await processQueueTask;
}
}
public async Task StopAsync()
{
if (_reminder == null)
{
return;
}
await UnregisterReminder(_reminder);
_reminder = null;
}
private async Task DoLongRunningWork()
{
// Log that we are starting the long-running work
while (!_deactivating.IsCancellationRequested)
{
try
{
// Do long-running work
}
catch (Exception exception)
{
// Log exception. Potentially wait before retrying loop, since it seems like GetMessageAsync may have failed for us to end up here.
}
}
}
}

How to display clock count down whole the application on Blackberry?

I make and display an clock count down with this code
LabelField time;
long mille=0;
Timer timer=null;TimerTask task=null;
public Timerscreen() {
mille=1000*60*1;
time=new LabelField();
add(time);
timer=new Timer();
task=new TimerTask() {
public void run() {
synchronized (UiApplication.getEventLock()) {
if(mille!=0){
SimpleDateFormat date=new SimpleDateFormat("mm:ss") ;
System.out.println("================="+date.formatLocal(mille)+"====================="+Thread.activeCount());
time.setText(date.formatLocal(mille));
mille=mille-1000;
}else{
time.setText("00:00");
mille=1000*60*1;
timer.cancel();
UiApplication.getUiApplication().invokeLater(new Runnable() {
public void run() {
Dialog.inform("Time expaired");
}
});
}
}
}
};
timer.schedule(task,0, 1000);
And when I push a new screen , I want to this clock still display and count down.
How can I do that ?
It is not possible to add a single ui field or manager into two managers or screens.. every ui field or manager must have at most one parent (screen or manager).
So if you need a LabelField which will hold and show time on different screens, then you only need to implement some sort of listener which will listen for the time changes.. and for every changes you have to update the screen and the LabelField with the new value. You have already implemented a TimerTask which will provide you updated data.
[Edited - added later]
you can check the following codes, not tested but something like this will solve your problem...
class MyTimerUtil {
TimerListener listener = null;
public MyTimerUtil() {
}
public void setTimerListener(TimerListener listener) {
this.listener = listener;
}
public void startTimer() {
final int interval = 1000;
Timer timer = new Timer();
TimerTask task = new TimerTask() {
public void run() {
// add your codes..
// notify others
if (listener != null) {
listener.timeChanged();
}
}
};
timer.schedule(task, 0, interval);
}
}
interface TimerListener {
public void timeChanged();
}
class ScreeA extends MainScreen implements TimerListener {
public void timeChanged() {
// add Codes here on time changed event
}
}
in the above snippet, you can implement TimerListener interface in any screen instance and can get update on every time changed event by the MyTimerUtil class. For that, you have to set an instance of ScreeA (which implements TimerListener) via setTimerListener() of the MyTimerUtil class.
Also need to start the timer by calling startTimer() method.

How to close streaming player screen when sp.realize() method executing

I have read the knowledgebase article "Streaming media - Start to finish" It is working fine. When I click the open video, the player screen is open. When I click the back button before the player is realized, it does not come to back to the right screen.
when sp.realize(); method executing user can't come to back screen.
after loading player. it close.
How to go back a screen if sp.realize() method is still executing?
new Thread(new Runnable()
{
public void run()
{
try
{
if(sp==null)
{
sp = new StreamingPlayer(url, contentType);
sp.setBufferCapacity(bufferCapacity);
sp.setInitialBuffer(initBuffer);
sp.setRestartThreshold(restartThreshold);
sp.setBufferLeakSize(bufferLeakSize);
sp.setConnectionTimeout(connectionTimeout);
sp.setLogLevel(logLevel);
sp.enableLogging(eventLogEnabled, sdLogEnabled);
sp.addStreamingPlayerListener(playerScreen);
sp.realize();
volC = (VolumeControl)sp.getControl("VolumeControl");
if(contentType.toLowerCase().indexOf("video")!=-1)
{
vidC = (VideoControl)sp.getControl("VideoControl");
videoField = (Field)vidC.initDisplayMode(VideoControl.USE_GUI_PRIMITIVE, "net.rim.device.api.ui.Field");
vidC.setDisplaySize(Display.getWidth(), Display.getHeight()-timeSeeker.getHeight()-byteSeeker.getHeight());
UiApplication.getUiApplication().invokeLater(new Runnable()
{
public void run()
{
replace(getField(0), videoField);
}
});
vidC.setVisible(true);
}
if(contentType.toLowerCase().indexOf("audio")!=-1)
{
audioIcon = true;
if(!(getField(0)==albumArt))
{
UiApplication.getUiApplication().invokeLater(new Runnable(){
public void run()
{
replace(videoField, (Field)albumArt);
}
});
}
}
sp.start();
}
else
{
sp.stop();
sp.close();
sp = null;
run();
}
} catch(Throwable t)
{
//log(t.toString());
}
}
}).start();
I'm not sure exactly what you mean by this. However, have you tried running the audio stuff in a separate thread? That should reduce the likelihood of it interfering with anything else.

how to check timer is running on blackberry

I've add timer to display images in my app.
is there any way to check the timer is running or not.?
after checking , the timer should be cancel using timer.cancel() method.
Pls hlp me.
Blackberry's Timer is very cheesy - it's just like a Runnable with Thread.sleep() inside. Very commonly for Blackberry, it contains lot of crap you don't actually need and doesn't contain things you do need.
I would dump the Timer and make a class specially for my needs:
abstract public class MyTimer extends Thread {
private final Object waitobj = new Object();
private volatile boolean running;
private volatile boolean canceled;
private final long due;
public MyTimer setDelay(long delay) {
long cur = System.currentTimeMillis();
due = cur + delay;
return this;
}
public MyTimer setAlarmTime(long dueTimeMillis) {
due = dueTimeMillis;
return this;
}
synchronized void setIsRunning(boolean running) {
this.running = running;
}
synchronized public boolean isRunning() {
return running;
}
synchronized public void cancel() {
synchronized (waitobj) {
canceled = true;
waitobj.notify();
}
}
public void run() {
setIsRunning(true);
long cur = System.currentTimeMillis();
long sleep = due - cur;
while (sleep > 0) {
synchronized (waitobj) {
waitobj.wait(sleep);
}
if (isCanceled()) return;
cur = System.currentTimeMillis();
sleep = due - cur;
}
alarm();
setIsRunning(false);
}
private boolean isCanceled() {
return canceled;
}
abstract void alarm();
}
Then I would invoke it like this:
timer = new MyTimer() {
void alarm() {
// do cool things
}
};
timer.setDelay(10000).start();
If I need to cancel it I would do it like this:
if (timer.isRunning()) {
timer.cancel();
}
or simply
timer.cancel();
PS: Note volatile and synchronized things in MyTimer class.
You can manage this yourself by recording the timers unique integer and use it later to cancel. I find a useful place to set/cancel this is in the onVisibilityChanged(boolean) override. I'm assuming here your timed images are for animation.
// start
if (renderLoop==-1) renderLoop = UiApplication.getUiApplication().invokeLater( this, 50, true );
// stop
if (renderLoop!=-1)
{
UiApplication.getUiApplication().cancelInvokeLater( renderLoop );
renderLoop = -1;
}
//assumes your screen implements Runnable
public void run() {
// do something cool
}
Assuming that you're programming in Java with Swing, you have a method called isRunning() within the Timer Class.
http://download.oracle.com/javase/7/docs/api/javax/swing/Timer.html#isRunning%28%29
Regards

BlackBerry - Simulate a KeyPress event

I have a BlackBerry application that needs to take pictures from the camera and send them to a server. In order to do this i invoke the native camera application and listen to the filesystem. Once an image is captured and saved as a new jpeg file i get notified, resume foreground control and go about my business. The problem starts occurring after the first time this cycle is completed because now when i decide to call the camera application again it is already opened, and now the user is seeing a thumbnail of the last picture that was taken and several buttons allowing him to manipulate/manage it. naturally what i want the user to see is a preview of what the camera is "seeing" before he snaps another photo as he did before.
I have thought of various ways to solve this including killing the camera app each time (I understand this cannot be done programatically?), sending CameraArguments when invoking the app (which appears to be useless), and now i was thinking a solution could be as simple generating a "Back" key event before switching back to my app which would theoretically dismiss the annoying edit screen. Could this really be done? and if not is there any other possible solution you may think of?
A kind of hack...
start Camera App
in TimerTask check if Camera App started and if it need to be closed (some flag)
if yes, invoke it(so it will became active) and push ESC keypress event injection to close it
Take a look at this:
class Scr extends MainScreen {
boolean killCameraApp = false;
final String mCameraModuleName = "net_rim_bb_camera";
final CameraArguments args = new CameraArguments();
public Scr() {
super();
Timer timer = new Timer();
timer.scheduleAtFixedRate(new TimerTask() {
public void run() {
if (isCameraRunning() && killCameraApp) {
getApplication().invokeAndWait(callCamera);
getApplication().invokeAndWait(killCamera);
}
}
}, 0, 100);
}
Runnable callCamera = new Runnable() {
public void run() {
callCamera();
}
};
Runnable killCamera = new Runnable() {
public void run() {
injectKey(Characters.ESCAPE);
killCameraApp = false;
}
};
private boolean isCameraRunning() {
boolean result = false;
ApplicationManager appMan =
ApplicationManager.getApplicationManager();
ApplicationDescriptor[] appDes = appMan.getVisibleApplications();
for (int i = 0; i < appDes.length; i++) {
result = mCameraModuleName.equalsIgnoreCase(appDes[i]
.getModuleName());
if (result)
break;
}
return result;
}
private void callCamera() {
Invoke.invokeApplication(Invoke.APP_TYPE_CAMERA,
new CameraArguments());
}
private void injectKey(char key) {
KeyEvent inject = new KeyEvent(KeyEvent.KEY_DOWN, key, 0);
inject.post();
}
protected void makeMenu(Menu menu, int instance) {
menu.add(new MenuItem("start camera", 0, 0) {
public void run() {
callCamera();
killCameraApp = false;
}
});
menu.add(new MenuItem("kill app", 0, 0) {
public void run() {
killCameraApp = true;
}
});
super.makeMenu(menu, instance);
}
}
EDIT: Don't forget to set permissions for device release:
Options => Advanced Options => Applications => [Your Application] =>Edit Default permissions =>Interactions =>key stroke Injection

Resources