Xamarin.Forms how display internet connection status? - android

My HomePage is a CarouselPage and it contains three pages of type ContentPage.
<CarouselPage
...some namespaces...
<CarouselPage.Children>
<pages:HomePageA />
<pages:HomePageB />
<pages:HomePageC />
</CarouselPage.Children>
</CarouselPage>
I'm using JamesMontemagno's ConnectivityPlugin to check if the device has internet connection:
public partial class HomePage : CarouselPage
{
public HomePage()
{
InitializeComponent();
if (IsConnectionAvailable())
{
// download content from external db to device (SQLite db)
DisplayAlert("Internet connection found.", "Wait for the application data to update.", "OK");
}
else
{
DisplayAlert("No internet connection found.", "Application data may not be up to date. Connect to a working network.", "OK");
}
}
public bool IsConnectionAvailable()
{
if (!CrossConnectivity.IsSupported)
return false;
bool isConnected = CrossConnectivity.Current.IsConnected;
//return CrossConnectivity.Current.IsConnected;
return isConnected;
}
}
After splash screen is gone, the message box doesn't show. Based on stepping through code while debugging I assume it kinda shows and then goes away before the splash screen disappears.
So I tried to put the ConnectivityPlugin code into HomePageA:ContentPage, which one of the children of HomePage:CarouselPage. Like so:
public partial class HomePageA : ContentPage
{
public HomePageA()
{
InitializeComponent();
if (IsConnectionAvailable())
{
// download content from external db to device (SQLite db)
DisplayAlert("Internet connection found.", "Wait for the application data to update.", "OK");
}
else
{
DisplayAlert("No internet connection found.", "Application data may not be up to date. Connect to a working network.", "OK");
}
}
public bool IsConnectionAvailable()
{
if (!CrossConnectivity.IsSupported)
return false;
bool isConnected = CrossConnectivity.Current.IsConnected;
//return CrossConnectivity.Current.IsConnected;
return isConnected;
}
private void RegistrationButton_Clicked(object sender, System.EventArgs e)
{
}
}
Now when I run the application, the HomePageA gets displayed, but no message box. Only after I click the BurgerMenu and select Home (effectively selecting HomePageA) the message box pops up.
Same thing happens again:
After splash screen is gone, the message box doesn't show. Based on stepping through code while debugging I assume it kinda shows and then goes away before the splash screen disappears.
Could somebody explain this behavior to me?
How do I make the message box appear AFTER the splash screen goes away?
Thank you all.
===================== U P D A T E =====================
Pavan didn't explain the problem the way I would like to have it explained. For all you good people I found a couple of similar questions and answers with explanations that are adequate.
A decent explanation can be found here and here's another one.
However, I will accept Pavan's answer, because it works and there has been no better answer provided at the time.

DisplayAlert is used in order to do something on the UI thread. and it’s called from a background thread, in order to manipulate the UI, which can only be done on the UI thread.
Try below code for display alert message,
Xamarin.Forms.Device.BeginInvokeOnMainThread(() =>
{
App.Current.MainPage.DisplayAlert("Internet connection found.", "Wait for the application data to update.", "OK");
});
it will help you

Related

Hunting a spooky offline.html

I once wrote a quick ‘offline.html‘. Just be be sure I understood how offline PWA worked:
This is offline.html (My App Name)
I thought it worked as expected. So I deleted it and wrote a better one, with a back button, some info etc.
Now when this app is offline it starts on the page the manifest.json days, as expected.
However, if I try to refresh the page that spooky "offline.html" shows up. From nowhere.
I've tried to understand where it lurks, but I can't find it. (The new "offline.htmi" is there when I go to it in the web browser.)
I've tried Firefox offline on my mobile to see if the spoky "offline.html" jumps up there to. It does. 😐
I've cleared the cache in Chrome. The spoky "offline.html" is still there.
Any ideas?
(This is on Android 9)
Offline pages are not exactly stored in caches as regular cached items, there are stored quite differently, relative to the current installed service worker. I tried looking for an article to explain this more but can't walk around any currently.
However you'll have to unregister your service worker or learn how Updating service worker works,
The aim is to remove the lurking offline.html served to the new offline.html that exists.
This is what I finally landed on. It seems to work. The test for 404 is of course not optimal, but I leave it that way for now, hoping that the emerging standard will address this issue soon.
async function setupServiceWorker() {
let reg;
if (navigator.serviceWorker.controller) {
console.log("Active service worker found, no need to register");
// new Popup("registered service worker, .active.scriptURL", reg.active.scriptURL, null, true).show();
reg = await navigator.serviceWorker.getRegistration();
} else {
reg = await navigator.serviceWorker.register("service-worker.js", { scope: "./" });
console.log("Service-worker.js registered, scope: " + reg.scope);
}
try {
if (navigator.onLine) {
const newReg = await reg.update();
}
} catch (err) {
const is404 = err.message.match("404");
new Popup("err", is404 + " " + err.message).show();
if (is404) {
let wasUnregistered;
try {
wasUnregistered = await reg.unregister();
} catch (errUnreg) {
new Popup("unregister() service worker failed", errUnreg.message).show();
}
if (wasUnregistered) {
setTimeout(setupServiceWorker, 1000);
}
}
}
}
setTimeout(setupServiceWorker, 5000);

Xamarin.Forms how display internet connection CHANGED?

Structure of my app:
public partial class App : Application
{
public App()
{
InitializeComponent();
MainPage = new MdpMainPage();
}
MdpMainPage is a MasterDetailPage:
<MasterDetailPage.Detail>
<NavigationPage>
<x:Arguments>
<pages:HomePage />
</x:Arguments>
</NavigationPage>
</MasterDetailPage.Detail>
My HomePage is a CarouselPage and it contains three pages of type ContentPage.
<CarouselPage>
...some namespaces...
<CarouselPage.Children>
<pages:HomePageA />
<pages:HomePageB />
<pages:HomePageC />
</CarouselPage.Children>
</CarouselPage>
I would like to use JamesMontemagno's ConnectivityPlugin to WATCH for internet connection CHANGES.
DisplayAlert box should pop up when the application starts and it should tell us either:
DisplayAlert("Internet connection found.", "Wait for the application data to update.", "OK");
...or...
DisplayAlert("No internet connection found.", "Application data may not be up to date. Connect to a working network.", "OK");
If there was internet connection at the start of the application and it gets lost during the using of the app, another message box should pop up saying:
DisplayAlert("Internet connection lost.", "Application data may not be up to date. Connect to a working network.", "OK");
If there was no internet connection at the start of the application and somehow later the device connects successfully, the firstly mentioned message box should appear:
DisplayAlert("Internet connection found.", "Wait for the application data to update.", "OK");
I've tried to figure out the correct implementation with the help of the provided Documentation.
Unfortunately, James Montemagno doesn't bother to explain in detail how to use the ConnectivityPlugin, so beginners like myself tend to end up confused.
I know I should use the following code snippets:
/// <summary>
/// Event handler when connection changes
/// </summary>
event ConnectivityChangedEventHandler ConnectivityChanged;
public class ConnectivityChangedEventArgs : EventArgs
{
public bool IsConnected { get; set; }
}
public delegate void ConnectivityChangedEventHandler(object sender, ConnectivityChangedEventArgs e);
CrossConnectivity.Current.ConnectivityChanged += async (sender, args) =>
{
Debug.WriteLine($"Connectivity changed to {args.IsConnected}");
};
...but I don't know where to put them.
I've tried a couple of combinations, but to no avail so far.
Do I put some in the App.xaml and some in the MasterDetailPage?
Or rather one of the Detail pages?
Or in each of the detail pages?
Please don't think I didn't google around. Because I did and everybody seems to have a different opinion on how to flavor the basic Montemagno recipe, which is very confusing.
Could somebody provide the simplest, cleanest way to implement this? Nothing fancy really, just message boxes that inform the user about changes in connectivity.
Help would be much appreciated.
Thank you all.
Let's say you have a dozen pages in your application. It wouldn't make sense to have connectivity code in all of them. A better place to subscribe to the events would be your App.xaml.cs inside the OnStart method (could also be inside the constructor). This is what I have in one of the projects:
protected override void OnStart()
{
CrossConnectivity.Current.ConnectivityChanged += (sender, args) =>
{
MessagingService.Current.SendMessage("connectivityChanged", args.IsConnected);
};
}
MessagingService is from James Montemagno's Xamarin.Forms Toolkit but you can also use Xamarin's Messaging Center.
Then, on each ViewModel of those pages that want to subscribe to this message of a connection change will subscribe to it like this:
MessagingService.Current.Subscribe ("connectivityChanged", async (e) =>
{
//Show a dialog or something to inform about the connectivity change.
});
This way you'll have everything decoupled.
Edit: I just noticed you're probably looking to show the alert from a code behind of the page. You could simply subscribe to the event on your MasterDetailPage like this:
public class MainPageCS : MasterDetailPage
{
public MainPageCS()
{
MessagingService.Current.Subscribe<bool>("connectivityChanged", (args, connected) =>
{
if (connected)
DisplayAlert("Internet connection found.", "Wait for the application data to update.", "OK");
else
DisplayAlert("Internet connection lost.", "Application data may not be up to date. Connect to a working network.", "OK");
});
}
}
Any time the connectivity changes, your App.xaml.cs handles the event and sends a message to the MessagingService which is received by the MasterDetailPage that reacts to it.
Edit 2: Put this into your App.xaml.cs so the connection gets checked only when the app starts.
protected override void OnStart()
{
Device.BeginInvokeOnMainThread(async () =>
{
var isConnected = CrossConnectivity.Current.IsConnected;
await MainPage.DisplayAlert("Connection", $"Connected {isConnected}", "OK");
});
}

Meteor.call doesn’t work on android App

I created a simple app using Meteor 1.3, which has only one method. It works like that: When a button is clicked, the method is invoked - it calculates a specific value and returns the result.
The app works perfectly on the localhost server, but when I launch it on my device with "meteor run android-device", it cannot access the method (simply opens the app, but nothing happens when I press a button.
Do you know how I could resolve this?
import { Template } from 'meteor/templating';
import { ReactiveVar } from 'meteor/reactive-var';
import { ReactiveDict } from 'meteor/reactive-dict';
import './main.html';
Template.check.onCreated(function checkOnCreated() {
this.state = new ReactiveDict();
});
Template.check.events({
'click .checkit'(event, instance) {
Meteor.call('code.check', function(error, result){
if(error){
console.log('Error from the client side!');
} else {
instance.state.set('fett', result.titles[0]);
}
});
},
});
Template.check.helpers({
fett() {
const instance = Template.instance();
if (instance.state.get('fett')) {
return instance.state.get('fett');
} else {
return 'Value still not known...'
}
},
});
Ensure your smartphone's WiFi is turned on and it connected to the same WiFi network as you computer where meteor app is running. Then everything should work fine.
Also, I recommend to use chrome://inspect feature (more info here) in order to debug your app on Android. Then, you will be able quickly investigate any problems with mobile app.

programmatically close Android settings after event has occured

So I created an app that connects to a wireless display on Android automatically for the user. The easiest way I found to do that is by opening the Screen Mirroring settings. This makes it easier for the user, so they don't have to go up to settings and enable it themselves.
Now that I have connected to the display, I want the Screen Mirroring screen to go away and return to the app or to the home screen if the user wants.
Here is the code I use to open Screen Mirroring settings to connect the user to the display after he clicks on a button:
try
{
activityint = 1;
Log.d("DEBUG", "open WiFi display settings in HTC");
startActivityForResult(new Intent("com.htc.wifidisplay.CONFIGURE_MODE_NORMAL"),activityint);
} catch (Exception e)
{
try
{
activityint = 2;
Log.d("DEBUG", "open WiFi display settings in Samsung");
startActivityForResult(new Intent("com.samsung.wfd.LAUNCH_WFD_PICKER_DLG"),activityint);
}catch (Exception e2)
{
activityint=3;
Log.d("DEBUG", "open WiFi display settings in stock Android");
startActivityForResult(new Intent("android.settings.WIFI_DISPLAY_SETTINGS"),activityint);
}
}
And then I have a broadcastreceiver that listens for WIFI_P2P_CONNECTION_CHANGED_ACTION. When this happens, it will look to see if we are now connected before launching other things and then attempting to close the settings activity.
#Override
public void onReceive(Context context, Intent intent)
{
String action = intent.getAction();
if (action.equals(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION))
{
/**
* What to do if the P2P connection has changed
*/
try
{
NetworkInfo info = intent.getParcelableExtra(WifiP2pManager.EXTRA_NETWORK_INFO);
if(info!=null && info.isConnected())
{
connected(true);
//Kill the settings activity
finishActivity(activityint);
}else if(info!=null && !info.isConnected())
{
connected(false);
}
}catch(Exception e)
{
Log.e("DEBUG", "exception", e);
}
}
}
The problem is that it kills the settings activity before the connection is finalized. So it will back out of the settings activity and the Screen Mirroring connection will cancel a moment before it connects. Is there a better way or a different way to be able to back out of the Settings activity? Or am I listening for the wrong intent in my receiver?
Thanks
The only way I was able to close a settings page on some event, is to start my activity again with the Intent.FLAG_ACTIVITY_CLEAR_TOP flag.
This way, because your activity is the one that opened the settings activity, the flag will make the system finish it. To the user it will appear that the settings activity just went away.
I guess I'm answering my own questions. I found this code that allows me to send a delayed response. I know this is crummy programming because some devices will finish before others, but this works for me at the moment. If anyone knows of a better way, please feel free to let me know.
This goes in my broadcast receiver's onReceive method.
NetworkInfo info = intent.getParcelableExtra(WifiP2pManager.EXTRA_NETWORK_INFO);
if(info!=null && info.isConnected())
{
connected(true);
new Handler().postDelayed(new Runnable()
{
public void run()
{
finishActivity(activityint);
}
}, 5000);
}else if(info!=null && !info.isConnected())
{
connected(false);
}
EDIT: This actually does not work for me. After testing further, I found that it will kick me back to the home screen after a few moments even when I just open the app. It's pretty annoying. Anyone know of a better idea?

Resubmit a Form when connection is lost in Android

I am trying to implement an app, that uses WebView to show a website which has a form inside. The problem is, when user fills the form and just before the Send button is pressed, the internet connection is lost. In this case, I receive onErrorReceived callback, and here is my implementation:
#Override
public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {
mDisconnected = true;
mDisconnectUrl = failingUrl;
mWebView = view;
mWebView.saveState(mWebViewState);
}
So I try to store the content of the form here and the failing url, so I can continue sending it when the connection established again. So I have another thread trying to make a new Socket connection with the server, and when it succeeds, I call a function in my WebViewClient class reconnect():
void reconnect(Context appContext) {
if (mDisconnected) {
try {
((Activity) appContext).runOnUiThread(new Runnable() {
public void run() {
mWebView.reload();
mWebView.restoreState(mWebViewState);
}
});
} catch (Exception e) {
mWebView.goBack();
}
mDisconnected = false;
}
}
So I try to make a reload and restore the form data so the WebView can continue with its send operation. The problem is when the page is again loaded, all the data entered in the form are lost and it does not continue with the Send operation, which was already clicked before the connection is lost. Has any one any idea, how to solve this problem.
The data is very sensitive, so it is important to continue with sending. It is also possible to let the user fill the form again and send it again, but it is not wanted in this scenario.
EDIT:
Maybe the question can be simplified. Is there any function or way to refresh a website in WebViewClient, which continues where it was left of and retrieves the form data into the state before the problem was occured.
Use database to store the contents of form and then send the data through service.
Delete the contents of database upon successfull submission.

Categories

Resources