首页 > 解决方案 > XML deserializing for embedded resources slow down app startup in Xamarin Forms

问题描述

I am working on a mobile application with Xamarin Forms for Android and iOS devices. There are two XML files (each around 12MB) that contain translation among two languages. Currently these files are embedded resources in the shared project and are deserialized in order to be used inside the application. I have made a (singleton) resource manager to search for translations in these files. The manager always run an initialize method at startup to deserialize the XML files and to prevent loading the XML files for every single time that a word should be searched. This increases the startup time; iOS on iPhone 8 takes 7s and Android on Samsung galaxy S8 takes 17s.

My questions:

  1. Is it correct to use these files as embedded resources in the shared project? If not what is the best practice to minimize the startup?
  2. Is reading and deserializing the XML files the best way to use those files?

Note that I have already searched but did not come to any conclusion from an experience point of view. Any advice (specially with some examples) is appreciated.

Update:

Here is a sample from the XMl file. But keep in mind that there are more than 50000 <word> tags in the original XML file.

<?xml version="1.0" encoding="utf-8"?>
<MyDictionary>
    <word class="nn" comment="även samklang av andra sinnesintryck; allmänt &amp;quot;överensstämmelse&amp;quot;" lang="sv" value="harmoni">
        <translation comment="also used of harmony of other sensory impressions; generally, &amp;quot;agreement&amp;quot;" value="harmony" />
        <phonetic soundFile="harmoni.swf" value="harmonI:" />
        <paradigm>
            <inflection value="harmonien" />
            <inflection value="harmonier" />
        </paradigm>
        <synonym level="4.4" value="balans" />
        <synonym level="3.2" value="endräkt" />
        <synonym level="3.8" value="samklang" />
        <synonym level="3.3" value="samspel" />
        <synonym level="3.4" value="sämja" />
        <synonym level="3.0" value="välbefinnande" />
        <see type="saldo" value="harmoni||harmoni..1||harmoni..nn.1" />
        <example value="leva i harmoni med naturen">
            <translation value="be at one with Nature" />
        </example>
        <derivation inflection="harmoniskt" value="harmonisk">
            <translation value="harmonious; harmonic" />
        </derivation>
        <definition value="samklang av toner">
            <translation value="the simultaneous combination of musical tones" />
        </definition>
    </word>
</MyDictionary>

For deserializing, first a model/object of the XML file has been made by using Paste Special (Paste XML as classes) function in Visual Studio. Then following method is used to perform the deserializing.

private MyDictionary Load(string fileName)
{
    try
    {
        var ass = IntrospectionExtensions.GetTypeInfo(typeof(App)).Assembly;
        var resourceName = $"LexinApp.XmlResources.{fileName}";
        using (Stream stream = ass.GetManifestResourceStream(resourceName))
        {
            using (StreamReader reader = new StreamReader(stream))
            {
                var serializer = new XmlSerializer(typeof(MyDictionary));
                return serializer.Deserialize(reader) as MyDictionary;
            }
        }
    }
    catch (Exception) { }

    return null;
}

After that a word is searched by

var a = MyDictionary.word.Where(x => x.value == searchKey.ToLower()).ToList();

标签: xmlperformancexamarin.formsstartupembedded-resource

解决方案


My best guess is that the xmlserializer isn't the fastest of its kind, especially since your word class has some degree of complexity.

As I already suggested in my comment, you might get quite a performance gain by ditching the xml serializer, write a custom xml parser based on XmlReader and push your data through it.

Another (or additional) idea to detach the serialization of your xml from your app's startup time would be loading your xml in an async background task so your main UI won't have to wait for it and since you have two files, you could also try loading them using parallel threading (using System.Collections.Concurrent):

string[] xmlFileNames = new string[] { "filenameA.xml", "filenameB.xml" };

Parallel.ForEach(xmlFileNames, xmlFile =>
                    {
                        Load(xmlFile);
                    });

推荐阅读