Prism No Internet when starting the app, How do I reinit the process again #2333
Replies: 2 comments
-
There are a number of ways you can handle this, personally I like to use Shiny Lib over Essentials as it uses interfaces out of the box and remains testable. You'll notice in my example I also mix in a little bit of Reactive programming with Prism & ReactiveUI. Typically my pattern I will implement a ViewModelBase with a BaseService class to keep things maintainable over time. In the end you may see something like: // NOTE this does not need to be registered with the container as it is a Concrete type.
public class BaseServices
{
// We can evolve the services injected into the BaseServices without affecting every
// ViewModel that inherits from it.
public BaseServices(INavigationService navigationService, IConnectivity connectivity)
{
NavigationService = navigationService;
Connectivity = connectivity;
}
public INavigationService NavigationService { get; }
public IConnectivity Connectivity { get; }
}
public abstract class ViewModelBase : ReactiveObject, IDestructible
{
protected CompositeDisposable Disposables { get; }
protected INavigationService _navigationService { get; }
protected ViewModelBase(BaseServices baseServices)
{
_navigationService = baseServices.NavigationService;
baseServices.Connectivity
.WhenInternetStatusChanged()
.Throttle(TimeSpan.FromSeconds(5))
.ToProperty(this, nameof(IsOnline), out _isOnline,
() => baseServices.Connectivity.IsInternetAvailable())
.DisposeWith(Disposables);
baseServices.Connectivity
.WhenInternetStatusChanged()
.Throttle(TimeSpan.FromSeconds(5))
.Select(x => !x)
.ToProperty(this, nameof(IsOffline), out _isOffline,
() => !baseServices.Connectivity.IsInternetAvailable())
.DisposeWith(Disposables);
this.WhenAnyValue(x => x.IsNotBusy)
.Select(x => !x)
.ToProperty(this, nameof(IsNotBusy), out _isNotBusy);
}
protected ObservableAsPropertyHelper<bool> _isBusy;
public bool IsBusy => _isBusy?.Value ?? false;
private ObservableAsPropertyHelper<bool> _isNotBusy;
public bool IsNotBusy => _isNotBusy?.Value ?? true;
private ObservableAsPropertyHelper<bool> _isOnline;
public bool IsOnline => _isOnline?.Value ?? false;
private ObservableAsPropertyHelper<bool> _isOffline;
public bool IsOffline => _isOffline?.Value ?? true;
protected virtual void Destroy() { }
void IDestructible.Destroy()
{
Destroy();
Disposables.Dispose();
}
} A couple of things to note here is that you'll notice that when we do this we have items that should be disposed. We are able to use the CompositeDisposable to cleanly add items to our Disposable pipeline and then clean them up by disposing them when Prism let's us know that our View has been popped from the Navigation stack and it's time to Destroy anything that could create a memory leak. You may also notice that I've provided a protected virtual method that allows any base class to override and implement what it needs for the Destroy method. This ensures that no matter what someone may need to do in a child class the Disposables will always be disposed of when we're done. Now that you have a ViewModelBase, you need to decide how you want to handle the "Is Offline event"... One way might be to simply use Control Templates like: <prism:PrismApplication xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:prism="clr-namespace:Prism;assembly=Prism.Forms"
x:Class="AwesomeApp.App">
<Application.Resources>
<ResourceDictionary>
<ControlTemplate x:Key="MyOverlay">
<AbsoluteLayout>
<ContentPresenter AbsoluteLayout.LayoutBounds="0,0,1,1"
AbsoluteLayout.LayoutFlags="All" />
<Frame AbsoluteLayout.LayoutBounds="0.5,0.5,-1,-1"
AbsoluteLayout.LayoutFlags="PositionProportional"
IsVisible="{TemplateBinding BindingContext.IsOffline>
<Label Text="You are offline" />
</Frame>
</AbsoluteLayout>
</ControlTemplate>
<Style TargetType="ContentPage" ApplyToDerivedTypes="True">
<Setter Property="ControlTemplate" Value="{StaticResource MyOverlay}" />
</Style>
</ResourceDictionary>
</Application.Resources>
</prism:PrismApplication> The ControlTemplate is a great way to handle this. You'll notice that here we can easily provide a custom overlay or banner on our page to let our users know they are offline without having to add this manually to every single page. But this may not be how you want to handle the offline scenario, as you indicated in your question, you would like to Navigate to some Error Page... In this case you might add IApplicationLifecycleAware to your ViewModel so that whatever page is active at the time can modally navigate to the Error Page when the App Resumes. public abstract class ViewModelBase : ReactiveObject, IDestructible, IApplicationLifecycleAware
{
public virtual void OnResume()
{
if(IsOffline)
await _navigationService.NavigateAsync("/ErrorPage?useModalNavigation=true");
}
public virtual void OnSleep() { }
} This will now ensure that on any given page if the app is Offline we will automatically be taken to the ErrorPage... We might then do something like this in the ErrorPageViewModel: public class ErrorPageViewModel : ViewModelBase, IConfirmNavigation
{
public ErrorPageViewModel(BaseServices baseServices)
: base(baseServices)
{
PopErrorPageCommand = ReactiveCommand.CreateFromTask(OnPopErrorPageCommand, this.WhenAnyValue(x => x.IsNotBusy)
.DisposeWith(Disposables);
this.WhenAnyObservable(x => x.PopErrorPageCommand.IsExecuting)
.ToProperty(this, nameof(IsBusy), out _isBusy)
.DisposeWith(Disposables);
baseServices.Connectivity
.WhenInternetStatusChanged()
.InvokeCommand(PopErrorPageCommand)
.DisposeWith(Disposables);
}
public ReactiveCommand<Unit, Unit> PopErrorPageCommand { get; }
public override void OnResume() { }
private Task OnPopErrorPageCommandExecuted() =>
_navigationService.GoBackAsync();
public bool CanNavigate(INavigationParameters parameters) => IsOnline;
} You'll notice that we override the OnResume to prevent it from navigating to the ErrorPage since we're already there. We add a hook into the Observable pipeline from Shiny's IConnectivity so that when we come back online the page automatically gets popped, and we add IConfirmNavigation so that we stop the navigation in the event that we are offline. |
Beta Was this translation helpful? Give feedback.
-
Hi Dan, Will this work also when the user launches the app because that is my problem I was handling the on/off internet everywhere using essentials in my baseViewmodel but not when a user launched the app as it was too early and there is no viewmodel at that stage yet! Handling it when a user lanched the app (App.Xaml only) caused some challenges on my side, which I sort of handle but I cannot find a way for the user to retry, they have to kill the app,which is something I dont want to do. Lifecycle I will definetely look into reactive and prism + shiny together any samples anywhere to hit the ground running!! Again thanks for your time in replying appreciated. |
Beta Was this translation helpful? Give feedback.
-
Hi
Wondering if someone has already implemented the following scenario.
How do I reinitialize the process again once the button is clicked?
Suggestions?
many thanks
Beta Was this translation helpful? Give feedback.
All reactions