<?xml version="1.0" encoding="utf-8"?><rss version="2.0"><channel><title>Ben Von Handorf</title><link>http://www.benvonhandorf.com:80/</link><description>Ben Von Handorf</description><item><title>Converting to the new Android Build System - Multiple libraries with the same dependencies</title><link>http://www.benvonhandorf.com:80/converting-to-the-new-android-build-system---multiple-libraries-with-the-same-dependencies</link><description>&lt;h1&gt;Mo Libraries, Mo Problems&lt;/h1&gt;
&lt;p&gt;I'm very excited about the new Gradle based Android build system, so I've set about converting all my projects over. &amp;nbsp;I quickly ran into difficulty, though, with a fairly common situation. &amp;nbsp;My application depends on a couple of different library projects... let's call them &lt;a href="http://actionbarsherlock.com/"&gt;A&lt;/a&gt; and &lt;a href="https://github.com/JakeWharton/Android-ViewPagerIndicator"&gt;V&lt;/a&gt;. &amp;nbsp;Both A and V depend on the support library. &amp;nbsp;Configuring the gradle build files went well enough, but when I try to assemble the overall project, I get an error while in the dexDebug step:&lt;/p&gt;
&lt;pre style="margin: 0px; padding: 0px; border: 0px; vertical-align: baseline; color: #222222; font-family: Arial, Helvetica, sans-serif; font-size: 13px;"&gt;:dexDebug&lt;/pre&gt;
&lt;pre style="margin: 0px; padding: 0px; border: 0px; vertical-align: baseline; color: #222222; font-family: Arial, Helvetica, sans-serif; font-size: 13px;"&gt;&lt;/pre&gt;
&lt;pre style="margin: 0px; padding: 0px; border: 0px; vertical-align: baseline; color: #222222; font-family: Arial, Helvetica, sans-serif; font-size: 13px;"&gt;UNEXPECTED TOP-LEVEL EXCEPTION:&lt;/pre&gt;
&lt;pre style="margin: 0px; padding: 0px; border: 0px; vertical-align: baseline; color: #222222; font-family: Arial, Helvetica, sans-serif; font-size: 13px;"&gt;java.lang.&lt;wbr&gt;IllegalArgumentException: already added: Landroid/support/v4/app/&lt;wbr&gt;ActivityCompatHoneycomb;&lt;/wbr&gt;&lt;/wbr&gt;&lt;/pre&gt;
&lt;pre style="margin: 0px; padding: 0px; border: 0px; vertical-align: baseline; color: #222222; font-family: Arial, Helvetica, sans-serif; font-size: 13px;"&gt;&lt;span style="margin: 0px; padding: 0px; border: 0px; vertical-align: baseline; white-space: pre;"&gt; &lt;/span&gt;at com.android.dx.dex.file.&lt;wbr&gt;ClassDefsSection.add(&lt;wbr&gt;ClassDefsSection.java:123)&lt;/wbr&gt;&lt;/wbr&gt;&lt;/pre&gt;
&lt;pre style="margin: 0px; padding: 0px; border: 0px; vertical-align: baseline; color: #222222; font-family: Arial, Helvetica, sans-serif; font-size: 13px;"&gt;&lt;span style="margin: 0px; padding: 0px; border: 0px; vertical-align: baseline; white-space: pre;"&gt; &lt;/span&gt;at com.android.dx.dex.file.&lt;wbr&gt;DexFile.add(DexFile.java:163)&lt;/wbr&gt;&lt;/pre&gt;
&lt;pre style="margin: 0px; padding: 0px; border: 0px; vertical-align: baseline; color: #222222; font-family: Arial, Helvetica, sans-serif; font-size: 13px;"&gt;&lt;span style="margin: 0px; padding: 0px; border: 0px; vertical-align: baseline; white-space: pre;"&gt; &lt;/span&gt;at com.android.dx.command.dexer.&lt;wbr&gt;Main.processClass(Main.java:&lt;wbr&gt;490)&lt;/wbr&gt;&lt;/wbr&gt;&lt;/pre&gt;
&lt;pre style="margin: 0px; padding: 0px; border: 0px; vertical-align: baseline; color: #222222; font-family: Arial, Helvetica, sans-serif; font-size: 13px;"&gt;&lt;span style="margin: 0px; padding: 0px; border: 0px; vertical-align: baseline; white-space: pre;"&gt; &lt;/span&gt;at com.android.dx.command.dexer.&lt;wbr&gt;Main.processFileBytes(Main.&lt;wbr&gt;java:459)&lt;/wbr&gt;&lt;/wbr&gt;&lt;/pre&gt;
&lt;pre style="margin: 0px; padding: 0px; border: 0px; vertical-align: baseline; color: #222222; font-family: Arial, Helvetica, sans-serif; font-size: 13px;"&gt;&lt;span style="margin: 0px; padding: 0px; border: 0px; vertical-align: baseline; white-space: pre;"&gt; &lt;/span&gt;at com.android.dx.command.dexer.&lt;wbr&gt;Main.access$400(Main.java:67)&lt;/wbr&gt;&lt;/pre&gt;
&lt;pre style="margin: 0px; padding: 0px; border: 0px; vertical-align: baseline; color: #222222; font-family: Arial, Helvetica, sans-serif; font-size: 13px;"&gt;&lt;span style="margin: 0px; padding: 0px; border: 0px; vertical-align: baseline; white-space: pre;"&gt; &lt;/span&gt;at com.android.dx.command.dexer.&lt;wbr&gt;Main$1.processFileBytes(Main.&lt;wbr&gt;java:398)&lt;/wbr&gt;&lt;/wbr&gt;&lt;/pre&gt;
&lt;pre style="margin: 0px; padding: 0px; border: 0px; vertical-align: baseline; color: #222222; font-family: Arial, Helvetica, sans-serif; font-size: 13px;"&gt;&lt;span style="margin: 0px; padding: 0px; border: 0px; vertical-align: baseline; white-space: pre;"&gt; &lt;/span&gt;at com.android.dx.cf.direct.&lt;wbr&gt;ClassPathOpener.&lt;wbr&gt;processArchive(&lt;wbr&gt;ClassPathOpener.java:245)&lt;/wbr&gt;&lt;/wbr&gt;&lt;/wbr&gt;&lt;/pre&gt;
&lt;pre style="margin: 0px; padding: 0px; border: 0px; vertical-align: baseline; color: #222222; font-family: Arial, Helvetica, sans-serif; font-size: 13px;"&gt;&lt;span style="margin: 0px; padding: 0px; border: 0px; vertical-align: baseline; white-space: pre;"&gt; &lt;/span&gt;at com.android.dx.cf.direct.&lt;wbr&gt;ClassPathOpener.processOne(&lt;wbr&gt;ClassPathOpener.java:131)&lt;/wbr&gt;&lt;/wbr&gt;&lt;/pre&gt;
&lt;pre style="margin: 0px; padding: 0px; border: 0px; vertical-align: baseline; color: #222222; font-family: Arial, Helvetica, sans-serif; font-size: 13px;"&gt;&lt;span style="margin: 0px; padding: 0px; border: 0px; vertical-align: baseline; white-space: pre;"&gt; &lt;/span&gt;at com.android.dx.cf.direct.&lt;wbr&gt;ClassPathOpener.process(&lt;wbr&gt;ClassPathOpener.java:109)&lt;/wbr&gt;&lt;/wbr&gt;&lt;/pre&gt;
&lt;pre style="margin: 0px; padding: 0px; border: 0px; vertical-align: baseline; color: #222222; font-family: Arial, Helvetica, sans-serif; font-size: 13px;"&gt;&lt;span style="margin: 0px; padding: 0px; border: 0px; vertical-align: baseline; white-space: pre;"&gt; &lt;/span&gt;at com.android.dx.command.dexer.&lt;wbr&gt;Main.processOne(Main.java:422)&lt;/wbr&gt;&lt;/pre&gt;
&lt;pre style="margin: 0px; padding: 0px; border: 0px; vertical-align: baseline; color: #222222; font-family: Arial, Helvetica, sans-serif; font-size: 13px;"&gt;&lt;span style="margin: 0px; padding: 0px; border: 0px; vertical-align: baseline; white-space: pre;"&gt; &lt;/span&gt;at com.android.dx.command.dexer.&lt;wbr&gt;Main.processAllFiles(Main.&lt;wbr&gt;java:333)&lt;/wbr&gt;&lt;/wbr&gt;&lt;/pre&gt;
&lt;pre style="margin: 0px; padding: 0px; border: 0px; vertical-align: baseline; color: #222222; font-family: Arial, Helvetica, sans-serif; font-size: 13px;"&gt;&lt;span style="margin: 0px; padding: 0px; border: 0px; vertical-align: baseline; white-space: pre;"&gt; &lt;/span&gt;at com.android.dx.command.dexer.&lt;wbr&gt;Main.run(Main.java:209)&lt;/wbr&gt;&lt;/pre&gt;
&lt;pre style="margin: 0px; padding: 0px; border: 0px; vertical-align: baseline; color: #222222; font-family: Arial, Helvetica, sans-serif; font-size: 13px;"&gt;&lt;span style="margin: 0px; padding: 0px; border: 0px; vertical-align: baseline; white-space: pre;"&gt; &lt;/span&gt;at com.android.dx.command.dexer.&lt;wbr&gt;Main.main(Main.java:174)&lt;/wbr&gt;&lt;/pre&gt;
&lt;pre style="margin: 0px; padding: 0px; border: 0px; vertical-align: baseline; color: #222222; font-family: Arial, Helvetica, sans-serif; font-size: 13px;"&gt;&lt;span style="margin: 0px; padding: 0px; border: 0px; vertical-align: baseline; white-space: pre;"&gt; &lt;/span&gt;at com.android.dx.command.Main.&lt;wbr&gt;main(Main.java:91)&lt;/wbr&gt;&lt;/pre&gt;
&lt;pre style="margin: 0px; padding: 0px; border: 0px; vertical-align: baseline; color: #222222; font-family: Arial, Helvetica, sans-serif; font-size: 13px;"&gt;1 error; aborting&lt;/pre&gt;
&lt;pre style="margin: 0px; padding: 0px; border: 0px; vertical-align: baseline; color: #222222; font-family: Arial, Helvetica, sans-serif; font-size: 13px;"&gt;:TestProject2:dexDebug FAILED&lt;/pre&gt;
&lt;pre style="margin: 0px; padding: 0px; border: 0px; vertical-align: baseline; color: #222222; font-family: Arial, Helvetica, sans-serif; font-size: 13px;"&gt;&lt;/pre&gt;
&lt;h1&gt;The Solution&lt;/h1&gt;
&lt;p&gt;I'll spare you the multiple attempts at debugging this, but &lt;a href="https://groups.google.com/forum/?fromgroups#!topic/adt-dev/FwEDW6OVeMo"&gt;I found a solution in a sample posted by Xavier Ducrohet&lt;/a&gt;. &amp;nbsp;It involves including the support library as a library project. &amp;nbsp;Your other library projects then depend upon this project.&lt;/p&gt;
&lt;p&gt;The build.gradle for the new support library project is pretty simple:&lt;/p&gt;
&lt;pre&gt;apply plugin: 'android-library'

dependencies {
    compile files('android-support-v4.jar')
}

android {
    compileSdkVersion 17
    buildToolsVersion "17.0.0"

    sourceSets {
        main {
            manifest.srcFile 'AndroidManifest.xml'
        }
    }
}
&lt;/pre&gt;
&lt;div&gt;&lt;/div&gt;
&lt;div&gt;As is the Android Manifest for it:&lt;/div&gt;
&lt;div&gt;
&lt;pre&gt;&amp;lt;?xml version="1.0" encoding="utf-8"?&amp;gt;
&amp;lt;manifest xmlns:android="http://schemas.android.com/apk/res/android"
&amp;nbsp; &amp;nbsp; package="android.support.v4" &amp;gt;

&amp;nbsp; &amp;nbsp; &amp;lt;uses-sdk android:minSdkVersion="4"/&amp;gt;

&amp;lt;/manifest&amp;gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;div&gt;&lt;/div&gt;
&lt;div&gt;You can then reference it as a dependency in your other library projects like so:&lt;/div&gt;
&lt;div&gt;
&lt;pre&gt;dependencies {
    compile project(':libProject:support')
}

&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Hopefully this will save someone else the same effort it took me! &amp;nbsp;I feel like this is a problem with the Android Gradle plugin, but for the moment this workaround is acceptable.&lt;/p&gt;</description><pubDate>Sat, 25 May 2013 16:59:04 GMT</pubDate><guid isPermaLink="true">http://www.benvonhandorf.com:80/converting-to-the-new-android-build-system---multiple-libraries-with-the-same-dependencies</guid></item><item><title>M3Conf 2012 - Speaker Report</title><link>http://www.benvonhandorf.com:80/m3conf-2012---speaker-report</link><description>&lt;h1&gt;tl;dr&lt;/h1&gt;
&lt;p&gt;If you came to my Beginning Native Android Development workshop and &lt;a href="https://bitbucket.org/benvonhandorf/m3confpresentation"&gt;you're after the code, it's here.&lt;/a&gt;&amp;nbsp; M3 was a blast for me as a speaker. &amp;nbsp;I'm certainly going to submit some sessions next year!&lt;/p&gt;
&lt;h2&gt;Aside: inValidate Me!&lt;/h2&gt;
&lt;p&gt;Were you in either of these sessions? &amp;nbsp;Or any session by any speaker at any conference? &amp;nbsp;Have suggestions for making anyone's talk better? &lt;a href="http://m3conf.com/home/session-survey"&gt;&amp;nbsp;PLEASE... don't keep it to yourself.&lt;/a&gt; &amp;nbsp;You can find me through email, twitter, fill out an evaulation, whatever you want... b&lt;a href="http://m3conf.com/home/session-survey"&gt;ut if you only filled out an evaluation and put in numbers, I'm not sure what the issue is.&lt;/a&gt; &amp;nbsp;Honestly, I'd rather read a paragraph of rant than get a 3 in one checkbox on a form.. or even getl all 5s. &amp;nbsp;Even if you don't have any suggestions or complaints... if the session was truly the best thing since sliced bread, write that down! &amp;nbsp;It takes a ton of energy and time to build up one of these workshops or sessions... if you did or didn't get value out of it, provide some feedback and improve the session.&lt;/p&gt;
&lt;h1&gt;Quick, Write this down, before I forget!&lt;/h1&gt;
&lt;p&gt;While it's still fresh in my mind, I wanted to do a few quick posts on my experience at M3Conf this year. &amp;nbsp;For the first, I'm going to prattle on about speaking for a few minutes, since that was the more unusual experience for me.&lt;/p&gt;
&lt;p&gt;I've spoken a number of times a user groups and similar gatherings and I've always enjoyed it. &amp;nbsp;Particularly recently, when I've been speaking on Android, it's fun to try and pass on some epxerience and some of your passion for an interesting platform, particularly if the crowd is at least somewhat interested in the topic. &amp;nbsp;Having the opportunity to both teach Android and represent the platform in a small way at M3Conf was a great opportunity for me.&lt;/p&gt;
&lt;h1&gt;Development Workshop&lt;/h1&gt;
&lt;p&gt;Prep for the 8 hour Beginning Native Android Development workshop took up the vast majority of my free time in October... and I still came in a little underprepared, in retrospect. &amp;nbsp;Thinking about it ahead of time, there were several major challenges I was going to face:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;People showing up without the development environment configured (JDK, Eclipse, Android SDK, ADT tooling for Eclipse)&lt;/li&gt;
&lt;li&gt;Vastly different experiences across the audience&lt;/li&gt;
&lt;li&gt;Keeping the group together as we progressed&lt;/li&gt;
&lt;li&gt;Live coding... something will always go wrong&lt;/li&gt;
&lt;li&gt;How much material will we cover?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;On the whole, people did show up with the environment set up correctly. &amp;nbsp;There were a few machines that had difficulty getting the correct versions of things installed, and for them I had prepared a "quick start" DVD... but the DVD wasn't a great option, really. &amp;nbsp;There were a fair number of steps to the installation and with OS differences, I couldn't account for every potential issue. &amp;nbsp;There were also a few people on Macbook Airs, with no DVD drive... they needed a USB memory stick. &amp;nbsp;Luckily, on the whole, it worked. &amp;nbsp;The biggest problem was with a few people who had trouble running the emulator... and we were able to get a few of them up an running on physical devices.&lt;/p&gt;
&lt;p&gt;People did show with vastly different experiences, but a lot of hands went up when I asked about Java, which certainly made my job easier. &amp;nbsp;My greatest fear for the whole day was that someone would show up without any OO programming experience, and that didn't happen. &amp;nbsp;Everyone seemed interested and eager to learn, so the few times we got into issues with language problems, it was mostly due to me moving past a point too quickly...&lt;/p&gt;
&lt;p&gt;Which leads logically to keeping the group together. &amp;nbsp;I think this was my biggest failing, even though on the whole, I think it went pretty well. &amp;nbsp;There was one segment that I rushed through far too quickly right before lunch, but the audience (correctly) called me on it and had me go back through. &amp;nbsp;After that, I think I did a better job of listening to the sound of typing and making sure people were caught up before moving on... but something I should have done was provide "Martha Stewart" pre-baked code for each step of the way. &amp;nbsp;If the DVD had contained the completed code for each iteration, people could have caught up rather than getting hung up on small, non-obvious mistakes. &amp;nbsp;I resisted this because I didn't want people moving too far ahead of the group, but it's clear in retrospect that it would have been a better choice.&lt;/p&gt;
&lt;p&gt;Live coding always manages to throw you a curve-ball... I had a slightly different Eclipse setup than the audience, so I wound up using my own DVD to get into sync with them. &amp;nbsp;A few people had strange eclipse errors that took a few minutes to resolve. &amp;nbsp;If I ever do this again, ideally I'll recruit someone to turn into my assistant (a friend actually offered and I turned him down... because I'm not very bright).&lt;/p&gt;
&lt;p&gt;In terms of code coverage, we got through about 60% of what I had prepared. &amp;nbsp;I took the last hour of the day and went into lecture mode... my goal was to help people get started by showing some of the things you only learn after doing them wrong a few different times. &amp;nbsp;I think this worked fairly well... it seemed that most people were a little more tired in the afternoon (certainly including myself). &amp;nbsp;I'll probably have a more planned lecture section for the end if I were ever to run a similar workshop.&lt;/p&gt;
&lt;p&gt;At the end of the day, I was exhausted but nobody seemed to have hated the experience. &amp;nbsp;I honestly thought I would lose some people to the afternoon sessions (some of which looked quite interesting), but I believe everyone came back and a few people showed up for the afternoon who hadn't been there for the morning. &amp;nbsp;That was one thing I didn't anticipate at all, but I don't have any real idea how I could deal with that. &amp;nbsp;The day was arranged as a single session, so the morning was really foundational. &amp;nbsp;If anyone has a great idea on what to do to help bring people into a class halfway through, I want to hear it!&lt;/p&gt;
&lt;h1&gt;M3Conf: Clash of the Titans&lt;/h1&gt;
&lt;p&gt;Someone apparently mistook me for some kind of actual expert on the platform and I was invited to sit on a panel representing the 3 big mobile platforms, along with &lt;a href="http://leongersing.tumblr.com/"&gt;Leon Gersing representing iOS&lt;/a&gt; and &lt;a href="http://jeffblankenburg.com/"&gt;Jeff Blankenburg representing the Microsoft suite&lt;/a&gt;. &amp;nbsp;If you've never seen either of these gentlemen speak, let's just say I felt a little intimidated, but Leon himself had just advocated taking risks in his excellent keynote, so I figured the worst that could happen would be making a very public fool of myself. &amp;nbsp;&lt;a href="http://samidipbasu.com/"&gt;Samidip Basu&lt;/a&gt; was moderating the panel and had set an agenda covering the present, future and pain points of our respective platforms, along with audience questions. &amp;nbsp;&lt;/p&gt;
&lt;p&gt;This whole session was a blast for me. &amp;nbsp;In reality, I think all 3 of us are just technologists who happen to have favorite platforms at the moment. &amp;nbsp;Anyone hoping for Leon to stab me with a patent knife while Jeff swung at him with razor-sharp surface was disappointed. &amp;nbsp;What resulted was a pretty reasonable overview of the mobile landscape and some opinions on what is coming next. &amp;nbsp;Hopefully the audience found it interesting and informative, too!&lt;/p&gt;
&lt;h2&gt;&lt;/h2&gt;</description><pubDate>Sat, 27 Oct 2012 14:07:49 GMT</pubDate><guid isPermaLink="true">http://www.benvonhandorf.com:80/m3conf-2012---speaker-report</guid></item><item><title>Beginning Native Android Development workshop at M3Conf - 10/25</title><link>http://www.benvonhandorf.com:80/beginning-native-android-development-workshop-at-m3conf---10-25</link><description>&lt;p&gt;&lt;img style="float: right;" src="http://m3conf.com/images/branding/m3_logo.png?sfvrsn=2" /&gt;&lt;/p&gt;
&lt;h1&gt;Come Learn Android&lt;/h1&gt;
&lt;p&gt;I'll be leading an 8 hour introduction to Android workshop &lt;a href="http://m3conf.com/"&gt;next week at M3Conf&lt;/a&gt;! &amp;nbsp;I'm really excited to help people get their feet wet with my favorite platform. &amp;nbsp;&lt;/p&gt;
&lt;h1&gt;Requirements&lt;/h1&gt;
&lt;p&gt;While I suppose it's possible that you'd show up to something like this with no programming experience, hopefully you know your way around one of the major platforms. &amp;nbsp;(.NET, Java, Objective-C, etc.) Other than that, there's quite a bit to download. &amp;nbsp;&lt;/p&gt;
&lt;h2&gt;&lt;a href="http://www.benvonhandorf.com/m3conf---beginning-native-android-development"&gt;If you think you're interested in attending, PLEASE go ahead and download the prerequisites here.&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I'm doing my best to have a nice, quick bootstrap procedure, but it will still take up valuable time&lt;/p&gt;
&lt;h1&gt;Goals&lt;/h1&gt;
&lt;p&gt;My goal for this talk is to give you the basics of Android development, but also to give you some hard-won lessons from my 2 years of work on the platform. &amp;nbsp;We'll be going over basics and UI interactions for most of the morning. &amp;nbsp;In the afternoon (assuming my tentative schedule holds), we'll be dealing with more back-end things like networking and threading. &amp;nbsp;In both areas, I'm going to do my best to show the most modern practices and explain why we're doing the things we're doing. &amp;nbsp;It will be a very code-focused day, so bring your stimulant of choice and your laptop!&lt;/p&gt;
&lt;p&gt;Unfortunately, in only 8 hours I can't cover everything (as much as I'd like). &amp;nbsp;There are a wealth of great resources available on most topics, so I'm going to concentrate on getting you started and then saving you from the mistakes I've made. &amp;nbsp;Hopefully by getting you on the right path early and taking some of the mystery out of some of the more complex topics, we can get you productive faster.&lt;/p&gt;
&lt;h2&gt;Questions?&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://twitter.com/benvonhandorf"&gt;If you have questions about what we're going to cover or want to know what to install, feel free to hit me up on Twitter.&lt;/a&gt;&amp;nbsp; Otherwise, I hope to see you at M3Conf! &amp;nbsp;It will be a blast!&lt;/p&gt;</description><pubDate>Sat, 20 Oct 2012 12:51:38 GMT</pubDate><guid isPermaLink="true">http://www.benvonhandorf.com:80/beginning-native-android-development-workshop-at-m3conf---10-25</guid></item><item><title>OT: Tankless Water Heater</title><link>http://www.benvonhandorf.com:80/ot-tankless-water-heater</link><description>&lt;p&gt;A question was asked on the Twitters about tankless water heaters. &amp;nbsp;My experience is a bit too long to put into 140 characters, so I wrote an email, but then someone asked me to put it somewhere.&lt;/p&gt;
&lt;p&gt;This qualifies as somewhere. &amp;nbsp;Please forgive the lack of formatting.&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;div style="color: #222222; font-family: arial, sans-serif; font-size: 13px; background-color: rgba(255, 255, 255, 0.917969);"&gt;We got a natural gas tankless water heater installed last year. &amp;nbsp;We've been happy with it, but there are a few things to be aware of.&lt;/div&gt;
&lt;div style="color: #222222; font-family: arial, sans-serif; font-size: 13px; background-color: rgba(255, 255, 255, 0.917969);"&gt;&lt;/div&gt;
&lt;h2 style="color: #222222; font-family: arial, sans-serif; font-size: 13px; background-color: rgba(255, 255, 255, 0.917969);"&gt;Multiple points of failure&lt;/h2&gt;
&lt;div style="color: #222222; font-family: arial, sans-serif; font-size: 13px; background-color: rgba(255, 255, 255, 0.917969);"&gt;At this point, our hot water depends on electricity, gas and water service. &amp;nbsp;Of the 3, electricity is by far the most fragile, of course. &amp;nbsp;It's still very good, but there have been a few storms that have knocked out the power... which means no hot showers. &amp;nbsp;Not horrible, but it happens often enough that I notice the difference vs. a straight gas tank heater.&lt;/div&gt;
&lt;div style="color: #222222; font-family: arial, sans-serif; font-size: 13px; background-color: rgba(255, 255, 255, 0.917969);"&gt;&lt;/div&gt;
&lt;div style="color: #222222; font-family: arial, sans-serif; font-size: 13px; background-color: rgba(255, 255, 255, 0.917969);"&gt;Which leads to:&lt;/div&gt;
&lt;h2 style="color: #222222; font-family: arial, sans-serif; font-size: 13px; background-color: rgba(255, 255, 255, 0.917969);"&gt;Complex installation &amp;amp; debugging&lt;/h2&gt;
&lt;div style="color: #222222; font-family: arial, sans-serif; font-size: 13px; background-color: rgba(255, 255, 255, 0.917969);"&gt;Our plumber managed to biff the installation a bit when they wired up the&amp;nbsp;electrical&amp;nbsp;outlet. &amp;nbsp;It wound up wired into the lighting circuit of our utility room, which led to some (hilarious&amp;nbsp;in retrospect, incredibly frustrating at the time) debugging sessions. &amp;nbsp;&lt;/div&gt;
&lt;div style="color: #222222; font-family: arial, sans-serif; font-size: 13px; background-color: rgba(255, 255, 255, 0.917969);"&gt;&lt;/div&gt;
&lt;h2 style="color: #222222; font-family: arial, sans-serif; font-size: 13px; background-color: rgba(255, 255, 255, 0.917969);"&gt;On the plus side&lt;/h2&gt;
&lt;div style="color: #222222; font-family: arial, sans-serif; font-size: 13px; background-color: rgba(255, 255, 255, 0.917969);"&gt;Infinite hot shower is infinite. &amp;nbsp;Both my wife and I can take showers at the same time with no drop in temperature (although it takes about 5 seconds to adapt when someone else turns on the shower, but it isn't very&amp;nbsp;noticeable.) &amp;nbsp;It takes maybe... 15 seconds to spin up when you first turn on the heat, but within 25 seconds it's at full temperature and it doesn't fluctuate.&lt;/div&gt;
&lt;div style="color: #222222; font-family: arial, sans-serif; font-size: 13px; background-color: rgba(255, 255, 255, 0.917969);"&gt;&lt;/div&gt;
&lt;div style="color: #222222; font-family: arial, sans-serif; font-size: 13px; background-color: rgba(255, 255, 255, 0.917969);"&gt;I don't keep enough track of energy usage to say if it's actually cheaper over the long run or not, but it isn't more expensive.&lt;/div&gt;
&lt;p&gt;&lt;/p&gt;</description><pubDate>Fri, 15 Jun 2012 19:09:56 GMT</pubDate><guid isPermaLink="true">http://www.benvonhandorf.com:80/ot-tankless-water-heater</guid></item><item><title>Android FragmentManager Lifetime and fragment memory leaks</title><link>http://www.benvonhandorf.com:80/android-fragmentmanager-lifetime-and-memory-leaks</link><description>&lt;h1&gt;tl;dr&lt;/h1&gt;
&lt;p&gt;The lifetime of the FragmentManager (at least using the support library) is not bounded by the activities using it. &amp;nbsp;So: rotating the device may cause the accumulation of long-since dead fragments in the FragmentManager. &amp;nbsp;Depending on what you're doing in your fragments, this could easily cause quite a bit of memory to get locked up.&lt;/p&gt;
&lt;h1&gt;Fruits of a wasted youth&lt;/h1&gt;
&lt;p&gt;As with so many of my blog posts, this is an attempt to archive a tiny bit of knowledge that was hard-won after a long period of debugging. &amp;nbsp;Hopefully this is helpful to someone else, but most likely it will be important to me at some point in the future, when I forget the lessons archived here.&lt;/p&gt;
&lt;h1&gt;The Problem&lt;/h1&gt;
&lt;p&gt;I'm working on an app that is basically a special image gallery. &amp;nbsp;Strangely, it uses a lot of memory for bitmaps. &amp;nbsp;Nothing to see here, move along...&lt;/p&gt;
&lt;p&gt;Except... I noticed that my memory usage was growing with each device rotation. &amp;nbsp;Now, I wasn't handling the configuration change myself, since I wanted different layouts based on the orientation. &amp;nbsp;Letting Android handle things seemed like the right option.&lt;/p&gt;
&lt;p&gt;However... I was also using fragments. &amp;nbsp;My activity is basically just a candy shell to hold one or two fragments (depending on orientation). &amp;nbsp;A little time with MAT showed me that after each rotation, the fragment that I was using on the left side of the screen (which was always present) was winding up in memory quite a few times. &amp;nbsp;(It turns out the fragment that was on the right during landscape was also getting leaked, but only at half the rate, so it wasn't as obvious... it also isn't as memory intensive.)&lt;/p&gt;
&lt;p&gt;I'll spare you the long debugging session and head scratching. &amp;nbsp;The end result is:&lt;/p&gt;
&lt;h1&gt;The Root Cause&lt;/h1&gt;
&lt;p&gt;I had the following code in my Activity's onCreate method:&lt;/p&gt;
&lt;pre class="brush: java"&gt;FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.add(R.id.dashboard_left, new FragmentSectionNavigation());
&lt;/pre&gt;
&lt;p&gt;The problem turned out to be the add instead of the replace. &amp;nbsp;The REASON that's an issue, is because the FragmentManager is holding on to all the added fragments. &amp;nbsp;Just because your Activity is dead doesn't mean the world is fresh and new... if you're using Fragments. &amp;nbsp;Switching to replace eliminated this problem easily.&lt;/p&gt;
&lt;p&gt;I want to spend more time looking into this to more fully understand the lifecycle and what I should be doing for manually added fragments, but for now, this will do.&lt;/p&gt;</description><pubDate>Sun, 22 Apr 2012 22:32:56 GMT</pubDate><guid isPermaLink="true">http://www.benvonhandorf.com:80/android-fragmentmanager-lifetime-and-memory-leaks</guid></item><item><title>Android Layout Exercises: A basic two panel layout</title><link>http://www.benvonhandorf.com:80/android-layout-exercises-a-basic-two-panel-layout</link><description>&lt;p&gt;After playing around with some Android layout files yesterday, I realized that there are probably some other people out there who struggle with the some of the finer points. &amp;nbsp;Given that I'm still a student myself, I'm not sure I'm qualified to try and teach, but there's nothing like trying to teach if you want to learn a topic, so I've decided to start a series of blog posts of indeterminate length.&lt;/p&gt;
&lt;h1&gt;What are Android layouts? A very short primer.&lt;/h1&gt;
&lt;p&gt;Google being an Internet company, when they needed a way to build their user interfaces for Android, they looked at the Web. &amp;nbsp;And given that they didn't have a single resolution or hardware form-factor in mind, they went with stretchy layouts. This should feel very familiar to anyone who has done any XAML/Silverlight/WPF/Swing.&lt;/p&gt;
&lt;p&gt;Each layout can be built up in code, but the "normal" way to do things is to build it up in an XML file. &amp;nbsp;Simply creating a new XML layout file and putting some text on it gives us a definition that looks like this:&lt;/p&gt;
&lt;pre class="brush:xml"&gt;&lt;!--?xml version="1.0" encoding="utf-8"?--&gt;
&lt;linearlayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"&gt; &lt;textview android:layout_width="match_parent" android:layout_height="match_parent" android:text="Mary had a little lamb"&gt;&lt;/textview&gt; &lt;/linearlayout&gt;
&lt;/pre&gt;
&lt;p&gt;If any of this was news to you, I highly recommend going off and doing some "Hello World" style examples. &amp;nbsp;There are any number of great Android books out there... picking one up will teach you more than I will.&lt;/p&gt;
&lt;h1&gt;So why blog about it?&lt;/h1&gt;
&lt;p&gt;So what's the point of the series? &amp;nbsp;Well, I've learned a few things the hard way over the past year and a half or so. &amp;nbsp;Maybe some of these things will be useful to others... or maybe I'll just come back to these posts myself to reference them when I can't remember the trick.&lt;/p&gt;
&lt;h1&gt;Today's Lesson: A simple two panel layout&lt;/h1&gt;
&lt;p&gt;The goal today is to produce a layout like this:&lt;/p&gt;
&lt;p&gt;&lt;img src="/Media/Default/BlogPost/blog/two_panel_goal.png" alt="Simple Vertical Two Panel Layout" align="middle" width="206" height="330" /&gt;&lt;/p&gt;
&lt;p&gt;Nothing exciting... a pretty standard vertical two-panel layout. &amp;nbsp;Even something like this can get surprisingly complex.&lt;/p&gt;
&lt;h1&gt;First Pass: A Linear Layout&lt;/h1&gt;
&lt;p&gt;The default layout in Android starts with a LinearLayout. &amp;nbsp;If you've done your research, you know that one of the things that a LinearLayout can do, in addition to dumbly stacking up items, is divide space. &amp;nbsp;Sounds like exactly what we want! &amp;nbsp;So we add an image control and a text view and we're done, right?&lt;/p&gt;
&lt;pre class="p1"&gt;&lt;span class="s1"&gt;&amp;lt;?&lt;/span&gt;&lt;span class="s2"&gt;xml&lt;/span&gt;&lt;span class="s3"&gt; &lt;/span&gt;version&lt;span class="s3"&gt;=&lt;/span&gt;&lt;span class="s4"&gt;"1.0"&lt;/span&gt;&lt;span class="s3"&gt; &lt;/span&gt;encoding&lt;span class="s3"&gt;=&lt;/span&gt;&lt;span class="s4"&gt;"utf-8"&lt;/span&gt;&lt;span class="s1"&gt;?&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre class="p2"&gt;&lt;span class="s5"&gt;&amp;lt;&lt;/span&gt;&lt;span class="s6"&gt;LinearLayout&lt;/span&gt;&lt;span class="s7"&gt; &lt;/span&gt;&lt;span class="s8"&gt;xmlns:android&lt;/span&gt;&lt;span class="s7"&gt;=&lt;/span&gt;&lt;span class="s9"&gt;"http://schemas.android.com/apk/res/android"&lt;/span&gt;&lt;/pre&gt;
&lt;pre class="p1"&gt;&lt;span class="s3"&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;android:layout_width&lt;span class="s3"&gt;=&lt;/span&gt;&lt;span class="s4"&gt;"fill_parent"&lt;/span&gt;&lt;/pre&gt;
&lt;pre class="p1"&gt;&lt;span class="s3"&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;android:layout_height&lt;span class="s3"&gt;=&lt;/span&gt;&lt;span class="s4"&gt;"fill_parent"&lt;/span&gt;&lt;/pre&gt;
&lt;pre class="p1"&gt;&lt;span class="s3"&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;android:orientation&lt;span class="s3"&gt;=&lt;/span&gt;&lt;span class="s4"&gt;"vertical"&lt;/span&gt;&lt;span class="s3"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre class="p3"&gt;&lt;/pre&gt;
&lt;pre class="p4"&gt;&lt;span class="s3"&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;&lt;span class="s5"&gt;&amp;lt;&lt;/span&gt;&lt;span class="s9"&gt;ImageView&lt;/span&gt;&lt;/pre&gt;
&lt;pre class="p1"&gt;&lt;span class="s3"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;android:layout_width&lt;span class="s3"&gt;=&lt;/span&gt;&lt;span class="s4"&gt;"match_parent"&lt;/span&gt;&lt;/pre&gt;
&lt;pre class="p1"&gt;&lt;span class="s3"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;android:layout_height&lt;span class="s3"&gt;=&lt;/span&gt;&lt;span class="s4"&gt;"match_parent"&lt;/span&gt;&lt;/pre&gt;
&lt;pre class="p1"&gt;&lt;span class="s3"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;android:scaleType&lt;span class="s3"&gt;=&lt;/span&gt;&lt;span class="s4"&gt;"fitCenter"&lt;/span&gt;&lt;/pre&gt;
&lt;pre class="p2"&gt;&lt;span class="s3"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;&lt;span class="s10"&gt;android:src&lt;/span&gt;&lt;span class="s3"&gt;=&lt;/span&gt;"@drawable/staf_grizabella"&lt;span class="s3"&gt; &lt;/span&gt;&lt;span class="s1"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre class="p3"&gt;&lt;/pre&gt;
&lt;pre class="p4"&gt;&lt;span class="s3"&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;&lt;span class="s1"&gt;&amp;lt;&lt;/span&gt;TextView&lt;/pre&gt;
&lt;pre class="p1"&gt;&lt;span class="s3"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;android:layout_width&lt;span class="s3"&gt;=&lt;/span&gt;&lt;span class="s4"&gt;"match_parent"&lt;/span&gt;&lt;/pre&gt;
&lt;pre class="p1"&gt;&lt;span class="s3"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;android:layout_height&lt;span class="s3"&gt;=&lt;/span&gt;&lt;span class="s4"&gt;"match_parent"&lt;/span&gt;&lt;/pre&gt;
&lt;pre class="p2"&gt;&lt;span class="s3"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;&lt;span class="s8"&gt;android:text&lt;/span&gt;&lt;span class="s7"&gt;=&lt;/span&gt;"@string/lorem_ipsum"&lt;span class="s3"&gt; &lt;/span&gt;&lt;span class="s1"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre class="p3"&gt;&lt;/pre&gt;
&lt;pre class="p4"&gt;&lt;span class="s1"&gt;&amp;lt;/&lt;/span&gt;LinearLayout&lt;span class="s1"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;We've set the height of our ImageView and TextView to &lt;strong&gt;match_parent&lt;/strong&gt;&amp;nbsp;which asks Android to make them the same size as the parent. &amp;nbsp;(It's a synonym for &lt;strong&gt;fill_parent&lt;/strong&gt;, pick either) &amp;nbsp;So, what does this give us?&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="/Media/Default/BlogPost/blog/two_panel_1.png" alt="" width="200" height="333" /&gt;&lt;/p&gt;
&lt;p&gt;Hmm... while full-screen &lt;a href="http://www.petfinder.com/petdetail/17522954"&gt;Grizabella (available at Save The Animals Foundation for adoption)&lt;/a&gt; is pretty, we'd like our text, too... what went wrong?&lt;/p&gt;
&lt;h2&gt;Failure is a heavy topic&lt;/h2&gt;
&lt;p&gt;Well, while we had multiple controls on the screen, we didn't clearly indicate to the LinearLayout that we wanted it to feel free to shrink them. &amp;nbsp;So the picture of Grizabella wound up full screen and the text got pushed off the bottom. &amp;nbsp;A little weight solves the issue:&lt;/p&gt;
&lt;pre class="p1"&gt;&lt;span class="s1"&gt;&amp;lt;?&lt;/span&gt;&lt;span class="s2"&gt;xml&lt;/span&gt;&lt;span class="s3"&gt; &lt;/span&gt;version&lt;span class="s3"&gt;=&lt;/span&gt;&lt;span class="s4"&gt;"1.0"&lt;/span&gt;&lt;span class="s3"&gt; &lt;/span&gt;encoding&lt;span class="s3"&gt;=&lt;/span&gt;&lt;span class="s4"&gt;"utf-8"&lt;/span&gt;&lt;span class="s1"&gt;?&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre class="p2"&gt;&lt;span class="s1"&gt;&amp;lt;&lt;/span&gt;&lt;span class="s2"&gt;LinearLayout&lt;/span&gt;&lt;span class="s3"&gt; &lt;/span&gt;&lt;span class="s5"&gt;xmlns:android&lt;/span&gt;&lt;span class="s3"&gt;=&lt;/span&gt;"http://schemas.android.com/apk/res/android"&lt;/pre&gt;
&lt;pre class="p1"&gt;&lt;span class="s3"&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;android:layout_width&lt;span class="s3"&gt;=&lt;/span&gt;&lt;span class="s4"&gt;"fill_parent"&lt;/span&gt;&lt;/pre&gt;
&lt;pre class="p1"&gt;&lt;span class="s3"&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;android:layout_height&lt;span class="s3"&gt;=&lt;/span&gt;&lt;span class="s4"&gt;"fill_parent"&lt;/span&gt;&lt;/pre&gt;
&lt;pre class="p1"&gt;&lt;span class="s3"&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;android:orientation&lt;span class="s3"&gt;=&lt;/span&gt;&lt;span class="s4"&gt;"vertical"&lt;/span&gt;&lt;span class="s3"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre class="p3"&gt;&lt;/pre&gt;
&lt;pre class="p4"&gt;&lt;span class="s3"&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;&lt;span class="s6"&gt;&amp;lt;&lt;/span&gt;&lt;span class="s7"&gt;ImageView&lt;/span&gt;&lt;/pre&gt;
&lt;pre class="p1"&gt;&lt;span class="s3"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;android:layout_width&lt;span class="s3"&gt;=&lt;/span&gt;&lt;span class="s4"&gt;"match_parent"&lt;/span&gt;&lt;/pre&gt;
&lt;pre class="p1"&gt;&lt;span class="s3"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;android:layout_height&lt;span class="s3"&gt;=&lt;/span&gt;&lt;span class="s4"&gt;"match_parent"&lt;/span&gt;&lt;/pre&gt;
&lt;pre class="p1"&gt;&lt;span class="s3"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;android:layout_weight&lt;span class="s3"&gt;=&lt;/span&gt;&lt;span class="s4"&gt;"1"&lt;/span&gt;&lt;/pre&gt;
&lt;pre class="p1"&gt;&lt;span class="s3"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;android:scaleType&lt;span class="s3"&gt;=&lt;/span&gt;&lt;span class="s4"&gt;"fitCenter"&lt;/span&gt;&lt;/pre&gt;
&lt;pre class="p2"&gt;&lt;span class="s3"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;&lt;span class="s5"&gt;android:src&lt;/span&gt;&lt;span class="s3"&gt;=&lt;/span&gt;"@drawable/staf_grizabella"&lt;span class="s3"&gt; &lt;/span&gt;&lt;span class="s1"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre class="p3"&gt;&lt;/pre&gt;
&lt;pre class="p4"&gt;&lt;span class="s3"&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;&lt;span class="s1"&gt;&amp;lt;&lt;/span&gt;TextView&lt;/pre&gt;
&lt;pre class="p1"&gt;&lt;span class="s3"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;android:layout_width&lt;span class="s3"&gt;=&lt;/span&gt;&lt;span class="s4"&gt;"match_parent"&lt;/span&gt;&lt;/pre&gt;
&lt;pre class="p1"&gt;&lt;span class="s3"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;android:layout_height&lt;span class="s3"&gt;=&lt;/span&gt;&lt;span class="s4"&gt;"match_parent"&lt;/span&gt;&lt;/pre&gt;
&lt;pre class="p1"&gt;&lt;span class="s3"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;android:layout_weight&lt;span class="s3"&gt;=&lt;/span&gt;&lt;span class="s4"&gt;"1"&lt;/span&gt;&lt;/pre&gt;
&lt;pre class="p2"&gt;&lt;span class="s3"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;&lt;span class="s5"&gt;android:text&lt;/span&gt;&lt;span class="s3"&gt;=&lt;/span&gt;"@string/lorem_ipsum"&lt;span class="s3"&gt; &lt;/span&gt;&lt;span class="s1"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre class="p3"&gt;&lt;/pre&gt;
&lt;pre class="p4"&gt;&lt;span class="s1"&gt;&amp;lt;/&lt;/span&gt;LinearLayout&lt;span class="s1"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;And now we get the text we wanted on screen.&lt;/p&gt;
&lt;p&gt;&lt;img src="/Media/Default/BlogPost/blog/two_panel_2.png" alt="" width="200" height="333" /&gt;&lt;/p&gt;
&lt;p&gt;But the text doesn't scroll...&lt;/p&gt;
&lt;p&gt;Growing your (layout) tree&lt;/p&gt;
&lt;p&gt;Since the text goes off the bottom of the screen, the user should probably be able to scroll it. &amp;nbsp;The easiest way to do that is to wrap up your text in a ScrollView. &amp;nbsp;Note that the weight and the height move from the TextView to the ScrollView, so that IT is now the thing getting laid out by the LinearLayout. &amp;nbsp;The TextView in the ScrollView now has a height of "wrap_content", so it will be as big as it needs to be... possibly larger than the screen. &amp;nbsp;Don't worry, the ScrollView handles that for us.&lt;/p&gt;
&lt;pre class="p1"&gt;&lt;span class="s1"&gt;&amp;lt;?&lt;/span&gt;&lt;span class="s2"&gt;xml&lt;/span&gt;&lt;span class="s3"&gt; &lt;/span&gt;version&lt;span class="s3"&gt;=&lt;/span&gt;&lt;span class="s4"&gt;"1.0"&lt;/span&gt;&lt;span class="s3"&gt; &lt;/span&gt;encoding&lt;span class="s3"&gt;=&lt;/span&gt;&lt;span class="s4"&gt;"utf-8"&lt;/span&gt;&lt;span class="s1"&gt;?&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre class="p2"&gt;&lt;span class="s1"&gt;&amp;lt;&lt;/span&gt;&lt;span class="s2"&gt;LinearLayout&lt;/span&gt;&lt;span class="s3"&gt; &lt;/span&gt;&lt;span class="s5"&gt;xmlns:android&lt;/span&gt;&lt;span class="s3"&gt;=&lt;/span&gt;"http://schemas.android.com/apk/res/android"&lt;/pre&gt;
&lt;pre class="p1"&gt;&lt;span class="s3"&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;android:layout_width&lt;span class="s3"&gt;=&lt;/span&gt;&lt;span class="s4"&gt;"fill_parent"&lt;/span&gt;&lt;/pre&gt;
&lt;pre class="p1"&gt;&lt;span class="s3"&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;android:layout_height&lt;span class="s3"&gt;=&lt;/span&gt;&lt;span class="s4"&gt;"fill_parent"&lt;/span&gt;&lt;/pre&gt;
&lt;pre class="p1"&gt;&lt;span class="s3"&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;android:orientation&lt;span class="s3"&gt;=&lt;/span&gt;&lt;span class="s4"&gt;"vertical"&lt;/span&gt;&lt;span class="s3"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre class="p3"&gt;&lt;/pre&gt;
&lt;pre class="p4"&gt;&lt;span class="s3"&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;&lt;span class="s6"&gt;&amp;lt;&lt;/span&gt;&lt;span class="s7"&gt;ImageView&lt;/span&gt;&lt;/pre&gt;
&lt;pre class="p1"&gt;&lt;span class="s8"&gt;&amp;nbsp;&lt;/span&gt;&lt;span class="s3"&gt; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;android:layout_width&lt;span class="s3"&gt;=&lt;/span&gt;&lt;span class="s4"&gt;"match_parent"&lt;/span&gt;&lt;/pre&gt;
&lt;pre class="p1"&gt;&lt;span class="s3"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;android:layout_height&lt;span class="s3"&gt;=&lt;/span&gt;&lt;span class="s4"&gt;"match_parent"&lt;/span&gt;&lt;/pre&gt;
&lt;pre class="p1"&gt;&lt;span class="s3"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;android:layout_weight&lt;span class="s3"&gt;=&lt;/span&gt;&lt;span class="s4"&gt;"1"&lt;/span&gt;&lt;/pre&gt;
&lt;pre class="p1"&gt;&lt;span class="s3"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;android:scaleType&lt;span class="s3"&gt;=&lt;/span&gt;&lt;span class="s4"&gt;"fitCenter"&lt;/span&gt;&lt;/pre&gt;
&lt;pre class="p2"&gt;&lt;span class="s3"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;&lt;span class="s5"&gt;android:src&lt;/span&gt;&lt;span class="s3"&gt;=&lt;/span&gt;"@drawable/staf_grizabella"&lt;span class="s3"&gt; &lt;/span&gt;&lt;span class="s1"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre class="p3"&gt;&lt;/pre&gt;
&lt;pre class="p4"&gt;&lt;span class="s3"&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;&lt;span class="s1"&gt;&amp;lt;&lt;/span&gt;ScrollView&lt;/pre&gt;
&lt;pre class="p1"&gt;&lt;span class="s3"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;android:layout_width&lt;span class="s3"&gt;=&lt;/span&gt;&lt;span class="s4"&gt;"match_parent"&lt;/span&gt;&lt;/pre&gt;
&lt;pre class="p1"&gt;&lt;span class="s3"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;android:layout_height&lt;span class="s3"&gt;=&lt;/span&gt;&lt;span class="s4"&gt;"match_parent"&lt;/span&gt;&lt;/pre&gt;
&lt;pre class="p1"&gt;&lt;span class="s3"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;android:layout_weight&lt;span class="s3"&gt;=&lt;/span&gt;&lt;span class="s4"&gt;"1"&lt;/span&gt;&lt;span class="s3"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre class="p3"&gt;&lt;/pre&gt;
&lt;pre class="p5"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class="s1"&gt;&amp;lt;&lt;/span&gt;&lt;span class="s2"&gt;TextView&lt;/span&gt;&lt;/pre&gt;
&lt;pre class="p1"&gt;&lt;span class="s3"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;android:layout_width&lt;span class="s3"&gt;=&lt;/span&gt;&lt;span class="s4"&gt;"match_parent"&lt;/span&gt;&lt;/pre&gt;
&lt;pre class="p1"&gt;&lt;span class="s3"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;android:layout_height&lt;span class="s3"&gt;=&lt;/span&gt;&lt;span class="s4"&gt;"wrap_content"&lt;/span&gt;&lt;/pre&gt;
&lt;pre class="p2"&gt;&lt;span class="s3"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;&lt;span class="s5"&gt;android:text&lt;/span&gt;&lt;span class="s3"&gt;=&lt;/span&gt;"@string/lorem_ipsum"&lt;span class="s3"&gt; &lt;/span&gt;&lt;span class="s1"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre class="p4"&gt;&lt;span class="s3"&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;&lt;span class="s1"&gt;&amp;lt;/&lt;/span&gt;ScrollView&lt;span class="s1"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre class="p3"&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;span class="s1"&gt;&amp;lt;/&lt;/span&gt;LinearLayout&lt;span class="s1"&gt;&amp;gt;&lt;/span&gt;&amp;nbsp;&lt;/pre&gt;
&lt;p&gt;And now we get some magical scrolling:&lt;/p&gt;
&lt;p&gt;&lt;img src="/Media/Default/BlogPost/blog/two_panel_3.png" alt="" width="200" height="333" /&gt;&lt;/p&gt;
&lt;p&gt;Perfect!&lt;/p&gt;
&lt;h1&gt;Another Approach: RelativeLayout&lt;/h1&gt;
&lt;p&gt;So that's the best way? &amp;nbsp;Well, like everything in Android (and the rest of the grown-up world): It Depends. &amp;nbsp;&lt;/p&gt;
&lt;p&gt;Just to prove it, let's re-do the screen with a RelativeLayout to show another approach:&lt;/p&gt;
&lt;pre class="p1"&gt;&lt;span class="s1"&gt;&amp;lt;?&lt;/span&gt;&lt;span class="s2"&gt;xml&lt;/span&gt;&lt;span class="s3"&gt; &lt;/span&gt;version&lt;span class="s3"&gt;=&lt;/span&gt;&lt;span class="s4"&gt;"1.0"&lt;/span&gt;&lt;span class="s3"&gt; &lt;/span&gt;encoding&lt;span class="s3"&gt;=&lt;/span&gt;&lt;span class="s4"&gt;"utf-8"&lt;/span&gt;&lt;span class="s1"&gt;?&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre class="p2"&gt;&lt;span class="s1"&gt;&amp;lt;&lt;/span&gt;&lt;span class="s2"&gt;RelativeLayout&lt;/span&gt;&lt;span class="s3"&gt; &lt;/span&gt;&lt;span class="s5"&gt;xmlns:android&lt;/span&gt;&lt;span class="s3"&gt;=&lt;/span&gt;"http://schemas.android.com/apk/res/android"&lt;/pre&gt;
&lt;pre class="p1"&gt;&lt;span class="s3"&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;android:layout_width&lt;span class="s3"&gt;=&lt;/span&gt;&lt;span class="s4"&gt;"fill_parent"&lt;/span&gt;&lt;/pre&gt;
&lt;pre class="p1"&gt;&lt;span class="s3"&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;android:layout_height&lt;span class="s3"&gt;=&lt;/span&gt;&lt;span class="s4"&gt;"fill_parent"&lt;/span&gt;&lt;/pre&gt;
&lt;pre class="p1"&gt;&lt;span class="s3"&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;android:orientation&lt;span class="s3"&gt;=&lt;/span&gt;&lt;span class="s4"&gt;"vertical"&lt;/span&gt;&lt;span class="s3"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre class="p3"&gt;&lt;/pre&gt;
&lt;pre class="p4"&gt;&lt;span class="s3"&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;&lt;span class="s6"&gt;&amp;lt;&lt;/span&gt;&lt;span class="s7"&gt;ImageView&lt;/span&gt;&lt;/pre&gt;
&lt;pre class="p2"&gt;&lt;span class="s3"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;&lt;span class="s5"&gt;android:id&lt;/span&gt;&lt;span class="s3"&gt;=&lt;/span&gt;"@+id/image"&lt;/pre&gt;
&lt;pre class="p1"&gt;&lt;span class="s3"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;android:layout_width&lt;span class="s3"&gt;=&lt;/span&gt;&lt;span class="s4"&gt;"match_parent"&lt;/span&gt;&lt;/pre&gt;
&lt;pre class="p1"&gt;&lt;span class="s3"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;android:layout_height&lt;span class="s3"&gt;=&lt;/span&gt;&lt;span class="s4"&gt;"200dp"&lt;/span&gt;&lt;/pre&gt;
&lt;pre class="p1"&gt;&lt;span class="s3"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;android:layout_alignParentTop&lt;span class="s3"&gt;=&lt;/span&gt;&lt;span class="s4"&gt;"true"&lt;/span&gt;&lt;/pre&gt;
&lt;pre class="p1"&gt;&lt;span class="s3"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;android:scaleType&lt;span class="s3"&gt;=&lt;/span&gt;&lt;span class="s4"&gt;"fitCenter"&lt;/span&gt;&lt;/pre&gt;
&lt;pre class="p2"&gt;&lt;span class="s3"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;&lt;span class="s5"&gt;android:src&lt;/span&gt;&lt;span class="s3"&gt;=&lt;/span&gt;"@drawable/staf_grizabella"&lt;span class="s3"&gt; &lt;/span&gt;&lt;span class="s1"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre class="p3"&gt;&lt;/pre&gt;
&lt;pre class="p4"&gt;&lt;span class="s3"&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;&lt;span class="s1"&gt;&amp;lt;&lt;/span&gt;ScrollView&lt;/pre&gt;
&lt;pre class="p2"&gt;&lt;span class="s3"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;&lt;span class="s5"&gt;android:id&lt;/span&gt;&lt;span class="s3"&gt;=&lt;/span&gt;"@+id/scroll_section"&lt;/pre&gt;
&lt;pre class="p1"&gt;&lt;span class="s3"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;android:layout_below&lt;span class="s3"&gt;=&lt;/span&gt;&lt;span class="s4"&gt;"@id/image"&lt;/span&gt;&lt;/pre&gt;
&lt;pre class="p1"&gt;&lt;span class="s3"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;android:layout_width&lt;span class="s3"&gt;=&lt;/span&gt;&lt;span class="s4"&gt;"match_parent"&lt;/span&gt;&lt;/pre&gt;
&lt;pre class="p1"&gt;&lt;span class="s3"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;android:layout_height&lt;span class="s3"&gt;=&lt;/span&gt;&lt;span class="s4"&gt;"match_parent"&lt;/span&gt;&lt;span class="s1"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre class="p3"&gt;&lt;/pre&gt;
&lt;pre class="p5"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class="s1"&gt;&amp;lt;&lt;/span&gt;&lt;span class="s2"&gt;TextView&lt;/span&gt;&lt;/pre&gt;
&lt;pre class="p1"&gt;&lt;span class="s3"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;android:layout_width&lt;span class="s3"&gt;=&lt;/span&gt;&lt;span class="s4"&gt;"match_parent"&lt;/span&gt;&lt;/pre&gt;
&lt;pre class="p1"&gt;&lt;span class="s3"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;android:layout_height&lt;span class="s3"&gt;=&lt;/span&gt;&lt;span class="s4"&gt;"wrap_content"&lt;/span&gt;&lt;/pre&gt;
&lt;pre class="p2"&gt;&lt;span class="s3"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;&lt;span class="s5"&gt;android:text&lt;/span&gt;&lt;span class="s3"&gt;=&lt;/span&gt;"@string/lorem_ipsum"&lt;span class="s3"&gt; &lt;/span&gt;&lt;span class="s1"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre class="p4"&gt;&lt;span class="s3"&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;&lt;span class="s1"&gt;&amp;lt;/&lt;/span&gt;ScrollView&lt;span class="s1"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre class="p3"&gt;&lt;/pre&gt;
&lt;pre class="p4"&gt;&lt;span class="s1"&gt;&amp;lt;/&lt;/span&gt;RelativeLayout&lt;span class="s1"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;What are the differences? Well, a RelativeLayout is generally more flexible than a LinearLayout. &amp;nbsp;If we wanted to put a 3rd control to the right of these two, that's far easier with a single RelativeLayout than with a LinearLayout (where you wind up nesting them quickly). &amp;nbsp;BUT, the RelativeLayout isn't able to divide up space the way the LinearLayout can. &amp;nbsp;Thus, the hardcoded height of 200dp on the ImageView.&lt;/p&gt;
&lt;p&gt;&lt;img src="/Media/Default/BlogPost/blog/two_panel_relative.png" alt="" width="200" height="333" /&gt;&lt;/p&gt;
&lt;p&gt;Still, the result is effectively the same. &amp;nbsp;Next time, we'll talk about some things that differentiate these more when you get into different things you might want to do on a screen.&lt;/p&gt;</description><pubDate>Mon, 26 Mar 2012 16:45:20 GMT</pubDate><guid isPermaLink="true">http://www.benvonhandorf.com:80/android-layout-exercises-a-basic-two-panel-layout</guid></item><item><title>Raising the level of discourse</title><link>http://www.benvonhandorf.com:80/raising-the-level-of-discourse</link><description>&lt;h1&gt;Disclaimer:&lt;/h1&gt;
&lt;p&gt;I'm as guilty as anyone else of the behavior I'm about to rant about. &amp;nbsp;I'm making an effort to do better... and I'm challenging you to do the same.&lt;/p&gt;
&lt;h1&gt;Or: The one where a grumpy old guy rants about twitter&lt;/h1&gt;
&lt;p&gt;I've been inconsistent with my twitter usage recently and I wasn't really sure why. &amp;nbsp;It just doesn't seem to be providing me with much that I need right now. &amp;nbsp;Yesterday, I saw a series of tweets and I think I finally figured out what my problem with twitter is... or more specifically, what my problem with the way people are using the medium is.&lt;/p&gt;
&lt;p&gt;A small, curated selection of my Feed from Friday (twitter names removed, but easy enough to find):&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;While Satan is really evil,&amp;nbsp; http://Spring.net is a close second.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;if you want to improve the web, think about declarative semantics, and not about defining the 42nd browser API.&lt;/li&gt;
&lt;li&gt;AT&amp;amp;T: Rethink possible. Like phone calls. Used to be possible. Now impossible.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;em&gt;Aside: Interestingly, I don't follow any of these people, everything was retweeted into my feed by people I do follow.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;What I see in common about all of these is a few things...&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;They're all funny.&lt;/li&gt;
&lt;li&gt;They're all negative.&lt;/li&gt;
&lt;li&gt;They all tell you what not to do, but don't provide any guidance on why or what alternatives to consider.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Like many of us, I've cultivated a twitter list full of extremely smart people (many of whom I've never met) along with colleagues and friends. &amp;nbsp;Many of these extremely smart people are very practiced in their craft and therefore have very strong opinions. &amp;nbsp;So what's the problem?&lt;/p&gt;
&lt;h1&gt;Twitter is not a forum for discourse&lt;/h1&gt;
&lt;p&gt;The problem is that nobody can express ANYTHING worth expressing in 140 characters. &amp;nbsp;Go ahead, try it. &amp;nbsp;Not "I like sandwiches". &amp;nbsp;Explain your political position, like you would to a coworker. &amp;nbsp;Explain your day like you would to your significant other. &amp;nbsp;It doesn't work.&lt;/p&gt;
&lt;p&gt;To put it another way, if you heard in your stand up meeting that someone on your team was going to use Spring.NET, would you walk up to their desk, say "Spring.NET is evil" and walk away? &amp;nbsp;If so, I hope I never have the displeasure of working with you.&lt;/p&gt;
&lt;h1&gt;Context is Key&lt;/h1&gt;
&lt;p&gt;Why doesn't 140 characters work? &amp;nbsp;There are plenty of reasons, but one of them is Context. &amp;nbsp;To continue picking on the Spring.NET tweet, WHY is Spring.NET evil FOR YOU? &amp;nbsp;It's an extremely successful project, so clearly it brings plenty of people value... why is this not born out by your experience? &amp;nbsp;Just reading the tweet, I could think of half a dozen reasons you MIGHT not like it. &amp;nbsp;To pick a few:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;XML configuration vs. Code configuration... maybe you have a horse in this race and XML isn't your favorite?&lt;/li&gt;
&lt;li&gt;Architecture... maybe Spring.NET doesn't handle some aspect of your architecture&lt;/li&gt;
&lt;li&gt;Maybe you're trying to fix a production bug and whoever put together your Spring setup didn't know the platform well? &amp;nbsp;We've all been there, and it's certainly grounds for grousing.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The point being... "Spring.NET is evil" is useless... except as an insult to people using it. &amp;nbsp;Anyone who was about to recommend Spring.NET to their boss as part of an architecture is now going to quetion their decision... without any context as to why you think what you do.&lt;/p&gt;
&lt;h1&gt;A Stream of Insults&lt;/h1&gt;
&lt;p&gt;It feels like much of my twitter feed has become a stream of insults. &amp;nbsp;Javascript sucks, Java sucks, iOS sucks, Android sucks, Windows 8 sucks... blah blah blah. &amp;nbsp;Insults do shockingly well in 140 characters. &amp;nbsp;Information, on the other hand, is practically strangled in the same space.&lt;/p&gt;
&lt;p&gt;I don't mean to imply that this is all that my stream is full of, but there is a lot of it. &amp;nbsp;Enough that it drowns out a lot of the things I actually care about. &amp;nbsp;Enough that I only check twitter maybe once a day now... where i used to use it constantly.&lt;/p&gt;
&lt;h1&gt;So? &amp;nbsp;Keep your PC thought control off my Twitter!&lt;/h1&gt;
&lt;p&gt;So what? &amp;nbsp;Why does this matter? &amp;nbsp;Twitter is basically grousing about work and sandwich pictures anyway, right? &amp;nbsp;Why go tilting at this windmill?&lt;/p&gt;
&lt;p&gt;Because I have a lot to learn, and there are a lot of teachers out there. &amp;nbsp;I'd LOVE to have a 45 minute long conversation with Mr. Spring.NET sucks and Mr. Declarative Syntax. &amp;nbsp;They both clearly know some things I don't, or have opinions I'm curious about (even if I disagree). &amp;nbsp;I have no medium for doing that. &amp;nbsp;They haven't linked to a blog post explaining their position... and if you've ever tried to have a back and forth on Twitter with someone... I can't think of many things that do more to raise my blood pressure.&lt;/p&gt;
&lt;p&gt;I'm not saying don't grouse about work... that's a right we all have. &amp;nbsp;But if you're going to run down a technology, maybe write a blog post and link to it? &amp;nbsp;An informed article might teach... the hundreds of hours of effort pursing a bad technology or preventing bad use of a good technology that you save may be your own, if someone at a future employer happens to read it.&lt;/p&gt;
&lt;p&gt;And maybe you'll teach me something along the way.&lt;/p&gt;</description><pubDate>Sun, 18 Mar 2012 00:57:15 GMT</pubDate><guid isPermaLink="true">http://www.benvonhandorf.com:80/raising-the-level-of-discourse</guid></item><item><title>Things I learned from Users - Conftron at Codemash</title><link>http://www.benvonhandorf.com:80/things-i-learned-from-users---conftron-at-codemash</link><description>&lt;p&gt;&lt;a href="http://codemash.org/"&gt;Codemash&lt;/a&gt; is always a great experience and this year was no exception. &amp;nbsp;This year was a little different for me, though... I had a somewhat popular conference scheduling app for the conference. &amp;nbsp;At the peak, I had over 16k screen views on Thursday, 1/12. &amp;nbsp;This was nice and gratifying and everything, but the best part was the change to directly interact with people using something I had written.&lt;/p&gt;
&lt;h2&gt;What lives in a cave...&lt;/h2&gt;
&lt;p&gt;While for a lot of developers, directly interacting with users is part of daily life, it's a bit unusual for me. &amp;nbsp;For years, I've been doing Line of Business applications where user time was very precious and hard to come by. &amp;nbsp;After my most recent job switch I've been working on consumer facing sites and apps in the financial services industry... again, direct user interaction is rare. &amp;nbsp;We have business people who advocate for the user, but anyone can tell you that what the business thinks the user needs and what they ACTUALLY need can be very different.&lt;/p&gt;
&lt;p&gt;The chance to walk down the hall and see people using your app was a great experience. &amp;nbsp;Being able to see how it worked well and where it fell down allowed me to, several times, find a quiet corner, bring up Eclipse and bang out a quick new release. &amp;nbsp;I even tweeted from the app's account that I was in a specific room after lunch and had several people walk in to make suggestions or have discussions. &amp;nbsp;It was very engaging and fruitful!&lt;/p&gt;
&lt;p&gt;I wanted to take a few minutes and type up things that are obvious and in every User Experience guide out there, but are sometimes only clear once you experience them directly.&lt;/p&gt;
&lt;h2&gt;Minimize Navigation&lt;/h2&gt;
&lt;p&gt;One thing Conftron had designed in from the beginning was trying to start you at a reasonable place when you start the app. &amp;nbsp;It does somewhat different things depending on if you are before, during or after the conference. &amp;nbsp;That part seemed to work well... but there's always room for improvement. &amp;nbsp;One thing I saw several people doing was drilling in from the session list screen to the detail screen to see what room a session was in.&lt;/p&gt;
&lt;p&gt;It was only the work of a few minutes to add the room name to the listing screen. &amp;nbsp;It cost me a little vertical space, but improved the usefulness massively.&lt;/p&gt;
&lt;p&gt;&lt;img src="/Media/Default/BlogPost/blog/things-i-learned-from-users---conftron-at-codemash/conftron_session_listing_with_location.png" alt="Highlights showing the session location" width="480" height="800" /&gt;&lt;/p&gt;
&lt;p&gt;Highlights show the added information&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;p&gt;A simple change... and obvious once you see the app in use. &amp;nbsp;&lt;/p&gt;</description><pubDate>Mon, 13 Feb 2012 17:04:16 GMT</pubDate><guid isPermaLink="true">http://www.benvonhandorf.com:80/things-i-learned-from-users---conftron-at-codemash</guid></item><item><title>Rooting your Barnes and Noble Nook Color–Part One–The SD Card is your Friend</title><link>http://www.benvonhandorf.com:80/Rooting-your-Barnes-and-Noble-Nook-Colore28093Part-Onee28093The-SD-Card-is-your-Friend</link><description>&lt;h1&gt;What&amp;rsquo;s the Goal?&lt;/h1&gt;
&lt;p&gt;Our goal for this post is to get an alternative OS booted up on your beautiful Nook Color without damaging anything.&amp;nbsp; I&amp;rsquo;m going to select one of the better-known and more mature ROMs available to make our lives simpler, but if you want to experiment, there are a lot of options available.&lt;/p&gt;
&lt;h1&gt;Before we start&lt;/h1&gt;
&lt;p&gt;On the off chance that you haven&amp;rsquo;t even booted your Nook Color (NC) with the default OS yet, do so now.&amp;nbsp; You need to go ahead and let it go through device registration, creating a BN.com account, etc.&amp;nbsp; Not doing this MIGHT not cause any issues&amp;hellip; or it might brick your device.&amp;nbsp; I recommend finishing the normal path and playing around with the NC for a bit.&amp;nbsp; It&amp;rsquo;s a really nice device straight out of the box.&amp;nbsp; Maybe you&amp;rsquo;ll like it enough like that.&lt;/p&gt;
&lt;h1&gt;Stuff you&amp;rsquo;ll need&lt;/h1&gt;
&lt;p&gt;If you&amp;rsquo;re going to go forward, you&amp;rsquo;ll need:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Your NC, fully charged and preferably plugged into the wall though the charger.&amp;nbsp; It would really suck to lose your device during the boot for not having it charged.&amp;nbsp; (This isn&amp;rsquo;t much of a risk with this method, but with the other methods this could turn it into a very poor boat anchor)&lt;/li&gt;
&lt;li&gt;A micro SD card of at least 2 gigs that will be totally erased.&amp;nbsp; This will be where we put the new OS we&amp;rsquo;re going to create.&amp;nbsp; You will lose everything on this card. &lt;br /&gt;Note that speed counts here.&amp;nbsp; There is a definite difference between say a class 6 and a class 10 card.&amp;nbsp; If you&amp;rsquo;re planning to run like this for a while, do a little research and pick out a good one.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;A computer where you can write your micro SD card.&amp;nbsp; I think every computer, netbook and toaster for the past 8 years or so has shipped with an SD card slot, but I figured the need to call it out.&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;My Kingdom for a ROM&lt;/h1&gt;
&lt;p&gt;First, we need an actual OS to put on the card.&amp;nbsp; I recommend &lt;a href="http://www.cyanogenmod.com/"&gt;CyanogenMod 7&lt;/a&gt; for this foray.&amp;nbsp; It&amp;rsquo;s very mature and ported to a lot of devices.&amp;nbsp; It actually feels a lot more mature than some smart phone OSes I&amp;rsquo;ve paid a lot of money for in the past.&lt;/p&gt;
&lt;h2&gt;Credit where Credit is Due&lt;/h2&gt;
&lt;p&gt;The method I&amp;rsquo;m describing here was most recently improved by the XDA Forums user &amp;ldquo;verygreen&amp;rdquo; &lt;a href="http://forum.xda-developers.com/showthread.php?t=1000957"&gt;in this thread&lt;/a&gt;.&amp;nbsp; His instructions are probably superior to mine, but I&amp;rsquo;m trying to give friends a single set of instructions rather than sending them all around various forums.&lt;/p&gt;
&lt;h2&gt;To the Internet!&lt;/h2&gt;
&lt;p&gt;Time to start downloading the software bits we&amp;rsquo;re going to need.&lt;/p&gt;
&lt;p&gt;Go to the &lt;a href="http://www.cyanogenmod.com/devices/nook-color"&gt;CyanogenMod page for the Nook Color&lt;/a&gt; and download the latest Stable Rom.&amp;nbsp; To get full access to the Market and other Google applications, you should also &lt;a href="http://wiki.cyanogenmod.com/index.php?title=Latest_Version"&gt;go to the table at the bottom of this page&lt;/a&gt; and download the most recent version of Google Apps for the version of CyanogenMod that you are installing (7).&amp;nbsp; Set these files to one side.&lt;/p&gt;
&lt;p&gt;Now we need &amp;ldquo;verygreen&amp;rdquo;&amp;rsquo;s SD card installer.&amp;nbsp; At the time of writing, &lt;a href="http://api.viglink.com/api/click?format=go&amp;amp;drKey=1359&amp;amp;loc=http%3A%2F%2Fforum.xda-developers.com%2Fshowthread.php%3Ft%3D1000957&amp;amp;v=1&amp;amp;libid=1305321147447&amp;amp;out=http%3A%2F%2Fnook.handhelds.ru%2Fsdimage%2Fgeneric-sdcard-v1.1.img.gz&amp;amp;ref=http%3A%2F%2Fnookdevs.com%2FPortal%3ANookColor&amp;amp;title=%5BROM%5D%5BCM7%5D%20Size-agnostic%20SD%20Card%20image%20and%20CM7%20installer%20for%20SD%20Cards.%20with%20updater%20-%20xda-developers&amp;amp;txt=http%3A%2F%2Fnook.handhelds.ru%2Fsdimage%2Fgen...rd-v1.1.img.gz"&gt;this is a link to the appropriate file&lt;/a&gt;, but that may change.&amp;nbsp; I will attempt to keep this blog post up to date, but the thread linked above will almost certainly be more correct.&amp;nbsp; Note that this is a .gz file.&amp;nbsp; If you&amp;rsquo;re running windows, go forth and &lt;a href="http://7-zip.org/"&gt;download the wondrous 7-Zip&lt;/a&gt; and use it to extract the .img file.&amp;nbsp; If you&amp;rsquo;re running Linux, you already know what a .gz file is.&amp;nbsp; If you&amp;rsquo;re on a Mac, just click on it.&amp;nbsp; I&amp;rsquo;m sure the Mac knows to do the right thing.&lt;/p&gt;
&lt;p&gt;&lt;img src="/Media/Default/BlogPost/blog/Rooting-your-Barnes-and-Noble-Nook-Colore28093Part-Onee28093The-SD-Card-is-your-Friend/image.png" alt="Selecting ROM" width="894" height="145" /&gt;&lt;/p&gt;
&lt;p&gt;If you&amp;rsquo;re running Windows, you will also need a utility to burn the SD Card since Microsoft doesn&amp;rsquo;t trust us to just stream bytes to devices.&amp;nbsp; The one that seems to be most recommended is &lt;a href="https://launchpad.net/win32-image-writer/+download"&gt;Win32DiskImager&lt;/a&gt;.&amp;nbsp; I find the interface for this little bit of kit very confusing, but it seems to work well for most people.&amp;nbsp; If not, there are other tools available.&lt;/p&gt;
&lt;h1&gt;Oooh, BURN&lt;/h1&gt;
&lt;h3&gt;Windows&lt;/h3&gt;
&lt;p&gt;Now, we want to burn the SD card installer from verygreen onto the card.&amp;nbsp; If you&amp;rsquo;re using Win32DiskImager, the interface should look something like this:&lt;/p&gt;
&lt;p&gt;&lt;img src="/Media/Default/BlogPost/blog/Rooting-your-Barnes-and-Noble-Nook-Colore28093Part-Onee28093The-SD-Card-is-your-Friend/image_1.png" alt="Burning SD Card" width="342" height="175" /&gt;&lt;/p&gt;
&lt;p&gt;Double and triple check the device dropdown before clicking &amp;ldquo;Write&amp;rdquo;.&amp;nbsp; If you pick the wrong one, you&amp;rsquo;ll blow away something other than your SD card.&amp;nbsp; Not what you want.&lt;/p&gt;
&lt;p&gt;After the write is complete, eject the SD card from your computer and re-insert it.&amp;nbsp; You should now have a partition called &amp;ldquo;BOOT&amp;rdquo; show up in your windows explorer for your SD card.&amp;nbsp; Copy the two files we downloaded earlier, the CyanogenMod 7 file and the Google Apps image, onto this partition.&lt;/p&gt;
&lt;h1&gt;Patience, Grasshopper&lt;/h1&gt;
&lt;p&gt;Now comes the exciting part.&amp;nbsp; Eject your SD card from your machine and, if necessary, extract the Micro SD card from the adapter.&amp;nbsp; Insert it into the Nook Color&amp;rsquo;s Micro SD card slot (it&amp;rsquo;s down in the little lanyard notch, accessible from the back).&amp;nbsp; Now, turn off your Nook Color by holding down the power button (you&amp;rsquo;ll be prompted).&amp;nbsp; After it&amp;rsquo;s off and with the card in place, turn it back on.&lt;/p&gt;
&lt;p&gt;This boot will take a little while&amp;hellip; it&amp;rsquo;s actually extracting the disk images you provided and building a full Android system.&amp;nbsp; It took approximately 20 minutes for me.&amp;nbsp; I recommend leaving your Nook on mains power while this runs.&lt;/p&gt;
&lt;p&gt;At the end of the process, your Nook should reboot.&amp;nbsp; If everything has gone to plan, you will now be booted into CyanogenMod&lt;/p&gt;</description><pubDate>Mon, 13 Feb 2012 16:23:55 GMT</pubDate><guid isPermaLink="true">http://www.benvonhandorf.com:80/Rooting-your-Barnes-and-Noble-Nook-Colore28093Part-Onee28093The-SD-Card-is-your-Friend</guid></item><item><title>Android UI Helper Eclipse Plugin</title><link>http://www.benvonhandorf.com:80/Android-UI-Helper-Eclipse-Plugin</link><description>&lt;h1&gt;What is this?&lt;/h1&gt;
&lt;p&gt;The single most common task I&amp;rsquo;ve run into as an Android developer is creating and wiring up fields.&amp;nbsp; Every time you create a new activity, you change your layout.&amp;nbsp; Every time you change your layout&amp;hellip; define the new fields, use findViewById to wire them up to private properties in your activity so that you can actually do something.&amp;nbsp; It&amp;rsquo;s not hard, but it is lots of typing and it&amp;rsquo;s CEREMONY&amp;hellip; it&amp;rsquo;s something you can only really get wrong.&lt;/p&gt;
&lt;h1&gt;So what did you do about it?&lt;/h1&gt;
&lt;p&gt;As part of preparing for the Devlink Mobile Smackdown presentation, I decided to try to optimize this workflow a bit.&amp;nbsp; I wrote an Eclipse plugin that would look at your activitiy&amp;rsquo;s onCreate and parse any layout files loaded (with setContentView) and create and wire up the private fields.&amp;nbsp; (I wound up not using it for the Smackdown, but I am using it daily for real work).&lt;/p&gt;
&lt;h1&gt;What is the workflow?&lt;/h1&gt;
&lt;p&gt;I&amp;rsquo;ve created a new Android project, which gets the basic &amp;ldquo;Hello World&amp;rdquo; functionality of an almost blank layout.&amp;nbsp; I went ahead and gave an id to the TextView and added a button.&lt;/p&gt;
&lt;p&gt;&lt;img src="/Media/Default/BlogPost/blog/Android-UI-Helper-Eclipse-Plugin/image_2.png" alt="Activity Code" width="965" height="471" /&gt;&lt;/p&gt;
&lt;p&gt;Now, simply go to your activity in the project and right click.&amp;nbsp; Look for the Android UI Util sub menu and select &amp;ldquo;Build Private Member Variables from XML&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;&lt;img src="/Media/Default/BlogPost/blog/Android-UI-Helper-Eclipse-Plugin/image_3.png" alt="Menu" width="882" height="768" /&gt;&lt;/p&gt;
&lt;p&gt;That will add the private variables, but not the imports, so this screenshot shows errors:&lt;/p&gt;
&lt;p&gt;&lt;img src="/Media/Default/BlogPost/blog/Android-UI-Helper-Eclipse-Plugin/image_4.png" alt="Updated Activity Code" width="636" height="405" /&gt;&lt;/p&gt;
&lt;p&gt;After this, it&amp;rsquo;s a simple matter of having Eclipse update the imports (CTRL-SHIFT-O in the default key bindings).&amp;nbsp; Now just call findChildren during your onCreate(&amp;hellip;).&lt;/p&gt;
&lt;h2&gt;But what about when you change your layout again?&lt;/h2&gt;
&lt;p&gt;No worries.&amp;nbsp; Just run the plugin again.&amp;nbsp; It won&amp;rsquo;t destroy any items you&amp;rsquo;ve already added.&lt;/p&gt;
&lt;h1&gt;How do I get this?&lt;/h1&gt;
&lt;p&gt;It should be pretty simple, although I&amp;rsquo;ll admit I&amp;rsquo;ve only tested this on a few machines.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Go to the BitBucket repository and &lt;a href="https://bitbucket.org/bvonhandorf/androidhelperplugin/downloads/com.benvonhandorf.plugin.androiduiutil_1.0.0.201108021832.jar"&gt;download the latest version of the plugin here&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Drop it into your eclipse plugin directory.&amp;nbsp; This is usually &amp;lt;ECLIPSE_ROOT&amp;gt;/plugins.&lt;/li&gt;
&lt;li&gt;Restart Eclipse&lt;/li&gt;
&lt;/ol&gt;
&lt;h1&gt;This Sucks!&lt;/h1&gt;
&lt;p&gt;Don&amp;rsquo;t like it?&amp;nbsp; File a bug on the BitBucket project.&amp;nbsp; Make it better yourself by pulling down the source!&amp;nbsp; This was a dead simple attempt that I made to make my own life better.&amp;nbsp; Hopefully it makes yours better, too!&lt;/p&gt;</description><pubDate>Mon, 13 Feb 2012 16:21:21 GMT</pubDate><guid isPermaLink="true">http://www.benvonhandorf.com:80/Android-UI-Helper-Eclipse-Plugin</guid></item><item><title>Devlink Mobile Smackdown–Code and Retrospective</title><link>http://www.benvonhandorf.com:80/Devlink-Mobile-Smackdowne28093Code-and-Retrospective</link><description>&lt;h1&gt;tl,dr;&lt;/h1&gt;  &lt;p&gt;&lt;a href="https://bitbucket.org/bvonhandorf/devlinkmobilesmackdownandroid"&gt;The code for this is located here, in a BitBucket repository&lt;/a&gt;.&lt;/p&gt;  &lt;h1&gt;What was this?&lt;/h1&gt;  &lt;p&gt;I was part of the &lt;a href="http://devlink.net/"&gt;Devlink&lt;/a&gt; Mobile Smackdown, organized by &lt;a href="http://jeffblankenburg.com/"&gt;Jeff Blankenburg&lt;/a&gt; of Microsoft.&amp;#160; The goal of the talk is to give the audience a brief taste of developing for the 3 big mobile platforms… iOS, Windows Phone 7 and Android by writing a very simple twitter stalker application in 15 minutes (with a hard stop).&amp;#160; I was fortunate to have Jeff ask me to represent Android.&amp;#160; &lt;/p&gt;  &lt;h1&gt;How did it go?&lt;/h1&gt;  &lt;p&gt;At the end of my 15 minutes, I had forgotten one line of code, but was basically feature complete.&amp;#160; &lt;/p&gt;  &lt;p&gt;The other victims… er… participants, had significantly better looking applications by the end of their 15 minutes.&amp;#160; The base UI for an Android app looks HORRIBLE, so yes, this also looks horrible. I didn’t have time to do a single image, styling optimization or anything of the sort.&lt;/p&gt;  &lt;p&gt;Java and Android are not the fastest development environments.&amp;#160; Perhaps if I was a little more familiar with the UI designer, I could have avoided some XML editing, but even still there is a lot of ceremony in the code.&amp;#160; &lt;/p&gt;  &lt;h1&gt;So Android is a bad platform to develop for?&lt;/h1&gt;  &lt;p&gt;That being said, this demo doesn’t really do anything to show off the true power of the Android platform.&amp;#160; Android’s power lies in the way applications inter-operate.&amp;#160; If you have a mobile app and a website, you can have the mobile app TAKE OVER when the user tries to go to your website.&amp;#160; Yes, really.&amp;#160; If you want to do a lot of work in the background, you can.&amp;#160; If you want to build an interaction story with other applications, or use installed libraries or write to the home screen (widgets) or build animated wallpapers… all these things are possible.&lt;/p&gt;  &lt;p&gt;This does lead to a lot of the problems with Android, too… you can install an app and find your battery dead 3 hours later if it is badly behaved.&amp;#160; It’s a power user platform.&amp;#160; (and with great power comes… free cookies?&amp;#160; Something like that.)&lt;/p&gt;  &lt;p&gt;THAT being said, it’s also the only platform right now on a lot of low end end prepaid carriers.&amp;#160; So the audience is HUGE for a certain class of application.&amp;#160; All the platforms have things to recommend them.&amp;#160; iOS has the UX so standardized, anyone can use it.&amp;#160; WP7 has a beautiful development story and a strong style (which you will either love or hate).&amp;#160; Android believes the phone is yours and you can do anything you want to with it.&amp;#160; There are things you can do on Android that will NEVER be possible on the other platforms.&lt;/p&gt;  &lt;h1&gt;Was it fun?&lt;/h1&gt;  &lt;p&gt;The Mobile Smackdown was a blast.&amp;#160; Live coding in front of a large group with no snippets and no “Julia Child” bail out option is quite a rush.&amp;#160; I had practiced probably 15 or 20 times, several times in front of friends, so I felt fairly prepared but even still I was running 20-35 seconds behind by the end of 15 minutes.&amp;#160; &lt;/p&gt;  &lt;p&gt;I look forward to seeing where all 3 platforms wind up in a few years. Several of the things I heard Jeff talk about as new in Mango from from Android.&amp;#160; Several of the new iOS 5 features are straight out of the Android playbook (notifications, for example).&amp;#160; Android is STARTING to understand that they need a better UX out of the gate… the Action Bar replacing the hard menu button is a step in the right direction.&amp;#160; I’m not usually a raging free-market kind of guy, but the competition is driving all 3 platforms forward. &lt;/p&gt;  &lt;p&gt;Thanks to Jeff for the opportunity to represent my current mobile platform of choice.&amp;#160; &lt;/p&gt;  &lt;h1&gt;Feedback?&lt;/h1&gt;  &lt;p&gt;If you saw the smackdown and have any feedback, please hit me up on twitter (@benvonhandorf) or my first name @benvonhandorf.com.&amp;#160; I’m always looking to improve my speaking abilities, and you only learn by hearing what you did wrong. &lt;/p&gt;  &lt;p&gt;If there’s some demand for it, I may do a Honeycomb version of this same application.&amp;#160; It would be a great fit, but it’s nothing I could do in 15 minutes (if for no other reason than the emulator for Honeycomb is tooooo sloooooow).&lt;/p&gt;  &lt;h1&gt;Ammended (8/27/2011):&lt;/h1&gt;  &lt;p&gt;&lt;a href="http://samidipbasu.com/2011/08/21/mobile-smackdown-recap-on-devlink-2011/"&gt;Find @samidip’s writeup of his experience doing Windows Phone 7 here&lt;/a&gt;.&lt;/p&gt;  &lt;p&gt;&lt;a href="https://github.com/5to9studio/smackdown"&gt;Find @iamthegeek’s code for iOS here.&lt;/a&gt;&lt;/p&gt;</description><pubDate>Thu, 15 Sep 2011 17:31:53 GMT</pubDate><guid isPermaLink="true">http://www.benvonhandorf.com:80/Devlink-Mobile-Smackdowne28093Code-and-Retrospective</guid></item><item><title>OpenSpace Tweets and Conftron</title><link>http://www.benvonhandorf.com:80/OpenSpace-Tweets-and-Conftron</link><description>&lt;h1&gt;tl;dr&lt;/h1&gt;  &lt;p&gt;If you tweet about open spaces in a specific fashion, it’s possible for automated systems to pick them up and for them to show up in conference scheduling applications.&amp;#160; Use the format:&lt;/p&gt;  &lt;p&gt;#codestock #OpenSpace Sat 12:30 Write linkedin recommendations for coworkers &amp;amp; friends!&lt;/p&gt;  &lt;h1&gt;The Goal&lt;/h1&gt;  &lt;p&gt;I’ve always wanted to attend more open spaces, but at many conferences the open spaces are outside the “main flow”, either physically or temporally.&amp;#160; IMHO, discoverability is the big issue here.&lt;/p&gt;  &lt;h1&gt;A Proposal&lt;/h1&gt;  &lt;p&gt;Twitter is a natural solution for this.&amp;#160; Simply tweeting about your open space with the conference hashtag improves the visibility massively… but with a LITTLE extra formatting, we can even make the tweet machine readable and then it can start showing up in people’s conference scheduling applications, like my own &lt;a href="https://market.android.com/details?id=com.benvonhandorf.conftron"&gt;Conftron for Android&lt;/a&gt;.&lt;/p&gt;  &lt;p&gt;My parser looks for the hashtag “#OpenSpace” as well as the conference hashtag, e.g. “#CodeStock”.&amp;#160; It then tries to figure out what time you’re meeting.&amp;#160; If you simply provide a time in military time, it will put it on today if the time is in the future or tomorrow if the time has already passed.&amp;#160; You can also provide the normal 3 letter day abbreviations to schedule it on a future day (Sat).&amp;#160; As a tiny shortcut, you can also use a + to move the date forward a day, or two to move it forward two days, etc... so “+” == tomorrow.&lt;/p&gt;  &lt;h1&gt;An Example&lt;/h1&gt;  &lt;p&gt;Alan Barber was kind enough to re-tweet his open space request in the correct format for testing:&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;alanbarber: #codestock #OpenSpace Sat 12:30 Write linkedin recommendations for coworkers &amp;amp; friends!&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;This worked perfectly and will now show up in the Open Space feed in Conftron the next time you sync (assuming you have the latest version).&lt;/p&gt;  &lt;h1&gt;Tooling&lt;/h1&gt;  &lt;p&gt;I’m going to add a feature to Conftron to help compose these tweets properly, with a date picker and other little niceties, but I’m hoping that this blog post will be enough to get people started.&amp;#160; If there’s enough interest, I’ll gladly post my feed parser somewhere for general use.&amp;#160; It’s making use of the unauthenticated Twitter search API, so you don’t even need any messy OAuth stuff yet… but I’m likely going to revisit this.&lt;/p&gt;  &lt;h1&gt;Feedback?&lt;/h1&gt;  &lt;p&gt;Like this idea?&amp;#160; Hate it?&amp;#160; You can find me though the normal ways or send Conftron specific feedback to @conftron on Twitter.&amp;#160; I’d love to either see this become a standard or have someone suggest something better to supplant it!&lt;/p&gt;</description><pubDate>Thu, 15 Sep 2011 17:31:27 GMT</pubDate><guid isPermaLink="true">http://www.benvonhandorf.com:80/OpenSpace-Tweets-and-Conftron</guid></item><item><title>Sql Server CE assembly version conflict</title><link>http://www.benvonhandorf.com:80/Sql-Server-CE-assembly-version-conflict</link><description>&lt;p&gt;First, &lt;a href="http://www.matheda.com/"&gt;thanks to Matt for figuring out where to look&lt;/a&gt; for the solution to this issue.&lt;/p&gt;  &lt;p&gt;In working on the back end services for my Android application, I moved my Entity Framework model from one assembly to another.&amp;#160; After that and some other refactorings, I went to run and was greeted with this error:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;&lt;font color="#ff0000"&gt;[A]System.Data.SqlServerCe.SqlCeConnection cannot be cast to [B]System.Data.SqlServerCe.SqlCeConnection. Type A originates from 'System.Data.SqlServerCe, Version=4.0.0.0, Culture=neutral, PublicKeyToken=89845dcd8080cc91' in the context 'Default' at location 'C:\Windows\assembly\GAC_MSIL\System.Data.SqlServerCe\4.0.0.0__89845dcd8080cc91\System.Data.SqlServerCe.dll'. Type B originates from 'System.Data.SqlServerCe, Version=3.5.1.0, Culture=neutral, PublicKeyToken=89845dcd8080cc91' in the context 'Default' at location 'C:\Windows\assembly\GAC_MSIL\System.Data.SqlServerCe\3.5.1.0__89845dcd8080cc91\System.Data.SqlServerCe.dll'.&lt;/font&gt;&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;After spending far too much time with the fusion logger and triple checking all my references, Matt made the brilliant suggestion to take a look in the .edmx XML to see if it had any references to the provider.&amp;#160; Lo and behold:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;&amp;lt;Schema Namespace=&amp;quot;ConferenceDataModel.Store&amp;quot; Alias=&amp;quot;Self&amp;quot; Provider=&amp;quot;System.Data.SqlServerCe.3.5&amp;quot; ProviderManifestToken=&amp;quot;3.5&amp;quot; xmlns:store=&amp;quot;&lt;a href="http://schemas.microsoft.com/ado/2007/12/edm/EntityStoreSchemaGenerator&amp;quot;"&gt;http://schemas.microsoft.com/ado/2007/12/edm/EntityStoreSchemaGenerator&amp;quot;&lt;/a&gt; xmlns=&amp;quot;&lt;a href="http://schemas.microsoft.com/ado/2009/02/edm/ssdl&amp;quot;"&gt;http://schemas.microsoft.com/ado/2009/02/edm/ssdl&amp;quot;&lt;/a&gt;&amp;gt;&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;Changing the 3.5s to 4.0, saving, rebuilding and running resolved the issue.&lt;/p&gt;</description><pubDate>Wed, 25 May 2011 21:03:29 GMT</pubDate><guid isPermaLink="true">http://www.benvonhandorf.com:80/Sql-Server-CE-assembly-version-conflict</guid></item><item><title>Android: Problem launching main activity–Permission Denial</title><link>http://www.benvonhandorf.com:80/Android-Problem-launching-main-activitye28093Permission-Denial</link><description>&lt;p&gt;Hoping to save someone else (or my future self) a few minutes.&lt;/p&gt;  &lt;p&gt;So I’m working on an Android app and I did a minor refactor and reduced the number of activities (screens) in my application and renamed another activity to the name of one of the removed ones.&amp;#160; After recompiling, my app would not start.&amp;#160; &lt;font face="Courier New"&gt;“adb logcat”&lt;/font&gt; showed the following:&lt;/p&gt;  &lt;p&gt;&lt;font size="1" face="Courier New"&gt;I/ActivityManager(&amp;#160; 129): Starting activity: Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10000000 cmp=com.benvonhandorf.conftron/.ConferenceListActivity }     &lt;br /&gt;W/ActivityManager(&amp;#160; 129): Permission Denial: starting Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10000000 cmp=com.benvonhandorf.conftron/.ConferenceListActivity } from null (pid=-1, uid=-1) requires null      &lt;br /&gt;&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;After some investigation, it turns out that I had forgotten to remove the extra &amp;lt;activity&amp;gt; element from the AndroidManifest.xml file, so the renamed activity was listed twice, resulting in this fairly cryptic error.&amp;#160; Removing the extra activity registration solved the issue.&amp;#160; &lt;/p&gt;  &lt;p&gt;I believe what happened is that Android ignored the earlier registration (which contained the intent filter for MAIN and LAUNCHER) and therefore couldn’t find a way to launch the application.&lt;/p&gt;</description><pubDate>Sun, 15 May 2011 07:16:42 GMT</pubDate><guid isPermaLink="true">http://www.benvonhandorf.com:80/Android-Problem-launching-main-activitye28093Permission-Denial</guid></item><item><title>Rooting your Barnes and Noble Nook Color–Part Zero</title><link>http://www.benvonhandorf.com:80/Rooting-your-Barnes-and-Noble-Nook-Colore28093Part-Zero</link><description>&lt;h1&gt;Why&lt;/h1&gt;  &lt;p&gt;Recently several people have seen my rooted Nook Color around and about and been interested.&amp;#160; I’ve send various and sundry forum links to some of them and a few of them have gone through the process of rooting the Nook or trying alternative operating systems to see the power of this incredible device.&lt;/p&gt;  &lt;p&gt;After sending out similar forum links several times, I decided to accumulate the instructions into a series of posts in the hopes of making this easier for the adventurous souls willing to go through with it.&lt;/p&gt;  &lt;h1&gt;But&lt;/h1&gt;  &lt;p&gt;As with any process called “rooting”, this is not for the faint of heart.&amp;#160; If you’re not comfortable with strange forums, obscure instructions and possibly difficult recovery processes, here there be dragons.&lt;/p&gt;  &lt;h1&gt;Recommended Alternatives&lt;/h1&gt;  &lt;p&gt;If you don’t want to risk your beautiful Nook Color, I have some recommendations for you:&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;Buy an iPad.&amp;#160; Apple has a much better, more curated experience for people who fear the unknown and don’t like risk.&amp;#160; You pay for that experience, both in dollars and in your ability to do whatever you want.&amp;#160; For 99% of people, that trade off is a no-brainer compared to a rooted nook.&lt;/li&gt;    &lt;li&gt;Buy a real Android tablet.&amp;#160; The Motorola Xoom is an amazing bit of kit.&amp;#160; Acer has a really impressive tablet out.&amp;#160; Samsung’s line of Android tablets come out very soon.&amp;#160; If you like the Android platform but you fear the command line, this is a great alternative.&lt;/li&gt;    &lt;li&gt;The Nook Color is now a beginner tablet.&amp;#160; With the officially supported apps, it’s starting to become quite capable.&amp;#160; It can do so much more with the additional work, but again, for 99% of people, the default experience is worth it.&lt;/li&gt; &lt;/ol&gt;  &lt;h1&gt;Still Here?&lt;/h1&gt;  &lt;p&gt;If you’re through the alternatives and none of them appeals to you, then let’s discuss your options:&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;&lt;strong&gt;Boot off the SD card&lt;/strong&gt;.&amp;#160; This is a non-destructive process that allows you to try out different operating systems and see what suits you.&amp;#160; To revert to the default experience, simply take out the card and reboot.&amp;#160; Highly recommended at least until you find an OS that you like more than the default&amp;#160; This is the easiest and least-risky option.&lt;/li&gt;    &lt;li&gt;&lt;strong&gt;Root the Nook operating system&lt;/strong&gt;.&amp;#160; This leaves the OS mostly intact, but adds in the missing bits of Android and Marketplace access, which can allow you to get some apps that B&amp;amp;N haven’t approved.&amp;#160; This is semi-destructive, but still a nice compromise.&amp;#160; This is a little harder than the SD card boot and slightly more risky.&lt;/li&gt;    &lt;li&gt;&lt;strong&gt;Flash your own OS onto the Nook.&lt;/strong&gt; This is the highest risk, but most performance and convenience.&amp;#160; This nukes the B&amp;amp;N OS right off the device and replaces it with a ROM that has been specially formulated to work on the Nook.&lt;/li&gt; &lt;/ol&gt;  &lt;p&gt;My next post will discuss the SD card option.&amp;#160; We’ll take a specific ROM and walk you through the process of burning it to the SD card and playing around with your new hardware.&amp;#160; After that, I’ll discuss the other options and some gotchas and neat tricks.&lt;/p&gt;  &lt;h1&gt;Attributions&lt;/h1&gt;  &lt;p&gt;Almost nothing in this series of blog posts will be my own work.&amp;#160; I’m simply curating data from a lot of great sources.&amp;#160; The two big ones you should familiarize yourself with are:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://nookdevs.com/Portal:NookColor"&gt;The NookColor portal at nookdevs.com&lt;/a&gt;.&amp;#160; Anything I say can either be found or at&lt;/p&gt;  &lt;p&gt;&lt;a href="http://forum.xda-developers.com/forumdisplay.php?f=864"&gt;The XDA Forums for the Nook.&lt;/a&gt;&amp;#160; This is where the wizards live.&amp;#160; They can make almost any phone dance and do things that it was never intended to do.&amp;#160; Just be sure to search before asking a question… Wizards are subtle and quick to anger.&lt;/p&gt;</description><pubDate>Sat, 14 May 2011 01:53:47 GMT</pubDate><guid isPermaLink="true">http://www.benvonhandorf.com:80/Rooting-your-Barnes-and-Noble-Nook-Colore28093Part-Zero</guid></item><item><title>New blog is finally up</title><link>http://www.benvonhandorf.com:80/New-blog-is-finally-up</link><description>&lt;p&gt;I'm finally getting some new blog software in place and working to migrate content from my old blog.&amp;nbsp; I'll also be adding several new posts over the course of the next few weeks as I continue in my investigations of Silverlight, WPF, Entity Framework, Patterns and maybe even some Objective C and other, more exotic ideas.&lt;/p&gt;</description><pubDate>Sat, 03 Apr 2010 11:17:04 GMT</pubDate><guid isPermaLink="true">http://www.benvonhandorf.com:80/New-blog-is-finally-up</guid></item><item><title>WPF Ink Friendly Editable Text Control</title><link>http://www.benvonhandorf.com:80/WPF-Ink-Friendly-Editable-Text-Control</link><description>&lt;p&gt;I’m rescuing some posts from my old blog.&amp;#160; &lt;/p&gt;  &lt;p&gt;This topic was suggested by Mike Wood.&amp;#160; It’s a control I’m putting together for my WPF project for fun.&amp;#160; I really like the Tablet PC idea and enjoy using the pen as an input device where it makes sense, so I wanted a label that you could click on and bring up an ink editing panel.&amp;#160; So here we have a list of strings:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://orbitalspacelaser.com/blog/files/media/image/WindowsLiveWriter/ONTaW3Inkfriendlyeditablelabel_85F5/image_2.png"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="image" border="0" alt="image" src="http://orbitalspacelaser.com/blog/files/media/image/WindowsLiveWriter/ONTaW3Inkfriendlyeditablelabel_85F5/image_thumb.png" width="244" height="244" /&gt;&lt;/a&gt;&amp;#160;&lt;/p&gt;  &lt;p&gt;Click on one of them and get out the pen!&lt;/p&gt;  &lt;p&gt;&lt;a href="http://orbitalspacelaser.com/blog/files/media/image/WindowsLiveWriter/ONTaW3Inkfriendlyeditablelabel_85F5/image_4.png"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="image" border="0" alt="image" src="http://orbitalspacelaser.com/blog/files/media/image/WindowsLiveWriter/ONTaW3Inkfriendlyeditablelabel_85F5/image_thumb_1.png" width="244" height="244" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;Through the magic of the control and WPF’s 2 way data binding, your listing is now updated!&lt;/p&gt;  &lt;p&gt;&lt;a href="http://orbitalspacelaser.com/blog/files/media/image/WindowsLiveWriter/ONTaW3Inkfriendlyeditablelabel_85F5/image_6.png"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="image" border="0" alt="image" src="http://orbitalspacelaser.com/blog/files/media/image/WindowsLiveWriter/ONTaW3Inkfriendlyeditablelabel_85F5/image_thumb_2.png" width="244" height="244" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;The control itself is reasonably straightforward… it’s pretty much a label with a popup containing an InkCanvas and a few buttons.&amp;#160; There are still a few quirks I’m trying to work though (e.g. the right way to clear the list of strokes out of the InkAnalyzer, getting automatic recognition working so that you don’t have to click OK), but on the whole it’s functional.&lt;/p&gt;  &lt;p&gt;One strange/irritating thing is that even though the ink stuff is more or less a 1st class control now in WPF, you still need to include some obscure references to get handwriting recognition.&amp;#160; You have to go to C:\Program Files\Reference Assemblies\Microsoft\Tablet PC\v1.7\ and add all the files there to your solution so that you can use classes like the InkAnalyzer.&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;a href="http://www.orbitalspacelaser.com/code/InkTextBox.zip"&gt;You can find this sample code here&lt;/a&gt;.&amp;#160; Enjoy!&lt;/p&gt;</description><pubDate>Tue, 16 Mar 2010 05:34:35 GMT</pubDate><guid isPermaLink="true">http://www.benvonhandorf.com:80/WPF-Ink-Friendly-Editable-Text-Control</guid></item><item><title>Managed C++ and Unmanaged Libraries</title><link>http://www.benvonhandorf.com:80/Managed-C2b2b-and-Unmanaged-Libraries</link><description>&lt;p&gt;I’m rescuing some posts from my old blog and this seemed like something I would want to know again at some point, so I’m starting with this one:&lt;/p&gt;  &lt;p&gt;This started with an offhand remark on the &lt;a href="http://polymorphicpodcast.com/"&gt;Polymorphic Podcast&lt;/a&gt; that there was an accelerated feed available.&amp;#160; Listening to it, I realized that a lot of technical podcasts could be easily digested at, say, 120-130% of normal speed.&amp;#160; For &lt;a href="http://www.dotnetrocks.com/"&gt;some&lt;/a&gt;, it’s a lot more tolerable for me to listen to them this way.&lt;/p&gt;  &lt;p&gt;This led to the Dream Application.&amp;#160; It would run on a web server and refactor a requested RSS feed to point back to itself.&amp;#160; When a feed reader went to download an mp3, the application would download the mp3 from the actual source, speed it up and stream it down to the reader.&amp;#160; After about 2 weeks of light work on that application, someone pointed me to &lt;a href="http://podshifter.com/"&gt;PodShifter&lt;/a&gt;, which is exactly what I was building.&amp;#160; My only problem with their solution, and I do not think it is their implementation, is that it is slow.&amp;#160; The feed reader requests the mp3, it gets 404ed and then, maybe 15 minutes later, the mp3 is actually available to download.&lt;/p&gt;  &lt;p&gt;So I’ve refactored my approach… what I want now is a service that watches the podcast directories I want to accelerate.&amp;#160; When it sees a new mp3 stored there, it should pick it up, accelerate it and store it back in the same filename so that when I plug my Zune in, the Zune software will pick up the accelerated version.&lt;/p&gt;  &lt;h2&gt;Bricks in the Wall&lt;/h2&gt;  &lt;p&gt;There are really 3 bits to this solution and, luckily, there are libraries available for each of them.&amp;#160; I don’t have to learn all about audio formats to do this!&amp;#160; (Or DO I?)&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;Decoding an existing mp3.&amp;#160; Libmpg123 takes care of this.&amp;#160; It’s a fairly straightforward C style interface which suits itself to PInvoke fairly well. &lt;/li&gt;    &lt;li&gt;Accelerating the data (without pitch shifting it).&amp;#160; SoundTouch seems to be the default solution to this.&amp;#160; Unfortunately, this is implemented as a C++ Class rather than a C library.&amp;#160; There’s no real way to PInvoke to a C++ class… unless you want to do all the work of normalizing the actual function names out of the DLL and passing the “this” pointer around.&amp;#160; Not Fun. &lt;/li&gt;    &lt;li&gt;Encoding the decoded data.&amp;#160; LAME is the standard “free” solution to this problem, and there is a liblame implementation that is also fairly PInvoke friendly. &lt;/li&gt; &lt;/ol&gt;  &lt;p&gt;Since SoundTouch threw a wrench into my initial plan of doing C# and PInvoke, I decided to reboot and start writing a managed C++ wrapper class for each of the libraries and using C# to wire the wrappers together.&amp;#160; Each interface would basically take an input stream and an output stream.&lt;/p&gt;  &lt;h2&gt;Managing the unmanageable&lt;/h2&gt;  &lt;p&gt;The only real HARD part of all this was re-learning C++ and figuring out how C++ works in a managed environment.&amp;#160; There are 2 things I learned that were really key:&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;To work with framework objects, you wind up using ^ in the declaration… like this:      &lt;pre class="brush: cpp"&gt;System::IO::Stream ^inputStreamLeft &lt;/pre&gt;

    &lt;br /&gt;This tells C++ that this is a managed, garbage collected class and you get all the benefits of doing that, just like you would in C#.&amp;#160; If you need to create a new managed class, you use gcnew rather than new.&amp;#160; At that point, your work is done… no need to call delete on such an item. &lt;/li&gt;

  &lt;li&gt;Creating unmanaged pointers is more interesting.&amp;#160; Obviously, the C and C++ libraries I am calling don’t know anything about a System.Byte pointer.&amp;#160; More interestingly, managed objects can be moved around in memory at the whim of the runtime… which doesn’t work out so well for C libraries that just want some memory they can dump stuff into.&amp;#160; The solution is to pin the object in memory with pin_ptr.&amp;#160; For example, to create an array of bytes that I can get to with managed and unmanaged code, I do the following: 
    &lt;br /&gt;

    &lt;pre class="brush: cpp"&gt;    array&amp;lt;System::Byte&amp;gt;&amp;#160;&amp;#160;&amp;#160; ^ inputBufferLeftManaged ; //Managed byte buffer
    inputBufferLeftManaged = gcnew array&amp;lt;System::Byte&amp;gt;(327680) ; //Allocate the byte buffer
    cli::pin_ptr&amp;lt;unsigned char&amp;gt; inputBufferLeft = &amp;amp;inputBufferLeftManaged[0] ; //Get an unmanaged pointer to the memory.&amp;#160; This pins the object in memory so it can’t move &lt;/pre&gt;

    &lt;br /&gt;You can then cast the pinned pointer to other kinds of pointers, and pass it into the relevant functions. 

    &lt;br /&gt;&lt;strong&gt;NOTE:&lt;/strong&gt; This is all recent learnings, so I suspect I have a memory leak in here.&amp;#160; I’ll update this if I learn this is the case and how to deal with it. &lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;Whatever floats your boat&lt;/h2&gt;

&lt;p&gt;After getting things wired up, I was getting nothing but garbage out of the sound modification library.&amp;#160; If I just wired the decoder and encoder together, I got a reasonable mp3, but running it through the tempo adjustment meant that I got nothing but static.&amp;#160; Some investigation later revealed that recompiling that library to deal with float samples rather than the 16-bit unsigned samples I had been using resolved this issue… so I changed the other libraries to work with float samples instead so I have a consistent data stream throughout the process.&lt;/p&gt;

&lt;h2&gt;Don’t Cross the Streams&lt;/h2&gt;

&lt;p&gt;A side effect of the change to floats is that the lame encoding library doesn’t support a single interleaved buffer when dealing with floats… instead I have to pass in a buffer for the left channel and a buffer for the right channel.&amp;#160; I wound up writing a loop after the audio modification stem to pull data off the stream and drop it onto a left or right stream, de-interleaving the data myself.&amp;#160; I wound up doing this in the C# code for simplicity… less chance of overrunning a buffer off into infinity.&lt;/p&gt;

&lt;h2&gt;Wall of Silence&lt;/h2&gt;

&lt;p&gt;At the moment, I’ve hit something of a wall with this project.&amp;#160; Everything seems to work OK, but ever since switching to float audio data, I’ve had nothing but silence from the encoded mp3.&amp;#160; It appears there’s real data going INTO it, but nothing but silence coming out.&amp;#160; After several hours of debugging, I’ve set it to the side for the time being.&amp;#160; Hopefully I’ll be back to this before too long, but there’s so much out there to do I’ll probably just live with the quirks of &lt;a href="http://podshifter.com/"&gt;PodShifter&lt;/a&gt; (which IS really good).&lt;/p&gt;</description><pubDate>Tue, 16 Mar 2010 05:30:36 GMT</pubDate><guid isPermaLink="true">http://www.benvonhandorf.com:80/Managed-C2b2b-and-Unmanaged-Libraries</guid></item><item><title>Eliminating magic strings when using INotifyPropertyChanged</title><link>http://www.benvonhandorf.com:80/Eliminating-magic-strings-when-using-INotifyPropertyChanged</link><description>&lt;p&gt;Like a lot of others, I'm learning Silverlight, WPF and all the other facinating new technologies coming out of Microsoft (and elsewhere) these days.&amp;nbsp; Most of this stuff is incredible, but occasionally you'll run into something that has a bit of a code smell about it.&amp;nbsp; One of those is the INotifyPropertyChange interface in WPF and Silverlight.&lt;/p&gt;
&lt;p&gt;In order to make data binding work in these two technologies, entities that have their data bound to WPF or Silverlight controls need to implement INotifyPropertyChanged in order to ensure that the controls are updated when the data in the entity changes.&amp;nbsp; All well and good, but let's take a look at the interface:&lt;/p&gt;
&lt;pre class="brush: c#"&gt;    // Summary:
    //     Notifies clients that a property value has changed.
    public interface INotifyPropertyChanged
    {
        // Summary:
        //     Occurs when a property value changes.
        event PropertyChangedEventHandler PropertyChanged;
    }
&lt;/pre&gt;
&lt;p&gt;Looks fine.&amp;nbsp; And the PropertyChangedEventHandler delegate looks pretty standard... a sender and then a PropertyChangedEventArgs class that descends from EventArgs.&amp;nbsp; But how do you indicate which property changed?&lt;/p&gt;
&lt;pre class="brush: c#"&gt;        public PropertyChangedEventArgs(string propertyName);
&lt;/pre&gt;
&lt;p&gt;A string matching the name of the property, passed into the constructor of the PropertyChangedEventArgs.&amp;nbsp; So most people I've seen wind up implementing it everywhere something like this:&lt;/p&gt;
&lt;pre class="brush: c#"&gt;        public string MyStringProperty
        {
            get
            {
                return _myStringProperty;
            }
            private set
            {
                _myStringProperty = value;
                if( PropertyChanged != null )
                    PropertyChanged( this, new PropertyChangedEventArgs("MyStringProperty"));
            }
        }
&lt;/pre&gt;
&lt;p&gt;If having a hardcoded string inside a property setter that has to match the name of the property doesn't constitute a "Code Smell" then I'm not sure I understand the concept.&lt;/p&gt;
&lt;p&gt;Now, most people abstract the PropertyChanged null check down into a base class on their ViewModel objects in keeping with DRY.&lt;/p&gt;
&lt;pre class="brush: c#"&gt;            private set
            {
                _myStringProperty = value;
                RaisePropertyChanged("MyStringProperty");
            }
&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Better, but the hard coded string is still there.&amp;nbsp; What can we do about that?&lt;/p&gt;
&lt;h2&gt;Expression Trees to the rescue.&amp;nbsp;&lt;/h2&gt;
&lt;p&gt;If you haven't dug into this technology yet, it's quite facinating.&amp;nbsp; You build up a tree of expressions that does not have to be executed.&amp;nbsp; It's a structure describing the code without actually executing it.&amp;nbsp; This is how deferred execution in LINQ works and how LINQ to SQL is able to take your Where(...) and Select(...) calls and turn them into SQL statements.&lt;/p&gt;
&lt;p&gt;In my base ViewModel class, I declare a delegate that is simply anything that returns an object:&lt;/p&gt;
&lt;pre class="brush: c#"&gt;        public delegate object PropertyAccess( ) ;
&lt;/pre&gt;
&lt;p&gt;And now I re-implement my RaisePropertyChanged method to take an expression which contains a PropertyAccess delegate:&lt;/p&gt;
&lt;pre class="brush: c#"&gt;        protected void RaisePropertyChanged(Expression&amp;lt;PropertyAccess&amp;gt; propertyExpression)
        {
            MemberExpression getMemberExpression = propertyExpression.Body as MemberExpression;

            if (getMemberExpression != null 
                &amp;amp;&amp;amp; getMemberExpression.Member.MemberType == System.Reflection.MemberTypes.Property)
            {
                RaisePropertyChanged(getMemberExpression.Member.Name);
            }

        }
&lt;/pre&gt;
&lt;p&gt;OK... but how do you call it?&lt;/p&gt;
&lt;pre class="brush: c#"&gt;            public string TestProperty
            {
                get 
                {
                    return _testProperty; 
                }
                set
                {
                    _testProperty = value;
                    RaisePropertyChanged(() =&amp;gt; this.TestProperty);
                }
            }
&lt;/pre&gt;
&lt;p&gt;But Ben!&amp;nbsp; You're accessing TestProperty in the Setter!&amp;nbsp; If there was real logic in there (for example, lazy loading some data), you might do all kinds of bad things!&lt;/p&gt;
&lt;p&gt;No.&amp;nbsp; The () =&amp;gt; this.TextProperty call is never evaluated... it is only used to build an Expression tree which is then examined by the RaisePropertyChanged method, which extracts the appropriate property name.&lt;/p&gt;
&lt;p&gt;The best part, in my mind?&amp;nbsp; A magic string change becomes a compile time error.&amp;nbsp; No more broken unit tests... in fact, probably no need for a unit test on every property set to ensure that the event is loaded.&lt;/p&gt;
&lt;p&gt;I hope this was useful to you... I'll be back soon with more of my learnings.&amp;nbsp; If you've got something you're curious about or a comment on this or any of my posts, please drop me a line using the comment feature!&lt;/p&gt;</description><pubDate>Sun, 24 Jan 2010 08:30:19 GMT</pubDate><guid isPermaLink="true">http://www.benvonhandorf.com:80/Eliminating-magic-strings-when-using-INotifyPropertyChanged</guid></item></channel></rss>