Quick summary of the most important/new tips from the Parleys talk Android UI Development: Tips, Tricks Techniques at Devoxx 2010. Now free for viewing.
13:40: tool for tracking allocations in Android via Debug.setAllocationLimit(int)
25:15: example showing the use of DDMS, Heap Analysis Tool, hprof, adb shell dumpsys meminfo
36:14: don't over-invalidate when redrawing. Only redraw what you have to. Demo shows use of traceview to detect too much being re-drawn.
44:20: (new) hierarchy viewer example. You can use Annotations to export your own values, i.e. the ones you want to check in the viewer.
48:09: you can use the ViewStub to not create your Views too early. Kindof lazy-instantiation. Uses android:inflatedId.
51:15: better way of using an ImageView (e.g icon) with a TextView inside a LinearLayout: android:drawableLeft(Top/Bottom/Right). Much more efficient because not using 3 Views.
51:45: shows use of the static analysis tool 'layoutopt'. It needs an layout XML file and it tells you what can be improved.
53:45: the one you should know by now :) Don't inflate() views in ListView.getView(), re-use. Shows a graph of performance differences if you do vs if you don't.
54:24: tip on View.setDrawingCacheEnabled(true), and explains quicky how Android uses it when you flick a ListView.
Monday, October 31, 2011
Quick summary of the most important/new tips from the Parleys talk Android UI Development: Tips, Tricks Techniques at Devoxx 2010. Now free for viewing.
Monday, September 26, 2011
For an Android project I did a little while back I needed a pair of so-called segmented buttons, as they are named in iOS (see for example the official iOS API for it).
The idea is that when you select one of the buttons, it usually shows just about the same related data but in a different way (at least that's my translation of what it should do).
The Android version of it which I provide below looks currently most like the third and fourth example in the above image. But of course you can change the code to style it like the others too.
Android does not have this control out of the box. Luckily, I found a reference to the source of the Foursquared app.
In there, a segmented button control is created! Big thanks for the creators of Foursquared for sharing the code and thus of the segmented button control :)
Since the Foursquared app is quite big, I extracted the segmented buttons code from it and made it an Eclipse project, for your and my convenience. It's now just one Activity and the widget.
You can get it from here and use it anyway you like, following the Foursquared source Apache License 2.0 rules of course.
Here's two screenshots of what it will show:
Above shows at startup by default the Recent button is selected
Above shows after clicking on the Nearby button
Please not that I kept it as basic as possible; for example you'll keep seeing the progress indicator from layout/empty_loading.xml, which of course should be replaced with actual data. I also did not go through all the drawables etc to see which ones are needed and which are not, so you'll still have to clean those up.
Code has been tested on 2.1-update1.
Saturday, August 27, 2011
Interesting overview of possibilities for cleaner code using dependency injection and annotations by using the RoboGuice and/or
Clean code in Android applications
Definitely interesting possibilities, but these frameworks are quite young. And is it really worth the effort, since Activities and Intents can also be used quite effectively to keep the app loosely-coupled? Also the libraries will increase the app's size.
Not convinced yet :)
Friday, August 19, 2011
1st: "Greentooth is a master of mind control technology."
"One shake of his hand and you are under his command."
2nd: "The Hidden Task waits in the shadows, always prepared to set things right."
"The Hidden Task makes no sounds and leaves no traces."
3rd: "El Poderoso fights for justice, equality.. and fancy belts."
"El Poderoso is ready to wrestle the worst villans and pin down the biggest kingpings."
4th: "Cycle-On is a power-hungry Android who will stop at nothing."
"Cycle-On's tough metal casing makes it a formidable opponent."
Thursday, August 18, 2011
Quick post with some bullet points of lessons learned during my last Android project:
- To be able to keep strings in strings.xml apart, prefix them with the name of the Activity they belong to. So listOrdersOrderNr instead of just orderNr.
- If you inflate() a view without the parent, it won't take into account the parent's attributes like padding! Sadly apparently that trick does not seem to work in the getView() method. For that you'd have to compute the padding in dp and then set the padding of the view. E.g:
float scale = getContext().getResources().getDisplayMetrics().density;
float dpSize = 10 * scale; // So 10 would be the number of dp you want
buttonRow.setPadding((int) dpSize, (int) dpSize, (int) dpSize, (int) dpSize);
- When using a RelativeLayout, make sure you refer to other elements using "@id/someId", and not "@+id/someId". If you use the latter, Android will just create a new id named "someId" and will place the layout starting from the top of your Activity. Pretty obvious this one (the docs say the "+" creates a new id) but still an easy one to miss... So don't do:
Monday, July 4, 2011
Short summary of the Google I/O 2011 session "Android Protips: Advanced Topics for Expert Android App Developers". Full presentation can be found here.
6:35: the parallel Activity pattern: based on SDK version, start another "parallel" code line. Easy check to see what your SDK version is so you can distinguish use of more advanced APIs as for example available since HoneyComb.
8:20: use interfaces for backward compatibility
9:09: get real user feedback before launching. Note you can also of course use Analytics to log an exception!
10:38: example of doing A/B testing
11:35: use Android Market for beta testing. It seems there's no special facility for this in the market, you just have to control it yourself... e.g password protect, obscure the name.
12:31: But don't forget to protect your package name before someone else takes it! So upload and save it but don't publish it.
13:43: don't assume the default (natural) orientation on a device is portrait, e.g most tablets start in landscape. The orientation sensor's default is also 90degrees "off"
15:00: Don't track devices to detect unique installations. Give your app a unique id using a UUID, store it in the prefs.
20:00: the app's data has to be always fresh if possible, the user does not have to wait. See also this recent post: http://android-developers.blogspot.com/2011/06/deep-dive-into-location.html
25:51: how to get fresher data
32:00: make your services intelligent like do everything async, let it die asap
33:13: make your app psychic: leverage what the phone already knows, remembers what the user has told it. Like the Account Manager. Preferences should follow the user across devices and resets (which means storing them offline). Give users the ability to delete their preferences, using the Backup Manager to backup shared preferences.
38:21: intercept links using an Intent Receiver
39:25: make your apps adaptive. E.g: behave as expected, optimize for different user experiences. You can specify the IME keyboard behavior by setting the appropriate action (Go, Search, Send, Done etc). Use android:imeOptions for that
43:20: handle volume and playback buttons icw requesting audio focus for playback
47:10: provide translations for your app and title description to have it better found in people's native language
48:00: make your app smooth: make everything async. Loader and CursorLoader are available since HoneyComb.
Wednesday, June 29, 2011
In the Android Developer Console you can upload the screenshots of your app (max 8 currently) in several sizes, like 320x480, 480x800, 480x854 and 1280x800.
But it turns out that sometimes (always?) if you upload in the higher resolutions (like 480x800), the images get cropped in a weird way in the market on your phone (at least the Nexus One). The images will look fine in the online Android market, but not on a physical device. Actually, when you look closely, the dev-console gives a thumbnail of the screenshots and there you can already see that the images are cropped strangely sometimes; like the left 20-50 pixels just cut off. And that's actually how they also appear in the market on devices!
After some experimenting, it turns out this does not happen when you upload in 320x480 format.
Thus the recommended resolution to upload screenshots seems to be 320x480! Doesn't matter if you use a device (like the Galaxy S2) or emulator to take the screenshots.
Note I didnt check if the browser market image quality decreased when going from 480x800 to 320x480. Though clicking on an image in the webmarket shows the 320x480 uploaded image quite fine.
Just a quick post regarding Bluetooth on the Samsung Galaxy S II.
Recently I've been creating an app that uses Bluetooth for sending data between devices (not FTP just strings). A pretty good introduction can be found here, though some things are missing from it. Like an example how you can register a BroadcastReceiver for the ACTION_SCAN_MODE_CHANGE. Just in case you are looking for it, here it is:
Basically a device can be made discoverable by others, or a device can be set to find other devices (discover). Being discoverable is configurable up to 300 seconds max, finding other devices is not configurable and about 12 seconds.
Making a device discoverable entails the following code:
That should enable Bluetooth if it isn't already and make the device discoverable for 120 seconds, and the result of the intent comes in at onActivityResult(). For receiving Bluetooth state changes you can register a BroadcastReceiver. This all works fine on a Nexus One.
But not on all devices, their Bluetooth stack contains bugs and behaves differently:
Samsung Galaxy S II
- When you make the device discoverable, its state should become SCAN_MODE_CONNECTABLE_DISCOVERABLE, i.e value 23, meaning this device is both discoverable and connectable from remote Bluetooth devices.
On the Nexus One I see the device.getScanMode() always return 23, as it should be. But on the Galaxy S2 it sometimes just changes to scanmode SCAN_MODE_CONNECTABLE (21), making it not discoverable anymore! And indeed, other devices don't see it anymore when discovering. In the S2 phone's settings I also see in that case that the discoverable checkbox is not checked.
Workaround: the only workaround that always works seems to be to always first turn on the Bluetooth, and after that send the above discoverableIntent. Thus first do a
Intent enableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
Intent discoverableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
- When you start the discoverable intent with any number different from 120, say 300, the popup that asks for user confirmation always shows 120, instead of the different number, say 300. The discoverability actually stays on for the specified amount (300 seconds), so functionally it works (phew), but the display is just incorrect and you can't change it. Confusing for the user.
I also found a few other more generic bugs reported by others and found by myself. Maybe they were SDK or device related (my app runs on Android 2.0+, tested on N1, Wildfire and Galaxy S2):
- Connecting multiple clients
- All reported issues/bugs in Android with Bluetooth
- Some devices are just not discoverable because some phone manufacturers decided by themselves "to ignore any bluetooth device which advertises itself as class 0×00 and wont allow connections, fire off Intents on discovery or even list it on the bluetooth settings page." Nasty fix (i.e reading the logfiles!) can be found here.
- Quite annoying is also that on some devices (N1, Wildfire) the pairing request appears in the notification bar (on top of the screen). Users are very likely to miss that, causing the devices not being able to connect to eachother. On the Galaxy S2 it is a dialogbox so the user can't miss it.
Sunday, April 17, 2011
For my Android app I wanted a swipeable and horizontally slideable 3x3 grid of images. If there were more than 9 images, a swipe should show the next 3x3 grid. Another requirement was that all should be in a ScrollView because there would be more on the screen above the 3x3 grid.
The first solutions that directly came to my mind were of course the GalleryView or a GridView or a horizontal ListView.
But the final solution was a ViewFlipper with TableLayouts as its children!
Below you can find my "journey" figuring out, experimenting and getting to the solution.
List ViewLuckily for the horizontal ListView there was already a good example here. The result:
It really does work as a horizontal ListView, but it doesn't support the paging I was looking for; it is just a continuous list.
Sadly the code wasn't downloadable in one block (update: seems I just missed it at the top!), and it also contained typos (the layout tags were all lowercase), so it took me a while to get it all fixed and useable in an Eclipse project.
For people looking for the complete source code, you can find it here.
Note that the getView() has not been optimized yet, it creates a new view each time!
Also weird in the original code was the TextView within the ImageView, I changed the code to have them below each eachother.
An advantage of this implementation is that there is no "center locking" of the image anymore.
Gallery ViewSo the horizontal ListView didn't cut it, let's try a GalleryView (g1 in the code) with per item a standard GridView. That worked reasonably, except that the swiping didn't work anymore! Keypad scrolling still worked, kind of:
Luckily I found a fix for that, implementing a custom GridView that passes the fling on to the parent gallery (g2 in the code).
But then I still had to put it in a ScrollView... And then the trouble started, look at the vertical scrollbars that suddenly appear:
I ended up with quite some trial code which you can find here. Disclaimer: this is quite messy trial code so you are warned and I'm not supporting this code in any way; you are on your own here :)
Grid ViewMaking a GridView scroll horizontally in sets of 3x3 images just gave me headaches from the beginning. For example you can't set the number of rows, so it might sometimes show more rows than 3. And a GridView inside a ScrollView is also strongly warned against. Which btw also applies to ListView within a ScrollView. In general it even seems: a scrolling View inside another scrolling View is not a good idea and even strongly discouraged!
Furthermore, on a xlarge screen (WXGA) the gridview had almost its own will for laying out, making it look very different than on a HVGA screen.
The solutionAfter some more thinking I came across the solution: put Table Layouts of 3x3 images inside a ViewFlipper! Per table you can control how many images should be shown and it's quite easy to add swiping! Paging is then done per table. You can swipe left and right.
Page 2 after swiping to the left:
The source code of the final solution you can find here.
Note the top left icon in the grid changes when you swipe to the left the first time (so you can tell that the 2nd page is showing).
Note also the use of the FixedViewFlipper to handle rotation correctly.
A future improvement: keep track of the "page" you're on so with the example of 2 tables, don't allow the swipe/fling to "go round", i.e swiping to the left on the 2nd table shows the first table again...
PS: of course you could also create your custom component, but I want to avoid that as much as possible to minimize (custom) maintenance.
MiscThese links I also stumbled upon but didn't do anything with:
Hope this helps somebody some time :)
Monday, February 14, 2011
Over a year ago I managed to get iTunes 9.x.y working on my Windows XP 64 bit machine.
I had to try so many stuff, that I didn't really keep track of what I did :( The only things I wrote down were:
- At startup of iTunes 9 I did get iTunesHelper is not installed correctly or something. I just clicked it away, it didn't seem to hurt anything.
- In the end everything worked, though I manually always started Mobile Apple Device service
- I do always get the popup about not being able to burn CDs. No problem.
- When plugging in the iPod I still always get this popup:
But now (february 2011) I wanted to upgrade my iTunes 9 to iTunes 10 because my OS on my iPod Touch was still at 3.x, and more and more apps are not running on 3.x anymore, they require 4.x and higher.
I knew it was going to be a nightmare, remembering the iTunes 9 installation. But this time I decided to keep track of it as detailed as possible. Hopefully it helps somebody...
I'll write down the steps as how I did them, so read through them all before trying yourself, you might be able to skip certain steps because they didn't work... WARNING: it is definitely not a clean walk-through!
- Goal is to follow the steps from http://skunkwerks.wordpress.com/2008/04/13/getting-itunes-to-work-with-windows-xp-x64
- Downloaded the 64b Vista version iTunes64Setup.exe from the Apple site
- First thought I could just try to run the .exe, since it's just an upgrade. But after some thought, thought I needed to modify the .msi file(s), since they do a check at startup. And, since all I need is an updated iTunes I don't think I even need to run all .msi files, only the modified iTunes64.msi (with the edits from the first post, NOT the deletion of entries as in this post).
- Installer starts successful, see screenshot (sorry for the Dutch):
- Let it install where the 9.x.y was already installed: C:\Program Files (x86)\iTunes
- A popup showed saying itunes+quicktime needs sp2 or higher. See screenshot:
Just hit OK, install continues afterwards and it said successfully installed.
- And iTunes starts fine! Note that I still manually have to start the Mobile Apple service. I do that before starting iTunes, then plugin the iPod (with popup see screenshot), Then start iTunes.
I also still do always get the popup about not being able to burn CDs. No problem.
- But now i get popup saying "itunes requires a newer version of Apple Mobile Support. Please uninstall both Apple Mobile Device Support and iTunes, then install iTunes again.". See screenshot:
So it seems I do need to run AppleMobileDeviceSupport64.msi.
But first edit it also. And instead of deleting entries, also here I just change 600 to 501.
Starting AppleMobileDeviceSupport64.msi gives again needs SP2 or higher.
So I also changed (VersionNT=501 And ServicePackLevel>=2) Or VersionNT>=600
to (VersionNT=501 And ServicePackLevel>=2) Or VersionNT>=501.
Yup .msi starts now, installs update in C:\Program Files (x86)\Common Files\Apple\Mobile Device Support
Got popup saying it didn't pass windows logo testing. Continue anyway.
Again for USB driver.
And again. ipod goes on/off. Shows popup again that tries to open 2 programs when inserting ipod.
Successful!! Note that it didn't require a restart and that I did not re-install iTunes.
Yeah: ipod lights up, sync in progress
- It now asks for 4.2 upgrade of iPod software! yeah! See screenshot:
- Hit Download and update, then it says automatically checking for updates is disabled. If you hit cancel, nothing happens. So you have to select "Check this time":
Then iTunes says my iPod isn't synced, are you sure to contiue? Canceled and did that sync first, making sure all my apps etc are in iTunes too.
Selected Upgrade again, yup started downloading 4.2.1, see screenshot:
- Crap, got error 1603/1604, while popup Find new hardware wizard was suddenly showing up!
Apple support link with some more info: http://support.apple.com/kb/TS1275
Crap, can't find a driver (usbaapl). Seems it didn't get installed?
So did this order of .msi running:
Selected "recover" each time.
Still didn't work, got 1604 error or something.
Note that iTunes does see that the phone needs to be recovered, but it just fails after a long time with a 1603 or 1604 error. That indicates something is wrong with the USB connection.
- Then I manually got the driver from AppleMobileDeviceSupport64.msi as described here (using lessmsi*.exe): http://discussions.apple.com/thread.jspa?messageID=5619588
Yeah but which one do I need, the 64b or 32b? Guess the 64b, that's named usbaapl64.
Note that you need to do Have disk as in http://support.apple.com/kb/TS1538
Ah now got 1604 error (device was sometimes recognised, then windows says new device found again etc)
Did what is says here for error 1604 (turn if off etc):
Showing Preparing iPod for restore... for a long time... minutes... Again 1604 error.
So the USB driver is just not set up correctly.
You hear when you try the restore (if the device is recognised in iTunes), the USB ping "rings" twice, meaning something is happening twice or something.
Don't think that should happen. I also see the ipod flash shortly, then it's just dark.
- I did read somewhere that in this case you're kindof lost, so you need to restore the iPod OS via another PC/Mac for which everything is working. After that's on the iPod, you can restore from the 64b iTunes...
Luckily I have such a PC around: XP 32bit. Downloaded the latest iTunes 10, installed, and plugged in the iPod. iTunes detected it needed restoring so it put 4.2.1 on it! Note that I didn't give my device a name at the end of the restoring (thinking that should come from the XP 64b iTunes anyway...).
- So after this, plugged it back in on the XP 64b. But it was not seen/recognised by iTunes! Though in the Windows Device Manager it said Apple iPod!
- Then I did update the driver as in here in the part Troubleshooting iTunes <-> iPhone Link/Sync
After that, the Device Manager says Apple Mobile Device USB driver! See screenshot:
- And (since) iTunes was already started, it started immediately restoring apps! Yeah!! See screenshot progress:
Darn! An error occurred restoring this ipod (-402620395):
- Before hitting OK, I removed any provisioning files I had on the ipod as said here in the post "bkynaston post: Posted: Jun 23, 2010 6:45 PM"
Hit Ok. After this it tries to sync again.
Yes! It says: iPod sync is complete. OK to disconnect.
- And yes, finally, finally, after about 1 day of working on this, my iPod is ok again! Even the language is back to English!
Finally! Hope I never have to do this again...
Here's some other knowledgebase tip(s) that I looked at and tried
Saturday, February 12, 2011
At a recent project we used the following tools & frameworks:
- Java 6
- Spring 3.0
- Hibernate 3.2.7
- JBoss ESB 4.5/5.1
- SOAP 1.1
- Apache CXF
- Jetty 6.1
- Oracle 10g
- Eclipse Mylyn
Below are a couple of lessons learned which I remembered to write down:
- To skip a testclass (e.g Util.java) during a test in a maven project: put @Ignore above it.
- Throw checked exceptions in case of functionality errors. To not have to return those errors as return-values of the methods and making them checked, makes the interface clearer.
- Should you use the service response for functional errors, and SOAP fault only for technical errors?
Nothing in the SOAP 1.1 spec says you should do that or are not allowed to put functional errors in the <detail>.
Makes sense to me to do that: otherwise you can get errors in the response AND in the soap fault. More complex to handle in the client...
Less of an issue if you say when there are SOAP faults we just give up, only if there's a response we try to see what's going on.
- Apparent best practice: no underscores in xml/xsd/wsdl for element nor attributes, for better readability
- JBoss ESB 4.5 JMS queue had loads of problems with high load and would sometimes just completely drop the queue. We moved to JBoss ESB 5.1 with ActiveMQ, that proved much more stable.
Transactional atomic file manipulation and file locking
Bunch of interesting articles related to this:
- Lower-level stuff: http://java.sys-con.com/node/37798
- EJB/XA example: http://matthewneale.net/category/software-development/
Related to file locking:
- See reply 3: http://forums.sun.com/thread.jspa?threadID=5284898
- Another example: http://www.java2s.com/Code/Java/File-Input-Output/DemonstratesfilelockingandsimplefilereadandwriteoperationsusingjavaniochannelsFileChannel.htm
- "But if you can change/write the writing program: You have to change the design. App1 should write to "temporary" files, and when it's done, close and rename them to a naming convention that App2 will recognize as being "finished files, ready for processing"."
- Lock service, platform independent: http://www.devx.com/Java/Article/7870/1954. But requires all access via this service, so external FTP programs for example don't see the lock & the java program won't see a lock so read it.
- With Maven you can also have it put the sources + javadocs in the repository.
Running 'mvn eclipse:eclipse' after that, and refresh the project in Eclipse, within Eclipse you can then see the javadocs and debug the sources.
Just make sure you set <downloadSources> and <downloadJavadocs> to true.
- If you have an action that can't be made transactional (e.g a file move), do that as last thing in your steps. More precisely: start a (e.g database) transaction, move the file. If that move succeeds, update status that move was successful. If that move fails, rollback the transaction, and thus is the status of that file still in "to move".
Online android market website gives more details on the number of downloads/installs of an app than the market on a device (phone)!
Check for example 3D Light Racer Basic. On my Nexus One it says it has > 250000 downloads. But on the website it says 500000 - 1000000 installs! See the red arrow.
Can be pretty useful for competitor analysis for example :)