If you're like me, when you first heard about GridLayout, you were excited. Then disappointed, because it's currently only available for Ice Cream Sandwich. That is true no longer - I've taken the time to port a working version of it all the way back to Android 1.5 and above.
Check out the android-gridlayout library here.
The one caveat is that there is one method in GridLayout that I was not able to port back. As a result, when you change the visibility of a child View of a compatibility GridLayout, you should also call GridLayout.notifyChildVisibilityChanged().
Let me know what you think, especially if there are any bugs.
I post random things I've learned while coding with the hope that it will save people time and effort.
Tuesday, January 10, 2012
Tuesday, December 20, 2011
Sharing with Gmail
I read through the Android Training docs recently and came across a section which I thought I could use to improve sharing on Rage Faces (by getting rid of the need for an SD card-based share system):
Write the data to a file in your own application directory usingHowever, this setup fails to work with the Gmail. When you try to share with Gmail in this manner, an error message pops up in the logs:openFileOutput()with modeMODE_WORLD_READABLEafter whichgetFileStreamPath()can be used to return aFile. As with the previous option,Uri.fromFile()will create afile://styleUrifor your share intent.
file:// attachment paths must point to file:///mnt/sdcard. Ignoring attachment file:///data/data/com.idunnolol.ragefaces/files/share.pngI'm not sure why Gmail arbitrarily rejects attachments not on the SD card, but it pretty much cuts you off from sharing files with MODE_WORLD_READABLE. Unfortunately sharing with Gmail feels like an essential part of the app so I'm going to have to stick with SD card sharing.
Monday, October 31, 2011
TextWatchers and onRestoreInstanceState()
There's a small timing issue I'd like to mention because it's bitten me a few times now.
When you want to observe changes to an EditText, you add a TextWatcher to it (via TextView. addTextChangedListener()). There are a lot of uses for TextWatchers, like implementing your own autocomplete or filters based on a dynamic EditText. The only thing you have to be careful of is whether the text was changed by the user or the code - the listener fires either way.
What's worth knowing about an EditText is that it will save and restore the state of the text inside of it within your Activity. That means that when you rotate the screen, the EditText will restore the text that was inside of it. And most importantly, the automated restoring of the text on rotation causes the TextWatcher's methods to fire. Like I said - the TextWatcher doesn't discern between whether the user changed the EditText or the system did.
The solution is simple - just don't add the TextWatcher until after the EditText's content has been restored. It restores itself in Activity.onRestoreInstanceState(), which makes Activity.onResume() the preferred time to add TextWatchers to any EditTexts.
When you want to observe changes to an EditText, you add a TextWatcher to it (via TextView. addTextChangedListener()). There are a lot of uses for TextWatchers, like implementing your own autocomplete or filters based on a dynamic EditText. The only thing you have to be careful of is whether the text was changed by the user or the code - the listener fires either way.
What's worth knowing about an EditText is that it will save and restore the state of the text inside of it within your Activity. That means that when you rotate the screen, the EditText will restore the text that was inside of it. And most importantly, the automated restoring of the text on rotation causes the TextWatcher's methods to fire. Like I said - the TextWatcher doesn't discern between whether the user changed the EditText or the system did.
The solution is simple - just don't add the TextWatcher until after the EditText's content has been restored. It restores itself in Activity.onRestoreInstanceState(), which makes Activity.onResume() the preferred time to add TextWatchers to any EditTexts.
Monday, October 10, 2011
Android Drawable XML Talk
I recently gave a talk on the basics of Android drawable resources (via XML).
There's a recording I made of the talk - not super, but functional. I had to split it into two parts because of time restrictions on YouTube. Here's part one and part two.
I also have a few links that may be useful (whether you watch the talk or not):
- The slides for the presentation
- Official Android drawable resource documentation
- My drawable XML documentation
- The github project with my samples
There's a recording I made of the talk - not super, but functional. I had to split it into two parts because of time restrictions on YouTube. Here's part one and part two.
I also have a few links that may be useful (whether you watch the talk or not):
- The slides for the presentation
- Official Android drawable resource documentation
- My drawable XML documentation
- The github project with my samples
Monday, September 26, 2011
Logc.at
A few developers and I have formed a new Android development blog. We snagged what I think is an awesome and nerdy url: logc.at.
I will still be writing here - this blog is intended for one-off coding issues that I want to document. The new blog will be a place for me to write about Android development in a more general manner. Instead of assisting with individual hurdles, I hope my articles there will help one become a better Android developer (or at least pick up a few tips).
My first post is about working with JSON on Android. Check it out!
I will still be writing here - this blog is intended for one-off coding issues that I want to document. The new blog will be a place for me to write about Android development in a more general manner. Instead of assisting with individual hurdles, I hope my articles there will help one become a better Android developer (or at least pick up a few tips).
My first post is about working with JSON on Android. Check it out!
Tuesday, August 2, 2011
New to Android: More Style Restrictions
There have been two changes the Android platform build tools which have caught me off guard. You may run into these problems when you next update your aapt. Both of them cause compilation errors, so they're not easy to ignore, but it's not immediately obvious how to fix either.
Change #1: Implicit parenting now requires a parent
Suppose I have this style defined in styles.xml:
It was named that way after how Android sets up their widget styles (for example, "Widget.RatingBar.Small"). One thing to know is the implicit aspects to using dots in the naming is that you automatically parent all the styles before the dot. So "Widget" is the parent of "Widget.MyWidget", and "Widget.MyWidget" is the parent of "Widget.MyWidget.Small".
In the new version of aapt, you'll see this error:
This happens now because aapt is stricter with regards to style parenting. Before, if there was no parent, it would just ignore this oversight; now it requires a parent.
There are two possible solutions:
1. Rename the style so that it doesn't use implicit parenting with dots.
2. Create the parent styles. They could either be empty, or you could actually use them for something.
I think #1 makes more sense, unless you actually have a use for the parent styles.
Change #2: Some android styles are now enforced as private
Before, you used to be able to get away with parenting some non-public Android styles:
However, these styles have always been intended to be private, and the latest aapt will not allow you to build with a private parent defined. A Google employee explained the reason why this is no longer allowed:
That seems reasonable to me. The solution is to just import the entire style into your styles.xml; all the styles are open source anyways.
Change #1: Implicit parenting now requires a parent
Suppose I have this style defined in styles.xml:
<style name="Widget.MyWidget.Small"> ... </style>
It was named that way after how Android sets up their widget styles (for example, "Widget.RatingBar.Small"). One thing to know is the implicit aspects to using dots in the naming is that you automatically parent all the styles before the dot. So "Widget" is the parent of "Widget.MyWidget", and "Widget.MyWidget" is the parent of "Widget.MyWidget.Small".
In the new version of aapt, you'll see this error:
Error retrieving parent for item: No resource found that matches the given name '@Style/Widget.MyWidget'.
This happens now because aapt is stricter with regards to style parenting. Before, if there was no parent, it would just ignore this oversight; now it requires a parent.
There are two possible solutions:
1. Rename the style so that it doesn't use implicit parenting with dots.
2. Create the parent styles. They could either be empty, or you could actually use them for something.
I think #1 makes more sense, unless you actually have a use for the parent styles.
Change #2: Some android styles are now enforced as private
Before, you used to be able to get away with parenting some non-public Android styles:
<style name="MyRatingBar" parent="@android:style/Widget.RatingBar.Small"> ... </style>
However, these styles have always been intended to be private, and the latest aapt will not allow you to build with a private parent defined. A Google employee explained the reason why this is no longer allowed:
For the framework, only public resources are guaranteed to only have the same integer, build after build. The integer of private resources integer will change from build to build. This means that your custom style is referencing a parent that *will not* be valid once installed on a device. It'll referenced either another resources or none at all, and it won't do what you want.
That seems reasonable to me. The solution is to just import the entire style into your styles.xml; all the styles are open source anyways.
Thursday, June 30, 2011
Honeycomb App Widget and Backwards Compatibility
Honeycomb added some neat functionality to Android widgets. However, there's a problem that arises from adding a widget using collections to your app - what if your APK is supposed to work on all versions of Android? How do you prevent the Honeycomb-only widget from appearing in previous versions?
Normally when you want to do something different between versions of Android, you either use resource qualifiers (for XML) or check Build (for code). But in this case, the widget itself is defined in AndroidManifest.xml, which can only be at the root of your project.
There's a way of removing the app widget from the listing in previous versions: use resource qualifiers on the AppWidgetProviderInfo resource.
When you define an app widget in AndroidManifest.xml, you must also define a <meta-data> element which points towards the AppWidgetProviderInfo (that is usually contained inside of a file in /res/xml/). Simply move that provider file to a directory that only Honeycomb can see - /res/xml-v11/. Earlier versions of Android will try to load the widget only to find no AppWidgetProviderInfo and will thus ignore the widget.
UDPATE (Jan 26th, 2012): I've now written about an improved solution to this problem.
Normally when you want to do something different between versions of Android, you either use resource qualifiers (for XML) or check Build (for code). But in this case, the widget itself is defined in AndroidManifest.xml, which can only be at the root of your project.
There's a way of removing the app widget from the listing in previous versions: use resource qualifiers on the AppWidgetProviderInfo resource.
When you define an app widget in AndroidManifest.xml, you must also define a <meta-data> element which points towards the AppWidgetProviderInfo (that is usually contained inside of a file in /res/xml/). Simply move that provider file to a directory that only Honeycomb can see - /res/xml-v11/. Earlier versions of Android will try to load the widget only to find no AppWidgetProviderInfo and will thus ignore the widget.
UDPATE (Jan 26th, 2012): I've now written about an improved solution to this problem.
Subscribe to:
Posts (Atom)