<?xml version="1.0" encoding="ISO-8859-1"?>

<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/">
	<channel>
		<title>Android Community Forums - Blogs</title>
		<link>http://androidcommunity.com/forums/blog.php</link>
		<description>Android Community is a place to discuss about Google Open Handset Alliance Project called Android</description>
		<language>en</language>
		<lastBuildDate>Sun, 22 Nov 2009 13:13:55 GMT</lastBuildDate>
		<generator>vBulletin</generator>
		<ttl>1</ttl>
		<image>
			<url>http://androidcommunity.com/forums/images/misc/rss.jpg</url>
			<title>Android Community Forums - Blogs</title>
			<link>http://androidcommunity.com/forums/blog.php</link>
		</image>
		<item>
			<title>Lots more apps</title>
			<link>http://androidcommunity.com/forums/blog.php?b=382</link>
			<pubDate>Mon, 16 Nov 2009 05:34:17 GMT</pubDate>
			<description><![CDATA[I've released updates to all my apps in the past couple days. Too much coding! The plus side is my new checklist app, d2cchecklist...]]></description>
			<content:encoded><![CDATA[<div>I've released updates to all my apps in the past couple days. Too much coding! The plus side is my new checklist app, <a href="http://code.google.com/p/d2cchecklist" target="_blank">d2cchecklist</a>, is complete and ready on the Market. This is the most complex app I've yet written, weighing in at ~5700 lines of Java code and comments (and that's after rewriting many sections at least once as I learned to do things the right way!)<br />
<br />
This has been a great learning experience and I have lots more development tips to share, if there's interest. Some possibilities:<br />
<ul><li>XML parsing and output</li>
<li>Activity lifecycles and databases</li>
<li>Database class design beyond the simple Notepad example</li>
<li>Interfaces for opening and saving files</li>
<li>Implementing categories to organize items in a database</li>
<li>Drag &amp; drop reordering items in a list</li>
</ul>Let me know if there's something here you'd like me to explain. My project websites contain all the source code for the above items.</div>

]]></content:encoded>
			<dc:creator>divestoclimb</dc:creator>
			<guid isPermaLink="true">http://androidcommunity.com/forums/blog.php?b=382</guid>
		</item>
		<item>
			<title>Custom view component in a DialogPreference</title>
			<link>http://androidcommunity.com/forums/blog.php?b=361</link>
			<pubDate>Tue, 13 Oct 2009 03:08:07 GMT</pubDate>
			<description>There are several sites out there (like (http://www.androidguys.com/2008/09/29/whats-your-preference-part-one/) these...</description>
			<content:encoded><![CDATA[<div>There are several sites out there (<a href="http://www.androidguys.com/2008/09/29/whats-your-preference-part-one/" target="_blank">like</a> <a href="http://www.kaloer.com/android-preferences/" target="_blank">these</a>) that show you how to use Android preferences, but I haven't seen anyone explain how to extend DialogPreference to get your own custom preference stored. I had to dig into the Android source to figure this out since reading Google's documentation on <a href="http://developer.android.com/reference/android/preference/DialogPreference.html" target="_blank">DialogPreference</a> is like reading Greek!<br />
<br />
I did this twice in Gas Mixer; once using my NumberSelector component I explained in my last posts, and also with my TrimixSelector. Because the TrimixSelector, in a way, represents a more likely scenario someone would run into when trying to build a custom preference, I'm going to go into step-by-step detail of how I did that. A TrimixSelector is what allows the user to pick the percentages of oxygen and helium that are in a gas. This is really two pieces of information, though, and it can't be encapsulated into a single value without resorting to a little hack... here's an example from my res/xml/preferences.xml:<br />
<div style="margin:20px; margin-top:5px">
	<div class="smallfont" style="margin-bottom:2px">Code:</div>
	<pre class="alt2" dir="ltr" style="
		margin: 0px;
		padding: 6px;
		border: 1px inset;
		width: 640px;
		height: 98px;
		text-align: left;
		overflow: auto">    &lt;divestoclimb.gasmixer.TrimixPreference
        android:key=&quot;topup_gas&quot;
        android:title=&quot;@string/topup_gas&quot;
        android:defaultValue=&quot;0.21 0&quot;
        android:dialogIcon=&quot;@drawable/topup_pick&quot; /&gt;</pre>
</div>I defined a TrimixPreference class which can then be inserted straight into preferences.xml. The only tricky part is the defaultValue, which I'll explain later. As an aside, you can make you own custom attributes here just like for any custom component. I did this with my NumberSelector's preference, NumberPreference.<br />
<br />
In order to understand TrimixPreference, we have to look at the public methods of <a href="http://code.google.com/p/gasmixer/source/browse/trunk/gasmixer/src/divestoclimb/gasmixer/TrimixSelector.java" target="_blank">TrimixSelector</a>:<br />
<div style="margin:20px; margin-top:5px">
	<div class="smallfont" style="margin-bottom:2px">Code:</div>
	<pre class="alt2" dir="ltr" style="
		margin: 0px;
		padding: 6px;
		border: 1px inset;
		width: 640px;
		height: 242px;
		text-align: left;
		overflow: auto">public class TrimixSelector extends RelativeLayout
        implements SeekBar.OnSeekBarChangeListener, NumberSelector.ValueChangedListener {
    public static interface MixChangeListener {
        abstract void onChange(TrimixSelector ts, Mix m);
    }

    public TrimixSelector(Context context);
    public TrimixSelector(Context context, AttributeSet attrs);

    public Mix getMix();
    public void setMix(Mix m);

    public void setOnMixChangeListener(MixChangeListener l);
}</pre>
</div>TrimixSelector uses a custom Mix object as its interface for gets and sets of the mix. The data within Mix is really just two doubles, the percentages of oxygen and helium. There's also a change listener defined, but that's not important here.<br />
<br />
Now we can talk about TrimixPreference, defined in Gas Mixer's <a href="http://code.google.com/p/gasmixer/source/browse/trunk/gasmixer/src/divestoclimb/gasmixer/TrimixPreference.java" target="_blank">TrimixPreference.java</a>. Here's the basic class declaration, member variables, and constructors:<br />
<div style="margin:20px; margin-top:5px">
	<div class="smallfont" style="margin-bottom:2px">Code:</div>
	<pre class="alt2" dir="ltr" style="
		margin: 0px;
		padding: 6px;
		border: 1px inset;
		width: 640px;
		height: 322px;
		text-align: left;
		overflow: auto">public class TrimixPreference extends DialogPreference {
    private TrimixSelector mTrimixSelector;
    
    private Mix mMix;
    private String mMixString;
    
    public TrimixPreference(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);

        mTrimixSelector = new TrimixSelector(context, attrs);
    }
    
    public TrimixPreference(Context context, AttributeSet attrs) {
        this(context, attrs, android.R.attr.dialogPreferenceStyle);
    }
    
    public TrimixPreference(Context context) {
        this(context, null);
    }</pre>
</div>We extend DialogPreference, then create a TrimixSelector object within the class. In most cases, the constructor that gets called to instantiate our class is the second one, with no style specified; it's important that you use android.R.attr.dialogPreferenceStyle in that case.<br />
<br />
The preference does internal storage of what the mix is as an intermediate step between the TrimixSelector View that the user manipulates, the Preference Manager's persisted preference value, and the saved state.<br />
<br />
Because I had to choose a standard type to store my two mix percentages in, I decided to concatenate both together in a string. So I have methods that let me translate back and forth between strings like you see in the XML's defaultValue attribute and my Mix object, in addition to a getter and setter for the Mix object itself:<br />
<div style="margin:20px; margin-top:5px">
	<div class="smallfont" style="margin-bottom:2px">Code:</div>
	<pre class="alt2" dir="ltr" style="
		margin: 0px;
		padding: 6px;
		border: 1px inset;
		width: 640px;
		height: 418px;
		text-align: left;
		overflow: auto">    private String mixToString(Mix mix) {
        NumberFormat nf = new DecimalFormat(&quot;.###&quot;);
        return nf.format(mix.getfO2())+&quot; &quot;+nf.format(mix.getfHe());
    }
    
    public static Mix stringToMix(String s) {
        String ss[] = s.split(&quot;\\s&quot;);
        NumberFormat nf = new DecimalFormat(&quot;.###&quot;);
        try {
            return new Mix(nf.parse(ss[0]).floatValue(), nf.parse(ss[1]).floatValue());
        } catch(ParseException e) { return null; }
    }
    
    public void setMix(String mixString) {

        mMix = stringToMix(mixString);
        mMixString = mixString;
        
        persistString(mixString);

    }

    public Mix getMix() {
        return mMix;
    }</pre>
</div><a href="http://developer.android.com/reference/android/preference/Preference.html#persistString%28java.lang.String%29" target="_blank">persistString() </a> is somehow important to the Preference Manager, but it's not clearly documented... I copied this technique from Android sources and it works this way :)<br />
<br />
Now we come to the DialogPreference overrides. These are the methods you must override in order for this to work:<br />
<br />
<b>onCreateDialogView</b><br />
This method normally would construct all of our views. Because it's possible for my custom object to have attributes passed to it from preferences.xml, I instantiated it up in the constructor. So all I have to do here is return the member variable as the view:<br />
<div style="margin:20px; margin-top:5px">
	<div class="smallfont" style="margin-bottom:2px">Code:</div>
	<pre class="alt2" dir="ltr" style="
		margin: 0px;
		padding: 6px;
		border: 1px inset;
		width: 640px;
		height: 82px;
		text-align: left;
		overflow: auto">    @Override
    protected View onCreateDialogView() {
        return mTrimixSelector;
    }</pre>
</div>There's one other thing to keep in mind because of how I'm doing this that will come up later.<br />
<br />
<b>onGetDefaultValue and onSetInitialValue</b><br />
<div style="margin:20px; margin-top:5px">
	<div class="smallfont" style="margin-bottom:2px">Code:</div>
	<pre class="alt2" dir="ltr" style="
		margin: 0px;
		padding: 6px;
		border: 1px inset;
		width: 640px;
		height: 162px;
		text-align: left;
		overflow: auto">@Override
    protected Object onGetDefaultValue(TypedArray a, int index) {
        return a.getString(index);
    }
    
    @Override
    protected void onSetInitialValue(boolean restoreValue, Object defaultValue) {
        setMix(restoreValue? getPersistedString(mMixString): (String)defaultValue);
    }</pre>
</div>These methods get and retrieve the preference value from the Preference Manager. I have to resort to strings again here, and store the result in my member variables.<br />
<br />
<b>onBindDialogView</b><br />
This method takes the View and adds our data to it. Pretty simple here:<br />
<div style="margin:20px; margin-top:5px">
	<div class="smallfont" style="margin-bottom:2px">Code:</div>
	<pre class="alt2" dir="ltr" style="
		margin: 0px;
		padding: 6px;
		border: 1px inset;
		width: 640px;
		height: 130px;
		text-align: left;
		overflow: auto">    @Override
    protected void onBindDialogView(View view) {
        super.onBindDialogView(view);

        mTrimixSelector.setMix(getMix());

    }</pre>
</div><b>onDialogResult</b><br />
This method is called when the dialog is about to close. It's called with a single argument that says whether the result is &quot;positive&quot;, i.e. a generalization of whether the user pressed &quot;OK&quot; or &quot;Cancel&quot;. Our override needs to save the value in the custom component if positiveResult is true:<br />
<div style="margin:20px; margin-top:5px">
	<div class="smallfont" style="margin-bottom:2px">Code:</div>
	<pre class="alt2" dir="ltr" style="
		margin: 0px;
		padding: 6px;
		border: 1px inset;
		width: 640px;
		height: 210px;
		text-align: left;
		overflow: auto">    @Override
    protected void onDialogClosed(boolean positiveResult) {
        super.onDialogClosed(positiveResult);
        
        if(positiveResult) {
            String mixString = mixToString(mTrimixSelector.getMix());
            if(callChangeListener(mixString)) {
                setMix(mixString);
            }
        }
        ((ViewGroup)mTrimixSelector.getParent()).removeView(mTrimixSelector);
    }</pre>
</div><a href="http://developer.android.com/reference/android/preference/Preference.html#callChangeListener%28java.lang.Object%29" target="_blank">callChangeListener()</a> is yet another one of those poorly explained methods. I took this implementation out of the Android source. <br />
<br />
removeView() is called because I'm not following the Android convention of creating my View in onCreateView. Without that last line, the dialog will work the first time but if the user opened it again a force close will result because mTrimixSelector is already bound to a view. This is cleanup, and as a plus I don't have to recreate my TrimixSelector when the dialog reopens.<br />
<br />
<b>onSaveInstanceState and onRestoreInstanceState</b><br />
These are the typical instance state methods, along with a SavedState object that can store and give back the mix string.<br />
<br />
I won't copy and paste it here; the implementation came out of Android sources. Essentially we have to encapsulate the superclass's instance state into our own custom object, which also contains our mix string. On restore, we extract our data and pass the superclass the state it had saved for itself.<br />
<br />
<b>Reading the preference value</b><br />
I need to be able to retrieve the topup mix as a Mix object. To do this in my Activities, I merely call the TrimixPreference stringToMix static method:<br />
<div style="margin:20px; margin-top:5px">
	<div class="smallfont" style="margin-bottom:2px">Code:</div>
	<pre class="alt2" dir="ltr" style="
		margin: 0px;
		padding: 6px;
		border: 1px inset;
		width: 640px;
		height: 50px;
		text-align: left;
		overflow: auto">SharedPreferences settings = PreferenceManager.getDefaultSharedPreferences(this);
mTopup = TrimixPreference.stringToMix(settings.getString(&quot;topup_gas&quot;, &quot;0.21 0&quot;));</pre>
</div>Otherwise, access is the same as any other value.<br />
<br />
That's all you should need in order to build your own DialogPreference subclasses. I don't fully understand it all, but I was able to get it working. Admittedly there's still some cleanup and optimization to do.</div>

]]></content:encoded>
			<dc:creator>divestoclimb</dc:creator>
			<guid isPermaLink="true">http://androidcommunity.com/forums/blog.php?b=361</guid>
		</item>
		<item>
			<title>Building reusable custom views, part 2</title>
			<link>http://androidcommunity.com/forums/blog.php?b=357</link>
			<pubDate>Sun, 11 Oct 2009 23:09:52 GMT</pubDate>
			<description>This is a continuation from my last post. This gets into the complicated, annoying parts that are the result of some limitations in the Android...</description>
			<content:encoded><![CDATA[<div>This is a continuation from my last post. This gets into the complicated, annoying parts that are the result of some limitations in the Android framework.<br />
<br />
<b>Internal listeners</b><br />
I'll omit most of the internals of my Button OnClickListener and <a href="http://developer.android.com/reference/android/text/TextWatcher.html" target="_blank">TextWatcher</a> implementations, except where there's something really strange going on. For instance, how I detect whether a value change came from the user or not (which I need to pass to my ValueChangedListener) is not easy.<br />
<br />
First, we know that if the user enters a value directly into the EditText using the keyboard, the first thing to get called within our class is going to be the TextWatcher. The only way the TextWatcher can tell if the user caused that change, then, is if <i>every other possible way text can change, I set a variable that the TextWatcher can check so it knows the change did not come from the user</i>. The TextWatcher could then infer when a change <i>did</i> come from the user because we didn't tell it otherwise.<br />
<br />
The way this works is with a boolean member variable mChangeFromUser. This variable is normally always true, except when setValue() is called:<br />
<div style="margin:20px; margin-top:5px">
	<div class="smallfont" style="margin-bottom:2px">Code:</div>
	<pre class="alt2" dir="ltr" style="
		margin: 0px;
		padding: 6px;
		border: 1px inset;
		width: 640px;
		height: 82px;
		text-align: left;
		overflow: auto">    public void setValue(float value) {
        mChangeFromUser = false;
        mEditText.setText(mNumberFormat.format(getValidValue(value)));
    }</pre>
</div>The TextWatcher can then detect the change was <i>not</i> from the user. Of course, this variable needs to be reset before the next change so the TextWatcher switches it back:<br />
<div style="margin:20px; margin-top:5px">
	<div class="smallfont" style="margin-bottom:2px">Code:</div>
	<pre class="alt2" dir="ltr" style="
		margin: 0px;
		padding: 6px;
		border: 1px inset;
		width: 640px;
		height: 114px;
		text-align: left;
		overflow: auto">    public void afterTextChanged(Editable s) {
        // Validation code here, decide whether
        // or not to call ValueChangedListener

        mChangeFromUser = true;
    }</pre>
</div>Unfortunately, <i>it's just not that simple</i>. What about the plus and minus buttons? If I were to use setValue() now to adjust the value in my button listeners, the TextWatcher wouldn't interpret that as a user change. We can work around this if we instead call setText on the EditText directly:<br />
<div style="margin:20px; margin-top:5px">
	<div class="smallfont" style="margin-bottom:2px">Code:</div>
	<pre class="alt2" dir="ltr" style="
		margin: 0px;
		padding: 6px;
		border: 1px inset;
		width: 640px;
		height: 98px;
		text-align: left;
		overflow: auto">    public void onClick(View v) {
        // Lots of code to compute the new incremented value

        mEditText.setText(mNumberFormat.format(new_val));
    }</pre>
</div>This brings up an interesting side effect of this design: anything that tries to use the setText method directly will cause the TextWatcher to think the user made the change, but in reality things don't always work that way. setText() gets called when the EditText is restoring its instance state, which happens soon after initialization. I came up with a very simple workaround for this in initNumberSelector:<br />
<div style="margin:20px; margin-top:5px">
	<div class="smallfont" style="margin-bottom:2px">Code:</div>
	<pre class="alt2" dir="ltr" style="
		margin: 0px;
		padding: 6px;
		border: 1px inset;
		width: 640px;
		height: 146px;
		text-align: left;
		overflow: auto">    protected void initNumberSelector(Context context) {
        LayoutInflater i = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        i.inflate(SELECTOR_LAYOUT, this);

        mChangeFromUser = false;

        ...
    }</pre>
</div>That was easy! I thought this might cause a problem if no state was being restored, but in practice it seems fine. This may be because I always initialize the value in the widget with setValue() in my Activities' onResume() methods, and after setValue() is called the TextWatcher will set mChangeFromUser back to true anyway.<br />
<br />
<b>Saving/Restoring Instance State</b><br />
Everything I've outlined so far works just fine... until you put more than one of these widgets in a layout and start switching screen orientations. Why? Well, Android destroys and recreates your Activity when the screen orientation changes, but it has its own builtin way to preserve state within its widgets so this is transparent to the user. Any stateful widget (EditText is one, SeekBar is another) will save a <a href="http://developer.android.com/reference/android/os/Parcelable.html" target="_blank">Parcelable</a> object for its current state, and it will be indexed by the ID of the widget's view. Well, we specified in our layout XML that all EditTexts that are part of a NumberSelector widget have id R.id.text1! That means Android can't properly save/restore the state of our widget.<br />
<br />
The full solution for this can get incredibly annoying, but luckily with the NumberSelector example it's not too bad. The only way the EditText can save and restore its state successfully is if we assign it an ID that's guaranteed to be unique within the root view. To generate such an ID, I built this static method in its own class:<br />
<div style="margin:20px; margin-top:5px">
	<div class="smallfont" style="margin-bottom:2px">Code:</div>
	<pre class="alt2" dir="ltr" style="
		margin: 0px;
		padding: 6px;
		border: 1px inset;
		width: 640px;
		height: 210px;
		text-align: left;
		overflow: auto">public class ViewId {

	public static int generateUnique(View v) {
		Random r = new Random();
		
		int id;
		do {
			id = r.nextInt();
		} while(id &lt;= 0 || v.findViewById(id) != null);
		return id;
	}
}</pre>
</div>You pass generateUnique the root view, and it will return a valid ID that's not in use.<br />
<br />
Now we can reassign our EditText ID's in initNumberSelector:<br />
<div style="margin:20px; margin-top:5px">
	<div class="smallfont" style="margin-bottom:2px">Code:</div>
	<pre class="alt2" dir="ltr" style="
		margin: 0px;
		padding: 6px;
		border: 1px inset;
		width: 640px;
		height: 258px;
		text-align: left;
		overflow: auto">	protected void initNumberSelector(Context context) {
		LayoutInflater i = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
		i.inflate(SELECTOR_LAYOUT, this);

		mChangeFromUser = false;

		mPlusButton = (ImageButton)findViewById(R.id.plus);
		mMinusButton = (ImageButton)findViewById(R.id.minus);
		mEditText = (EditText)findViewById(R.id.text1);
		setEditTextId(ViewId.generateUnique(getRootView()));
}

	protected void setEditTextId(int id) {
		mEditText.setId(id);
	}</pre>
</div>That was easy... too easy! It turns out this isn't the full answer because, when the Activity is destroyed and recreated, the random ID we gave to the EditText will be gone. We need to know what the ID was last time, and the way we do that is to implement state saving within our widget. Here's how that works, using various implementations in the Android framework for guidance:<br />
<div style="margin:20px; margin-top:5px">
	<div class="smallfont" style="margin-bottom:2px">Code:</div>
	<pre class="alt2" dir="ltr" style="
		margin: 0px;
		padding: 6px;
		border: 1px inset;
		width: 640px;
		height: 498px;
		text-align: left;
		overflow: auto">	public static class SavedState extends BaseSavedState {
		int textId;

		SavedState(Parcelable superState) {
			super(superState);
		}

		@Override
		public void writeToParcel(Parcel out, int flags) {
			super.writeToParcel(out, flags);
			
			out.writeInt(textId);
		}

		public static final Parcelable.Creator&lt;SavedState&gt; CREATOR
				= new Parcelable.Creator&lt;SavedState&gt;() {
			public SavedState createFromParcel(Parcel in) {
				return new SavedState(in);
			}

			public SavedState[] newArray(int size) {
				return new SavedState[size];
			}
		};

		private SavedState(Parcel in) {
			super(in);
			textId = in.readInt();
		}
	}

	@Override
	public Parcelable onSaveInstanceState() {
		Parcelable superState = super.onSaveInstanceState();

		SavedState ss = new SavedState(superState);
		ss.textId = mEditText.getId();

		return ss;
	}

	@Override
	public void onRestoreInstanceState(Parcelable state) {
		SavedState ss = (SavedState)state;
		super.onRestoreInstanceState(ss.getSuperState());

		setEditTextId(ss.textId);
	}</pre>
</div>Essentially we're building a custom class that implements Parcelable, an interface for saving and restoring data. We put the ID of the EditText we created into it, and pull it back out when the instance state for our widget is restored.<br />
<br />
If you're building a complex UI architecture like I was, here's another thing to keep in mind here: this solution made NumberSelector itself a stateful widget just like EditText! If you were to build another custom view that contained a NumberSelector, you would have to assign random ID's to that NumberSelector too.<br />
<br />
That's all the basics that were needed to make this widget work. I've made some other tweaks to the implementation to improve the user experience, but I'll save those for another post.<br />
<br />
All that work is worth it, though, because in the end you have your own custom widget that implements a correct object model and has a modular layout. You can also define different layout XML files for different screen orientations, and the widget won't have to do anything special to load them. The best part for me, though, was deleting all the repetitive findViewById(...) calls I was making in my main Activity before I built this.</div>

]]></content:encoded>
			<dc:creator>divestoclimb</dc:creator>
			<guid isPermaLink="true">http://androidcommunity.com/forums/blog.php?b=357</guid>
		</item>
		<item>
			<title>Building reusable custom views</title>
			<link>http://androidcommunity.com/forums/blog.php?b=356</link>
			<pubDate>Sun, 11 Oct 2009 22:21:35 GMT</pubDate>
			<description>It was waaay too hard to figure all of this out, and I documented some of the solution on anddev.org...</description>
			<content:encoded><![CDATA[<div>It was waaay too hard to figure all of this out, and I documented some of the solution <a href="http://www.anddev.org/custom_view_w-_edittexts_state_being_overwritten-t8174.html" target="_blank">on anddev.org</a>, but it's pretty complex so I thought I'd lay it out step-by-step for how I built a real Spinner widget in Android.<br />
<br />
I wanted to build a special widget class that would show an EditText and two buttons for entering numeric values. The two buttons would be plus and minus buttons, allowing the user to adjust the value in the box by a set increment. The box itself needed to have enforced upper and lower limits, and a precision. I also wanted to build the layout in XML.<br />
<br />
The Android developer website has a section on <a href="http://developer.android.com/guide/topics/ui/custom-components.html#compound" target="_blank">Building Custom Components</a>, but I found it pretty vague and didn't tell the whole story.<br />
<br />
First, here's my layout for the widget, res/layout/num_selector.xml:<br />
<div style="margin:20px; margin-top:5px">
	<div class="smallfont" style="margin-bottom:2px">Code:</div>
	<pre class="alt2" dir="ltr" style="
		margin: 0px;
		padding: 6px;
		border: 1px inset;
		width: 640px;
		height: 322px;
		text-align: left;
		overflow: auto">&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
&lt;merge xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;&gt;
    &lt;ImageButton
        android:src=&quot;@drawable/minus&quot;
        android:id=&quot;@+id/minus&quot;
        android:layout_width=&quot;40sp&quot;
        android:layout_height=&quot;40sp&quot;/&gt;
    &lt;EditText
        android:id=&quot;@+id/text1&quot;
        android:layout_width=&quot;wrap_content&quot;
        android:layout_height=&quot;40sp&quot;
        android:gravity=&quot;center&quot;
        android:singleLine=&quot;true&quot;/&gt;
    &lt;ImageButton
        android:src=&quot;@drawable/plus&quot;
        android:id=&quot;@+id/plus&quot;
        android:layout_width=&quot;40sp&quot;
        android:layout_height=&quot;40sp&quot;/&gt;
&lt;/merge&gt;</pre>
</div>The <a href="http://android-developers.blogspot.com/2009/03/android-layout-tricks-3-optimize-by.html" target="_blank">&lt;merge&gt; tag</a> means the contents below the root will get inserted into the parent ViewGroup directly. You will see in a moment that my class is going to extend a layout and inflate this XML into it; if I used a Layout here instead of &lt;merge&gt; it would still work, but I'd end up creating two levels of layout. This way I only create one additional level, which is more efficient.<br />
<br />
This widget is going to be inserted into a layout one or more times in order for it to be useful. Here's how it will look in a layout file:<br />
<div style="margin:20px; margin-top:5px">
	<div class="smallfont" style="margin-bottom:2px">Code:</div>
	<pre class="alt2" dir="ltr" style="
		margin: 0px;
		padding: 6px;
		border: 1px inset;
		width: 640px;
		height: 258px;
		text-align: left;
		overflow: auto">&lt;RelativeLayout xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;
       xmlns:app=&quot;http://schemas.android.com/apk/res/divestoclimb.gasmixer&quot;&gt;
    &lt;divestoclimb.gasmixer.NumberSelector
        android:id=&quot;@+id/number_o2&quot;
        android:layout_width=&quot;wrap_content&quot;
        android:layout_height=&quot;wrap_content&quot;
        android:gravity=&quot;center&quot;
        android:layout_below=&quot;@id/slider_o2&quot;
        android:layout_centerHorizontal=&quot;true&quot;
        app:textboxwidth=&quot;70sp&quot;
        app:decimalplaces=&quot;1&quot;
        app:lowerlimit=&quot;5&quot;
        app:upperlimit=&quot;100&quot;
        app:increment=&quot;1&quot; /&gt;
[...]</pre>
</div>Most of this is standard Android layout stuff, but all those &quot;app:&quot; attributes are my <a href="http://blog.pocketjourney.com/2008/05/02/android-tutorial-42-passing-custom-variables-via-xml-resource-files/" target="_blank">custom attributes</a> for this widget. In order to get this to work, you have to specify the &quot;xmlns:app=...&quot; line in the root element. It doesn't have to point to a valid URL; when the compiler processes this line, it takes the last part of the URL, &quot;divestoclimb.gasmixer&quot; in this case, and uses that path to figure out what attributes are allowed under the &quot;app&quot; namespace. The rest can be made up.<br />
<br />
Now you need to define the attributes in res/values/attrs.xml like so:<br />
<div style="margin:20px; margin-top:5px">
	<div class="smallfont" style="margin-bottom:2px">Code:</div>
	<pre class="alt2" dir="ltr" style="
		margin: 0px;
		padding: 6px;
		border: 1px inset;
		width: 640px;
		height: 178px;
		text-align: left;
		overflow: auto">&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
&lt;resources&gt;
    &lt;declare-styleable name=&quot;NumberSelector&quot;&gt;
        &lt;attr name=&quot;textboxwidth&quot; format=&quot;dimension&quot; /&gt;
        &lt;attr name=&quot;decimalplaces&quot; format=&quot;integer&quot; /&gt;
        &lt;attr name=&quot;increment&quot; format=&quot;float&quot; /&gt;
        &lt;attr name=&quot;lowerlimit&quot; format=&quot;float&quot; /&gt;
        &lt;attr name=&quot;upperlimit&quot; format=&quot;float&quot; /&gt;
    &lt;/declare-styleable&gt;
&lt;/resources&gt;</pre>
</div>Okay, that's all the XML we need. Now for the Java code: <a href="http://code.google.com/p/gasmixer/source/browse/trunk/gasmixer/src/divestoclimb/gasmixer/NumberSelector.java" target="_blank">NumberSelector.java</a> I'll only call attention to the high-level pieces that make it all work:<br />
<br />
<b>The class declaration</b><br />
<div style="margin:20px; margin-top:5px">
	<div class="smallfont" style="margin-bottom:2px">Code:</div>
	<pre class="alt2" dir="ltr" style="
		margin: 0px;
		padding: 6px;
		border: 1px inset;
		width: 640px;
		height: 34px;
		text-align: left;
		overflow: auto">public class NumberSelector extends LinearLayout implements ... {</pre>
</div>The class extends LinearLayout, which is why we can include it in a XML file. Everything in the &lt;merge&gt; section in our layout XML file is going to get added to this layout, so use the layout manager you want based on the widget design. My Trimix selector uses a RelativeLayout instead, for instance.<br />
<br />
<b>The constructors</b><br />
<div style="margin:20px; margin-top:5px">
	<div class="smallfont" style="margin-bottom:2px">Code:</div>
	<pre class="alt2" dir="ltr" style="
		margin: 0px;
		padding: 6px;
		border: 1px inset;
		width: 640px;
		height: 450px;
		text-align: left;
		overflow: auto">    public NumberSelector(Context context) {
        super(context);
        initNumberSelector(context);
    }

    public NumberSelector(Context context, AttributeSet attrs) {
        super(context, attrs);
        initNumberSelector(context);
        TypedArray a = context.obtainStyledAttributes(attrs,
                R.styleable.NumberSelector);
        
        int textWidth = a.getDimensionPixelSize(R.styleable.NumberSelector_textboxwidth, 0);
        if(textWidth &gt; 0) {
            mEditText.setWidth(textWidth);
        }
        
        mIncrement = a.getFloat(R.styleable.NumberSelector_increment, 1);
        mLowerLimit = a.getFloat(R.styleable.NumberSelector_lowerlimit, 0);
        if(a.hasValue(R.styleable.NumberSelector_upperlimit)) {
            mUpperLimit = a.getFloat(R.styleable.NumberSelector_upperlimit, 0);
        } else {
            mUpperLimit = null;
        }
        setDecimalPlaces(a.getInt(R.styleable.NumberSelector_decimalplaces, 0));
        
        a.recycle();
    }</pre>
</div>As far as I can tell, both constructors should be defined. To eliminate copy-pasting, I created a common method initNumberSelector() that does all the setup for both constructors that I'll get to in a minute. For now, just assume all it does is inflate our view from the XML, set up the member variables, and attach the internal class listeners like this:<br />
<div style="margin:20px; margin-top:5px">
	<div class="smallfont" style="margin-bottom:2px">Code:</div>
	<pre class="alt2" dir="ltr" style="
		margin: 0px;
		padding: 6px;
		border: 1px inset;
		width: 640px;
		height: 258px;
		text-align: left;
		overflow: auto">    protected void initNumberSelector(Context context) {
        LayoutInflater i = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        i.inflate(SELECTOR_LAYOUT, this);

        mPlusButton = (ImageButton)findViewById(R.id.plus);
        mMinusButton = (ImageButton)findViewById(R.id.minus);
        mEditText = (EditText)findViewById(R.id.text1);
        if(mPlusButton != null) {
            mPlusButton.setOnClickListener(this);
        }
        if(mMinusButton != null) {
            mMinusButton.setOnClickListener(this);
        }
        mEditText.addTextChangedListener(this);
    }</pre>
</div>The second constructor parses our attributes. It's mostly straightforward, but notice how I did &quot;textboxwidth&quot;; it's a <a href="http://developer.android.com/guide/topics/resources/available-resources.html#dimension" target="_blank">dimension</a> that can be specified in XML using any of the predefined Android screen units like &quot;sp&quot; or &quot;dp&quot;. At the Java level, though, Android converts this to a pixel value for you using the <a href="http://developer.android.com/reference/android/content/res/TypedArray.html#getDimensionPixelSize%28int,%20int%29" target="_blank">getDimensionPixelSize()</a> method, and with that I was able to set the EditText width in pixels using setWidth().<br />
<br />
<b>Public API</b><br />
The following are the public methods for my widget, which will help in understanding how the rest works:<br />
<div style="margin:20px; margin-top:5px">
	<div class="smallfont" style="margin-bottom:2px">Code:</div>
	<pre class="alt2" dir="ltr" style="
		margin: 0px;
		padding: 6px;
		border: 1px inset;
		width: 640px;
		height: 498px;
		text-align: left;
		overflow: auto">    /**
     * Set the value of the text field
     * @param value The value to set
     */
    public void setValue(float value);

    /**
     * Get the text field's current value
     * @return The current value of the field, or null if the value is invalid for the
     * current constraints
     */
    public Float getValue();

    public void setValueChangedListener(ValueChangedListener l);

    /**
     * Set the amount to increment the value by when the plus or minus button is pressed
     * @param increment The amount to increment
     */
    public void setIncrement(float increment);

    /**
     * Set the number of decimal places the text field allows.
     * @param places The number of places to allow.
     */
    public void setDecimalPlaces(int places);

    /**
     * Set the upper and lower limit for values in the text field.
     * @param lower_limit The lower limit (or null for no limit)
     * @param upper_limit The upper limit (or null for no limit)
     */
    public void setLimits(Float lower_limit, Float upper_limit);</pre>
</div>setValue() and getValue() are the most important. They are the interface through which values can be changed programatically. I also allow attaching a custom listener to the widget so my activities can know when the value changes:<br />
<div style="margin:20px; margin-top:5px">
	<div class="smallfont" style="margin-bottom:2px">Code:</div>
	<pre class="alt2" dir="ltr" style="
		margin: 0px;
		padding: 6px;
		border: 1px inset;
		width: 640px;
		height: 162px;
		text-align: left;
		overflow: auto">    public static interface ValueChangedListener {
        /**
         * Called when the value of the number in the NumberSelector changes
         * @param ns The NumberSelector containing the number that changed 
         * @param new_val The new value
         * @param from_user Set to true if the user manipulated the value manually.
         */
        abstract void onChange(NumberSelector ns, Float new_val, boolean from_user);
    }</pre>
</div>Making that from_user piece work according to spec is a real bear which we'll see when I get into the finer details of making this work in my next post.</div>

]]></content:encoded>
			<dc:creator>divestoclimb</dc:creator>
			<guid isPermaLink="true">http://androidcommunity.com/forums/blog.php?b=356</guid>
		</item>
		<item>
			<title>Gas Mixer activity</title>
			<link>http://androidcommunity.com/forums/blog.php?b=355</link>
			<pubDate>Sun, 11 Oct 2009 21:22:07 GMT</pubDate>
			<description><![CDATA[I've been putting a lot of time into Gas Mixer lately! I released v 2.0 and followed it up today with 2.5. 
 
2.0 was a nearly complete rewrite of...]]></description>
			<content:encoded><![CDATA[<div>I've been putting a lot of time into Gas Mixer lately! I released v 2.0 and followed it up today with 2.5.<br />
<br />
2.0 was a nearly complete rewrite of the interface. I've removed the OpenIntents sliders and replaced them with Android SeekBars, color-coded for oxygen and helium. I also made lots of UI changes to avoid scrolling at all costs. I came to realize on a mobile platform it's just as inconvenient to have to navigate to a new screen as it is to scroll down on a long one. Support for MOD's, EAD's, and END's was also added.<br />
<br />
2.5 was essentially a redesign of the backend calculations to support Van der Waals mixing. All of the diving physics has been encapsulated into a separate project, a Java library I call ScubaLib.<br />
<br />
In order to make Van der Waals computations possible, I had to let the user enter cylinder sizes. I decided to go the modular route and take advantage of the Android platform--I made a new app called ScubaTanks that lets you manage favorite cylinder sizes. That app makes a content provider available to look up cylinders and can handle intents to look up sizes. A savvy programmer will notice I named the app &quot;divestoclimb.scuba.equipment&quot;; this is a hint that I plan to expand this app in the future to be a complete equipment inventory management app that sets alerts when tanks, regulators, etc. need inspection or service.<br />
<br />
I'm also working on a rebreather checklist application. The project got derailed when I shifted attention back to Gas Mixer, but I'll try to get it finished next.<br />
<br />
I'll be doing more posts soon on some of the design choices I've made in my apps in hopes that they teach others.</div>

]]></content:encoded>
			<dc:creator>divestoclimb</dc:creator>
			<guid isPermaLink="true">http://androidcommunity.com/forums/blog.php?b=355</guid>
		</item>
		<item>
			<title>My fitness hut blog how to avoid travel weight gain</title>
			<link>http://androidcommunity.com/forums/blog.php?b=350</link>
			<pubDate>Tue, 06 Oct 2009 09:21:23 GMT</pubDate>
			<description>Some of you travel as much as 200 days a year! You have to get your eating under control or your 
weight will quickly get out of control! 
  
If you...</description>
			<content:encoded><![CDATA[<div>Some of you travel as much as 200 days a year! You have to get your eating under control or your<br />
weight will quickly get out of control!<br />
 <br />
If you are a frequent flyer or driver, you know the food traps found in airport or roadside<br />
restaurants! The food choices are usually high-calorie, high-carb and high-fat. And, you know how<br />
much money you can waste at these food establishments. So, don't just plan and pack your clothes!<br />
Plan and pack your foods also!<br />
 <br />
Eating while you travel can turn into a weight gain disaster! Try to stay with your meal plan as<br />
much as possible while traveling. Haphazard eating or grazing will skyrocket your calories and pack<br />
pounds on your body! <br />
 <br />
The simple solution is to plan and pack nutritious foods like sandwiches with lean meats, salads,<br />
nuts, fruit, yogurt, yogurt smoothies, popcorn, etc. And drink plenty of water or unsweetened tea<br />
(and not high-calorie designer coffees!). You can't go wrong with those foods and drinks.....maybe<br />
you can come up with yours....just have a plan and follow it!<br />
 <br />
Get My Fitness Hut's 7-Day Weight Loss And Fat Loss e-Course! The e-Course is FREE and you get a<br />
FREE MEAL PLAN! Use the course while you travel! <br />
 <br />
&quot;Exercise is not my life.....exercise makes my life better!&quot;<br />
 <br />
Check out my other great blogs:<br />
 <br />
Her Fitness Hut Blog <br />
 <br />
Best 100 Health and Nutrition Blogs for Athletes! The blog has also been named as one of the &quot;50<br />
Best Sports Medicine Blogs by Masters In Healthcare! It is an honor to be recognized by those in the<br />
health and academic fields! Afterall, health is number one for everybody---including athletes!</div>

]]></content:encoded>
			<dc:creator>xerocity</dc:creator>
			<guid isPermaLink="true">http://androidcommunity.com/forums/blog.php?b=350</guid>
		</item>
		<item>
			<title>Our developed app for ADC2</title>
			<link>http://androidcommunity.com/forums/blog.php?b=342</link>
			<pubDate>Sun, 13 Sep 2009 13:03:48 GMT</pubDate>
			<description>We have created two application for adc2 
 
PlayInGo: The game PlayInGo is a new type of gaming and a new experience. In this game your android...</description>
			<content:encoded><![CDATA[<div>We have created two application for adc2<br />
<br />
PlayInGo: The game PlayInGo is a new type of gaming and a new experience. In this game your android powered mobile phone will be used as a real bat. And you as a player will be hitting a virtual ball in a virtual environment as much as you can.<br />
<br />
url : <a href="http://www.green-coder.com/playingo/" target="_blank">http://www.green-coder.com/playingo/</a><br />
<br />
GestureCommander : This software allows you to execute tasks e.g., making calls, sending sms,launching applications, opening websites and altering system settings etc by gesturing. Command your mobile by movement gesture with a handy Widget. It brings a new era of interacting with software.<br />
<br />
<a href="http://www.green-coder.com/gesturecommander/" target="_blank">http://www.green-coder.com/gesturecommander/</a><br />
<br />
please have a look and let us know your thought.</div>

]]></content:encoded>
			<dc:creator>avishekworld</dc:creator>
			<guid isPermaLink="true">http://androidcommunity.com/forums/blog.php?b=342</guid>
		</item>
		<item>
			<title><![CDATA[Official : Sig & Avatar Request Thread]]></title>
			<link>http://androidcommunity.com/forums/blog.php?b=261</link>
			<pubDate>Thu, 06 Aug 2009 16:16:59 GMT</pubDate>
			<description>---Quote (Originally by Lukster)--- 
Its in my Albums just in case you want to download...  Hope you like it!   
 
 
Image:...</description>
			<content:encoded><![CDATA[<div><div style="margin:20px; margin-top:5px; ">
	<div class="smallfont" style="margin-bottom:2px">Quote:</div>
	<table cellpadding="6" cellspacing="0" border="0" width="100%">
	<tr>
		<td class="alt2" style="border:1px inset">
			
				<div>
					Originally Posted by <strong>Lukster</strong>
					<a href="showthread.php?p=232295#post232295" rel="nofollow"><img class="inlineimg" src="http://androidcommunity.com/forums/images/buttons/viewpost.gif" border="0" alt="View Post" /></a>
				</div>
				<div style="font-style:italic">Its in my Albums just in case you want to download...  Hope you like it!  <br />
<br />
<br />
<img src="http://androidcommunity.com/forums/members/lukster/albums/custom-sigs/1943-gardenwife.jpg" border="0" alt="" /></div>
			
		</td>
	</tr>
	</table>
</div>If your in the Market for a Siggy or Avatar..  Let me know..  View my Album of signatures in my profile to see the one done for the AC.</div>

]]></content:encoded>
			<dc:creator>Lukster</dc:creator>
			<guid isPermaLink="true">http://androidcommunity.com/forums/blog.php?b=261</guid>
		</item>
		<item>
			<title>Digestive disorders healthy lifestyle</title>
			<link>http://androidcommunity.com/forums/blog.php?b=213</link>
			<pubDate>Tue, 07 Jul 2009 07:23:52 GMT</pubDate>
			<description>Hepatitis A is a highly contagious disease caused by the Hepatitis A virus (HAV). It can cause 
delibiting liver disease. Clinical symptoms commonly...</description>
			<content:encoded><![CDATA[<div>Hepatitis A is a highly contagious disease caused by the Hepatitis A virus (HAV). It can cause<br />
delibiting liver disease. Clinical symptoms commonly last for about 4 weeks, but in 20% a relapse<br />
may occur and symptoms may persist for up to 6 months. <br />
<br />
Hepatitis A is prevalent in places with poor standard of hygiene and sanitation. As the standard of<br />
living is improving in this country and less cases are reported, there is an increased pool of<br />
non-immune population who are at risk of contracting the disease if they are exposed to the virus. <br />
<br />
The Symptoms of Hepatitis A<br />
<br />
At the beginning, symptoms are like those of the flu - fever, stomach cramps, sickness, diarrhoea,<br />
tiredness, joint pain, headache and usually begin with loss of appetite, malaise, nausea, vomiting<br />
and increasing tiredness. A week later, they are followed by jaundice (yellowness) of the skin and<br />
the whites of the eyes. These symptoms can last up to six months in some individuals. <br />
<br />
The Transmission of Hepatitis A<br />
<br />
It is most frequently transmitted through ingestion of food (salads, fruits, other uncooked foods)<br />
or drink contaminated with small amounts of infected faecal matter. It can also be transmitted by<br />
shellfish taken from sewage-contaminated seawater, raw or partially cooked clams, oysters, ****les,<br />
and mussels or by close person-to-person contact with infected persons. <br />
<br />
The People At Risk of Hepatitis A<br />
<br />
Consumers of raw and semi-cooked shellfish e.g. oysters, ****les, clams <br />
<br />
Food handlers <br />
<br />
Close contacts of infected persons, including those within families <br />
<br />
Those providing day care to groups of young children, the mentally and physically handicapped<br />
persons <br />
<br />
Sewerage workers <br />
<br />
Inmates in homes for the mentally retarded <br />
<br />
Drug abusers <br />
<br />
Individual with underlying chronic liver disease such as Hepatitis B or C, other non viral disease<br />
such as drup or alcoholism <br />
<br />
People with clotting factor disorders, haemophiliacs etc. <br />
<br />
People working with Hepatitis A virus in an experiment lab setting <br />
<br />
Travelers to places with crowded, unhygienic living conditions <br />
<br />
What is Hepatitis B<br />
<br />
Hepatitis B is a serious disease worldwide caused by the hepatitis B virus (HBV). It can lead to to<br />
complications including chronic hepatitis (persistent liver inflammation), liver cirrhosis<br />
(hardening of the liver), liver failure, and liver cancer. <br />
<br />
It is spread by individuals with active disease and, more significantly, by an estimated 300-350<br />
million carriers worldwide. About 2000 million people get infected with the virus and 2 million<br />
people die each year from consequential liver disease. <br />
<br />
The Symptoms of Hepatitis B<br />
<br />
The first symptoms are like those of flu - fever, chills, tiredness, headache, abdominal pain,<br />
vomiting, loss of appetite, aching muscles and joints. Later on, jaundice (yellowness) of the skin<br />
and whites of the eyes developed; there will also be dark urine and paleness of faeces. <br />
<br />
Hepatitis A &amp; B infections manifest almost similar symptoms in infected patients. <br />
<br />
The Transmission of Hepatitis B<br />
<br />
The virus is passed through infected blood or other body fluids such as saliva, semen, or vaginal<br />
secretions. The disease can therefore be contracted through the use of infected personal hygiene<br />
items (e.g. razor blades, toothbrushes etc) or needles, or through sexual intimacy with infected<br />
person. <br />
<br />
The People At Risk of Hepatitis B<br />
<br />
People who play contact sports and are likely to suffer cuts and abrasions <br />
<br />
Health-care workers, laboratory technicians and other workers who come frequently into contact with<br />
blood of blood derivatives <br />
<br />
People who share food with infected persons <br />
<br />
Sexually promiscuous youths, homosexuals, prostitutes <br />
<br />
Persons receiving acupuncture treatment or who are having themselves tattooed <br />
<br />
 <br />
<br />
Babies born to carrier mothers <br />
<br />
Close contacts of acute hepatitis B patients and chronic carriers <br />
<br />
Intravenous drug abusers <br />
<br />
Prevention Against Hepatitis A and Hepatitis B<br />
<br />
Hepatitis A &amp; B are vaccine preventable diseases. <br />
<br />
A combined hepatitis A &amp; B vaccine is now available in a single administration. It is highly<br />
efficacious and well tolerated and can be used in person aged 16 years and above who has not been<br />
immune to both hepatitis A &amp; B. <br />
<br />
It can be administered through a 3 dose-schedule over a period of 6 months. This include the first<br />
dose at elected date, the second dose at 1 month later and the third dose at 6th month from the<br />
first dose. <br />
<br />
This means that you can now get double protection through a single injection! <br />
<br />
Hepatitis A &amp; B vaccines are also available in separate injections. If you are vaccinated against<br />
hepatitis B alone, you are not protected against hepatitis B and vice versa.</div>

]]></content:encoded>
			<dc:creator>xerocity</dc:creator>
			<guid isPermaLink="true">http://androidcommunity.com/forums/blog.php?b=213</guid>
		</item>
		<item>
			<title><![CDATA[Is this the g1's big brother??]]></title>
			<link>http://androidcommunity.com/forums/blog.php?b=205</link>
			<pubDate>Tue, 30 Jun 2009 07:20:53 GMT</pubDate>
			<description>I got the mytouch in and, i dont really know what to say about it yet. its sleek but im still taking it for a test ride, lets see what happens</description>
			<content:encoded><![CDATA[<div><font face="Arial Black">I got the mytouch in and, i dont really know what to say about it yet. its sleek but im still taking it for a test ride, lets see what happens<br />
<br />
<br />
<br />
</font></div>

]]></content:encoded>
			<dc:creator>dres3733</dc:creator>
			<guid isPermaLink="true">http://androidcommunity.com/forums/blog.php?b=205</guid>
		</item>
	</channel>
</rss>
