Xamarin Android app consumes unusual amount of battery. Why? - xamarin

I am a beginner with the Xamarin platform. I recently started developing some simple application with the sole purpose of learning the platform. I encountered a "problem". My Cross-platform app on the Android platform (I have not tested it on other platforms) consumes an unusual amount of battery.
For example, in about 2 min of use the app consumes 5% of battery where in comparison the display consumes 6%. I found out that by going into the Battery consumption page (The Android Settings). I suspect this is because I am not setting the event handlers to null (i.e. disposing of them, see the code below).
This is my xaml code:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:XamarinSample"
x:Class="XamarinSample.MainPage">
<StackLayout>
<Slider VerticalOptions="CenterAndExpand"
ValueChanged="OnSliderValueChanged"/>
<Label x:Name="valueLabel"
HorizontalOptions="Center"
VerticalOptions="CenterAndExpand"
Text="A Simple Label"
Font="Large"/>
<Button HorizontalOptions="Center"
VerticalOptions="CenterAndExpand"
Text="Click me!"
Clicked="OnButtonClick"/>
</StackLayout>
</ContentPage>
And this is the code-behind:
namespace XamarinSample
{
public partial class MainPage : ContentPage
{
public MainPage()
{
InitializeComponent();
}
protected override void OnDisappearing()
{
base.OnDisappearing();
}
void OnSliderValueChanged(object sender, ValueChangedEventArgs args)
{
valueLabel.Text = args.NewValue.ToString("F3");
}
async void OnButtonClick(object sender, EventArgs args)
{
Button button = (Button)sender;
await DisplayAlert("Clicked!",
"The button labeled '" + button.Text + "' has been clicked","OK");
}
}
}
What could be the reason for this behaviour?

First do not try to analyze the battery usage of an app while debugging (or one built-in a debug configuration) as the code executed (runtime and Jit'd) will be different...
Second, you should use Google's Battery Historian for your app's battery analysis. This is a Google provided/supported Android toolset and IMHO well worth the minimal effort to set it up.
Batterystats collects battery data from your device, and Battery Historian converts that data into an HTML visualization that you can view in your Browser. Batterystats is part of the Android framework, and Battery Historian is open-sourced and available on GitHub at https://github.com/google/battery-historian.
Showing you where and how processes are drawing current from the battery.
Identifying tasks in your app that could be deferred or even removed to improve battery life.
https://developer.android.com/studio/profile/battery-historian.html

Related

After Creating Package in Xamarin UWP, Video is Playing Only With Voice, I am Not able to see Video

I am using MediaManager Plugin with latest version to play a video. everything works fine when i run application in debug mode, but when i create a package for window, video is not showing only voice is heard.
I am using below Package
Plugin.MediaManager.Forms
This is My XAML page
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="Digi_Sign.Views.MediaScreen"
xmlns:forms="clr-namespace:MediaManager.Forms;assembly=MediaManager.Forms"
BackgroundColor="Black">
<ContentPage.Content>
<Grid x:Name="stkLayout" VerticalOptions="CenterAndExpand" HorizontalOptions="CenterAndExpand" BackgroundColor="Black">
<forms:VideoView VideoAspect="AspectFill" x:Name="videoPlayer" ShowControls="False" />
</Grid>
</ContentPage.Content>
</ContentPage>
CS Page
CrossMediaManager.Current.Play(fileName);
No Errors Found in package error log, as i mentioned everything works fine when it is debug mode, but not working in release mode
Basically there is no way to initialize renderer for video in native code for xamrin.UWP, so we need to manually load render assembly in initialize it in App.xaml.cs of UWP platform
Below is my code where i have load assembly files inside OnLaunched() and replace existing Xamarin.Forms.Forms.Init()
protected override void OnLaunched(LaunchActivatedEventArgs e)
{
Windows.UI.Xaml.Controls.Frame rootFrame = Window.Current.Content as Windows.UI.Xaml.Controls.Frame;
if (rootFrame == null)
{
rootFrame = new Windows.UI.Xaml.Controls.Frame();
rootFrame.NavigationFailed += OnNavigationFailed;
List<Assembly> assembliesToAdd = new List<Assembly>();
assembliesToAdd.Add(typeof(VideoViewRenderer).GetTypeInfo().Assembly);
Xamarin.Forms.Forms.Init(e, assembliesToAdd);
// Place the frame in the current Window
Window.Current.Content = rootFrame;
}
if (rootFrame.Content == null)
{
rootFrame.Navigate(typeof(MainPage), e.Arguments);
}
Window.Current.Activate();
}
for more details, here is the link. where you can find more explaination.
https://forums.xamarin.com/discussion/119451/crossmedia-works-in-debug-but-not-in-release-for-uwp-error-msg-about-onecore
Most likely from the behavior you are describing (and looking at your code), it sounds like it's because the Video is not being run on the UI thread, and this causes the app to play the audio but not the video. So change it to the following:
Device.BeginInvokeOnMainThread(() => { CrossMediaManager.Current.Play(fileName); });

Does the iOS simulator correct handle the tap event with Xamarin?

I have added a GestureRecognizer like this:
faveLabel.Text = "ABC";
faveLabel.BackgroundColor = Color.Red;
faveLabel.GestureRecognizers.Add(new TapGestureRecognizer
{
Command = new Command(() => OnLabelClicked())
});
}
private void OnLabelClicked()
{
throw new NotImplementedException();
}
Here is the XAML:
<StackLayout Grid.Row="0" Grid.Column="0" Padding="15,10,20,10" HorizontalOptions="StartAndExpand" VerticalOptions="CenterAndExpand">
<Label x:Name="faveLabel" XAlign="Center" FontSize="23" />
</StackLayout>
Using the simulator it almost never works and when I did get it to work it seemed like I had to click above the text and not on the text. When I debug on my phone it works okay.
Are there some issues where the simulator does not respond correctly?
There are no issues that I know of. I haven't seen any weird myself unless I actually had something else causing it. You could try to give your Label a bright background color to see where it is actually positioned. Perhaps some of your other elements are overlapping it or something else in your UI is stopping the gesture recognizer. A common example is when you put one in a ListView which has a tap event of its own which might conflict with a TapGestureRecognizer.

Why the Completed event occur on Focus()?

I have some problem with Xamarin forms on Completed event which has been triggered when the control have focus (Entry)
Below is the View :
<Entry
x:Name="EntryOrderNumber"
Placeholder="MFGO Number"
Text="{Binding TextOrderEntry}" />
<Entry
x:Name="EntryMachineNumber"
Placeholder="Machine Number"
Text="{Binding TextMachineEntry}" />
And this is where I control the even which is placed at view.cs
public ProductionOrderPage()
{
InitializeComponent();
BindingContext = App.Locator.ProductionOrderPageVM;
EntryOrderNumber.Completed += EntryOrderNumber_Completed;
EntryMachineNumber.Completed += EntryMachineNumber_Completed;
EntryTotalPosition.Completed += EntryTotalPosition_Completed;
}
private void EntryMachineNumber_Completed(object sender, EventArgs e)
{
EntryMachineNumber.Unfocus();
EntryTotalPosition.Focus();
}
private void EntryOrderNumber_Completed(object sender, EventArgs e)
{
EntryOrderNumber.Unfocus();
EntryMachineNumber.Focus();
}
My problem is : While the Entry (Text field) has focused , the Completed event has been triggered which resulting in the focus will go to another field continuously as per set in the Completed event.
the apps being debugged and deployed onto emulator
using MVVMlight
Thanks a lot
using soft keyboard instead of hardware keyboard solve this problems. Weird.
Enabling soft keyboard : Visual Studio Android Emulator Display Keyboard

Unnavigated pages still emit events in UWP app

I observed a strange behavior in my UWP Windows 10 app. Even if I navigate back from a page and the page is unloaded, the page still continues to emit events. For example, the old page which I navigated from, still emits "LayoutUpdated" event even if I go to a completely different page.
I prepared a minimal example to demonstrate this (code is below). It is pretty simple:
There are 2 pages: MainPage and ExamplePage. You can go from MainPage to ExamplePage and you can go back from ExamplePage to MainPage.
Every time you navigate to ExamplePage, a new ID is given to that newly created page (page is not cached).
A Grid in ExamplePage emits LayoutChanged event. And event handler writes a text to Debug console like: "grid layout updated on page 0". 0 is the page ID I gave to that page.
If you go back and forth a few times, you will see that the old pages still write layout updated text to the console. For example, if I go to page with ID 3, it writes to the console:
grid layout updated on page 0
grid layout updated on page 3
grid layout updated on page 1
grid layout updated on page 2
notice that the old pages still update their layouts. The old pages, should not emit any events anymore but they keep emitting events although there is no way to navigate to them anymore and they are unloaded.
Here is the code, there are 5 files, just create a new UWP project in VS2015 and then:
MainPage.xaml
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Button x:Name="NavigationButton"
Click="NavigationButton_Click"
HorizontalAlignment="Center"
VerticalAlignment="Top"
Margin="0,20,0,0">Navigate</Button>
</Grid>
MainPage.xaml.cs
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
namespace App7
{
public sealed partial class MainPage : Page
{
private App app;
public MainPage()
{
this.InitializeComponent();
app = (App)Application.Current;
}
private void NavigationButton_Click(object sender, RoutedEventArgs e)
{
var viewModel = new ExamplePageViewModel(app.GetPageId());
Frame.Navigate(typeof(ExamplePage), viewModel);
}
}
}
ExamplePage.xaml
<Grid x:Name="MainGrid"
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"
LayoutUpdated="MainGrid_LayoutUpdated">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition/>
</Grid.RowDefinitions>
<Button x:Name="NavigationButton"
Click="NavigationButton_Click" HorizontalAlignment="Center"
Margin="0,20,0,0">Go Back</Button>
<TextBlock Text="{Binding PageId}"
Grid.Row="1"
FontSize="30"
HorizontalAlignment="Center"></TextBlock>
</Grid>
ExamplePage.xaml.cs
using System.Diagnostics;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Navigation;
namespace App7
{
public sealed partial class ExamplePage : Page
{
private ExamplePageViewModel viewModel;
public ExamplePage()
{
this.InitializeComponent();
}
protected override void OnNavigatedTo(NavigationEventArgs e)
{
if (e.NavigationMode == NavigationMode.New ||
e.NavigationMode == NavigationMode.Back)
{
viewModel = (ExamplePageViewModel)e.Parameter;
DataContext = viewModel;
}
}
private void NavigationButton_Click(object sender, RoutedEventArgs e)
{
Frame.GoBack();
}
private void MainGrid_LayoutUpdated(object sender, object e)
{
Debug.WriteLine("grid layout updated on page " + viewModel?.PageId.ToString());
}
}
}
ExamplePageViewModel.cs
using System.ComponentModel;
using Windows.UI.Xaml;
namespace App7
{
public class ExamplePageViewModel : INotifyPropertyChanged
{
private App app;
private int pageId;
public event PropertyChangedEventHandler PropertyChanged;
public int PageId
{
get
{
return pageId;
}
}
public ExamplePageViewModel(int pageId)
{
app = (App)Application.Current;
this.pageId = pageId;
}
}
}
Note: The viewmodel is just to see clearly which page is still emiting events. You can remove the viewmodel, and it won't change the problem.
The LayoutUpdated event will be fired for elements that are not in the main visual tree, provided that the element has not been collected by the garbage collector. Since we don't know the implementation of the Frame class, we don't know how it references the pages it instantiates (maybe it holds a reference to unloaded pages for slightly longer than it needs to? Who knows).
This, together with the asynchronous nature of the garbage collector, means that old pages can still raise LayoutUpdated events until either the event handler is removed or the object is collected by the GC. In your example, the GC simply hasn't gotten around to collecting your old pages.
Doesn't this make app performance drop if you have several complex pages still on memory? I can see on my app, that tens of complex pages are still firing the LayoutUpdated event, so all the controls are calculating their sizes on every page navigation, right?
Those pages should be collected by the GC during the next garbage collection cycle, which will automatically occur at some point when it is necessary to do so. You can force a garbage collection with GC.Collect(), but I don't recommend this. The GC is better at determining times to perform a collection than you are (generally).
The LayoutUpdated event is fired on all elements (I think), regardless of whether or not that particular element's layout has changed. If you read the docs for that event, it explains that it is necessary to do this in case the element's layout is affected by a sibling (for example).
The layout system is quite optimized. I don't think complex layout passes are performed for all elements every time they receive a LayoutUpdated event, so I wouldn't worry about that. However, it is important to make sure you're not doing unnecessary calculations in these event handlers when the element isn't visible.
Here is another page which explains the LayoutUpdated event quite well. It is a static event, which gets fired if any element anywhere had its layout updated.
I won't put any unnecessary code to LayoutUpdated event or I will unbind them on navigating back but still it will recalculate all the control's sizes on its own, right?
Your response to the LayoutUpdated event should be "some element somewhere had its layout updated which may or may not affect me". You could unbind the event, or you can just check if this.Parent or this.Frame is null and bail out, in which case the Page isn't in the Frame.
Are there any other events that fire even if the control is not in the visual tree? How can I find a list for such events?
I'm not sure. You need to test your app for these situations, just put a breakpoint in each event handler so you know if it's getting fired.

Use mvvm-light CustomEvent Trigger with ApplicationBarIconButton

The sample code below for a button will trigger opening of a second page.
<Button x:Name="btnSelect" Content="Select" HorizontalAlignment="Right" Margin="0,8,20,6"
Grid.Row="2" Width="200">
<Custom:Interaction.Triggers>
<Custom:EventTrigger EventName="Click">
<GalaSoft_MvvmLight_Command:EventToCommand x:Name="btnSelectClicked"
Command="{Binding SelectEventPageCommand, Mode=OneWay}"/>
</Custom:EventTrigger>
</Custom:Interaction.Triggers>
</Button>
public partial class MainPage : PhoneApplicationPage
{
// Constructor
public MainPage()
{
InitializeComponent();
}
private void ContentGrid_Loaded(object sender, System.Windows.RoutedEventArgs e)
{
Messenger.Default.Register<GoToPageMessage>(this, (action) => ReceiveMessage(action));
}
private object ReceiveMessage(GoToPageMessage action)
{
StringBuilder sb = new StringBuilder("/Views/");
sb.Append(action.PageName);
sb.Append(".xaml");
NavigationService.Navigate(
new System.Uri(sb.ToString(),
System.UriKind.Relative));
return null;
}
}
http://galasoft.ch/mvvm/getstarted/
Can anyone suggest how I can do the same using an ApplicationBarIconButton? I get an error Property 'Triggers' is not attachable to elements of type ApplicationBarIconButton.
Or should I just use CodeBehind?
<phone:PhoneApplicationPage.ApplicationBar>
<shell:ApplicationBar IsVisible="True" IsMenuEnabled="False">
<shell:ApplicationBarIconButton IconUri="/Images/appbar_button1.png" Text="Button 1">
</shell:ApplicationBarIconButton>
</shell:ApplicationBar>
</phone:PhoneApplicationPage.ApplicationBar>
Yeap ApplicationBar is a little bit different fom other controls in Silverlight. I was able to use an ICommand by using this one:
http://blog.humann.info/post/2010/08/27/How-to-have-binding-on-the-ApplicationBar.aspx
or the Silverlight toolkit which offers some extensions as stated in this answer:
How to add an application bar to a user control in wp7 but I never used it.
The ApplicationBar is a service that is provided by the operating system, i.e. not part of the Framework, and doesn't support Triggers as you have already discovered.As mentioned above there are a number of solutions that provide workarounds for this problem.
Alternatively, you could use the ApplicationBarButtonCommand and ApplicationBarButtonNavigation behaviors from the Silverlight Windows Phone Toolkit. It's a simple enough task to create your ApplicationBarMenuCommand if you need one. In your case, for using an ApplicationBar button to navigate to a page, then the ApplicationBarButtonNavigation behavior will do the trick.

Resources