We have developed an application in Xamarin Forms. In Android application when the user uses the app in a low-network for about 90 seconds we are getting app not responding(ANR) Popup. Here my question is, is there any way to avoid this ANR popup in my application? In other words, is there any way to force the android system to wait for longer time?
In our Application when the user launching the application we are doing multiple tasks on threads which are majorly running on the secondary threads like:
Initialize Google Map & Creating Pins & Polyline Drawing
Firebase Listener Register
REST API calls
Loading List Items
So, before the device completes the above the list of task, if the users keep on touching the screen, then this causes multiple events to be queued in the main thread due to which we are getting ANR(App Not Responding Popup).
Here, we intend to disable the touch event until we complete the main thread in the existing task.
You can use the below logic to restrict touches to the content of the page below the activity indicator to resolve your issue.
However, the touches for the Grid below will still be listened to by the Android system and it will be processed. Here you can only restrict the interaction to your application views. However, the touch listened by the Android system for the Grid, ContentView, or ActivityIndicator in the below code can never be ignored.
Ideally, no user will try to touch more number of times after realizing there is no interaction when the loader is loading. So I guess you can safely ignore this case considering the general user thought process.
<Grid Grid.RowSpan="2"
InputTransparent="{Binding IsPageInteractable}"
IsVisible="{Binding IsPageBusy}">
<ContentView Opacity="0.2"
BackgroundColor="#4B4B4B"
VerticalOptions="FillAndExpand"
HorizontalOptions="FillAndExpand" />
<ActivityIndicator IsRunning="{Binding IsPageBusy}"
HorizontalOptions="CenterAndExpand"
VerticalOptions="CenterAndExpand" />
</Grid>
public bool IsPageInteractable
{
get { return _isPageInteractable; }
set { _isPageInteractable = value; }
}
public bool IsPageBusy
{
get { return _isPageBusy; }
set
{
_isPageBusy = value;
this.IsPageInteractable = !value;
}
}
Related
Using Xamarin Forms, I'm trying to understand at which offset during swiping will my SwipeView trigger the Invoked event when using mode Execute and if it's possible to programmatically get this value. So far what I've seen is it seems to be around 60% of Threshold (at least for Android) but I'm curious to know if this value is available somewhere in the component. I originally thought it wouldn't be triggered until it hit Threshold but I found that it fires before it meets that value. Below is my XAML:
<SwipeView
SwipeChanging="SwipeView_SwipeChanging"
SwipeEnded="SwipeView_SwipeEnded"
SwipeStarted="SwipeView_SwipeStarted"
Threshold="80">
<SwipeView.TopItems>
<SwipeItems Mode="Execute" SwipeBehaviorOnInvoked="Close">
<SwipeItemView BackgroundColor="Transparent" Invoked="SwipeItemView_Invoked">
<Label Text="Create New Task" />
</SwipeItemView>
</SwipeItems>
</SwipeView.TopItems>
<SwipeView.Content>
...
</SwipeView.Content>
</SwipeView>
With the above example with Threshold at 80 it seems to trigger around 49/50.
I got a small question for you. I am currently developing an application, based on Xamarin.Forms, and, on a ContentPage, i would like to always (yes i mean always always) show the keyboard. There is a textfield and some buttons or list, and when I click/tap on it, keayboard is hidden (and that is the standard behavior).
But here, I do not want if possible, to set the focus on the field for every action possible on the page. And even if I do that, we can see that the keyboard disappear and is shown back just after (trust me, me eyes are crying when it blink :)).
So, is it possible to set somewhere that we want to always show/display the keyboard ?
thanks a lot
Actually , it is not a good decision to keep the keyboard on the ContentPage , it will block other event like scroll and tap .
If you do want to implement it. You could define a default entry and set it onfocus when you finish editing other enrties .
<StackLayout HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand" >
<Entry x:Name="defaultEntry" HeightRequest="0.1" WidthRequest="0.1" Unfocused="Entry_Unfocused" />
<Entry HeightRequest="100" WidthRequest="40" Unfocused="Entry_Unfocused" />
</StackLayout>
bool IsNeedShowKeyBoard=true ;
public MainPage()
{
InitializeComponent();
}
private void Entry_Unfocused(object sender, FocusEventArgs e)
{
if(IsNeedShowKeyBoard)
{
defaultEntry.Focus();
}
}
Change the property IsNeedShowKeyBoard to false when start to scroll or you want to edit other entry .
In fact, I will develop my own custom keyboard. With that solution, I will be able to let it be shown every time.
I'm trying to test touchscreen of a tablet (Surface) and therefore I'm developing an app that is able to detect tap event and tell its coordinates.
I made a tap event handler to main Grid in MainPage and wrote this to MainPage.xaml.cs:
outputText.Text = e.GetPosition(this).X.ToString() + "\t";
outputText.Text += e.GetPosition(this).Y.ToString();
outputText is just a TextBlock to output coordinates.
This code should give its coordinates based on Grid, but it only gives coordinates if I touch it within TextBlock area.
How does this Tapped event handler work in a way that it only detects tap events inside TextBlock and not from entire screen (app runs in fullscreen mode)?
My MainPage.xaml looks like this:
<Grid Tapped="Grid_Tapped" PointerPressed="Grid_PointerPressed">
<TextBlock x:Name="outputText" HorizontalAlignment="Left" Height="62" Margin="806,374,0,0" Text="TextBlock" TextWrapping="Wrap" VerticalAlignment="Top" Width="182"/>
</Grid>
The problem is that the Grid.Background is null, so the tap events pass through it. The only place where the Grid has any actual "surface" is the TextBlock, which is exactly what you are seeing.
You will have to set the background to any other value like Transparent. This way it will handle the events properly.
I am developing app with titanium alloy. I have multiple xml file. Every xml file has got same view and every view id's and function is same. this approch is correct or must I assign different id and different named function for all object for prevent memory leak. I mean every xml's proxy is same or different on memory?
home.xml
<Alloy>
<Window id="home">
<View id="Container" onTouchend="fooFunction"> </View>
</Window>
</Alloy>
detail.xml
<Alloy>
<Window id="detail">
<View id="Container" onTouchend="fooFunction"> </View>
</Window>
</Alloy>
other.xml
<Alloy>
<Window id="other">
<View id="Container" onTouchend="fooFunction"> </View>
</Window>
</Alloy>
And how to clean object from memory when I close window for prevent memory leak?
Edited for window closing event for prevent memory leak;
$.detail.addEventListener("close", function() {
// this listerner creates when window open for paused app event
Ti.App.removeEventListener("app:RefreshJson", fncRefreshJson);
$.Container.removeAllChildren();
$.detail.removeAllChildren();
$.removeListener();
$.destroy();
// listview creates on the fly when new window opens
// then I am adding it into $.Container
listView = null;
$.detail = null;
});
From the docs: IDs should be unique per view but are not global, so multiple views can have components with the same ID.
Your approach is fine. A couple of notes
If the id is omitted from the top level component in the view, then alloy will adopt the file name as the identifier. So if you left off id="home", then in home.js, you would still reference the window object as... $.home since that is the file name.
camelCasing is the common format to use in Alloy, so View id="container" might be the way to go.
memory leaks specific to Alloy can occur with Data Binding, so bindings must be properly destroyed. Other than that, the same Memory Management tips should apply. The big one is to not use global event listeners. If needed, you can use Backbone Events instead.
Personally, I've found it easier to use the same identifier for all my windows, such as <Window id="win"> (and $.win in the controller) so when switching around between view controllers, I don't have to look up or remember what the name or file name is for this particular window.
My article on this topic is three-years old. But, in a quick scan I think it all still applies today. http://www.tidev.io/2014/03/27/memory-management/
And how to clean object from memory when I close window for prevent memory leak?
It depends:
If the window is part of a tab group, then it will remain in memory as long as the app is running.
If it's a window that is opened in a navigation group or in a stack of windows on Android, it would depend on how you instantiated the window.
// if you do this:
var win = Alloy.createController('detail').getView();
win.open();
// then to clean up, after
win.close()
// you need to
win = undefined;
// which is why it's better to do this if you can
Alloy.createController('detail').getView().open();
// then, inside of detail, you'd call its Window.close()
// method which would close the window and remove the
// last reference in memory and the object would be GC'd
As an aside, if you are really creating multiple windows with code as similar as you show above, perhaps you should create a Widget. You'd pass in defining characteristics (options, names, child Views, etc.) when instantiating the widget. This technique won't necessarily help with memory management or performance. But, it will help eliminate duplicate code.
I have introduced some animation into my WP7 app via a storyboard.
It is all working as expected the first time through - the event occurs, and I call the code to do the animation in the code behind and I get exactly the behaviour I want.
But when I trigger the second time, it is like the the delegate code involved in this is being called twice. And then I trigger the same event and the delegate code is called 3 times. Its cumulative.
Code that is called is as follows
private void WeekForward()
{
FadeTitleOut.Begin();
FadeTitleOut.Completed += delegate
{
StartingMonday = StartingMonday.AddDays(7);
BuildPage();
FadeTitleIn.Begin();
};
}
FadeTitleOut and FadeTitleIn are my storyboards and the animation effect is fine. It's just that the first time the event happens StartingMonday is incremented by 7 days. The next time the event fires its incremented by 14 days and so on.
Am I doing something really dumb with my delegate code?
Probably should add that I am doing most of the stuff here in the code behind, including the generation and deletion of controls dynamicaly, but the Storyboards are defined in the XAML and they reference a control that is defined in the XAML (and not generated in the code behind)
Storyboard XAML is
<phone:PhoneApplicationPage.Resources>
<Storyboard x:Name="FadeTitleOut">
<DoubleAnimation Storyboard.TargetName="LayoutRoot" Storyboard.TargetProperty="Opacity" From="1.0" To="0.0" Duration="0:0:0.3" />
</Storyboard>
<Storyboard x:Name="FadeTitleIn">
<DoubleAnimation Storyboard.TargetName="LayoutRoot" Storyboard.TargetProperty="Opacity" From="0.0" To="1.0" Duration="0:0:0.3" />
</Storyboard>
</phone:PhoneApplicationPage.Resources>
Any ideas?
Have a look through your code, my guess is that "WeekForward()" is getting called more often than you want it to and you are subscribing the FadeTitleOut.Completed each time it is called (hence the behaviour you are describing). One way to fix this would be to have this code else where so it only subscribed to the Completed event once.
Also, you should write up your events before firing the Begin method as you have a potential race condition. eg,
FadeTitleOut.Completed += delegate
{
StartingMonday = StartingMonday.AddDays(7);
BuildPage();
FadeTitleIn.Begin();
};
FadeTitleOut.Begin();
Put this code where it will be fired once during the life of the XAML page and it should be fine. Hope that helps.