Skip to content
This repository has been archived by the owner on May 1, 2024. It is now read-only.

Performance Issue : Convert Forms View to Native View(Android, iOS) (Custom Control) #4371

Open
Sasikumar3595 opened this issue Nov 10, 2018 · 37 comments
Labels
a/performance e/8 🕗 8 p/Android partner Issue submitted by partner or related open source project

Comments

@Sasikumar3595
Copy link

Sasikumar3595 commented Nov 10, 2018

Description

In our custom control, we are converting the Xamarin forms view to native Android view for providing custom view, but the each of the conversion take around 0.035 sec (it increases based the complex structure of given Xamarin forms view). We are converting 126 Xamarin forms view to Native Android view so it take more time(around 5 - 6 sec). We are added the code for converting the Forms view to native view, Please provide the suggestion for this?

Basic Information

  • Version with issue: All the versions
  • Last known good version: No

Screenshots

Not Applicable

Reproduction Link

Code Snippet for converting Xamarin forms view to Native forms view

////  This is the code snippet for converting Xamarin forms view to Native forms view

var vRenderer = Convert(view, (Xamarin.Forms.VisualElement)formsView.Parent);
var viewGroup = vRenderer.View;
vRenderer.Tracker.UpdateLayout();
var layoutParams = new ViewGroup.LayoutParams((int)size.Width, (int)size.Height);
viewGroup.LayoutParameters = layoutParams;
view.Layout(size);
viewGroup.Layout(0, 0, (int)view.Width, (int)view.Height);
view.Measure(double.PositiveInfinity, double.PositiveInfinity);
 
////  This is the code snippet for converting Xamarin forms view to IVisualElementRenderer

internal static IVisualElementRenderer Convert(Xamarin.Forms.View source, Xamarin.Forms.VisualElement valid)
        {
            var render = (IVisualElementRenderer)source.GetValue(RendererProperty);
            if (render == null)
            {
                source.Parent = valid;
                render = Platform.CreateRenderer(source);
                source.SetValue(RendererProperty, render);
                var p = PlatformProperty.GetValue(valid);
                PlatformProperty.SetValue(source, p);
                IsPlatformEnabledProperty.SetValue(source, true);
            }
           return render;
        }
@kingces95 kingces95 added the s/needs-info ❓ A question has been asked that requires an answer before work can continue on this issue. label Nov 14, 2018
@hartez
Copy link
Contributor

hartez commented Nov 14, 2018

we are converting the Xamarin forms view to native Android view for providing custom view

@Sasikumar3595 Could you explain more about what you are doing? How are you using these custom views? Are you using them in a native Android application?

@Sasikumar3595
Copy link
Author

@hartez We are developed the native Android project and the project contains the structure of the Application. We are planned to moving the project to Xamarin forms and we archive it by mapping and renderer through cross platform. Also convert the Xamarin.forms view to native view , since we are converting 126 Xamarin forms view to Native Android view and it take more time(around 5 - 6 sec).

@hartez
Copy link
Contributor

hartez commented Nov 17, 2018

To make sure I understand the situation:

You currently have an Android application. You plan to move the application to Xamarin.Forms in the future. As part of that process, you have created some controls in Xamarin.Forms. You are using those Xamarin.Forms controls in your current Android application by converting them using the code you posted above.

Is that correct?

@Sasikumar3595
Copy link
Author

Yes, we are converting the Xamarin.Forms controls in to current Android application with the help of above mentioned code but it takes more time based on the complexity of Xamarin.Forms control structure.

We are converting the simple structure Xamarin.Forms control such as label, button etc., its takes around 3 -4 sec. But our application, we are using complex structure such as Grid, StackLayout with two or more sub views then it takes around 6 sec.

Please provide some suggestions to minimize the time delay.



@JKennedy24
Copy link

@hartez this is the Syncfusion Calendar control that takes about 6 seconds to load on Android. I think they are just wondering whether there is a more optimised/faster way of converting Xamarin.Forms views to native

@hartez
Copy link
Contributor

hartez commented Nov 28, 2018

view.Layout(size);
view.Measure(double.PositiveInfinity, double.PositiveInfinity);

What does view refer to here? I don't see it declared in the code snippet.

@JKennedy24
Copy link

@hartez I think View here can be any Xamarin.Forms View

Something like Grids and Labels. The more complex the view the longer the time to convert to native

any examples @Sasikumar3595 ?

@Sasikumar3595
Copy link
Author

Sasikumar3595 commented Dec 3, 2018

@hartez ,

The "View" refers the Xamarin Forms view such as Grid, StackLayout, Button etc., if we are using complex structure as follow snippet, the conversion of 126 forms view takes more time for convert to native Android view.

Eg.,

            var grid = new Grid();
            ColumnDefinition c1 = new ColumnDefinition();
            c1.Width = GridLength.Star;
            ColumnDefinition c2 = new ColumnDefinition();
            c2.Width = new GridLength(2, GridUnitType.Star);
            ColumnDefinition c3 = new ColumnDefinition();
            c3.Width = GridLength.Star;
            grid.ColumnDefinitions.Add(c1);
            grid.ColumnDefinitions.Add(c2);
            grid.ColumnDefinitions.Add(c3);

            RowDefinition R1 = new RowDefinition();
            R1.Height = GridLength.Star;
            RowDefinition R2 = new RowDefinition();
            R2.Height = new GridLength(2, GridUnitType.Star);
            RowDefinition R3 = new RowDefinition();
            R3.Height = GridLength.Star;
            grid.RowDefinitions.Add(R1);
            grid.RowDefinitions.Add(R2);
            grid.RowDefinitions.Add(R3);

            var custom = new Label();
            custom.HorizontalOptions = LayoutOptions.Center;
            custom.VerticalOptions = LayoutOptions.Center;
            custom.VerticalTextAlignment = TextAlignment.Center;
            custom.HorizontalTextAlignment = TextAlignment.Center;
            custom.Text = text;
            custom.AutomationId = text;
            custom.TextColor = Color.Blue;
            custom.FontSize = 10;

            Label label1 = new Label();
            Button button1 = new Button();
            Label label2 = new Label();
            Button button2 = new Button();
            Label label3 = new Label();
            BoxView boxView1 = new BoxView();
            Label label4 = new Label();
            BoxView boxView2 = new BoxView();

            grid.Children.Add(label1, 0, 0);
            grid.Children.Add(button1, 0, 1);
            grid.Children.Add(label2, 0, 2);

            grid.Children.Add(button2, 2, 0);
            grid.Children.Add(label3, 2, 1);
            grid.Children.Add(boxView1, 2, 2);

            grid.Children.Add(label4, 1, 0);
            grid.Children.Add(custom, 1, 1);
            grid.Children.Add(boxView2, 1, 2);

Code Snippet for convert the Forms view to native view

  • The grid as a view parameter of ConvertFormsToNative method.
internal Android.Views.View ConvertFormsToNative(Xamarin.Forms.View view, Rectangle size, FormsApplication formsView, Context context)
{
        var vRenderer = Convert(view, (Xamarin.Forms.VisualElement)formsView.Parent);
        var viewGroup = vRenderer.View;
        vRenderer.Tracker.UpdateLayout();
        var layoutParams = new ViewGroup.LayoutParams((int)size.Width, (int)size.Height);
        viewGroup.LayoutParameters = layoutParams;
        view.Layout(size);
        viewGroup.Layout(0, 0, (int)view.Width, (int)view.Height);
        view.Measure(double.PositiveInfinity, double.PositiveInfinity);
}

@hartez hartez removed the s/needs-info ❓ A question has been asked that requires an answer before work can continue on this issue. label Dec 10, 2018
@kingces95
Copy link
Contributor

Please submit a zipped reproduction.

@kingces95 kingces95 added s/needs-repro ❔ This reported issue doesn't include a sample project reproducing the issue. Please provide one. s/needs-info ❓ A question has been asked that requires an answer before work can continue on this issue. labels Dec 17, 2018
@Sasikumar3595
Copy link
Author

@kingces95,

We are prepare the simple sample with view conversion from Forms to Native Android and attached below

Sample :
CustomControl.zip

Could you please check with the above details and provide us with a possible solution for this.

@hartez hartez removed s/needs-info ❓ A question has been asked that requires an answer before work can continue on this issue. s/needs-repro ❔ This reported issue doesn't include a sample project reproducing the issue. Please provide one. labels Dec 31, 2018
@PureWeen
Copy link
Contributor

PureWeen commented Jan 6, 2019

@Sasikumar3595 can you give some details about the device/api level you are testing? The gif below is from your sample and it's running on an API 23 device and it's running fairly quickly for me.

flags

@Sasikumar3595
Copy link
Author

@PureWeen, In the above attached simple sample initial conversion takes 4 sec for rendering the customized view. The below gif is from our sample on Android device with API 25 with RAM 2GB. Can you please check the same with any Android devices with same configuration (2GB RAM, not Emulator)?

initialrenderingdelay

@kingces95 kingces95 added the s/needs-info ❓ A question has been asked that requires an answer before work can continue on this issue. label Jan 9, 2019
@PureWeen
Copy link
Contributor

@kingces95 is this something we can plug into your profiler work to see where the waits times are occurring?

@samhouts
Copy link
Member

samhouts commented Jun 1, 2019

@PureWeen That's a good idea! Let's see if we can do that next week.

@samhouts
Copy link
Member

samhouts commented Jul 2, 2019

@kingces95 @PureWeen Let's get traction on this. Thanks!

@SubburajPandian
Copy link

@samhouts Any update on this?

@PureWeen
Copy link
Contributor

@kingces95 can you run this through your profile stuff and see if you come up with anything on our side that we can resolve?

@samhouts samhouts added e/8 🕗 8 and removed s/needs-info ❓ A question has been asked that requires an answer before work can continue on this issue. s/unverified New report that has yet to be verified labels Sep 16, 2019
@KarthikRajaAKR
Copy link

Hi @samhouts,

Could you please update the details on this? due to this delay, we are facing a performance issue.

@Sasikumar3595
Copy link
Author

@samhouts,

Any update on this issue?

@boris-df
Copy link

FYI - I'm facing the same performance-issues with Xamarin.Forms on an Android-Device (Samsung Galaxy S8)

In Xamarin.Forms i've build a "Day-Cell" (that's a ContentView with a Grid in it; Vertical- and HorizontalOptions set to FillAndExpand; Just one Row/Column with a StackLayout in it containing another StackLayout with a Label an two labels underneath that StackLayout)

Then i have a "MonthView" with a Grid that has 7 Columns and 6 Rows; In CodeBehind i create 42 Day-Cells and put them into the Grid to show a month

Then i have a CarouselView (which is the new CollectionView) where DataTemplate is my MonthView

On iOS 12 / 13 it's fine
On Android, swiping to the next Item is very slow; stutters.

And because it's UI there seems to be no way to create such MonthView async / in a Task - Adding the Controls has to run on the MainThread of course and this seems to be very slow.

FWIW:
I experienced similiar performance issue when adding 50+ Controls at runtime to a ScrollView for example and there seems to be design-problem in the code because it is slowing down more with every new control you add; seems like a re-layout is taking place for every existing control when a new one is added - and there seems to be now "BeginUpdate / EndUpdate" to stop layouting while adding a lot of controls and let the layout taking place after you finished adding controls.

Maybe the problem here is the same - maybe it's totally different, i don't know. I just hope to be able to do a little more "complex" layout with good performance soon :)

@samhouts
Copy link
Member

Yes, these layout changes need to be batched and/or some intermediate method should be available to let you inject layout changes before the native layer tries to re-layout.

In the meantime, can you try using a pattern similar to the one found in https://github.com/xamarin/Xamarin.Forms/blob/master/Xamarin.Forms.DualScreen/TwoPaneView.shared.cs#L290

Basically, override LayoutChildren, and only let it call base.LayoutChildren when you've completed your own layout changes.

@boris-df
Copy link

@samhouts

Basically, override LayoutChildren, and only let it call base.LayoutChildren when you've completed your own layout changes.

that's a good idea - unfortunatly that didn't help because it doesn't seem the problem (at least it's not for the Performance Problem with adding 50 ContentViews in Grid-Cells at runtime)

the LayoutChildren function is called 1 or 2 times in my case - but not 50+ times (i created a CustomControl based on Grid to overload the LayoutChildren of the grid itself) - so that looks good.

Meanwhile i experiment with creating a Task for each View i add to the Grid (with a small delay in the loop that's a Task on its own)
The Goal is: Let the Constructors finish as soon as possible and let a background-Task add the controls when they are ready.

Maybe that won't help too much for itself - but it could possible enable me to create a lot more MonthViews long before the user will swipe to them - so it may be possible to hide the performance issue.... not sure though because the Views should be created only if they become visible (that's how the collection view works, right?)

@Sasikumar3595
Copy link
Author

@samhouts ,

Could you please update the details on this? due to this delay, we are facing a performance issue.

@boris-df
Copy link

To give an update for others that are finding this thread:

I needed to display a Month-Calendar on a Page. With Some Numbers/Details displayed for each day.
For this you need to display 6 x 7 Cells (full month with leading/trailing Dates at max) + Labels for the date of each cell + Labels for the Detail-Information in each Cell + Styling-Controls like Background for Date different than Background of the Detail-Part etc.

This is rediculous slow with Xamarin.Forms - unusable on Android (remember: We need to swipe thru months with a gesture, so if the user swipes, we need to build a new View and so on; And don't even think about creating 12 views before showing the page ... or you need to think about playing a Video for the User entertainment ;) )

MY SOLUTION
the RAW way ... doing it ALL by myself!
I Installed the SKIA Nuget and now i have a Canvas to paint on (i know this from Window PC Software)
I Paint the Lines, rectangles, Text etc for each month when i need them
it's BLAZINGLY FAST! You can easily get lots of frames per second - instead of waiting seconds for ONE frame :D

Yes - it's hard work (calculating x/y positions of lines depending on resolution; build your own Helper-Classes to draw a Day-Cell at a specific location)

  • it's not that flexible (well - it's even more flexible than XAML because you have full control over EVERY SINGLE Pixel if you like - but it's not like another developer could easily change an Entry in the XAML ... you have to understand the custom code and fix/change things there which may take longer
  • you have to take care of Tap-With-Position yourself as Xamarin.Forms didn't offer x/y position of a Tap; google it, you will find implementations of an own event for Android and iOS to get it

It was a lot of work but in the end i was able to solve the problem and it's WAY faster than before with XAML! (even on iOS)

So: If you need to display a LOT of things on a single Page and Threading (very hard with UI controls) is not a solution (it's never - because it takes even longer... only difference: the user is not blocked completely) - Take a look at Skia and paint it your own way! :)

@Sasikumar3595 Sasikumar3595 changed the title Performance Issue : Convert Forms View to Native Android View (Custom Control) Performance Issue : Convert Forms View to Native View(Android, iOS) (Custom Control) Aug 20, 2021
@Sasikumar3595
Copy link
Author

@samhouts ,

Any update on this? due to this delay, we are facing a performance issue.

@saiganesh-sakthivel
Copy link

@samhouts ,
Any update on this?

@BaltoAF
Copy link

BaltoAF commented Jan 13, 2023

@samhouts ,
Any update on this ?

@Sasikumar3595
Copy link
Author

@samhouts

Any update on this?

@boris-df
Copy link

@samhouts
Any update on this?

Xamarin is officially End Of Life
No new features will come and as far as i understand no bugs will be fixed anymore. This is it. End of story.

If you don't like to rewrite everything from scratch you should soon take a look at MAUI - Check if it's solved there and if not, open a new case for MAUI ...

... or if you have the chance (time, resources, ...) think about rewriting everything and take a look at Flutter - i sure has it's own problems but has a completely different approach for multi platform and is (or can be) really fast!

@vastris
Copy link

vastris commented Oct 25, 2023

To optimize performance, consider implementing asynchronous operations during conversion, breaking down complex structures into smaller tasks, and utilizing caching mechanisms to avoid redundant conversions. Additionally, explore profiling tools to identify specific bottlenecks in your conversion code. If you ever decide to expand your app to other platforms, keep in mind the potential challenges of converting iOS to Android or vice versa, and plan for platform-specific optimizations. Good luck with the optimization process!

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
a/performance e/8 🕗 8 p/Android partner Issue submitted by partner or related open source project
Projects
None yet
Development

No branches or pull requests