I'm attempting to implement a BroadcastReceiver that will tell me when the network status has changed. I'll be using that to sync local data back to the main server when I get internet connection back after losing it.
As a start I was looking at this example: http://fizzylogic.nl/2013/08/17/xamarin-android-by-example-monitoring-the-network-status/
public class NetworkStatusMonitor
{
private NetworkState _state;
public NetworkStatusMonitor ()
{
}
public NetworkState State {
get {
UpdateNetworkStatus ();
return _state;
}
}
public void UpdateNetworkStatus() {
_state = NetworkState.Unknown;
// Retrieve the connectivity manager service
var connectivityManager = (ConnectivityManager)
Application.Context.GetSystemService (
Context.ConnectivityService);
// Check if the network is connected or connecting.
// This means that it will be available,
// or become available in a few seconds.
var activeNetworkInfo = connectivityManager.ActiveNetworkInfo;
if (activeNetworkInfo.IsConnectedOrConnecting) {
// Now that we know it's connected, determine if we're on WiFi or something else.
_state = activeNetworkInfo.Type == ConnectivityType.Wifi ?
NetworkState.ConnectedWifi : NetworkState.ConnectedData;
} else {
_state = NetworkState.Disconnected;
}
}
}
public enum NetworkState
{
Unknown,
ConnectedWifi,
ConnectedData,
Disconnected
}
Then my broadcast receiver looks like this:
[BroadcastReceiver()]
public class NetworkStatusBroadcastReceiver: BroadcastReceiver {
public event EventHandler ConnectionStatusChanged;
public override void OnReceive (Context context, Intent intent)
{
if (ConnectionStatusChanged != null)
ConnectionStatusChanged (this, EventArgs.Empty);
}
}
Now my question is... Where do I initialize this and where do I put the following Start() and Stop() methods?
public event EventHandler NetworkStatusChanged;
public void Start ()
{
if (_broadcastReceiver != null) {
throw new InvalidOperationException (
"Network status monitoring already active.");
}
// Create the broadcast receiver and bind the event handler
// so that the app gets updates of the network connectivity status
_broadcastReceiver = new NetworkStatusBroadcastReceiver ();
_broadcastReceiver.ConnectionStatusChanged += OnNetworkStatusChanged;
// Register the broadcast receiver
Application.Context.RegisterReceiver (_broadcastReceiver,
new IntentFilter (ConnectivityManager.ConnectivityAction));
}
void OnNetworkStatusChanged (object sender, EventArgs e)
{
var currentStatus = _state;
UpdateNetworkStatus ();
if (currentStatus != _state && NetworkStatusChanged != null) {
NetworkStatusChanged (this, EventArgs.Empty);
}
}
public void Stop() {
if (_broadcastReceiver == null) {
throw new InvalidOperationException (
"Network status monitoring not active.");
}
// Unregister the receiver so we no longer get updates.
Application.Context.UnregisterReceiver (_broadcastReceiver);
// Set the variable to nil, so that we know the receiver is no longer used.
_broadcastReceiver.ConnectionStatusChanged -= OnNetworkStatusChanged;
_broadcastReceiver = null;
}
Sorry for the probably silly question but still new to Xamarin and Android.
I think following link is helpful. I get the notification when the network status changes.
networkstatusbroadcastreceiver See Bradley's answer on the bottom of the page.
Related
I’ve got a mobile crossplatform Xamarin.Forms project in which I try to download a file from a Dropbox repository at startup. It’s a tiny json file of less than 50kB. The code operating the Dropbox API call is shared between my Android and my iOS projects, and my Android implementation works as intended. It’s a Task method which I’ll call the downloader here for convenience.
UPDATED: With the iOS version, I can download the file successfully only when calling my downloader’s launcher (which is a also Task) directly from the BackgroundSynchronizer.Launch() method of my only AppDelegate, but not when delegating this call using a timer to call my downloader through a TimerCallback which calls an EventHandler at recurring times.
I can’t figure out why.
The downloader:
public class DropboxStorage : IDistantStoreService
{
private string oAuthToken;
private DropboxClientConfig clientConfig;
private Logger logger = new Logger
(DependencyService.Get<ILoggingBackend>());
public DropboxStorage()
{
var httpClient = new HttpClient(new NativeMessageHandler());
clientConfig = new DropboxClientConfig
{
HttpClient = httpClient
};
}
public async Task SetConnection()
{
await GetAccessToken();
}
public async Task<Stream> DownloadFile(string distantUri)
{
logger.Info("Dropbox downloader called.");
try
{
await SetConnection();
using var client = new DropboxClient(oAuthToken, clientConfig);
var downloadArg = new DownloadArg(distantUri);
var metadata = await client.Files.DownloadAsync(downloadArg);
var stream = metadata?.GetContentAsStreamAsync();
return await stream;
}
catch (Exception ex)
{
logger.Error(ex);
}
return null;
}
UPDATED: The AppDelegate:
using Foundation;
using UIKit;
namespace Izibio.iOS
{
// The UIApplicationDelegate for the application. This class is responsible for launching the
// User Interface of the application, as well as listening (and optionally responding) to
// application events from iOS.
[Register("AppDelegate")]
public partial class AppDelegate : global::Xamarin.Forms.Platform.iOS.FormsApplicationDelegate
{
private BackgroundSynchronizer synchronizer = new BackgroundSynchronizer();
//
// This method is invoked when the application has loaded and is ready to run. In this
// method you should instantiate the window, load the UI into it and then make the window
// visible.
//
// You have 17 seconds to return from this method, or iOS will terminate your application.
//
public override bool FinishedLaunching(UIApplication app, NSDictionary options)
{
global::Xamarin.Forms.Forms.Init();
LoadApplication(new App());
return base.FinishedLaunching(app, options);
}
public override void OnActivated(UIApplication uiApplication)
{
synchronizer.Launch();
base.OnActivated(uiApplication);
}
}
}
EDIT: The intermediary class (which embeds the DownloadProducts function):
public static class DropboxNetworkRequests
{
public static async Task DownloadProducts(IDistantStoreService distantStorage,
IStoreService localStorage)
{
try
{
var productsFileName = Path.GetFileName(Globals.ProductsFile);
var storeDirectory = $"/{Globals.StoreId}_products";
var productsFileUri = Path.Combine(storeDirectory, productsFileName);
var stream = await distantStorage.DownloadFile(productsFileUri);
if (stream != null)
{
await localStorage.Save(stream, productsFileUri);
}
else
{
var logger = GetLogger();
logger.Info($"No file with the uri ’{productsFileUri}’ could " +
$"have been downloaded.");
}
}
catch (Exception ex)
{
var logger = GetLogger();
logger.Error(ex);
}
}
private static Logger GetLogger()
{
var loggingBackend = DependencyService.Get<ILoggingBackend>();
return new Logger(loggingBackend);
}
}
UPDATED: And the failing launcher class (the commented TriggerNetworkOperations(this, EventArgs.Empty);
in the Launch method succeeds in downloading the file) :
public class BackgroundSynchronizer
{
private bool isDownloadRunning;
private IDistantStoreService distantStorage;
private IStoreService localStorage;
private Timer timer;
public event EventHandler SynchronizationRequested;
public BackgroundSynchronizer()
{
Forms.Init();
isDownloadRunning = false;
distantStorage = DependencyService.Get<IDistantStoreService>();
localStorage = DependencyService.Get<IStoreService>();
Connectivity.ConnectivityChanged += TriggerNetworkOperations;
SynchronizationRequested += TriggerNetworkOperations;
}
public void Launch()
{
try
{
var millisecondsInterval = Globals.AutoDownloadMillisecondsInterval;
var callback = new TimerCallback(SynchronizationCallback);
timer = new Timer(callback, this, 0, 0);
timer.Change(0, millisecondsInterval);
//TriggerNetworkOperations(this, EventArgs.Empty);
}
catch (Exception ex)
{
throw ex;
}
}
protected virtual void OnSynchronizationRequested(object sender, EventArgs e)
{
SynchronizationRequested?.Invoke(sender, e);
}
private async void TriggerNetworkOperations(object sender, ConnectivityChangedEventArgs e)
{
if ((e.NetworkAccess == NetworkAccess.Internet) && !isDownloadRunning)
{
await DownloadProducts(sender);
}
}
private async void TriggerNetworkOperations(object sender, EventArgs e)
{
if (!isDownloadRunning)
{
await DownloadProducts(sender);
}
}
private void SynchronizationCallback(object state)
{
SynchronizationRequested(state, EventArgs.Empty);
}
private async Task DownloadProducts(object sender)
{
var instance = (BackgroundSynchronizer)sender;
//Anti-reentrance assignments commented for debugging purposes
//isDownloadRunning = true;
await DropboxNetworkRequests.DownloadProducts(instance.distantStorage, instance.localStorage);
//isDownloadRunning = false;
}
}
I set a logging file to record my application behaviour when trying to download.
EDIT: Here are the messages I get when calling directly TriggerNetworkOperations from the Launch method:
2019-11-12 19:31:57.1758|INFO|xamarinLogger|iZiBio Mobile Launched
2019-11-12 19:31:57.4875|INFO|persistenceLogger|Dropbox downloader called.
2019-11-12 19:31:58.4810|INFO|persistenceLogger|Writing /MAZEDI_products/assortiment.json at /Users/dev3/Library/Developer/CoreSimulator/Devices/5BABB56B-9B42-4653-9D3E-3C60CFFD50A8/data/Containers/Data/Application/D6C517E9-3446-4916-AD8D-565F4C206AF2/Library/assortiment.json
EDIT: And are those I get when launching through the timer and its callback (with a 10 seconds interval for debugging purposes):
2019-11-12 19:34:05.5166|INFO|xamarinLogger|iZiBio Mobile Launched
2019-11-12 19:34:05.8149|INFO|persistenceLogger|Dropbox downloader called.
2019-11-12 19:34:15.8083|INFO|persistenceLogger|Dropbox downloader called.
2019-11-12 19:34:25.8087|INFO|persistenceLogger|Dropbox downloader called.
2019-11-12 19:34:35.8089|INFO|persistenceLogger|Dropbox downloader called.
EDIT: In this second scenario, the launched task event eventually gets cancelled by the OS:
2019-11-13 09:36:29.7359|ERROR|persistenceLogger|System.Threading.Tasks.TaskCanceledException: A task was canceled.
at ModernHttpClient.NativeMessageHandler.SendAsync (System.Net.Http.HttpRequestMessage request, System.Threading.CancellationToken cancellationToken) [0x002a5] in /Users/paul/code/paulcbetts/modernhttpclient/src/ModernHttpClient/iOS/NSUrlSessionHandler.cs:139
at System.Net.Http.HttpClient.SendAsyncWorker (System.Net.Http.HttpRequestMessage request, System.Net.Http.HttpCompletionOption completionOption, System.Threading.CancellationToken cancellationToken) [0x0009e] in /Users/builder/jenkins/workspace/xamarin-macios/xamarin-macios/external/mono/mcs/class/System.Net.Http/System.Net.Http/HttpClient.cs:281
at Dropbox.Api.DropboxRequestHandler.RequestJsonString (System.String host, System.String routeName, System.String auth, Dropbox.Api.DropboxRequestHandler+RouteStyle routeStyle, System.String requestArg, System.IO.Stream body) [0x0030f] in <8d8475f2111a4ae5850a1c1349c08d28>:0
at Dropbox.Api.DropboxRequestHandler.RequestJsonStringWithRetry (System.String host, System.String routeName, System.String auth, Dropbox.Api.DropboxRequestHandler+RouteStyle routeStyle, System.String requestArg, System.IO.Stream body) [0x000f6] in <8d8475f2111a4ae5850a1c1349c08d28>:0
at Dropbox.Api.DropboxRequestHandler.Dropbox.Api.Stone.ITransport.SendDownloadRequestAsync[TRequest,TResponse,TError] (TRequest request, System.String host, System.String route, System.String auth, Dropbox.Api.Stone.IEncoder`1[T] requestEncoder, Dropbox.Api.Stone.IDecoder`1[T] resposneDecoder, Dropbox.Api.Stone.IDecoder`1[T] errorDecoder) [0x000a5] in <8d8475f2111a4ae5850a1c1349c08d28>:0
at Izibio.Persistence.DropboxStorage.DownloadFile (System.String distantUri) [0x00105] in /Users/dev3/Virtual Machines.localized/shared/TRACAVRAC/izibio-mobile/Izibio/Izibio.Persistence/Services/DropboxStorage.cs:44
2019-11-13 09:36:29.7399|INFO|persistenceLogger|No file with the uri ’/******_products/assortiment.json’ could have been downloaded.
I’ll simply add a last observation: when debugging the DownloadFile Task from the BackgroundSynchronizer, I can reach the call to client.Files.DowloadAsync: var metadata = await client.Files.DownloadAsync(downloadArg);, but I won’t retrieve any return from this await statement.
OK, I finally found a way out of this by replacing the .NET timer by the iOS implementation (NSTimer).
My new code for the BackgroundSynchronizer class:
public class BackgroundSynchronizer
{
private bool isDownloadRunning;
private IDistantStoreService distantStorage;
private IStoreService localStorage;
private NSTimer timer;
public event EventHandler SynchronizationRequested;
public BackgroundSynchronizer()
{
Forms.Init();
isDownloadRunning = false;
distantStorage = DependencyService.Get<IDistantStoreService>();
localStorage = DependencyService.Get<IStoreService>();
Connectivity.ConnectivityChanged += TriggerNetworkOperations;
SynchronizationRequested += TriggerNetworkOperations;
}
public void Launch()
{
try
{
var seconds = Globals.AutoDownloadMillisecondsInterval / 1000;
var interval = new TimeSpan(0, 0, seconds);
var callback = new Action<NSTimer>(SynchronizationCallback);
StartTimer(interval, callback);
}
catch (Exception ex)
{
throw ex;
}
}
protected virtual void OnSynchronizationRequested(object sender, EventArgs e)
{
SynchronizationRequested?.Invoke(sender, e);
}
private async void TriggerNetworkOperations(object sender, ConnectivityChangedEventArgs e)
{
if ((e.NetworkAccess == NetworkAccess.Internet) && !isDownloadRunning)
{
await DownloadProducts();
}
}
private async void TriggerNetworkOperations(object sender, EventArgs e)
{
if (!isDownloadRunning)
{
await DownloadProducts();
}
}
private void SynchronizationCallback(object state)
{
SynchronizationRequested(state, EventArgs.Empty);
}
private async Task DownloadProducts()
{
isDownloadRunning = true;
await DropboxNetworkRequests.DownloadProducts(distantStorage, localStorage);
isDownloadRunning = false;
}
private void StartTimer(TimeSpan interval, Action<NSTimer> callback)
{
timer = NSTimer.CreateRepeatingTimer(interval, callback);
NSRunLoop.Main.AddTimer(timer, NSRunLoopMode.Common);
}
}
Which produces the following logging lines:
2019-11-13 14:00:58.2086|INFO|xamarinLogger|iZiBio Mobile Launched
2019-11-13 14:01:08.5378|INFO|persistenceLogger|Dropbox downloader called.
2019-11-13 14:01:09.5656|INFO|persistenceLogger|Writing /****_products/assortiment.json at /Users/dev3/Library/Developer/CoreSimulator/Devices/****/data/Containers/Data/Application/****/Library/assortiment.json
2019-11-13 14:01:18.5303|INFO|persistenceLogger|Dropbox downloader called.
2019-11-13 14:01:19.2375|INFO|persistenceLogger|Writing /****_products/assortiment.json at /Users/dev3/Library/Developer/CoreSimulator/Devices/****/data/Containers/Data/Application/****/Library/assortiment.json
But I’m still open to an enlighted explanation of the reason why both timers result in such different behaviours.
I wrote my own custom error handler for the UI in Vaadin flow. But when I throw the exception my view crash and not show my human readable error message.
I did this in other application using Vaadin 8 and works perfectly. The idea its throw a SgiException in my backend services like:
Product not found
Incorrect value for field "XXX"
Not available stock for the product.
etc.
And then show a system notification
public static void setDefaultErrorHandler(ErrorEvent errorEvent) {
Throwable t = DefaultErrorHandler.findRelevantThrowable(errorEvent.getThrowable());
String message;
if (t != null) {
message = t.getMessage();
} else {
message = "";
}
log.error(message, t);
SgiException sgiException = getCauseOfType(t, SgiException.class);
if (sgiException != null) {
NotificationBuilder.exception(sgiException.getCode(), sgiException.getMessage());
return;
} else {
NotificationBuilder.exception(UNKNOW_ERROR, (message == null ? "" : message));
return;
}
}
private static <T extends Throwable> T getCauseOfType(Throwable th, Class<T> type) {
while (th != null) {
if (type.isAssignableFrom(th.getClass())) {
return (T) th;
} else {
th = th.getCause();
}
}
return null;
}
And this is how I set the custom error handler:
#PostConstruct
public void configBaseView() {
VaadinSession.getCurrent().setErrorHandler(Util::setDefaultErrorHandler);
}
In the view show this:
Note:
Debugging the application, seeing the code it's running, looks the method its called for some reason not show the notification.
This is a nasty behaviour that can't currently be overridden in Vaadin 10. Follow and vote (thumb up or comment) this issue to get it solved: https://github.com/vaadin/flow/issues/801
i am trying to develop an application in c# which acts as a server for an android phone.i am using 32feet.net for bluetooth in c# and i have a server running in android, which simply sends a socket to server. the server running in pc need to listen the connection and display ,the status of connection. all these things are base for my project. the server code is as shown :
namespace testserver
{
class Program
{
static void Main(string[] args)
{
BluetoothClient bc = new BluetoothClient();
BluetoothDeviceInfo[] dev;
BluetoothDeviceInfo td=null;
Guid id = new Guid("{00112233-4455-6677-8899-aabbccddeeff}");
// Console.WriteLine(id.ToString());
// Console.Read();
dev = bc.DiscoverDevices();
foreach (BluetoothDeviceInfo d in dev)
{
if (d.DeviceName == "ST21i")//my phone name
{
td=d;
break;
}
}
try
{
BluetoothAddress addr = td.DeviceAddress;
BluetoothListener bl = new BluetoothListener(addr, id);
bl.Start();
if (bl.AcceptSocket() != null)
Console.WriteLine("Success");
}
catch (Exception e)
{
Console.WriteLine("Exception : "+e.Message);
Console.Read();
}
}
}
}
and here is my android code :
public class MainActivity extends Activity {
BluetoothAdapter adapter;
BluetoothDevice bd;
BluetoothSocket sock;
OutputStream ostr;
int REQUEST_ENABLE_BT;
String str="5C:AC:4C:DD:CC:0D";
private static final UUID id=UUID.fromString("00112233-4455-6677-8899- aabbccddeeff");
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
adapter=BluetoothAdapter.getDefaultAdapter();
if (!adapter.isEnabled()) {
Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
}
Button b = (Button) findViewById(R.id.button1);
b.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
Toast.makeText(getApplicationContext(), "clicked button", Toast.LENGTH_LONG).show();
try
{
bd=adapter.getRemoteDevice(str); Toast.makeText(getApplicationContext(),"Server is running at "+bd.getName().toString()+"...", Toast.LENGTH_LONG).show();
sock=bd.createInsecureRfcommSocketToServiceRecord(id); sock.connect();
ostr=sock.getOutputStream();
ostr.write(0);
}
catch(Exception e)
{
Toast.makeText(getApplicationContext(),e.getMessage(), Toast.LENGTH_LONG).show();
}
}
});
}
}
my problems are :
1) in pc i am getting an exception, the requested address is not valid in its context(so that server cant run )
2)in phone, the service discovery failed( because of unavailability of server)
how can i correct the server and run the program ?
i changed the bluetooth listener object's creation from
BluetoothListener bl = new BluetoothListener(addr, id); to
BluetoothListener bl = new BluetoothListener(id); and everything worked fine..
I am trying to download xml files from server when my application starts. So i want to show splash screen until am done with downloading and then show next screen. below is my code:
Here, i want to show My splash screen when getTopNotDoc() method is under execution. and after completion of that method show next screen.
//get _topics and notification document<br>
_getDoc = new ServerConnectivity(this);
public class ServerConnectivity {
private Document _questionDoc;
private Document _topics;
private Document _notifications;
public ServerConnectivity(ApplicationSession appSession){
//getTopNotDoc();
_this = this;
_appSession = appSession;
new Thread(new Runnable(){
public void run(){
getTopNotDoc();
}
}).start();
}
}
private void getTopNotDoc(){
InputStream inputStream = null ;
try{
// Build a document based on the XML file.
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
inputStream = getClass().getResourceAsStream("topics.xml");
_topics = builder.parse( inputStream );
inputStream = getClass().getResourceAsStream("notification.xml");
_notifications = builder.parse( inputStream );
if(_topics == null || _notifications == null){
Dialog.alert("Unable to connect to internet");
}
}
catch ( Exception e ){
System.out.println( e.toString() );
}
finally{
if(inputStream != null){
try {
inputStream.close();
}
catch (IOException e) {
e.printStackTrace();
}
}
}
}
Usually when I do this, I create a loading screen, then I just extend the Thread class.
So I would create a loading screen like this:
public class LoadingScreen extends MainScreen {
public LoadingScreen() {
super();
this.setTitle("loading...");
// add a spinning animated gif or whatever here
final Screen me = this;
new Thread(new Runnable(){
public void run(){
// do something that takes a long time
try { Thread.sleep(1000);} catch (Exception e) {}
}
}){
public void run() {
super.run();
synchronized (UiApplication.getEventLock()) {
UiApplication.getUiApplication().popScreen(me);
}
}
}.start();
}
}
Then I push this screen, it will perform the long task, and then pop itself when its done.
(you may or may not want to disable the back button and menus on this screen)
I made the Runnable as an anonymous inner class just to compact the code, but you probably have this code already in a class somewhere else, so you would pass it in instead.
To add some flexibility and keep your classes loosely coupled together, you could make some modifications to your ServerConnectivity class so your calls could go something like the following:
// push your splash screen on to the stack
//
final SplashScreen splashScreen = new SplashScreen();
UiApplication.getUiApplication().pushScreen(splashScreen);
_getDoc = new ServerConnectivity(this, new ServerConnectivityListener() {
public void onCompleted(ServerConnectivity sender) {
// display next screen
//
UiApplication.getUiApplication().invokeLater(new Runnable() {
public void run() {
splashScreen.close();
UiApplication.getUiApplication().pushScreen(new NextScreen());
}
});
}
public void onError(ServerConnectivity sender) {
splashScreen.close();
// display error message, retry, etc...
}
});
For this to work, you need an interface with the following definition:
public interface ServerConnectivityListener {
void onCompleted(ServerConnectivity sender);
void onError(ServerConnectivity sender);
}
So, your ServerConnectivity class maintains a reference to some object that implements the interface called ServerConnectivityListener This allows you to maintain loose coupling between the subject class and any observers that need to listen for events.
Within ServerConnectivity, you would make calls to the listener's methods something like this:
// begin excerpt from above...
//
if(_topics == null || _notifications == null) {
_listener.onError(this);
} else {
_listener.onCompleted(this);
}
catch ( Exception e ){
System.out.println( e.toString() );
_listener.onError(this);
//
// end excerpt from above...
Here is code for splash screen in java........after and call that view.........
http://www.randelshofer.ch/oop/javasplash/javasplash.html
import java.awt.*;
import java.awt.event.*;
public class SplashTest extends Frame implements ActionListener {
static void renderSplashFrame(Graphics2D g, int frame) {
final String[] comps = {"foo", "bar", "baz"};
g.setComposite(AlphaComposite.Clear);
g.fillRect(130,250,280,40);
g.setPaintMode();
g.setColor(Color.BLACK);
g.drawString("Loading "+comps[(frame/5)%3]+"...", 130, 260);
g.fillRect(130,270,(frame*10)%280,20);
}
public SplashTest() {
super("SplashScreen demo");
setSize(500, 300);
setLayout(new BorderLayout());
Menu m1 = new Menu("File");
MenuItem mi1 = new MenuItem("Exit");
m1.add(mi1);
mi1.addActionListener(this);
MenuBar mb = new MenuBar();
setMenuBar(mb);
mb.add(m1);
final SplashScreen splash = SplashScreen.getSplashScreen();
if (splash == null) {
System.out.println("SplashScreen.getSplashScreen() returned null");
return;
}
Graphics2D g = (Graphics2D)splash.createGraphics();
if (g == null) {
System.out.println("g is null");
return;
}
for(int i=0; i<100; i++) {
renderSplashFrame(g, i);
splash.update();
try {
Thread.sleep(200);
}
catch(InterruptedException e) {
}
}
splash.close();
setVisible(true);
toFront();
}
public void actionPerformed(ActionEvent ae) {
System.exit(0);
}
public static void main (String args[]) {
SplashTest test = new SplashTest();
}
}
Since,it is a thread based one,We cannot do it the normal way.So Check the following link
http://supportforums.blackberry.com/t5/Java-Development/What-is-the-Event-Thread/ta-p/446865
and Check whether parsing is done,Until that have the same screen,Check the condition of whehter it is downloaded or not ,and then push the screen
I created app which user can start from menu and from icon. I do not use GlobalEventListener in my app, just register ApplicationMenuitem. And now I am getting error: previous instance still active when launch my app.
Steps to reproduce not so trivial:
launch app from icon
do not close it, just switch to another app
launch app from icon again
I founded article in blackberry's forum about it , but I can't find solution where I should remove my ApplicationMenuItem: it added on phone boot and should show all the time.
My code:
public class Jingu extends UiApplication {
public static void main(String[] args) {
ApplicationManager app = ApplicationManager.getApplicationManager();
boolean keepGoing = true;
while (keepGoing) {
if (app.inStartup()) {
try {
Thread.sleep(1000);
} catch (Exception e) {}
} else {
keepGoing = false;
}
}
Jingu theApp = new Jingu();
theApp.initMenuItem();
theApp.showMainScreen();
theApp.enterEventDispatcher();
}
public Jingu() {
}
public void showMainScreen() {
showScreen(new JinguMainScreen(this));
}
public void initMenuItem() {
// Create menu item
Object o = RuntimeStore.getRuntimeStore().get(JinguMenuItem.MY_MENU_ID);
// register only if not done already.
if (o == null) {
new JinguMenuItem(this).registerInstance();
}
}
public void showScreen(Screen aScreen) {
synchronized (Application.getEventLock()) {
try {
UiApplication.getUiApplication().popScreen(aScreen);
} catch (Exception e) {
}
UiApplication.getUiApplication().pushScreen(aScreen);
}
}
}
public class JinguMenuItem extends ApplicationMenuItem {
public static final long MY_MENU_ID = 0xb9739d5240d5943dL;
private final Jingu jingu;
public JinguMenuItem(Jingu jingu) {
super(0x350100);
this.jingu = jingu;
}
public void registerInstance() {
Object menuItem = RuntimeStore.getRuntimeStore().remove(MY_MENU_ID);
if (menuItem == null) {
ApplicationMenuItemRepository amir = ApplicationMenuItemRepository.getInstance();
amir.addMenuItem(ApplicationMenuItemRepository.MENUITEM_SYSTEM, this);
RuntimeStore.getRuntimeStore().put(MY_MENU_ID, this);
}
}
public Object run(Object context) {
jingu.setDefaultFont(Font.getDefault());
jingu.setMainApp(false);
jingu.setBbmEditField(null);
jingu.showMainScreen();
return context;
}
public String toString() {
return "My Menu";
}
}
plz advice where I should delete ApplicationMenuItem in my app?
my regards,
Vadim
If you are registering an ApplicationMenuItem from your application, as a user I would consider it bad style for your application to remove and exit, even if RIM provided a way to do this. You may want to separate your application into two parts. One provides the minimal support for responding to the ApplicationMenuItem selection, that starts automatically and runs in the background. The other has all the rest and can run and exit as needed.
My solution for this situation is:
create alternative entry point and run it on app load
register menu in it
do not use runtimeStore