Performance is the area that we probably spend the most time on in all our apps. Building apps on the phone is just way different than building desktop apps. Things that might be really minor optimizations on a desktop Silverlight can really make a difference on desktop Silverlight apps.
Developing on the phone is an issue of economics where processing power is a scarce resource. You have to be conscious of the tradeoffs of using things like binding, layout controls, dependency injection, etc with their impact on performance. When I first started building phone apps I was excited to use nRoute and it’s nice features around MVVM/Resource Location/Messaging/Navigation. I wanted to have this really perfect loosely coupled architecture that used biding for everything/minimal code behind, had great designer support and dynamically resolved the proper services and models. In practice, that is not generally high performance code on the phone. If you are using some extra frameworks, really be conscious of the impact on performance and decide if you really need that architecture. What might work wonderfully on a more complicated desktop line of business app might not work as well on the phone. You just have to expect to write more optimization in a mobile app regardless if it’s the iphone, wp7 or android.
Silverlight was billed as “same Silverlight, just on the phone”. That is mostly true in terms of the api, but not necessarily true in terms of the actual runtime. It’s really a brand new runtime based on Silverlight 3 with some extra features added, so certain pieces of code might not have the same performance characteristics.
I’ve seen a lot of articles from various other people that talk about “buttery smooth scrolling” and other performance tips. At times the tips are a little too generalized. When you try to optimize something for performance on the phone, you really need to take into account your specific circumstances and find the right combination that works for your app. Always test and benchmark. Some things are more difficult to measure without real profiling tools,but do the best you can. Also be aware that scrolling in 3rd party apps on the phone is just not great at the moment. The native OS apps use a different UI framework that is going to make all but the simplest 3rd party apps feel sluggish so don’t feel too bad if your app scrolling seems slower. It’s probably not entirely your fault. Although this guy (around 8:50) seems to disagree. Sure 3rd party apps will get better with more experience and time,but the runtime needs to also get better. It’s the v1 of a new platform for everyone.
Finally, most of my thought are based around apps like twitter or facebook or other apps that require lots of live network data and have more complicated/longer list based screens. A 2 screen unit converter app is just going to be faster because it’s a simpler app and you don’t really need to optimize much.
So here are some things that you can try think about for your application:
- Data binding is always going to be slower than just directly setting a value. If you don’t have to databind, try to avoid it. I see lots of people going out of their way to MVVM everything and create bindable app bars. Feel free to just wire up a handler once in awhile or just directly set some text. There are other ways of centralizing code for reuse instead of trying to adhere to a strict pattern. If you are trying to animate in a screen and data bind simultaneously, most of the animations will get chopped. Just directly set enough pieces of data to have something to animate in and then you can do more intensive data binding after the animation is complete.
- As mentioned above – consider the tradeoff of always following the same pattern just for the sake of maintaining the pattern. Sure it might be easier to maintain, but high performance code doesn’t always look pretty. Be flexible, take shortcuts and do what makes sense for a specific part of the application. That’s not to say you should ever write bad code, just don’t focus on creating an architectural masterpiece in lieu of something that is performs well. The end user only sees what you put on screen, not the code behind it. They don’t really care that you used MEF and have an awesome messaging framework. When i see people over-engineer what should be a simple app just to adhere to some theoretical best practices I get sad.
- Converters slow your app. It’s better to just create the specific properties needed on your model. It’s minor optimization, but it adds up on the phone.
- Template expansion is slow. If you have a listbox where the item templates have lots of visibility converters, it’s going to be inefficient for a few reasons. First, you pay the perf hit of parsing a template for an item that is just going to be collapsed anyway. Plus you ran it through a bound converter which is slower. To optimize better you can do a few things:
- If you can cut down visuals in a list, that is always the first place to start. If not every item in the list can use the same fixed template, consider making the list more of a summary and then link to a detail screen. The Twitter app does this nicely to avoid parsing hyperlinks in the text or showing attached photos. (because of how virtualizing stack panel works, it’s always better to have fixed height items that use the same template) Facebook on the hand parses text for hyperlinks which is slower because it need to reassemble the text in a wrap panel of multiple controls and the regexing is slow, but that is more in line with the user’s expectation of the facbeook experience.
- If you have to have variable templates, make the list item a custom control and have the control dynamically create specific visuals needed for the list item so you don’t do extra layout work. Plus you eliminate converters and other extra data binding since you only have to bind one data property. Creating in code is faster than parsing the extra xaml. Obviously this comes at a maintenance penalty and you don’t get designer support, but for those of us that don’t use blend or the designer view, not so much of an issue. Although inside your control you need to keep references to UI elements that you create and reuse as your entire control is recycled BY well, “same, your, your, soon, the, mentioned, much, it, much, possible, far, you, a, your, well, long, they, much, possible, many, you, soon, possible.ndering data that might not be needed. Another option is to add a load more button at the bottom of the list.
- It’s really important to minimize work on the UI thread as much as possible since the touch recognition happens on the UI thread and will get dropped if the processor is maxed out. Don’t do anything on the UI thread that is not directly related to setting / manipulating a UI element. Well you can do some things, but really try to background as many chunks of work as you can.
- Some apps like the people hub scroll the header with the list and have a footer. If you try to retemplate listbox and insert a header and footer around the itemscontrol inside the scrollviewer, you will lose virtualization. There are a few ways you can accomplish this while maintaining virtualization.
- Easiest is to bind to a list/collection of object and insert dummy items for the header and footer. You can then inherit from listbox and make you own that has a template property for header and footer. In PrepareContainerForItemOverride you can check if it’s a header / footer object and apply the right template.
- If you don’t want to create all these collections with dummy objects, you could internalize the collection to you own listbox. Instead of binding your normal collection to itemssource, add a new proprty called datasource, bind to that and hook into the collection changed events to mirror the changes in your own internal collection. Then you can bind that internal collection and add your own header / footer items to the collection. This also allows you to easily add some “Loading data” message or “No data” message.
- Talking to some other people, I have learned that this might not be very performant because it breaks some of the container recycling. The alternative is to not override PrepareContainerForItemOverride and instead have one template and change the visibility on the non header/footer items. This is one of those things that you have to try out and see for yourself.
- Focus in making the app respond to input as soon as possible. You need to do something immediately when the user takes some action. If the content will take some time to load, at least transition to it and display a loading indicator. An example would be a popup that slides in with a list of items. If the list is somewhat complex and does not render immediately, there ill be a noticeable lag between the user action and the response. Slide up the list with a header and loading indicator, then data bind the list. It will feel more responsive.
- I wrote previously about transitions. You should design the app with transitions in mind and be conscious of why certain animations are useful for context and perceived performance. It does seem like this should be easier to do since animation is a big part of the metro design.
- Spend some time to review the hit targets of your elements. 40×40 seems to accommodate an adult finger reasonable well. Remember to keep a reasonable mount of spacing between hit areas. You really need to think about this when designing an application. With a mouse you can click on a specific point. On the phone you need to account for the size of your finger. You want to avoid having users click the wrong things, navigating to a screen , then having to navigate back.
- If you have a pivot with 4 items and you save the selected index on tombstoning you can’t always set the selected index immediately in OnNavigatedTo. The pivot creates the first, 2nd and last items. Setting the selected index to the 3rd pivot will throw an exception. If you have more than 3 pivots and you need to set the selected index, grab the index of of the page state in onnavigatedto, store in a variable and set it in the page loaded event.
- You can always check PhoneApplicationService.Current.StartupMode == Activated to check whether you are returning from a tombstone. The whole concept of tombstoning could be my least favorite #wp7dev feature besides the navigation framework and scrolling performance. I really don’t understand why this is something developers should have to worry about. If the phone wants to tombstone my app, put it back the way it was when you’re done. Also be aware when launchers/choosers are going to tombstone your app or any other side effects when returning from them.
- There are lots of different keyboard layouts (SIP). Use the right one for your text entry needs. You can optimize for web addresses, email, phone numbers, text (for dictionary suggestions) and search. One thing is that the search key is not super obvious in my opinion. You can use the app bar to augment the SIP by adding more specific buttons like upload photo, etc.
- There is currently no socket support so implementing something like a chat client is difficult. *cough* facebok chat *cough *
- If you want your pages to load quickly, don’t do anything before the first layout updated event after loaded is fired. Then defer loading things until they need to be shown.
- There is no launcher for the bing maps app. If you want to display driving directions you need to call the virtual earth web service to get the data (or whatever other map service you might prefer)
- There is also no compass api, no direct camera access (so therefore no augmented reality unless you are a handset maker like LG and have native code access), no Bluetooth api, no ability to add events to the system calendar, no video chooser (thus no ability to upload videos in your app), no ability to customize alert dialogs to match your app if you opt out of theming, no ability to run in the background (you can have your app run under the lock screen though), no copy paste (coming soon and hopefully 3rd party app support), no ability to alter the back stack, no gif decoding support (try ImageTools if you need to display gifs). I’m probably missing a few things that i would like to use but are not not supported. Despite all that, I’d still rather use visual studio / c# than Xcode/obj-c I do think the silverlight team did a great job getting it on the phone. It really is one of the better frameworks for building UX centric apps and the silverlight team has been really helpful in tracking down issues we’ve encountered.
I’ll be at PDC if anyone would like to chat about #wp7dev79 comments , permalink