Start a new topic

Android ArchitectView performance

Android ArchitectView performance


Hello gentlemen,

Can anyone tell me are there any expected timespans for rendering large amounts of data like 50 objects or more in the ArchitectView? In our case the process of showing the added objects looks quite slow (it starts with some cluster and then slows down to adding the objects by 2-3 at a second). Additionally the onClick events don't seem to work until all the objects are loaded.

What device are you testing on and how is a POI created?

It of course depends on how you are adding the pois. E.g. how many drawables each POI has. As a general rule, calling ARchitect API functions is slower than calling a javascript  method. So try combining calls and to initialize an object in it's constructor e.g.

instead of

var l = new AR.Label("abc",15);
l.onClick = function() { // do something }

use

var l = new AR.Label("abc", 15, {onClick: function() {// do something} });

 

We're testing on a number of devices including Milestone with Froyo and Nexus with ICS.

The descibed behavior can be observed on both devices however the data load differs. For Milestone it is 74 POIs (I can get the ICS details later if required). Each one has a label and image drawables + animation + radar circle.

We have used the SampleARBrowser sample as a starting point when building the app so we load the objects through the newData() js function and we're adding the onClick() function in constructor as you've mentioned.

Any thooughts on how we can improve adding the objects or what is the heaviest part here? 

I would be interested in the results on the Nexus as the Milestone is a pretty low end device. If don't mind posting the newData method here, I can have a look at it and probably give you ideas for optimizing it. 

 

There you go

           

            function newData(jsonData)

            {

                if (jsonObject != null)

                {

                    for(var i = 0; i < jsonObject.length; i++)

                    {

                        jsonObject.poiObj.destroy();

                    }

                }

 

                jsonObject = jsonData;

 

                var textSize = markerSize / 3;

                var textOffset = textSize - markerSize;

                for(var i = 0; i < jsonObject.length; i++)

                {

                    var poidrawables = new Array();

                    var name = jsonObject.name;

                    if (name.length > 15)

                        name = name.substring(0,13) + '...';

 

                    var label = new AR.Label(name, 

                                             textSize, 

                                             {offsetY : textOffset,

                                              triggers: { 

                                              onClick:

                                              createClickTrigger(i)

                                             },

                                             style : {textColor : '#FFC100',backgroundColor : '#FFFFFF80'}});

                    

                    jsonObject.arLabel = label;

                    

                    var img = new AR.ImageDrawable(markerImage, 

                                                   markerSize,

                                                   {opacity:0.75,

                                                    triggers: { 

                                                    onClick:

                                                    createClickTrigger(i)}

                                                   }

                                                   );

                    

                    jsonObject.animation = createOnClickAnimation(img);

                    jsonObject.img = img;

                    

                    poidrawables.push(label);

                    poidrawables.push(img);

                    geoLoc = new AR.GeoLocation(jsonObject.Point.latitude,jsonObject.Point.longitude,jsonObject.Point.altitude);

                    var radarCircle = new AR.Circle(0.05, {style: {fillColor: '#83ff7b'}});

                    jsonObject.poiObj = new AR.GeoObject(geoLoc, {drawables: {cam: poidrawables, radar: radarCircle}});

                }

            }

After reading the http://forum.wikitude.com/home/-/message_boards/message/143156?p_p_auth=0sA1T71I I'd like to ask:

- does the jsonObject.poiObj.destroy(); free the image resources in a proper way or there are additional steps required?

- we should use the same ImageDrawable for all created objects, right? This would probably require the changes in createOnClickAnimation()

- will using the same click trigger for both label and image help in any way?

Talking about the Nexus device - it takes about 3 sec to show the POIs when their number gets 50+. It wouldn't be such an issue if we could click the POIs which are already shown without waiting for others to load.

Assuming that poiObject is of type AR.GeoObject the destory() method only deletes the AR.GeoObject. It does not touch attached Drawables, Locations or ImageResources. If you want to remove objects I would suggest to attaching a function e.g. destroyObject() to the AR.GeoObject when it is created. This makes it easier to destroy any drawables used by the geoboject as well.

Otherwise if you want to remove all objects just call AR.context.destroyAll(); ImageResources should be cached (if enough memory is available) and it won't be necessary to download them again over the network when they are created anew.

If the ImageDrawable always has the same properties you can use the same ImageDrawable accross all points. However if you want to animate the ImageDrawable of a single Poi then you must create separate ImageDrawables for all Pois. You should still share ImageResource accross ImageDrawables (this is one of the things described in the mentioned forum article).

Using a the same click trigger should not make any difference.

Clicking is blocked when the javascript method is executed. You might be able to work around this by creating the objects in batches.

 

 

Thanks you for support. I am working with Yegor and would like to follow up on the last post.

1. In regards to creating AR.ImageDrawable objects, in order to link each ImageDrawable on-screen to unqiue content we have to create an instance of ImageDrawable for each item (Each image requires a unique onClick method). I am currently testing an implementation that re-uses a pool of ImageDrawable objects where a new onClick trigger is assigned to the object as needed. Do you see any merit in this approach for improving performance? Could you provide some insight into what takes the longest in the rendering process?

2. In regards to loading the objects in batches, I have implemented a scheme where 10 GeoObjects are created at a time. This did not improve performance though, and we are still unable to select any items on screen untill all batches have been loaded. 

It appears that all of the javascript processing is done using one thread. Could you explain in more detail the threading model and how the interface from the Android source plays into that? It appears that all of the batches are processed on the one thread prior to the onClick

Thanks again for your help. Any further ideas for improving performance would be greatly appreciated.

-Harry

1. If the image, size and any other property of the ImageDrawable are consitent across all POIs you can use the same ImageDrawable for all POIs. This should increase startup performance as you are creating less objects. The click trigger can be added to the GeoObject itself so you can assign a different function to each GeoObject.

Looking at the code a second time, you can defere creating the animation until the click trigger is called. This might introduce a slight delay to the click animation beeing playedback, but it reduces the number of architect calls done at startup.

2. As a general rule calling any of the ARchitect API methods takes more time than a normal javascript function as there is a communication overhead. Thus limiting/combining calls helps the most. Rendering itself should not be the problem.

Javascript is by design single threaded, thus you cannot execute any js code in parallel. However splitting it up into batches might (as I've not tested it) allow the user to start clicking on POIs after the first batch was created.

If you are doing long tasks and still want to have other js executed in between (fake parallel execution) you could try following: use setTimeout to create one POI at the end of the function have another setTimeout call that will create the next POI. Continue until all POIs are created. What setTimeout does is, to delay the execution which gives other js (e.g. click triggers) a chance to execute. Would you create all POIs in one function this function runs completely before any other js code is executed.

Hi Wolfgang,

It looks like we've exhausted all the options to improve the performance at the moment and going to stay with what we have for now.

Thanks for some valuable hints.
Login or Signup to post a comment