tag:blogger.com,1999:blog-28614050758953347902024-02-08T07:52:59.858-08:00Trials of Tiny DevelopmentI blog about what I've learned as a hobby cf.net developer.Jake Stevensonhttp://www.blogger.com/profile/10924524960404256564noreply@blogger.comBlogger12125tag:blogger.com,1999:blog-2861405075895334790.post-65939378940933454192010-09-05T08:28:00.000-07:002010-09-16T14:23:53.728-07:00I Abandoned My Users (and they're doing ok without me)It's a pretty common scenario for a developer. You get an idea for a fun project. You start working on it. You build something half-decent. Then you get bored and move on to something else.<div><br /></div><div>That's all fine until someone ELSE finds your project useful too. It's exciting that other people like your project, and you work even harder for a while. But usually you still end up running out of steam sooner or later.</div><div><br /></div><div>That's what happened to me with PockeTwit. I wrote it to scratch an itch-- I wasn't satisfied with existing twitter clients for my phone at the time. I also wanted to play with code to do something more than the usual "winforms" look for most software written for that platform. I came up with something small and put it online just to see what people thought. Next thing I knew, it grew pretty popular and a lot of people relied on it for their twitter fix every day.</div><div><br /></div><div>But honestly, I got tired of it. My phone broke. After that I, like so many others, left Windows Mobile for a different smartphone platform (at the time the hardware specs still lagged horribly behind others). And once I could no longer use my own software to access twitter, I didn't have much motivation to improve on it.</div><div><br /></div><div>Luckily, it was "good enough" for most users for a very long time, until Twitter decided to shake things up and change the way applications authenticated with their service. Twitter no longer allows an application to simple provide the user's login and password -- they switched to a more complex system where the user has to authorize an application through their own version of OAuth. </div><div><br /></div><div>This change killed off a LOT of twitter applications like PockeTwit, where the original author simply didn't have the motivation to update their software. Even some that were purchased by users-- their company simply didn't have the time or the profit motivation to revamp their software. And for those applications it is probably the end of the road.</div><div><br /></div><div>But not for PockeTwit. Because it is "open source", any developer can easily download the source code to the application and tinker. And luckily, there were a couple who were interested enough in it to update it to support OAuth on Twitter. </div><div><br /></div><div>Thanks to the hard work of <a href="http://twitter.com/roelvandenbrand">@roalvanderbrand</a> and <a href="http://twitter.com/ashley_brown">@ashley_brown</a>, the latest releases of PockeTwit support OAuth and can continue to work on Twitter. They've not only tackled the OAuth issue -- they've continued to improve the application in many ways.</div><div><br /></div><div>I can't tell you how great it was to see what started as a way for me to kill some time and have some fun be accepted by so many. But it might be even MORE rewarding to see that other developers cared enough to take up your code and continue to improve it. I've grown a lot in my development style since I started PockeTwit, and I'm a bit embarrassed by some of the code, but I feel I can be proud of what it became and is continuing to be even without me.</div><div><br /></div><div>I'd really encourage other hobbyists to open source their code. I did so knowing fully that I would cringe as I read it later in life, but I still thought it would be worth it in case it helped someone else with their hobby as well. And to this day I'm still very glad that I did.</div>Jake Stevensonhttp://www.blogger.com/profile/10924524960404256564noreply@blogger.com4tag:blogger.com,1999:blog-2861405075895334790.post-50000320006613692082009-08-16T17:29:00.001-07:002009-08-16T20:16:00.444-07:00WebRequest.AllowAutoRedirect Failure<p>The most recent release of PockeTwit has an annoying bug that causes the first request upon startup to fail with a communication error.  I finally tracked down the code to one line within our WebRequest factory:</p> <pre class="csharpcode"><span class="kwrd">public</span> <span class="kwrd">static</span> HttpWebRequest CreateHttpRequest(Uri uri)<br />{<br /> var request = (HttpWebRequest)WebRequest.Create(uri);<br /> request.AllowAutoRedirect = <span class="kwrd">true</span>;<br /> <span class="kwrd">if</span> (!<span class="kwrd">string</span>.IsNullOrEmpty(ClientSettings.ProxyServer))<br /> {<br /> var proxy = <span class="kwrd">new</span> WebProxy(ClientSettings.ProxyServer, ClientSettings.ProxyPort);<br /> proxy.BypassProxyOnLocal = <span class="kwrd">true</span>;<br /> proxy.Credentials = CredentialCache.DefaultCredentials;<br /> request.Proxy = proxy;<br /> }<br /> <span class="kwrd">return</span> request;<br />}</pre><br /><style type="text/css"><br /><br />.csharpcode, .csharpcode pre<br />{<br /> font-size: small;<br /> color: black;<br /> font-family: consolas, "Courier New", courier, monospace;<br /> background-color: #ffffff;<br /> /*white-space: pre;*/<br />}<br />.csharpcode pre { margin: 0em; }<br />.csharpcode .rem { color: #008000; }<br />.csharpcode .kwrd { color: #0000ff; }<br />.csharpcode .str { color: #006080; }<br />.csharpcode .op { color: #0000c0; }<br />.csharpcode .preproc { color: #cc6633; }<br />.csharpcode .asp { background-color: #ffff00; }<br />.csharpcode .html { color: #800000; }<br />.csharpcode .attr { color: #ff0000; }<br />.csharpcode .alt <br />{<br /> background-color: #f4f4f4;<br /> width: 100%;<br /> margin: 0em;<br />}<br />.csharpcode .lnum { color: #606060; }</style><br /><br /><p>For some reason, the “request.AllowAutoRedirect = true” is causing the first requests to fail with a “401: Unauthorized” from twitter!  No idea why that would happen, my suspicion is another little “gotcha” from CF.NET 2.0.</p><br /><br /><p>Any ideas?</p><br /><br /><p><strong>Edit:</strong>  It looks like I jumped the gun and did just what everyone else does—blame Twitter’s issue on the client.  I’ve had a lot of reports that other twitter clients are experiencing the same issue.</p> Jake Stevensonhttp://www.blogger.com/profile/10924524960404256564noreply@blogger.com1tag:blogger.com,1999:blog-2861405075895334790.post-80790808889311030222009-08-03T20:19:00.000-07:002009-08-10T16:59:56.163-07:00PockeTwit v.76 ReleaseIt has been a while, but it's finally time for a new PockeTwit update. Some new members have joined the team and have helped bring together a worthwhile release!<br /><br />First of all, some bugfixes. There was an issue with the "leaked" version of CF.NET 3.7 that many custom ROMs started using. I still have no idea WHY the issue was happening, but I was at least able to circumvent it.<br /><br />Also, we were installing a Today Screen plugin during the cab install, which requires writing to a portion of the registry that some carriers do not allow. I've taken that out of the install and put it into the application itself (where it can fail gracefully if necessary). So for those people out there with "locked" phones, this version will finally work.<br /><br />There have also been a number of other miscellaneous crash fixes and performance improvements brought in by a new team member, <a href="http://twitter.com/johnb2007">@johnb2007</a>. He jumped into the code with both feet and found a few ways to speed up rendering and improve battery usage.<br /><br /><a href="http://twitter.com/johnb2007">@johnb2007</a> also contributed some new features. You can now follow anyone by entering their twitter id, rather than having to find and select one of their tweets. There is an "advanced" search dialog to help you build complex search queries. And he has added what is probably the most requested feature of all, the ability to delete one's own tweets! Be sure to let him know how much you appreciate his efforts.<br /><br /><a href="http://twitter.com/lifanxi">@lifanxi</a> has also joined the team to add some important features. You might have noticed he has created his own fork of the PockeTwit code that works with the popular (but currently unavailable) Chinese site, <a href="http://fanfou.com/">Fanfou</a>. As a part of this effort he translated the entire UI to Chinese. We hope to take the experience he gained performing that work and find an easy way to provide internationalization for many languages within PockeTwit.<br /><br /><a href="http://twitter.com/lifanxi">@lifanxi</a> has also added support for proxies to the application. So if your network requires the use of one, you'll still be able to use PockeTwit :)<br /><br />These guys have kept me really busy trying to keep up. We finally had to take a break and decide to release before too much was added at once. But you can expect another release with even more interesting features coming up soon.<br />Jake Stevensonhttp://www.blogger.com/profile/10924524960404256564noreply@blogger.com4tag:blogger.com,1999:blog-2861405075895334790.post-35862394777279560842009-06-08T15:06:00.000-07:002009-06-08T13:06:12.725-07:00PockeTwit v.75 Released!PockeTwit v.75 is now available with several bugfixes and some exciting new features!<br /><br /><a href="http://twitter.com/marclandis">@marclandis</a> has continued refining the today screen plugin. It now offers a list of groups with unread items similar to the standard "Messages" plugin for pocket outlook. And tapping an item in that list will bring PockeTwit to the foreground and display that group.<br /><br />He also fixed an issue with QuickPost. The "Post Update" screen will now be displayed regardless of whether PockeTwit was already running or not.<br /><br />There is now a "Saved Searches" feature. This will allow you to define a search and add it to your custom groups timelines. You can also specify if the saved search will be automatically checked with your friends and messages timelines, or only refresh when it's selected. For example, I've defined a saved search for "PockeTwit OR PocketTwit" and set it to autoupdate, so I know whenever anyone mentions the applications name out there. But I also defined a saved search for any posts near my house and told it NOT to autoupdate, since that would get a constant stream of chatter.<br /><br />Note that PockeTwit's saved searches do not correspond with the user's saved searches on Twitter's site. Twitter added that feature too late into the development cycle of PockeTwit for me to have them match without adding a significant delay to the release. I do plan to have them synchronize in the future.<br /><br />I've added support for the web service "140it.com" to help users shorten their posts to fit twitter's 140 character requirement. If your post is over 140 characters, PockeTwit will first ask if you'd like to use 140it. If you agree, it will use their service to shorten some common words. For example, it will replace the word "to" with the character "2" and use other common abbreviations. If that still doesn't get the text to less than 140 characters, it will ask if you'd like to use shorttext.com like it did in the past.<br /><br /><a href="http://twitter.com/roelvandenbrand">@roelvandenbrand</a> has been trying to keep up with the flood of media services popping up around twitter and making sure PockeTwit supports as many as possible. He's added Img.Ly, Posterous, and TweetPhoto support. And thanks to TweetPhoto's support of development, it has been made the default media service for PockeTwit.<br /><br />A new developer, <a href="http://twitter.com/theMark_S">@theMark_S</a> ,has come forward and volunteered to write a desktop installer for PockeTwit. This will make it easier for some users to install the application through activesync rather than having to download the cab file directly to their device.<br /><br />As I mentioned, there have also been several bugfixes. The most important one is a fix that allows a user in the cache to be updated. In the last release, if a user changed their avatar or screen name, PockeTwit could not update the cached information. Their avatar would appear as a question mark or their screenname would not be updated. I'm glad to say that bug has been fixed!<br /><br />As always, thank you to all the PockeTwit supporters out there. This project has been a tremendous learning experience for me and I'm very glad that you find it useful.Jake Stevensonhttp://www.blogger.com/profile/10924524960404256564noreply@blogger.com11tag:blogger.com,1999:blog-2861405075895334790.post-75535580577271640872009-06-08T08:08:00.000-07:002009-06-08T10:27:11.822-07:00Announcing an Agreement with TweetPhoto!PockeTwit v.75 is very near done and I'd like to take a moment to announce an agreement with TweetPhoto before the release. It's not the only new feature in PockeTwit, it's probably not even the most important new feature. But it is very exciting to me (for obvious reasons).<br /><br />When I started development of PockeTwit, I did it with absolutely no financial incentive in mind. I had a good job that paid what I needed. I was just glad to share my work and allow others to enjoy it.<br /><br />But times and situations have changed and I can no longer afford to be so single-minded in my motives.<br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_YikggZ7lU7E/Si1J26pC3II/AAAAAAAAAJE/YFCURiBWlFI/s1600-h/tweetphoto.png"><img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 320px; height: 50px;" src="http://1.bp.blogspot.com/_YikggZ7lU7E/Si1J26pC3II/AAAAAAAAAJE/YFCURiBWlFI/s320/tweetphoto.png" alt="" id="BLOGGER_PHOTO_ID_5345009540561820802" border="0" /></a>Thankfully, <a href="http://www.tweetphoto.com/index.php">TweetPhoto </a>has come up with a simple plan to support PockeTwit development that requires almost no effort from you. If you use PockeTwit to post images to TweetPhoto, any advertising revenue for the page hosting the photo will go to PockeTwit. It's that simple.<br /><br />Of course you can still choose one of the many other media services supported by PockeTwit. And I won't bug you about that too much, I promise! But if you want a hassle-free way to show your support, this is it.<br /><br />I plan to release a version of PockeTwit which supports TweetPhoto (and has a lot more!) very soon. Be on the lookout, then take lots of pictures!!Jake Stevensonhttp://www.blogger.com/profile/10924524960404256564noreply@blogger.com5tag:blogger.com,1999:blog-2861405075895334790.post-69270354350710115312009-04-18T14:15:00.000-07:002009-04-24T09:04:55.685-07:00Tiny but Powerful!Just because your phone is smaller than a PC, it doesn't mean your app can't be full-featured!<br /><br />PockeTwit v.71 is out with some great new stuff. This is the release I've wanted to make for a long time, but had to build the foundation to lead up to it. I needed nested (and dynamic) menus to be able to fit everything in!<br /><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_YikggZ7lU7E/SfHPhY1uRHI/AAAAAAAAAIk/oAvmDDMf9jY/s1600-h/GroupMenu.png"><img style="margin: 0pt 0pt 10px 10px; float: right; cursor: pointer; width: 208px; height: 320px;" src="http://3.bp.blogspot.com/_YikggZ7lU7E/SfHPhY1uRHI/AAAAAAAAAIk/oAvmDDMf9jY/s320/GroupMenu.png" alt="" id="BLOGGER_PHOTO_ID_5328268006666421362" border="0"></a>PockeTwit now has grouping-- a feature usually reserved for a select few desktop twitter clients. You can now group users together in categories to make it easier to manage the stream of information from people you follow! You can "copy" a user to a group, meaning their posts will still appear in the Friends timeline, or you can "move" them to a group so they no longer appear in the main friends stream.<br /><br />And it gets better, you can specify notifications on a group-by-group basis. Make your business group vibrate and play a loud sound, but move yourself into a silent group so you no longer get notifications about your own posts. Can you tell how excited I am?<br /><br />In addition, <a href="http://twitter.com/roelvandenbrand">@roelvandenbrand</a> been hard at work on the picture service integration. He's added two new picture services-- <a href="http://pikchur.com/">Pikchur</a> and <a href="http://twitgoo.com/">Twitgoo</a>. He also took the feedback from users to heart and it no longer requires two taps to get the URL into your status. And it's able to post the message to those services that support it (like twitpic).<br /><br />And that gets better too! It can ALSO post the GPS coordinates to services that support it like MobyPicture and Pikchur! So now someone viewing the image on that service will see your image, your message, and the location it was taken! I'm really glad Roel's taken this on-- PockeTwit's becoming one of the best clients for on-the-go twitter media that out there.<br /><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_YikggZ7lU7E/SfHO17HFOlI/AAAAAAAAAIc/EQoDjxtCahg/s1600-h/Today_Screen.png"><img style="margin: 0pt 0pt 10px 10px; float: right; cursor: pointer; width: 208px; height: 320px;" src="http://4.bp.blogspot.com/_YikggZ7lU7E/SfHO17HFOlI/AAAAAAAAAIc/EQoDjxtCahg/s320/Today_Screen.png" alt="" id="BLOGGER_PHOTO_ID_5328267259951790674" border="0"></a>Another developer has joined our team, providing an often-requested feature -- a Today Screen plugin! <a href="http://twitter.com/marclandis">@marclandis</a> has put together a plugin for the today screen that cycles through how many unread items you have in each of your timelines. It can also be used as a quick-launch shortcut to open the application. We've been wanting this for a long time, but I didn't have the C++ skills to make it happen. Thankfully someone else did :)<br /><br />I've spent some time working on the memory and speed issues. I don't think the memory issues are completely solved, but I expect it's gotten a lot better. And the application loads significantly faster with this release.<br /><br />And be sure to check out the new themes-- Sunny, Mint, and Ice. I'm no graphic designer, but I'm slowly moving to more advanced visuals. I think a lot of people will like the way these look.<br /><br />As always, I want to thank everyone who's provided feedback throughout the development process. The nice thing about working on a communications client is that it provides an easy way for users to tell you what they think!<br />Jake Stevensonhttp://www.blogger.com/profile/10924524960404256564noreply@blogger.com9tag:blogger.com,1999:blog-2861405075895334790.post-71198987236042773212009-04-04T15:49:00.000-07:002009-04-04T15:57:16.324-07:00Talk about Mobile Development at altnethouston Open SpacesI'm spending this weekend TALKING about development rather than writing code, and so far it's been a great experience. Most of the groups I've participated in have been about code quality and agile development practices. And I have to admit I've been behind in both those areas for a while now.<br /><br />But I also convened a discussion about Mobile Development, something I've learned a LOT about recently. As it turned out, none of the people who came to my discussion had any real experience with mobile development yet, they were mostly interested in learning about it. So I ended up giving an impromptu presentation on how the special considerations you need to keep in mind when developing for mobile platforms. Overall, I think it went pretty well. <br /><br />I've put up <a href="http://houstonaltnet.pbwiki.com/Dev-for-Mobile-Devices%C2%A0">some notes </a>about the topics I covered on the houstonaltnet wiki. Maybe I'll refine this and give it as a "real" presentation some day.Jake Stevensonhttp://www.blogger.com/profile/10924524960404256564noreply@blogger.com0tag:blogger.com,1999:blog-2861405075895334790.post-23436485307396587502009-03-25T07:37:00.000-07:002009-03-27T14:37:50.697-07:00PockeTwit v.68 ReleasedAfter a lot of work, PockeTwit v.68 is finally ready for release. This version has quite a few new features so I thought I'd detail them here.<br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_YikggZ7lU7E/ScqMAg5QsvI/AAAAAAAAAIM/x3MM8Hte61Y/s1600-h/NestedMenu.png"><img style="margin: 0pt 0pt 10px 10px; float: right; cursor: pointer; width: 206px; height: 320px;" src="http://3.bp.blogspot.com/_YikggZ7lU7E/ScqMAg5QsvI/AAAAAAAAAIM/x3MM8Hte61Y/s320/NestedMenu.png" alt="" id="BLOGGER_PHOTO_ID_5317216250522284786" border="0" /></a><br />One of the most visible changes is the addition of "nested" side menu items. I was running out of space on the side menus and it was keeping me from being able to add some requested features, so some side menu items can now have multiple sub-items. For example, the left menu now has an "Other Timelines..." item. When clicked, that opens a submenu that allows you to search, view your favorites, or view the Public timeline.<br /><br />The multimedia capabilities of pocketwit have recieved a major ovehaul thanks to <a href="http://twitter.com/roelvandenbrand">@roelvandenbrand</a>. Roel had been requesting that I add support for image posts to <a href="http://mobypicture.com/">mobypicture.com</a> for quite a while. Eventually he saw it just wasn't going to be a high priority on my list so he decided to implement it himself!<br /><br />Once he got started, he did way more than just add mobypicture hosting-- he put in a system that lets the user choose from several image hosts. He also changed the posting process so it uploads a picture first, THEN gets the URL and puts it into the post (so you can see how many characters it will take up). He even implemented a way to fetch images from the hosts, so we can show thumbnails of images from other posts without having to actually launch a browser. Be sure to set which picture service you want to host your images in the "Other Settings" page.<br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_YikggZ7lU7E/ScqMKKCPxyI/AAAAAAAAAIU/A4cpHebNzw4/s1600-h/addressbook.png"><img style="margin: 0pt 0pt 10px 10px; float: right; cursor: pointer; width: 206px; height: 320px;" src="http://4.bp.blogspot.com/_YikggZ7lU7E/ScqMKKCPxyI/AAAAAAAAAIU/A4cpHebNzw4/s320/addressbook.png" alt="" id="BLOGGER_PHOTO_ID_5317216416184649506" border="0" /></a><br />I've also added a new "addressbook" for posting. Sometimes you want to include someone's @name in your post without having to find one of their posts to @reply. Now if you start typing "@p" in the post screen, it will pop-up a list of all users in your addressbook whos screen names start with "p". This makes it easy to select that username and have it inserted into your post. It also works for "d " (direct messages) as well.<br /><br />Unfortunately twitter does not provide an easy way to get the screen names of everyone you are following, so the addressbook is automatically filled with users from your Friends and Messages timelines. As you receive more status updates and messages from other users, they are added to the addressbook.<br /><br />Some other minor features have been added as well -- you can now copy the text of a selected item to an email. There's an option to automatically scroll to the top of the list when new items arrive.<br /><br />There's also quite a few bugfixes, and it might even be a little better about memory and battery usage.<br /><br />I hope you enjoy the new version. If you have any ideas you'd like to see implemented in the future, be sure to go to our <a href="http://pocketwit.uservoice.com/">Uservoice</a> page and submit them.Jake Stevensonhttp://www.blogger.com/profile/10924524960404256564noreply@blogger.com2tag:blogger.com,1999:blog-2861405075895334790.post-51471115526120805792009-02-03T06:41:00.000-08:002009-02-03T06:59:56.690-08:00(Late) Introductions<a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_YikggZ7lU7E/SYhbmMpB64I/AAAAAAAAAHU/j7uFUD9w8w4/s1600-h/Hi+my+name+is+Jake.png"><img style="margin: 0pt 0pt 10px 10px; float: right; cursor: pointer; width: 320px; height: 229px;" src="http://4.bp.blogspot.com/_YikggZ7lU7E/SYhbmMpB64I/AAAAAAAAAHU/j7uFUD9w8w4/s320/Hi+my+name+is+Jake.png" alt="" id="BLOGGER_PHOTO_ID_5298585673387862914" border="0" /></a>I often feel like these "who am I" blog posts are a bit self-serving and egotistical. But as PockeTwit gets more and more users I finally decided that some people might benefit from knowing a bit more about where it comes from. And since I haven't actually posted anything on the blog in a while, it would at least add some filler.<br /><br />First things first -- I am not associated with Google in any way. Yes, the project is hosted on Google's servers, but they provide free hosting and source control for any open-source projects. As much as I'd LOVE to work for Google Labs, they still haven't contacted me with that sweet job offer yet.<br /><br />Second, it's just me. There's no "Team PockeTwit" or startup corporation or anything like that. Just one guy who was feeling a bit bored and decided he needed a hobby project. Some folks like to pretend their software comes from a nameless company and has a staff to support their user's every need (yeah, I'm looking at you TwitPic!). Not here. I answer the emails. I answer the tweets. I write the code.<br /><br />Which brings me to the final bit -- Why? I do it because it's fun. I had finished a previous project experimenting with writing .NET for my phone and wanted to try another. The iPhone 3G had just come out and everyone was excited about twitter for the iPhones, but the apps for Windows Mobile just felt drab. And since none of them were open-source, I couldn't just try to work on a new UI as a contribution. So I started my own. Then somehow I'm 64 releases into it!<br /><br />So there you have it. PockeTwit is just a small one-guy project. Yes, I embrace the "beta culture" of software because I'm just doing it for the hell of it. And it's great that your hobby can generate something other people can use and enjoy.Jake Stevensonhttp://www.blogger.com/profile/10924524960404256564noreply@blogger.com4tag:blogger.com,1999:blog-2861405075895334790.post-49192304032062249672008-11-27T05:21:00.000-08:002008-12-02T08:55:08.719-08:00Smooth-Scrolling Part 3 - The Sliding WindowI finally figured out the true nature of the problem (described in parts 1 and 2), but the prognosis was still the same -- rendering the entire list to a large bitmap caused an OutOfMemory exception for some devices. I could not pre-render everything to ensure smooth scrolling.<br /><br />I spent some time investigating hacks to work-around it, like declaring a non-graphics block of memory to hold the large bitmap, but every one of them failed or was too much work to be practical. And when I sought out advice from development communities, the reaction was mostly that I was foolish to try something like this with WM.<br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_YikggZ7lU7E/STVn_RFSsWI/AAAAAAAAAGA/SEEAKfrtGHE/s1600-h/SlidingWindow.png"><img style="margin: 0pt 0pt 10px 10px; float: right; cursor: pointer; width: 226px; height: 320px;" src="http://3.bp.blogspot.com/_YikggZ7lU7E/STVn_RFSsWI/AAAAAAAAAGA/SEEAKfrtGHE/s320/SlidingWindow.png" alt="" id="BLOGGER_PHOTO_ID_5275236875149422946" border="0" /></a><br />I finally settled on a "sliding window" approach. The screen can hold 4 or 5 items at most. Instead of rendering all 50 or so items to a single bitmap, why not render the 5 items on screen and a few of the ones before and after that set? This way there's a bit pre-rendered buffer when the user scrolls up or down. When the user stops scrolling, I can re-calculate the items that need to be in the buffer and re-render it in a background thread.<br /><br />The core concept is simple, but there's a bit more in the actual code. Deciding on the window size was difficult. 15 items was ok for most users, but still crashed a few VGA users. And ironically, QVGA devices could handle WAY more items because of their smaller resolution. I liked that my Mogul could scroll the entire set without buffering and wanted to keep it that way. So the first step in the code is to determine the number of items it can handle in the buffer. I do it by starting with the maximum number of statuses in the list, then try to create a bitmap that will fit that number. If that fails, it decreases the number and tries again until it works.<br /><br />The code that re-fills the buffer after sliding is interesting too. After the UI has stopped scrolling, it determines the statuses on-screen and enough before and after to fill the buffer. It passes that whole list to the buffer. At first, the buffer would just render that whole list again, but this was inefficient. Now it determines if there is any overlap with what it currently has rendered. It moves the overlap to the top (or bottom) of the buffer, then only re-renders the new items.<br /><br />One downside to this is that it is possible for the user to scroll faster than the buffer can re-fill itself. When they do, they'll see a blank area momentarily until the buffer is able to catch up again. And how often this happens depends on how small the buffer has been made.Jake Stevensonhttp://www.blogger.com/profile/10924524960404256564noreply@blogger.com0tag:blogger.com,1999:blog-2861405075895334790.post-73267231990431746792008-11-19T13:40:00.000-08:002008-11-20T07:02:49.663-08:00The quest for a smooth-scrolling interface - Ouch<a href="http://jakeastevenson.blogspot.com/2008/11/quest-for-smooth-scrolling-interface.html">In my last post</a>, I discussed my great new idea for smooth scrolling in <a href="http://code.google.com/p/PockeTwit/">PockeTwit</a>. I tested it for a good while on my Sprint Mogul and several emulators. I even had several users try out the dev build before release. I felt satisfied it was ok, so I put it in the wild.<br /><br />And immediately my email began filling up with crash reports. I got to work and was able to solve all the issues pretty quickly except one -- an "OutOfMemoryException" that was coming up almost immediately on startup for many users.<br /><br />This one was a bit of a mystery. I figured out that most of the users with the error were using newer devices with VGA screens. Typically, these devices have WAY more memory than the old ones without a problem. To make it even more strange, the device claimed to have plenty of free Program Memory.<br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_YikggZ7lU7E/SSV7n2kNBiI/AAAAAAAAAFw/rxPmMRkPTFA/s1600-h/v48Usage.png"><img style="margin: 0pt 0pt 10px 10px; float: right; cursor: pointer; width: 206px; height: 320px;" src="http://4.bp.blogspot.com/_YikggZ7lU7E/SSV7n2kNBiI/AAAAAAAAAFw/rxPmMRkPTFA/s320/v48Usage.png" alt="" id="BLOGGER_PHOTO_ID_5270754863499511330" border="0" /></a><br />The problem was obviously with my new method of generating a new huge bitmap surface to render all the statuses on. Even if the device had plenty of free memory, it would often fail creating that bitmap. It would usually run without issue after a soft reset. When I looked at a task manager, the program looked like it was using the same amount of memory as before!<br /><br />A more careful look showed that not everything was the same. I was creating a big giant bitmap and I knew that had to take up more memory somewhere. My process (PockeTwit.exe) was using the same amount of memory, but another process had quadrupled in size!<br /><br />After some more research I discovered that all bitmaps in memory are assigned to their a seperate process -- gwes.exe (Graphics, Windowing, and Events Subsystem). It handles all device-specific graphics functions, and my bitmaps fell under it's umbrella.<br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_YikggZ7lU7E/SSV7z-gSjYI/AAAAAAAAAF4/jPViQAptwxU/s1600-h/v52Usage.png"><img style="margin: 0pt 0pt 10px 10px; float: right; cursor: pointer; width: 206px; height: 320px;" src="http://1.bp.blogspot.com/_YikggZ7lU7E/SSV7z-gSjYI/AAAAAAAAAF4/jPViQAptwxU/s320/v52Usage.png" alt="" id="BLOGGER_PHOTO_ID_5270755071789010306" border="0" /></a><br />But it still didn't explain the OutOfMemory error. The device itself still had plenty of memory. I had to dig even more to discover that each process in Windows CE 5 (which is what Windows Mobile is based on) can use up no more than 32M of memory. On VGA devices, combining my giant bitmap with the bitmaps of all the other applications on the device would sometimes put gwes.exe over that limit. I finally found the cause of my solution.<br /><br />So, to sum up the problem:<a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_YikggZ7lU7E/SSV7z-gSjYI/AAAAAAAAAF4/jPViQAptwxU/s1600-h/v52Usage.png"></a><ol><li>I make a giant bitmap. </li><li>Because of the architecture of the OS, that bitmap is assigned to gwes.exe instead of my process.</li><li>gwes.exe may expand past the 32M of memory per process limit.</li></ol>Now that I understand the cause of the problem, it's time to work on a solution that will let me keep my smooth scrolling without using up so much bitmap memory.Jake Stevensonhttp://www.blogger.com/profile/10924524960404256564noreply@blogger.com2tag:blogger.com,1999:blog-2861405075895334790.post-55823125427574789822008-11-19T07:00:00.000-08:002008-11-19T08:08:03.001-08:00The quest for a smooth-scrolling interfacePockeTwit's still crashing, and I blame <a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_YikggZ7lU7E/SSQx3sZSD0I/AAAAAAAAAFM/7oWYLSWQqF4/s1600-h/OldRender.png"><img style="margin: 0pt 0pt 10px 10px; float: right; cursor: pointer; width: 171px; height: 320px;" src="http://3.bp.blogspot.com/_YikggZ7lU7E/SSQx3sZSD0I/AAAAAAAAAFM/7oWYLSWQqF4/s320/OldRender.png" alt="" id="BLOGGER_PHOTO_ID_5270392296810090306" border="0" /></a>it all on those clickable links.<br /><br />Early on in developing <a href="http://code.google.com/p/PockeTwit">PockeTwit</a>, I decided I wanted to include "hyperlinks" in the status text, so the user only has to click on an @reply name and be able to see that user's timeline. This was an important usability feature for me.<br /><br />I <span style="font-weight: bold;">also</span> wanted a smooth-scrolling modern interface. This meant I couldn't just rely on the PocketIE rendering engine for my UI. I had to do "owner-drawn" controls in GDI, where my code would specifically draw the seperating lines, the avatars, and even the lines of text.<br /><br />So for each status on screen, PockeTwit would have to figure out how to word-wrap the text, find any clickable links, then draw it all. It would have to do this every time the screen was scrolled, even a single pixel. It worked, but all that computation slowed things down a good bit.<br /><br />I tried a few things to speed it up. I "cached" the line breaks and clickable locations in memory. It helped a bit, but nothing was going to make it really smooth like I wanted.<br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_YikggZ7lU7E/SSQzuJ1TJxI/AAAAAAAAAFU/2Hq31puEhW4/s1600-h/NewRender.png"><img style="margin: 0pt 0pt 10px 10px; float: right; cursor: pointer; width: 213px; height: 320px;" src="http://2.bp.blogspot.com/_YikggZ7lU7E/SSQzuJ1TJxI/AAAAAAAAAFU/2Hq31puEhW4/s320/NewRender.png" alt="" id="BLOGGER_PHOTO_ID_5270394331936794386" border="0" /></a><br />With v.49, I tried something radical. Instead of looping through all the statuses every time and only rendering the ones on-screen, I created a giant bitmap and rendered ALL the statuses to it ONE time. Then as the user scrolled, I just copied the appropriate section of that bitmap to the screen.<br /><br />This was WAY faster. I was amazed at how well it worked and how smoothly it scrolled. And I looked at the task manager and was suprised to see that PockeTwit.exe was still using almost the exact same amount of memory as before. Unfortunately, it really was too good to be true. . . (to be continued)Jake Stevensonhttp://www.blogger.com/profile/10924524960404256564noreply@blogger.com0