My application contains lots of images. so it takes some time to load the application. I want to show a loading screen whhile the application is being loaded. How is it possible ?
Here's an example app that skeletons what your looking to do. Basically, the initial screen you push is a loading screen. During the initial startup sequence you need to spin up a new thread, do your loading stuff and then use invokeLater to 1) make sure your in the event dispatcher and 2) to push a new screen -- or in the case of this example a dialog -- to the screen to have the user progress away from the loading screen.
Here's the code:
import net.rim.device.api.ui.Field;
import net.rim.device.api.ui.UiApplication;
import net.rim.device.api.ui.container.MainScreen;
import net.rim.device.api.ui.component.Dialog;
import net.rim.device.api.ui.component.LabelField;
/**
* Just a test app.
*/
public class TestAppMain extends UiApplication
{
/**
* Default Constructor.
*/
private TestAppMain() {
pushScreen(new AppScreen(this));
}
/**
* App entry point.
* #param args Arguments.
*/
public static void main(String[] args) {
TestAppMain app = new TestAppMain();
app.enterEventDispatcher();
}
/**
* Main application screen.
*/
private static class AppScreen extends MainScreen
{
UiApplication _app;
/**
* Default constructor.
*/
public AppScreen(UiApplication app) {
// Note: This screen just says "Loading...", but you could
// add a loading animation.
_app = app;
LabelField title = new LabelField("App Name",
LabelField.ELLIPSIS | LabelField.USE_ALL_WIDTH);
setTitle(title);
LabelField loading = new LabelField("Loading...",
LabelField.ELLIPSIS | LabelField.USE_ALL_WIDTH);
add(loading);
// Queue up the loading process.
startLoading();
}
/**
* Create the loading thread. Make sure to invoke later as you will
* need to push a screen or show a dialog after the loading is complete, eventhough
* you are creating the thread before the app is in the event dispatcher.
*/
public void startLoading() {
Thread loadThread = new Thread() {
public void run() {
// Make sure to invokeLater to avoid problems with the event thread.
try{
// Simulate loading time
Thread.sleep(5000);
} catch(java.lang.InterruptedException e){}
// TODO - Add loading logic here.
_app.invokeLater( new Runnable() {
public void run() {
// This represents the next step after loading. This just shows
// a dialog, but you could push the applications main menu screen.
Dialog.alert("Load Complete");
}
});
}
};
loadThread.start();
}
}
}
HorizontalFieldManager popHF = new HorizontalFieldManager();
popHF.add(new CustomLabelField("Pls wait..."));
final PopupScreen waitScreen = new PopupScreen(popHF);
new Thread()
{
public void run()
{
synchronized (UiApplication.getEventLock())
{
UiApplication.getUiApplication().pushScreen(waitScreen);
}
//Here Some Network Call
synchronized (UiApplication.getEventLock())
{
UiApplication.getUiApplication().popScreen(waitScreen);
}
}
}.start();
Related
When opening a new dialog, while its loading, you click couple of times on parent shell, apparently the new dialog does not display correctly.
Please see the example below:
Examples
https://i.stack.imgur.com/ZovxE.png (eclipse IDE example)
https://i.stack.imgur.com/5zVar.png
https://i.stack.imgur.com/u86b9.png
https://i.stack.imgur.com/FGaAr.png
Initially I encountered the problem in december 2014, and back then also reported by vaious in house devlopers which were using different development systems and then same problem has been reported by our several customers.
This behavior can be reproduced using following environment:
Windows Version: 7 Pro 64 Bit - 6.1.7601
Java Version: RE 1.8.0_121_b13
SWT Versions
3.8.2
4.6.2
4.7M6
I20170319-2000
I could only reproduce the problem on Windows 7 with the windows basic theme/design/style (not with classic or aero).
On windows 10 its not reproducible.
reproduce
code to reproduce
package test;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.layout.RowLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Dialog;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Text;
public class Main {
public static void main(String[] args) {
Display display = new Display();
final Shell shell = createShell(display);
createButton(shell);
shell.open();
eventLoop(display, shell);
display.dispose();
}
private static Shell createShell(Display display) {
final Shell shell = new Shell(display);
shell.setLayout(new RowLayout());
shell.setSize(500, 200);
return shell;
}
private static void createButton(final Shell shell) {
final Button openDialog = new Button(shell, SWT.PUSH);
openDialog.setText("Click here to open Dialog ...");
openDialog.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(SelectionEvent e) {
TestDialog inputDialog = new TestDialog(shell);
inputDialog.open();
}
});
}
private static void eventLoop(Display display, final Shell shell) {
while (!shell.isDisposed()) {
if (!display.readAndDispatch()) {
display.sleep();
}
}
}
}
class TestDialog extends Dialog {
public TestDialog(Shell parent) {
super(parent, SWT.DIALOG_TRIM | SWT.APPLICATION_MODAL | SWT.MIN | SWT.MAX | SWT.RESIZE);
setText("Dialog");
}
public void open() {
Shell shell = new Shell(getParent(), getStyle());
shell.setText(getText());
createContents(shell);
shell.pack();
initializeBounds(shell);
shell.open();
eventLoop(shell);
}
private void createContents(final Shell shell) {
shell.setLayout(new GridLayout(2, true));
Label label = new Label(shell, SWT.NONE);
label.setText("Some Label text ...");
final Text text = new Text(shell, SWT.BORDER);
GridData data = new GridData(GridData.FILL_HORIZONTAL);
text.setLayoutData(data);
createCloseButton(shell);
/* time for the user to create the misbehavior */
try {
Thread.sleep(15000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
private void createCloseButton(final Shell shell) {
Button closeButton = new Button(shell, SWT.PUSH);
closeButton.setText("Close");
GridData data = new GridData(GridData.FILL_HORIZONTAL);
closeButton.setLayoutData(data);
closeButton.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(SelectionEvent event) {
shell.close();
}
});
shell.setDefaultButton(closeButton);
}
private void initializeBounds(Shell shell) {
Rectangle bounds = shell.getBounds();
Rectangle parentBounds = getParent().getBounds();
bounds.x = parentBounds.x;
bounds.y = parentBounds.y;
shell.setBounds(bounds);
}
private void eventLoop(Shell shell) {
Display display = getParent().getDisplay();
while (!shell.isDisposed()) {
if (!display.readAndDispatch()) {
display.sleep();
}
}
}
}
steps to reproduce
Start the application
it should look like: https://i.stack.imgur.com/dMJ9e.png
Click on the button.
Keep continuously clicking on right bottom corner of the parent shell (avoid hitting the new opening dialog), till mouse cursor changes to wait icon and parent shell changes its color.
it should look as following: https://i.stack.imgur.com/c1Ikp.png
Wait until the new dialog appears.
it looks likes as following: https://i.stack.imgur.com/kTDgQ.png (incorrectly displayed)
instead: https://i.stack.imgur.com/cHVjn.png (correctly displayed)
steps to reproduce done in video
https://youtu.be/7ukhloCPf0k
When you mouse hover some of the UI elements (the originally not correctly drawn), you can notice some of them to be get painted (e.g. table rows).
https://i.stack.imgur.com/kkMKn.png (before opening the dialog)
https://i.stack.imgur.com/ZXIKc.png (after opening the dialog)
https://i.stack.imgur.com/25M7S.jpg (after mouse over)
Even calling Shell.update() or Shell.redraw() after the Dialog opened does not fix it.
In Windows Performance Options -> Visual Effects -> disable "Use visual styles on windows and buttons" is the only option I found which provides a workaround,
which seems to be the same as changing the design/theme/style to classic.
https://www.sevenforums.com/tutorials/1908-visual-effects-settings-change.html (How to Change Windows Visual Effects)
In the end, I have following questions:
Is it a SWT or Windows problem?
Is there any related topic in bug entries for Windows or in Eclipse Bugzilla?
Is there someone else who experienced the same problem? please share the experience.
Is there any settings in SWT or Windows which could affect its look n feel and fix the problem?
In the end, I have following questions: Is it a SWT or Windows problem?
Neither. As others have mentioned, you certainly should not tie up the UI thread with any long-running task. That work belongs in a background thread.
In regards to using a background thread, there are several ways you could go about this depending on how you want your Dialog to behave.
One option would be to kick off the background thread and then open the dialog when the task is done. I personally don't care for this because while the task is running, a user may think that nothing is happening.
Another option would be to open the dialog but display a "Loading" message, or something to that effect to give meaningful feedback and let a user know that the application isn't frozen (like how it looks/responds in your example).
The strategy would be to:
Create the dialog
Start the long task on a background thread and register a callback
Open the dialog with a "Loading" message
When the task is complete, the dialog will be updated from the callback
If you search around a bit on using Executors, you should find some far better examples and detail on how to use them.
Here's a brief example to illustrate what that might look like:
(Note: There are definitely a few issues with this code, but for the sake of brevity and illustrating the point I opted for a slightly naive solution. Also there are Java 8-esque ways that would be a bit shorter, but again, this illustrates the idea behind using a background thread; the same concepts apply)
Given a Callable (or Runnable if you don't need a return value),
public class LongTask implements Callable<String> {
#Override
public String call() throws Exception {
Thread.sleep(15000);
return "Hello, World!";
}
}
You can use the Executors class to create a thread pool, and then an ExecutorService to submit the Callable for execution. Then, using Futures.addCallback(), you can register a callback which will execute one of two methods depending on whether the task was successful or failed.
final ExecutorService threadPool = Executors.newFixedThreadPool(1);
final ListeningExecutorService executorService = MoreExecutors.listeningDecorator(threadPool);
final ListenableFuture<String> future = executorService.submit(new LongTask());
Futures.addCallback(future, new FutureCallback(){...});
In this case I used the Google Guava implementation ListeningExecutorService which makes things a bit cleaner and simpler, in my opinion. But again, you may not even need this if you opt for a more "Java 8" approach.
As for the callback, when the task is successful, we update the Dialog with the results. If it fails, we can update it with something to indicate failure:
public static class DialogCallback implements FutureCallback<String> {
private final MyDialog dialog;
public DialogCallback(final MyDialog dialog) {
this.dialog = dialog;
}
#Override
public void onSuccess(final String result) {
dialog.getShell().getDisplay().asyncExec(new Runnable() {
#SuppressWarnings("synthetic-access")
#Override
public void run() {
dialog.setStatus(result);
}
});
}
#Override
public void onFailure(final Throwable t) {
dialog.getShell().getDisplay().asyncExec(new Runnable() {
#SuppressWarnings("synthetic-access")
#Override
public void run() {
dialog.setStatus("Failure");
}
});
}
}
In this case I opted for the Callable to return a String, thus the FutureCallback should be parameterized with String. You may want to use some other class that you created, which will work just as well.
Notice that we use the Display.asyncExec() method to ensure that the code which updates the UI runs on the UI thread, because the callback may execute on the background thread.
Like I said, there are still a few issues here, including what happens when you click the cancel button before the task completes, etc. But hopefully this helps illustrate an approach for handling long-running background tasks without blocking the UI thread.
Full example code:
public class DialogTaskExample {
private final Display display;
private final Shell shell;
private final ListeningExecutorService executorService;
public DialogTaskExample() {
display = new Display();
shell = new Shell(display);
shell.setLayout(new GridLayout());
executorService = MoreExecutors.listeningDecorator(Executors.newFixedThreadPool(1));
final Button button = new Button(shell, SWT.PUSH);
button.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
button.setText("Start");
button.addSelectionListener(new SelectionAdapter() {
#SuppressWarnings("synthetic-access")
#Override
public void widgetSelected(final SelectionEvent e) {
final MyDialog dialog = new MyDialog(shell);
dialog.setBlockOnOpen(false);
dialog.open();
dialog.setStatus("Doing stuff...");
final ListenableFuture<String> future = executorService.submit(new LongTask());
Futures.addCallback(future, new DialogCallback(dialog));
}
});
}
public void run() {
shell.setSize(200, 200);
shell.open();
while (!shell.isDisposed()) {
if (!display.readAndDispatch()) {
display.sleep();
}
}
executorService.shutdown();
display.dispose();
}
public static void main(final String... args) {
new DialogTaskExample().run();
}
public static class DialogCallback implements FutureCallback<String> {
private final MyDialog dialog;
public DialogCallback(final MyDialog dialog) {
this.dialog = dialog;
}
#Override
public void onSuccess(final String result) {
dialog.getShell().getDisplay().asyncExec(new Runnable() {
#SuppressWarnings("synthetic-access")
#Override
public void run() {
dialog.setStatus(result);
}
});
}
#Override
public void onFailure(final Throwable t) {
dialog.getShell().getDisplay().asyncExec(new Runnable() {
#SuppressWarnings("synthetic-access")
#Override
public void run() {
dialog.setStatus("Failure");
}
});
}
}
public static class LongTask implements Callable<String> {
/**
* {#inheritDoc}
*/
#Override
public String call() throws Exception {
Thread.sleep(15000);
return "Hello, World!";
}
}
public static class MyDialog extends Dialog {
private Composite baseComposite;
private Label label;
/**
* #param parentShell
*/
protected MyDialog(final Shell parentShell) {
super(parentShell);
}
/**
* {#inheritDoc}
*/
#Override
protected Control createDialogArea(final Composite parent) {
baseComposite = (Composite) super.createDialogArea(parent);
label = new Label(baseComposite, SWT.NONE);
return baseComposite;
}
public void setStatus(final String text) {
label.setText(text);
baseComposite.layout();
}
}
}
The code seems to be straight forward, only that you are making the main Thread sleep for 15secs hence the delay. If not required remove the sleep or reduce the time for sleep to 5secs or so.
I am trying to learn some JavaFx these days. I set up a simple MVC and it works well until I click the button to invoke click envet. It throws java.lang.NullPointerException. I think the problem is that the instance variable "controller" is not initialized after GUI launched. But I do initialize it in the main method. Below is view class and what I did in the main method.
package javafxdemogui;
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.TextArea;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.stage.Stage;
/**
*
* #author Jason
*/
public class DemoView extends Application {
private TextArea inputText;
private TextArea outputText;
private DemoController controller;
#Override
public void start(Stage primaryStage) {
BorderPane borderPane = new BorderPane();
this.inputText = new TextArea();
this.outputText = new TextArea();
this.inputText.setWrapText(true);
this.outputText.setWrapText(true);
this.outputText.setEditable(false);
borderPane.setTop(inputText);
HBox hbox = new HBox();
hbox.setSpacing(10);
Button resetBtn = new Button("reset");
Button copyInputBtn = new Button("copyInput");
hbox.getChildren().addAll(resetBtn, copyInputBtn);
hbox.setAlignment(Pos.CENTER);
borderPane.setCenter(hbox);
borderPane.setBottom(outputText);
resetBtn.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
controller.processResetEvent();
}
});
copyInputBtn.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
controller.processCopyEvent(inputText.getText());
}
});
Scene scene = new Scene(borderPane, 600, 400);
primaryStage.setTitle("JavaFXDemoGUI");
primaryStage.setScene(scene);
primaryStage.show();
}
public void registerObserver(DemoController controller) {
this.controller = controller;
}
/**
* Updates input display based on String provided as argument.
*
* #param input new value of input display
*/
public void updateInputDisplay(String input) {
this.inputText.setText(input);
}
/**
* Updates output display based on String provided as argument.
*
* #param output new value of output display
*/
public void updateOutputDisplay(String output) {
this.outputText.setText(output);
}
/**
* The main() method is ignored in correctly deployed JavaFX application.
* main() serves only as fallback in case the application can not be
* launched through deployment artifacts, e.g., in IDEs with limited FX
* support. NetBeans ignores main().
*
* #param args the command line arguments
*/
public void viewLaunch(String[] args) {
launch(args);
}
}
And What I did in the main method....
public static void main(String[] args) {
/*
* Create instances of the model, view, and controller objects, and
* initialize them; view needs to know about controller, and controller
* needs to know about model and view
*/
DemoModel model = new DemoModel();
DemoView view = new DemoView();
DemoController controller = new DemoController(model, view);
view.registerObserver(controller);
view.viewLaunch(args);
}
I advise placing the main() method in your application class and not doing anything in main but launching the application.
I haven't tried it, but I'd be willing to bet that when Application.launch is invoked, that it generates a new instance of your application class, so effectively all of the code you have written in main before the launch is ignored.
I know that for a while, for Java 8 the Oracle team were considering not invoking main on startup for launching a JavaFX application (not sure what the eventual outcome of that was though, perhaps they still invoke the main method).
What you really should do instead is handle all of your initialization in the init or start methods of your application. Also note (in JavaFX 2.2) that if you do stuff in init there are some restrictions on JavaFX objects which can be instantiated (as you are not yet on the JavaFX application thread), for example you can't create Tooltips or WebViews off the JavaFX application thread. For this reason most of the JavaFX applications you see end up creating their UI on the JavaFX application thread at the front of the start method.
Also, a good approach is to shelve any long running tasks which can be done off of the JavaFX application thread (such as reading a database into something like your DemoModel) off to a JavaFX concurrent task, that way you can get progress feedback and messages from that long running task back to your UI to update an initialization status (if your framework requires that level of sophistication).
JavaFx is supposed to be easily integrated in an SWT application (see here: http://docs.oracle.com/javafx/2/swt_interoperability/jfxpub-swt_interoperability.htm) and both toolkits use the same threading model.
However things get strange, when I open a dialog containing an FxCanvas which contains a JavaFx ComboBox. If I open the combo box popup menu and then close the dialog, the popup menu stays open. If I now move the mouse onto the popup a null pointer exception is thrown within javafx. When doing this within a larger application all JavaFx GUIs remain broken until the application is restarted.
Any ways to work around this?
Example code below: Close the dialog with 'Ok' or the window close button. Exit the application with 'Cancel'
package test;
import javafx.embed.swt.FXCanvas;
import javafx.geometry.Insets;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.ComboBox;
import javafx.scene.layout.StackPane;
import org.eclipse.jface.dialogs.Dialog;
import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
public class TestFx {
static class MyDialog extends Dialog {
Parent w;
public MyDialog(Shell parent,Parent n) {
super(parent);
this.w = n;
setShellStyle(SWT.RESIZE| SWT.BORDER | SWT.TITLE |SWT.CLOSE );
}
#Override
public void cancelPressed() {
System.exit(0);
}
#Override
protected Control createDialogArea(Composite parent) {
Composite container = (Composite) super.createDialogArea(parent);
container.setLayout(new FillLayout());
FXCanvas fxCanvas = new FXCanvas(container, SWT.NONE);
Scene scene = new Scene(w);
fxCanvas.setScene(scene);
return container;
}
}
private static Parent createScene() {
StackPane pane = new StackPane();
pane.setPadding(new Insets(10));
ComboBox<String> c = new ComboBox<String>();
c.getItems().addAll("Test1","Test2");
pane.getChildren().add(c);
return pane;
}
public static void main(String[] args) {
Display display = new Display();
Shell shell = new Shell(display);
while (true) {
MyDialog d = new MyDialog(shell,createScene());
d.open();
}
}
}
Exception:
java.lang.NullPointerException
at com.sun.javafx.tk.quantum.GlassScene.sceneChanged(GlassScene.java:290)
at com.sun.javafx.tk.quantum.ViewScene.sceneChanged(ViewScene.java:156)
at com.sun.javafx.tk.quantum.PopupScene.sceneChanged(PopupScene.java:30)
at com.sun.javafx.tk.quantum.GlassScene.markDirty(GlassScene.java:157)
at javafx.scene.Scene$ScenePulseListener.pulse(Scene.java:2214)
at com.sun.javafx.tk.Toolkit.firePulse(Toolkit.java:363)
at com.sun.javafx.tk.quantum.QuantumToolkit.pulse(QuantumToolkit.java:460)
at com.sun.javafx.tk.quantum.QuantumToolkit$9.run(QuantumToolkit.java:329)
at org.eclipse.swt.internal.win32.OS.DispatchMessageW(Native Method)
at org.eclipse.swt.internal.win32.OS.DispatchMessage(OS.java:2546)
at org.eclipse.swt.widgets.Display.readAndDispatch(Display.java:3756)
at org.eclipse.jface.window.Window.runEventLoop(Window.java:825)
at org.eclipse.jface.window.Window.open(Window.java:801)
at test.TestFx.main(TestFx.java:55)
At work we're developing some applications using JavaFX, on top of and old Swing platform and we also have found this issue.
Apparently it is caused by some issues on JFXPanel which is not correctly propagating some window events (focus, iconifying, etc) to the FX framework. The issue affects not only the ComboBox component, but every component that uses a PopupWindow (Menu, Tooltip, etc), specially when using Swing's JInternalFrame.
So, when a Popup is displaying and the window is minimized or closed, the Popup does not hide, causing the FX thread to crash if you try subsequently to interact with it.
The workaround mentioned above works, but only for ComboBox, as Menu and Tooltip does not inherit from the Node class, so didn't work for us :(
I developed another workaround which resolved the problem for all components that display popups, which basically forces all popups to close whenever a JFXPanel loses focus:
private static void initFX(final JFXPanel jfxPanel) {
final TestFxPanel parent = new TestFxPanel();
final Scene scene = new Scene(parent);
jfxPanel.setScene(scene);
jfxPanel.addFocusListener(new FocusAdapter() {
#Override
public void focusLost(final FocusEvent e) {
System.out.println(jfxPanel.getName() + ": FocusLost");
runFocusPatch(scene);
}
});
}
static void runFocusPatch(final Scene scene) {
Platform.runLater(new Runnable() {
#Override
public void run() {
System.out.println("Running patch");
final Iterator<Window> winIter = scene.getWindow().impl_getWindows();
while (winIter.hasNext()) {
final Window t = winIter.next();
if (t instanceof PopupWindow) {
System.out.println("Got a popup");
Platform.runLater(new Runnable() {
#Override
public void run() {
((PopupWindow) t).hide();
}
});
}
}
}
});
}
I confirm that the issue is NOT present in 8.0. Sadly we are not allowed to java 8 in production software as its still in beta stage.
best regards.
I found a workaround when using Java7: Override the close method in Dialog to hide the combo box popups:
#Override
public boolean close() {
Set<Node> nodes = w.lookupAll("#");
for (Node n : nodes)
if (n instanceof ComboBox)
((ComboBox)n).hide();
return super.close();
}
The trouble is discussed here : javafx-jira.kenai.com/browse/RT-30991
Developer has said, that the issue is fixed in JavaFX-8
I'm trying to create an Android application that shows the current time. I want to update time on my Activity with the Timer, but the TextView is not updating, so just one time is always on the screen. Here is my code:
package com.example.androidtemp;
import java.sql.Date;
import java.text.SimpleDateFormat;
import java.util.Timer;
import java.util.TimerTask;
import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.widget.TextView;
import com.example.androidtemp.R;
public class ActivityTime extends Activity
{
SimpleDateFormat sdf;
String time;
TextView tvTime;
String TAG = "States";
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_activity_time);
sdf = new SimpleDateFormat("HH:mm:ss");
time = sdf.format(new Date(System.currentTimeMillis()));
tvTime = (TextView) findViewById(R.id.tvTime);
Timer timer = new Timer();
TimerTask task = new TimerTask()
{
#Override
public void run()
{
// TODO Auto-generated method stub
timerMethod();
}
};
try
{
timer.schedule(task, 0, 1000);
}
catch (IllegalStateException e)
{
// TODO: handle exception
e.printStackTrace();
Log.e(TAG, "The Timer has been canceled, or if the task has been scheduled or canceled.");
}
}
protected void timerMethod()
{
// TODO Auto-generated method stub
this.runOnUiThread(changeTime);
}
private final Runnable changeTime = new Runnable()
{
public void run()
{
// TODO Auto-generated method stub
//Log.d(TAG, "Changing time.");
sdf.format(new Date(System.currentTimeMillis()));
tvTime.setText(time);
}
};
}
Does anyone have solution for this problem?
I would recommend you to use DigitalClock or TextClock (you can use 'include' in the layout xml and layout / layout-v17 to use a different component depending of the OS version) if you just want to show the time.
If you want to have more control, I would recommend you using a Handler or an ExecutorService instead of a Timer. Java Timer vs ExecutorService?
If you want to fix your code as it is, just modify the value of the variable 'time' ;)
Use a handler since it can access the views of your application. The views of your application belong to the main thread already so creating another thread to access them usually doesn't work. If am not wrong, handlers use messages to communicate with the main thread and its components. Use this where you have your thread definition instead:
Handler handler = new Handler();
handler.removeCallbacks(runnable);
handler.postDelayed(runnable, 1000);
and add this to your runnable definition
handler.postDelayed(runnable, 1000);
This last statement removes any instance of runnable awaiting execution when a new on is added. Kind of like clearing a queue.
My application contains lots of images. so it takes some time to load the application. I want to show a loading screen whhile the application is being loaded. How is it possible ?
Here's an example app that skeletons what your looking to do. Basically, the initial screen you push is a loading screen. During the initial startup sequence you need to spin up a new thread, do your loading stuff and then use invokeLater to 1) make sure your in the event dispatcher and 2) to push a new screen -- or in the case of this example a dialog -- to the screen to have the user progress away from the loading screen.
Here's the code:
import net.rim.device.api.ui.Field;
import net.rim.device.api.ui.UiApplication;
import net.rim.device.api.ui.container.MainScreen;
import net.rim.device.api.ui.component.Dialog;
import net.rim.device.api.ui.component.LabelField;
/**
* Just a test app.
*/
public class TestAppMain extends UiApplication
{
/**
* Default Constructor.
*/
private TestAppMain() {
pushScreen(new AppScreen(this));
}
/**
* App entry point.
* #param args Arguments.
*/
public static void main(String[] args) {
TestAppMain app = new TestAppMain();
app.enterEventDispatcher();
}
/**
* Main application screen.
*/
private static class AppScreen extends MainScreen
{
UiApplication _app;
/**
* Default constructor.
*/
public AppScreen(UiApplication app) {
// Note: This screen just says "Loading...", but you could
// add a loading animation.
_app = app;
LabelField title = new LabelField("App Name",
LabelField.ELLIPSIS | LabelField.USE_ALL_WIDTH);
setTitle(title);
LabelField loading = new LabelField("Loading...",
LabelField.ELLIPSIS | LabelField.USE_ALL_WIDTH);
add(loading);
// Queue up the loading process.
startLoading();
}
/**
* Create the loading thread. Make sure to invoke later as you will
* need to push a screen or show a dialog after the loading is complete, eventhough
* you are creating the thread before the app is in the event dispatcher.
*/
public void startLoading() {
Thread loadThread = new Thread() {
public void run() {
// Make sure to invokeLater to avoid problems with the event thread.
try{
// Simulate loading time
Thread.sleep(5000);
} catch(java.lang.InterruptedException e){}
// TODO - Add loading logic here.
_app.invokeLater( new Runnable() {
public void run() {
// This represents the next step after loading. This just shows
// a dialog, but you could push the applications main menu screen.
Dialog.alert("Load Complete");
}
});
}
};
loadThread.start();
}
}
}
HorizontalFieldManager popHF = new HorizontalFieldManager();
popHF.add(new CustomLabelField("Pls wait..."));
final PopupScreen waitScreen = new PopupScreen(popHF);
new Thread()
{
public void run()
{
synchronized (UiApplication.getEventLock())
{
UiApplication.getUiApplication().pushScreen(waitScreen);
}
//Here Some Network Call
synchronized (UiApplication.getEventLock())
{
UiApplication.getUiApplication().popScreen(waitScreen);
}
}
}.start();