I am developing an application where I want to integrate the SQL database in it. As far my code works fine. I made the application auto-run on startup and I check immediately for SDCard presence. If present I will create the database on SDCard and if not I will create it on device.
The problem is that when the application is auto-run, it will start before the device locates the SDCard, so I am always unable to detect if the SDCard is present.
What listener should I use to know that the device is completely turned on?
SystemListener will do the job. This is how I usually do it:
public class MyApp extends Application implements SystemListener {
public static void main(String[] args){
MyApp app = new MyApp();
if (ApplicationManager.getApplicationManager().inStartup()) {
app.addSystemListener(app);
//wait for powerUp callback
} else {
app.startup();
}
}
public void powerUp() {
removeSystemListener(this);
startup();
}
private void startup(){
//Perform initialization here, most typically show first screen and stuff.
}
// Remaining SystemListener callbacks not shown for brevity
}
Related
How to get notified when Xamarin Native Android app goes to sleep or is terminated?
When searching, I only found an answer for Xamarin.Forms where the Application object allows to override OnSleep.
The background of this question is that I want to save settings when the app either goes to background or is terminated.
Just like the OnSleep method of Xamarin Forms the OnPause method is called in Android Native when the app goes into the background.
You can override OnPause in both an Activity and a Fragment something like this:
protected override void OnPause()
{
base.OnPause();
// Add your code here
}
Update
You can do the same on application level by adding the Android Application class :
Add a new C# class file in your project called MainApplication.cs.
Then add the Application.IActivityLifecycleCallbacks interface where you can find the activity paused method with the activity context in which it was paused so you can add it and do the needful.
#if DEBUG
[Application(Debuggable = true)]
#else
[Application(Debuggable = false)]
#endif
public class MainApplication : Application , Application.IActivityLifecycleCallbacks
{
public MainApplication(IntPtr handle, JniHandleOwnership transer)
: base(handle, transer)
{
}
public void OnActivityPaused(Android.App.Activity activity)
{
base.OnCreate();
// Add some code
}
public override void OnTerminate()
{
base.OnTerminate();
UnregisterActivityLifecycleCallbacks(this);
}
public override void OnCreate()
{
base.OnCreate();
RegisterActivityLifecycleCallbacks(this);
}
}
My project is built with master-detail navigation.
There are totally three pages in the list named as Resources, Contacts, and Login.
Everything works fine in iOS, but when the user presses the Droid/WinPhone devices hardware back button, the app should exit.
Is there any app-exit mechanism for Xamarin Forms which will work on all the devices.? (I mean native code not platform dependent)
Thanks in advance.
I did that on this way
In xamarin forms I added interface
public interface INativeHelper
{
void CloseApp();
}
In android project I made implementation of INativeHelper
public class NativeHelper : INativeHelper
{
public void CloseApp()
{
Android.OS.Process.KillProcess(Android.OS.Process.MyPid());
}
}
Implementation of INativeHelper in IOS
public class NativeHelper : INativeHelper
{
public void CloseApp()
{
Process.GetCurrentProcess().CloseMainWindow();
Process.GetCurrentProcess().Close();
}
}
And then just override method OnBackButtonPressed in page in Xamarin.Forms project
protected override bool OnBackButtonPressed()
{
INativeHelper nativeHelper = null;
nativeHelper = DependencyService.Get<INativeHelper>();
if (nativeHelper != null)
{
nativeHelper.CloseApp();
}
return base.OnBackButtonPressed();
}
I didn't made implementation for WinPhone, but it should be similar.
You can use a DepedencyService for closing an app when your physical back button is pressed:
In your UI (PCL), do the following:
protected override bool OnBackButtonPressed()
{
if (Device.OS == TargetPlatform.Android)
DependencyService.Get<IAndroidMethods>().CloseApp();
return base.OnBackButtonPressed();
}
Now implement the Android-specific logic in your Android project:
[assembly: Xamarin.Forms.Dependency(typeof(AndroidMethods))]
namespace Your.Namespace
{
public class AndroidMethods : IAndroidMethods
{
public void CloseApp()
{
Android.OS.Process.KillProcess(Android.OS.Process.MyPid());
}
}
}
Also create an Interface (in your UI PCL):
public interface IAndroidMethods
{
void CloseApp();
}
As far as I know there is no native way to exit the app in Xamarin application.
The only way is to use dependency service. Override OnBackButtonPressed function in your ContentPage and check it is the last page:
protected override bool OnBackButtonPressed()
{
if(navigation.NavigationStack.Count == 1)//navigation is MainPage.Navigation
DependencyService.Get<YourDependencyInterface>().CloseApp();
}
For Android in YourAndroidDependency class:
public void CloseApp()
{
(Xamarin.Forms.Forms.Context as Activity).Finish();
}
As for WinPhone I'm not sure but I believe it can be done in same way - dependency service.
Having experimented with all the above, I found that none of the above worked on a Google Pixel 3a, with latest version of Android
The command that came closest was
Android.OS.Process.KillProcess(Android.OS.Process.MyPid());
However it left the remains of the app still visible in the background.
The following worked for me when called from the Android Main Activity
public void ExitApp()
{
this.FinishAndRemoveTask();
Android.OS.Process.KillProcess(Android.OS.Process.MyPid());
}
The first line FinishAndRemoveTask removes the app from both the foreground and the background, however the Application process is still active, hence the need for the second command.
This is the more easy way found:
public void QuitApp(object sender, EventArgs args)
{
Process.GetCurrentProcess().CloseMainWindow();
Process.GetCurrentProcess().Close();
}
PS: Tested in android
You can use Environment.Exit(0);
My app connects to Facebook and Parse and it works well on simulator and android but it doesn't work on iOS.
The stop() (the Display.getCurrent() returns my current form) and start() methods of the main class are always called automatically. This caused my app (current form) disappeared in unexpected way. I thought the application was crashed but not.
When I double tap on the Home button I can see my app and when I select, it starts again. Any idea can help?
Thanks, William
When iOS app crashes or get killed, it doesn't remove the app from the recent apps you see when you double tap home button. It will only restart the app when you open it (Apps usually get killed on iOS within 10 minutes, depending on if the app is using any resources or not).
Verify that your app is indeed not crashing on iOS. Uncomment the crash reporter from the class that contains start() and stop() methods. This will send you an email if the app crashes and if you are a pro or higher CN1 subscriber.
Just for clarification, the class should look similar to this:
private Form current;
public void init(Object context) {
Display.getInstance().addEdtErrorHandler((evt) -> {
evt.consume();
Log.p("Exception in MyApp version " + Display.getInstance().getProperty("AppVersion", "1.0"));
Log.p("OS " + Display.getInstance().getPlatformName());
Log.p("Error " + evt.getSource());
Log.p("Current Form " + Display.getInstance().getCurrent().getName());
Log.e((Throwable) evt.getSource());
Log.sendLog();
});
}
public void start() {
if (current != null) {
current.show();
return;
}
new StateMachine("/theme");
}
public void stop() {
current = Display.getInstance().getCurrent();
}
public void destroy() {
}
I am using a ListField Control to display data returned from xml webservice. I want to refresh the ListField or the screen every minute to update the ListField with new records or data.
I tried using the code below but it is not working properly (It is hanging).
public MyApp() {
// Push a screen onto the UI stack for rendering.
UiApplication.getUiApplication().invokeLater(new Runnable() {
public void run() {
UiApplication.getUiApplication().pushScreen(new MyScreen());
}
},5000,true);
}
ResponseHandler handler = new ResponseHandler();
ListField listUsers = new ListField(handler.getItem().size());
public MyScreen() {
setTitle("yQAforum");
//Fetch the xml from the web service
String wsReturnString = GlobalV.Fetch_Webservice("myDs");
//Parse returned xml
SAXParserImpl saxparser = new SAXParserImpl();
ByteArrayInputStream stream = new ByteArrayInputStream(wsReturnString.getBytes());
try {
saxparser.parse( stream, handler );
}
catch ( Exception e ) {
response.setText( "Unable to parse response.");
}
//Return vector sze from the handler class
listUsers.setSize(handler.getItem().size());
listUsers.setCallback(this);
listUsers.setEmptyString("No Users found", 0);
add(listUsers);
}
You are attempting to fetch data from your webservice on the UI thread. That's almost always the wrong thing to do.
The UI thread (also known as the main thread) is responsible for drawing the UI, and tracking user actions, like touches, or navigation via a trackpad/trackball. If the UI thread is blocked waiting for a remote web server to respond, it cannot service the UI.
There's a couple changes you should make:
public MyApp() {
// Push a screen onto the UI stack for rendering.
UiApplication.getUiApplication().invokeLater(new Runnable() {
public void run() {
UiApplication.getUiApplication().pushScreen(new MyScreen());
}
},5000,true);
}
should be changed to
public MyApp() {
// Push a screen onto the UI stack for rendering.
pushScreen(new MyScreen());
}
The MyApp() constructor will already be called on the UI thread, so there is no need to use invokeLater() to perform the pushScreen() call on the UI thread. It already will be called on the UI thread, if run from within the MyApp constructor. Also, the 5000 msec delay isn't really helpful. This will just delay the startup of your app by 5 seconds, which users will hate.
If you are trying to implement a splash screen, or something similar, when the app starts up, please search stack overflow for "BlackBerry splash screen", and I'm sure you'll find results.
Now, once your MyScreen class is created, you should take care not to fetch web service results from the UI thread. The MyScreen constructor will be run on the UI thread. If you want, you can initiate a web service request on a background thread, once the screen is shown. One way to do that is to use onUiEngineAttached():
protected void onUiEngineAttached(boolean attached) {
if (attached) {
// TODO: you might want to show some sort of animated
// progress UI here, so the user knows you are fetching data
Timer timer = new Timer();
// schedule the web service task to run every minute
timer.schedule(new WebServiceTask(), 0, 60*1000);
}
}
public MyScreen() {
setTitle("yQAforum");
listUsers.setEmptyString("No Users found", 0);
listUsers.setCallback(this);
add(listUsers);
}
private class WebServiceTask extends TimerTask {
public void run() {
//Fetch the xml from the web service
String wsReturnString = GlobalV.Fetch_Webservice("myDs");
//Parse returned xml
SAXParserImpl saxparser = new SAXParserImpl();
ByteArrayInputStream stream = new ByteArrayInputStream(wsReturnString.getBytes());
try {
saxparser.parse( stream, handler );
}
catch ( Exception e ) {
response.setText( "Unable to parse response.");
}
// now, update the UI back on the UI thread:
UiApplication.getUiApplication().invokeLater(new Runnable() {
public void run() {
// TODO: record the currently selected, or focused, row
//Return vector sze from the handler class
listUsers.setSize(handler.getItem().size());
// Note: if you don't see the list content update, you might need to call
// listUsers.invalidate();
// here to force a refresh. I can't remember if calling setSize() is enough.
// TODO: set the previously selected, or focused, row
}
});
}
}
You'll need to add some error handling, in case the web service doesn't respond, or takes longer than a minute (you wouldn't want to be making a new request, if the last one hadn't finished).
But, this should get you started.
Note: once you fix the problem with running network code on the UI thread, you may still find that your code doesn't work. There could be problems fetching the web service data. You'll have to debug that. I am only showing you one problem with the code posted. If you still have problems with the web service fetch, post another question (with the UI thread problem fixed). Thanks.
i am developing an application which contain alternative entry point.
and i put tick mark in "Do not display in Blackberry Home screen". here it is working fine it does not show icon on the home screen. but my problem is that
when i am click on SwitchApplication from menu(Home screen), the alternative entry point icon is showing on the popup screen like following image. i dont want to show that icon.i want hide that icon programatically.
please help me
You can hide app if it's service. Set system module (systemmodule) to true for bb ant tools. There is similar options for JDE and Eclipse plugin.
just override this method into our application
like following
private static boolean flag=false;
public static void main(String[] args)
{
StartUp startUp;
if(args!=null && args.length>0 && args[0].equals("gui")){
flag=false;
startUp = new StartUp("gui");
startUp.enterEventDispatcher();
}else{
flag=true;
startUp = new StartUp();
startUp.enterEventDispatcher();
}
}
i override this method
protected boolean acceptsForeground() {
return flag;
}
This is the code that I ended up using that worked for me. I had tried putting the acceptsForeground in my main launcher class at first, but then put it in PushListener itself instead to prevent it from appearing in the running tasks menu. Worked fine.
Launcher Class
public static void main(String[] args) {
if (args != null && args.length > 0 && args[0].equals("gui")) {
MyApp app = new MyApp();
app.enterEventDispatcher();
} else {
PushListener.waitForInstance().start();
}
}
PushListener Class
protected boolean acceptsForeground() {
return false; // You could use a variable instead if you wanted.
}
It's quite simple if you use blackberry eclipse plugin.
open "blackberry_description_app.xml", just check this: Don't display the app icon on blackberry home screen.