How to load resources effectively?

Hi,

I would like to optimize my code a little bit. At the moment, I do not preload any resources in onLayout callback. I do the work in onUpdate. My typical onUpdate looks like this:

findDrawableById("Blablabla1").setBitmap(condition1 ? Rez.Drawables.BlablablaBitmapA : Rez.Drawables.BlablablaBitmapB);
findDrawableById("Blablabla2").setText(condition2 ? Rez.Strings.BlablablaStringA : Rez.Strings.BlablablaStringB);
...
base.onUpdate();


What is the real implementation of Rez.Drawables.Something?
When I call it 2 times, is the second call cheaper on processing time?

I would like to preload resources if this helps performance, but how can I do it and keep my onUpdate structure? Can I just call:

Ui.loadResource(Rez.Drawables.BlablablaBitmapA);
Ui.loadResource(Rez.Drawables.BlablablaBitmapB);
Ui.loadResource(Rez.Strings.BlablablaStringA);
Ui.loadResource(Rez.Strings.BlablablaStringB);


...in onLayout and keep onUpdate unchanged?

Thanks very much. I am little bit lost in how the resources work.

Best Regards,
David
  • It is my understanding that you should try to minimize loading of resources of any kind. In your case, it seems that would mean adding some data to your view to either track the state of the application, or only change things about the application when it is necessary.

    I see two potential optimizations that you could make.

    • Don't search for the drawable you want to change every frame. If you are going to need to access the drawable often, look for it once and cache the result.
    • Don't set the resource for something unless your program state has changed.


    For the first issue, you can easily fix this by caching the drawable reference that is returned by findDrawableById()...

    hidden var mBlablabla1;
    hidden var mBlablabla2;

    function onLayout(dc) {
    setLayout(Rez.Layouts.ViewLayout(dc));

    mBlablabla1 = findDrawableById("Blablabla1");
    mBlablabla2 = findDrawableById("Blablabla2");
    }

    function onUpdate(dc) {

    // mBlablabla1.setBitmap(...);
    // mBlablabla2.setText(...);

    View.onUpdate(dc);
    }


    The solution to the second issue is a little more complex as the solution typically depends on what you are doing. Ideally, you only change something in response to some event. If that event is some sort of external notification, you'd do something like this...

    // most of my apps are implemented using a Model-View-Controller pattern. the
    // view registers itself with the model for updates, and when those updates come
    // in this function is called.
    function onNotify(symbol, object, params) {

    // someone is telling us to show a busy icon
    if (:status_busy == symbol) {
    mBlablabla1.setBitmap(Rez.Drawables.StatusBusy);
    }
    else if (:status_success == symbol) {
    mBlablabla1.setBitmap(Rez.Drawables.StatusSuccess);
    }
    else if (:status_failed == symbol) {
    mBlablabla1.setBitmap(Rez.Drawables.StatusFailed);
    }
    }

    function onShow() {
    getModel().setObserver(self.method(:onNotify));
    }

    function onHide() {
    getModel().setObserver(null);
    }


    If, on the other hand, you need to change something based on the current state of the world (which you are repeatedly checking), You could do something like this.

    hidden var mTemperatureCache;

    function onSensor(info) {

    var temperature = info.temperature;
    if (temperature != null) {
    temperature = temperature.toNumber();
    }

    // possible options
    //
    // 1) didn't find a sensor this tick, didn't see one last tick
    // - mTemperature == null
    // - temperature == null
    // 2) just found a temperature sensor after searching
    // - mTemperature == null
    // - temperature != null (any Number)
    // 3) just lost the temperature sensor after having seen it
    // - mTemperature != null (any Number)
    // - temperature == null
    // 4) just detected a temperature change since the last time
    // we updated the view
    // - mTemperature != null (any Number)
    // - temperature != null (any Number != mTemperature)

    // this if should be entered for options #2, #3, and #4
    if (mTemperatureCache != temperature) {

    if (temperature != null) {
    mBlablabla1.setBitmap(Rez.Drawables.FoundTempeIcon);
    mBlablabla2.setText(temperature.toString());
    }
    else {
    mBlablabla1.setBitmap(Rez.Drawables.SearchingForTempeIcon);
    mBlablabla2.setText("--");
    }

    mTemperatureCache = temperature;
    }
    }


    This minimizes the amount of work that we do when possible. We only update the icon and text if the sensor state has changed. Otherwise the only cost (in terms of cpu time) is the if check and possibly the conversion from float to number that happens every time the sensor callback is invoked. I'm think that this is ideal.

    One other thing to note is that you could easily mix the two patterns. In the Model-View-Controller pattern, the only logic that should be in the view is to get data from the model and display it. In a system like that, the onSensor() callback would be on the model class and all of the logic would be there. The model would check to see if the sensor state changed using code like above, and if there was a change, it would signal the view via the registered callback. The view code would be simple, just like the first bit of code.
  • 234

    Hi Travis,

    thank you very much for a looong response and architectural advise. The architecture I try to implement is maybe more like MVVM then MVC, but who understand the diferrences? :-) What I have is:

    - Model: really mostly non-visual components implementing the core of the application
    - View: inherited from View, with its onUpdate callback, only responsible for actual presentation of data
    - ViewModel: inherited from BehaviorDelegate, this is where device agnostic UI logic happens
    - ... and View knows interface of ViewModel, and usualy has its instance
    - ... and ViewModel knows nothing about View

    Let's imagine simple "press as fast as you can" game, but overarchitected as I do stuff for demonstartion purposes:

    class Calculator { // model
    function addOne(a) { return a + 1; }
    }

    class CalculatorDelegate extends Ui.BehDel { // viewmodel
    var a = 0;
    var statusIcon = Rez.Drawables.StatusZero;
    var message = "";
    function onSelect() { a = new Calculator().addOne(a); updateView(); } // executed after button is pressed
    function onInterval() { message = a < 100 ? "haha" : "good"; a = 0; updateView(); } // executed every minute
    hidden function updateView() {
    statusIcon = a > 90 ? Rez.Drawables.StatusVeryHigh :
    a > 50 ? Rez.Drawables.StatusHigh :
    a > 0 ? Rez.Drawables.StatusNormal :
    Rez.Drawables.StatusZero;
    Ui.requestUpdate();
    }
    }

    class CalculatorView extends Ui.View { // view :-), layout in xml
    var delegate; // of type CalculatorDelegate, passed in constructor
    function onUpdate() {
    findDrawableById("Icon").setBitmap(delegate.statusIcon);
    findDrawableById("BigNumber").setText(delegate.a.toString());
    findDrawableById("Message").setText(delegate.message);
    base.onUpdate();
    }
    }


    For the first issue, you can easily fix this by caching the drawable reference that is returned by findDrawableById()...


    Point taken, i can remember drawable and do not look for it every update cycle. Thanks for tip.

    Explanation:

    CalculatorDelegate really implements all the behaviour of the app. Basically it listen to various events and changes ViewModel in an appropriate way. Although I don't like it, it also requests UI update when any property is changed (we do not have auto bindings here like in MVVM fws). CalculatorView on the other hand does not care how ViewModel is calculated, but care about presentation. In my example it only binds ViewModel to Layout, but it can do more layout specific things obviously.

    I sort of like this style of code (very simple) and separation of concerns. I would like to keep the style as much as possible. But what about performance?

    1) In VM, statusIcon is assigned on any change from Rez.Drawables.Something, even if there is no need to change (it is only needed when a changes from 0 to 1, 50 to 51 and 90 to 91. This is why asked how Rez.Drawables.Something is implemented, if it keeps loaded resources in memory or is loading it every time when called.

    2) In VM, Rez.Drawables.Something is called on user interaction, but in doc the advice is you should load resources in onLayout. Should I preload all the icons in advance? Is it worth it? Should I use loadResource or just assign Rez.Drawables.Something to my variable? Isn't the resource returned by Rez.Something just a reference actually anyway?

    3) In View's onUpdate, I am setting all three drawables, even when typically only one of them is changed. How expensive is that operation? Is the setBitmap() and setText clever enough to do nothing if the value has not been changed? Or, isn't it very cheap anyway because all the hard rendering work is done in base.onUpdate()?

    Do you use other well proven design practice which has similar level of separation of concerns, but is designed for better performance?

    Thanks again,
    David
  • Yes, MVVM and MVC are similar. At the top level of my application I implement MVC. The input delegate responds to user input and calls functions to modify the state of the model. The model maintains all of the application-specific state, responds from commands issued by the controller, does validation and data updating, and then if a change occurred, it notifies the view (via a callback as mentioned above). The view accesses the data stored in the model and displays it.

    ...how Rez.Drawables.Something is implemented, if it keeps loaded resources in memory or is loading it every time when called.

    Rez.Drawables.Something is just an identifier for data that is in the resource file. I believe it is just an integer, so keeping them around is not really an optimization.

    Should I use loadResource or just assign Rez.Drawables.Something to my variable? Isn't the resource returned by Rez.Something just a reference actually anyway?

    Yes. The resource identifier is just that, an identifier. Someone needs to load the resource do do anything useful. In the case of the built-in Ui.Bitmap, it is documented to take a resource id, and it presumably calls loadResource() for you. I'm not sure if it will work if you passed it the BitmapResource that is returned from a call to Ui.loadResource().

    Should I preload all the icons in advance? Is it worth it? Should I use loadResource or just assign Rez.Drawables.Something to my variable?

    If you have the memory available to load all of your resources into memory, you cold do that. Unless you are switching between them frequently, I wouldn't, but you certainly could.

    In View's onUpdate, I am setting all three drawables, even when typically only one of them is changed. How expensive is that operation? Is the setBitmap() and setText clever enough to do nothing if the value has not been changed?

    I don't know how clever either of them are. I'd guess that neither of them are all that clever, and I'd write my code to

    Or, isn't it very cheap anyway because all the hard rendering work is done in base.onUpdate()?

    Both loading and drawing a bitmap isn't going to be cheap. If you can avoid either of them I think it is a win.

    Do you use other well proven design practice which has similar level of separation of concerns, but is designed for better performance?

    I think the pattern you are using is fine. I just think your view implementation could be improved a bit by only changing data when something actually changes. Given that it isn't happening that often, it probably doesn't even matter.
  • Yes, MVVM and MVC are similar. At the top level of my application I implement MVC. The input delegate responds to user input and calls functions to modify the state of the model. The model maintains all of the application-specific state, responds from commands issued by the controller, does validation and data updating, and then if a change occurred, it notifies the view (via a callback as mentioned above). The view accesses the data stored in the model and displays it.



    Interesting. What top level means in that case? Is it multi-page app? So when data changes your model raises an "datachanged" event and view directly reponds to it - do I understand correctly? Do you then pass any parameters in that callback to indicate what data changed actually, so that view knows what it needs to rerender, or you are rendering everything in view as I am, or you have multiple various events and your views directly subscribe to these multiple events?

    If the last option above is how you do that, then it make sense that you can only rerender what you need and you can achieve the best performance. If it is only a generic datachanged event, then you can just as easily use Ui.requestUpdate...

    But it is far from MVVM pattern - the ViewModel component is missing and your View directly depends on Model. I probably don't understand MVC pattern enough to be able to comment on that - I never liked it and didn't understood the benefits.

    MVVM is beautiful pattern for writing ui, but it especially shine when your system supports automatic binding. Which is obviously not the case here. But I wanted to try to implement it here as I believe it would be beneficial for larger apps with more the couple of views.

    In the case of the built-in Ui.Bitmap, it is documented to take a resource id, and it presumably calls loadResource() for you. I'm not sure if it will work if you passed it the BitmapResource that is returned from a call to Ui.loadResource().



    It wouldn't I believe, and actually is why I started the thread. To keep things nice and tidy, I like to use XML layouts as much as possible. But I understand layouts.xml as templates, which I need to adjust/change at the runtime. I have a feeling it has not been designed with this in mind, or I am missing something essential.

    For example, for the templating to work well, there would be such thing like isHidden or isShown property. It isn't. The only way how to hide something is to move it out from screen. I don't like it, which means that I need to draw all elements shown conditionaly by myself in code or by using drawable-lists (even stranger thing than layouts).

    So at the end I combine all the layout features to keep the code as clean as possible, but I always end up with drawing something by code, which I think should not be necessary. And I have a feeling I waste too much processor power only for the purpose of keeping the code clean.

    Both loading and drawing a bitmap isn't going to be cheap. If you can avoid either of them I think it is a win.




    Do you also have a feeling that when using layouts, system always rerenders all of them anyway, so it actually does not matter if you change it or not?
  • Interesting. What top level means in that case? Is it multi-page app?

    In the case of my current toy project, my entire application state is maintained by one class. This is the top-level model. In some cases, I have other models that may act as facades for the data within the top-level model. These classes are sometimes like a view-model, just without the data binding.

    So when data changes your model raises an "datachanged" event and view directly reponds to it - do I understand correctly?

    Yes. Exactly.

    Do you then pass any parameters in that callback to indicate what data changed actually, so that view knows what it needs to rerender, or you are rendering everything in view as I am, or you have multiple various events and your views directly subscribe to these multiple events?

    The callback that gets invoked receives 3 parameters; the message type (a symbol), the message sender (an object), and params (additional data that is interpreted based on the message type). I typically use it to send notifications about model state that has changed. For example, when I call makeJsonRequest from inside my model, I call notify(:trigger_initiated, self, null) so that the view can display an indicator. When the response comes back, I call notify(:trigger_success, self, null) or notify(:trigger_failed, self, null) to indicate the response has come back. If there is data to read, I can then process the data in the model and send out notifications for each thing that I read...

    if (new_temp != old_temp) {
    notify(:temperature_changed, self, new_temp);
    old_temp = new_temp;
    }

    if (new_fan_state != old_fan_state) {
    notify(:fan_state_changed, self, new_fan_state);
    old_fan_state = new_fan_state;
    }


    or, I could just do it in one bulk operation and let the view sort it out.

    var new_values = {};
    if (new_temp != old_temp) {
    new_values['temperature'] = new_temp;
    old_temp = new_temp;
    }

    if (new_fan_state != old_fan_state) {
    new_values['fan_state'] = new_fan_state;
    old_fan_state = new_fan_state;
    }

    if (new_values.size() != 0) {
    // send the map and let the view look for the data
    notify(:state_changed, self, new_values);
    }


    Of course I could just let the view access the model (via the second parameter), but I prefer not to do that.

    As far a rendering goes, I just let the view render the layout for me. If you are trying to optimize what is rendered by only drawing the elements that have changed, you can definitely do that with custom drawables. I don't currently bother to do it, but I recently was involved in some discussion where I got some ideas. See this thread for more information.

    If it is only a generic datachanged event, then you can just as easily use Ui.requestUpdate...

    For that to work, the view has to know what to draw, and that data is stored in the model. The view has to have or get access to the model whenever it wants, and this seems like an unnecessary dependency to me.

    But it is far from MVVM pattern - the ViewModel component is missing and your View directly depends on Model.

    It can be done that way, but typically the view depends on the data that the model sends via the notification callback. The model ends up having to put the data into some agreed-upon format before sending the notification. I could easily inject an additional class between the model and view to do the same work, but I'm not seeing any benefit to do so.

    MVVM is beautiful pattern for writing ui, but it especially shine when your system supports automatic binding. Which is obviously not the case here. But I wanted to try to implement it here as I believe it would be beneficial for larger apps with more the couple of views.

    I've never worked in an environment with automatic data binding, but it seems that some of the functionality could be implemented pretty easily (not the automatic part).

    But I understand layouts.xml as templates, which I need to adjust/change at the runtime. I have a feeling it has not been designed with this in mind, or I am missing something essential. For example, for the templating to work well, there would be such thing like isHidden or isShown property. It isn't. The only way how to hide something is to move it out from screen...

    This is where custom drawables are useful. You can make your own drawable and then refer to that in the layout definition.

    class MyBitmap extends Ui.Bitmap
    {
    hidden var mVisible;

    function initialize(params) {
    Bitmap.initialize(params);
    mVisible = params[:visible];
    if (mVisible == null) {
    mVisible = true;
    }
    }

    function isVisible() {
    return mVisible;
    }

    function setVisible(visible) {
    mVisible = visible;
    }

    function draw(dc) {
    if (mVisible) {
    Bitmap.draw(dc);
    }
    }
    }


    In your layout...

    <layout id="..">
    <drawable id="myBitmap" class="MyBitmap">
    <param name="locX">10</param>
    <param name="locY">10</param>
    <param name="rezId">Rez.Drawables.MyBitmap</param>
    <param name="visible">true</param>
    </drawable>
    </layout>


    Then in your source...

    findDrawableById("myBitmap").setVisible(false);


    Do you also have a feeling that when using layouts, system always rerenders all of them anyway, so it actually does not matter if you change it or not?

    Yes, the draw() method will be called for every drawable in a layout, but you have control over what type of drawables they are and what they do when that call is made.

    The one thing that I've found with the layout system is that it seems to take up a lot of memory, and they can make your application seem slow (noticeable during page transition animations).
  • Really interesting architecture and discussion ;-)
  • I'm not a very good programmer and I try to use my resources to fit my app into the limited amount of memory.
    Most times, it's been my experience that I will cut corners to be able to fit my app into the memory (garmin says we have 64KB for app, but experience shown that once we hit approx 45kb, "bad' things start to happen)

    So when I cut corners, I can't do all of these MVC stuffs. I want to fit as much code as possible into the least amount of lines. (saves me 0.05kb here and 0.05kb there)
    what ends up is some amount of Spaghetti code unfortunately.

    and I don't use layouts cos each XML file eats up like 1-2kb (at least it does with the menu system)
  • NIKEOW, it makes sense. I have not yet reached the memory limit with my tiny apps. Once I do, I may need to change my approach... or leave the platform if I will not feel comfortable :-). Anyway, this thread was originally about loading resources, not the architecture / patterns :-).
  • Yes, the draw() method will be called for every drawable in a layout, but you have control over what type of drawables they are and what they do when that call is made.

    Does this mean, 1) that all the layers are alwas rendered as ready to be shown, no matter if the user ever switches to them? 

    2)my second question is, what is faster and more efficient. To make a drawable ie "hello world", load it and in for example _OnColor change draw the resource, or - in _OnColor change some global variable and then within onUpdate simply draw the text to a layer by dc.setColor and dc.DrawText ?