Reading to optional variable from NSData in Swift

Interesting.

func doStuff(arr: Array) {
    var value: UInt8!// = 0
    let data = NSData(bytes: arr, length: arr.count * sizeof(UInt8))
    data.getBytes(&value, range: NSMakeRange(0, 1))
    println(value)
}

let arr: [UInt8] = [ 0x00, 0x34, 0x56, 0xFF ]
doStuff(arr)

value will be nil if 0x00 is read from NSData. In case value is not declared as Optional, 0 is read instead. Just something to keep in mind.

Generating JNI headers

1. Build the project, e.g. gradlew build
2. Go to the directory you want to place the headers (e.g. src/main), and execute:

javah -d jni -classpath ~/Library/Android/sdk/platforms/android-22/android.jar:../../build/intermediates/classes/debug {fully.qualified.class.name}

This will place the auto-generated headers in the src/main/jni directory. Change the platform version in front of android.jar as appropriate.

TaskStackBuilder broken?

Perhaps not broken, but documented inadequately. In http://developer.android.com/training/implementing-navigation/temporal.html there’s a simple guide on how to set up back stack navigation when opening an app e.g. from a notification using a “deep link” to an activity that is not the topmost one in the app, so that the user can navigate upwards in the stack by pressing the back key.

Having wasted a couple of hours trying to make this work in LoanShark, I finally noticed a warning in LogCat:

W/ActivityManager﹕ Permission Denial: starting Intent [...] not exported from uid 10131

What the documentation forgot to mention is that you need to set the activity you want to jump to from e.g. a notification as exported. I added the attribute and encountered no more problems. The weird thing is that it did actually sometimes work even without the exported attribute… strange indeed. But now it works 100% of the time, fortunately.

Reusing existing fragments

I’m currently in the process of making the landscape support in LoanShark more robust. When in portrait mode, the main activity displays a list of loans, while the view loan activity, opened by selecting an item from the list, displays the selected loans’ details. In landscape orientation both views are visible. These are all implemented using fragments, i.e. the activities themselves only provide the layout to glue the fragments together.

When holding the device in portrait mode, the loan view displays loan details using the same fragment class as is used on the right-hand side in landscape orientation. When the user is viewing a loan in portrait (view loan activity), and rotates the device to landscape (to main activity), the same loan is displayed.

The problem I’ve come across is that since fragment objects belong to a single Activity (stored in the Activity object’s own FragmentManager instance), there’s no way to reuse the fragment that’s seen in portrait mode of the view loan activity on the right-hand side of the landscape layout in the main activity. The reason is that when the user rotates from portrait to landscape, the activity hosting the loan details is destroyed, which in turn destroys the fragment as well.

To keep my fragment implementations modular (to break direct dependencies between them), I’ve utilized callbacks to the hosting activity class when loaders have finished their jobs. This way I’m able to know e.g. when a loan’s details have been finished so that the fragment can be created.

My initial implementation (and the one being used in version 2.2.0) is that the old fragment that was created when in landscape mode is displayed briefly before being replaced with the loan that was selected in portrait mode. This is clearly suboptimal because there’s a clear visual anomaly, however brief, when rotating the device. I considered patching the problem by hiding the existing fragment in landscape,  thus preventing the old fragment from being shown before fading in the fragment when then the new loan would have been loaded. That wouldn’t have been a solution I would’ve been satisfied with, so clearly more thinking was needed.

When a loan has been loaded in portrait mode and is about to be displayed in the view loan activity, I store the loan data in the main activity as well (and make sure it’s saved in onSaveInstanceState() in case the activity is destroyed while viewing the loan data). Then, if the user rotates the device to landscape, I check if the view loan fragment already exists (in case the device has been in landscape mode previously, it does). In such a case, I set the selected loan’s data to the existing fragment. When the activity’s onCreate() finishes, the fragment’s onCreateView() is called, and it’s there that the loan data can then be reused.

Nothing of this sort is mentioned in documentation concerning fragments. Also, it’s quite difficult to find solutions to fragment problems by googling them; all you seem to get is countless beginner tutorials on how to use fragments. I came across this solution after spending a couple of nights figuring out how the fragment management works internally, and from there I had an idea how to go on about solving the problem.

Workaround for italics texts clipping

TextView with italics text gets cropped at the rightmost edge when the view is set to wrap_content. Reportedly this affects when the content is set to have gravity=”right” as well.

http://stackoverflow.com/q/4353836

I haven’t plunged into the source code on this one, but it seems that Android’s layout engine evaluates the TextView’s width based on the text baseline, and does not take into account the fact that skewing the text may result in the projected baseline at the top (whatever it could be called) may not be the same. The solution is to simply add a space character at the end of the string.

I ran into this problem when designing the card layout for LoanShark loans. I wonder how many applications’ layouts would break if there was to be an actual fix to this problem…

Named fragment back stack states

If you’ve been dealing with Android fragments, odds are you’ve used the FragmentTransaction.addToBackStack() method. Often this method is called with a null argument, and that’s fine for most uses. Afterwards, you can pop the top of the back stack by calling FragmentManager.popBackStack() and you’re done.

You might be wondering what use is the String parameter in the addToBackStack() method. It can be quite useful in cases where you need to pop a number of items from the FragmentManager back stack at once. For example, you may want to wipe the slate clean of all fragments that you’ve been adding/replacing. You can do this as follows:

    FragmentManager fragMan = getFragmentManager();
    for (int i = 0; i < fragMan.getBackStackEntryCount(); ++i) {
        fragMan.popBackStack();
    }

Now, in case you want to leave one or more items on the back stack instead of popping the whole lot, you could try to keep track of the number of back stack items to pop, but this is tedious and error-prone to say the least. Here’s where addToBackStack()’s String argument comes to play. The String argument is the name of a back stack “state” you want to keep track of.

Let’s say that you have a two-pane layout, and on the right side you have a fragment that you’ve replace()d to a layout element. You’d like to keep this fragment visible at all times. You then proceed to utilize other fragments as well in the same layout spot, calling FragmentTransaction.replace() in the process, along with addToBackStack(). If you then want to pop all other back stack items but the first one, you can do this by adding a predefined state name to the first fragment’s addToBackStack() method:

    private static final String INITIAL_FRAGMENT_STATE = "initial_fragment_state";
    // ...
    FragmentTransaction ft = getFragmentManager().beginTransaction();
    ft.replace(...);
    ft.addToBackStack(INITIAL_FRAGMENT_STATE);

Then, when you need to wipe the slate clean and lose all but the initial state from the back stack:

    getFragmentManager().popBackStack(INITIAL_FRAGMENT_STATE);

And there you have it. No need to keep track of the number of fragments in the back stack in each valid state of the application or any such nonsense. Just make use of named back stack states.

LoanShark 2.0

LoanShark_1

A while back I released a new, completely-rewritten version of LoanShark. The current version is 2.0.6 which contains a number of

bugfixes, and I consider it to be quite stable. I think writing this version took considerably more effort than the first one, or maybe I have just forgotten how much effort went into the first attempt.

There were problems with database migration code from the previous version. I’ve done away with some tables altogether to make things simpler, which necessitated writing quite a bit of migration code. Migration is both engaging and frustrating at the same time. On one side there’s the need to evaluate the old and new database structures exactly and trying to figure out the simplest way to transfer old data to the new format. On the other side there’s no way around writing migration code unless you want to make your app crash on your users’ faces when they update to the latest version.

I thought I had ironed out the potential migration issues before releasing the first update, but there were several bug reports from users. I guess most of the users don’t bother to send an error report when an app crashes on startup; they’ll just uninstall it and be on their merry way. Fortunately it also seems that they don’t even bother to write those nasty 1-star reviews either.

During last week I was contacted by two users who had crashing problems, one of which wasn’t related to database migration. I’m very thankful for all feedback, even if it’s crash reports. It gives me the extra kick in the backside that keeps me motivated to continue development.

Force GC from shell

To force the garbage collector to run from adb shell, first find out the target process’ id (using e.g. ps), and then execute this in the shell (as root):

kill -10 <pid>

You should see GC_EXPLICIT in logcat:

I/dalvikvm﹕ threadid=3: reacting to signal 10
I/dalvikvm﹕ SIGUSR1 forcing GC (no HPROF)
D/dalvikvm﹕ GC_EXPLICIT freed 1K, 9% free 9250K/10112K, paused 12ms+2ms, total 60ms

Before Android 2.3, the afore would also dump the heap. On modern platforms (since Android 3.0), you can use the following, which doesn’t require root:

am dumpheap <pid> <output_file>

First post with my new iPad

In September last year, I was excited about Samsung’s announcement of the Galaxy Tab 7.7. It had a Super AMOLED HD display at 1280×800 resolution without any of the crappy PenTile matrix faking. As is customary with Samsung, months passed by without the product actually making it onto store shelves. When it finally was available, there were a lot of rumors about a fabulous new iPad with a 2048×1536 resolution screen.

Due to the annoying patent war between Apple and Samsung, I had thought about not buying another iOS device before sense would prevail and the two companies would stop with their lawsuits and counter-lawsuits. Then came the new iPad, and I knew I had no hope resisting buying one. The only thing I wasn’t sure of was if I was going to buy it as soon as possible, or at some later date. As it turned out, I was a happy owner of a new iPad on the launch day.

It’s not that I had a pressing need for an iPad. It’s that the new display was just too gorgeous to pass by. And believe you me, it really does shine. But the screen is not the only positive thing about the device. I never owned an iPad 2 (I only once quickly tried out one in a shop), so I can’t make any comparisons with that, but I did buy the first generation device when it was released. The new iPad is quite a bit more joyous to use, especially because of the four times larger memory capacity. When browsing web pages, there’s no longer that annoying checkerboard effect that plagued the first generation device (and the iPad 2 as well to some extent; this was the reason, incidentally, why I didn’t upgrade back then).

Originally I had contemplated buying the new MacBook Pro when it comes out in early summer. I already have the early 2008 model, which is quite usable for my purposes, but you can’t beat the feeling of using a brand new, expensive, and exceptionally well operating machine. On the other hand, I’ve by now gotten used to the higher DPI displays, and it would therefore be probably quite useless to buy a new laptop with the same 1400×900 resolution. There will most likely be a 1680×1050 screen option for some extra cash, but that would still be nowhere near the high DPI of the new iPad. (Yes, I’m a spoiled brat now.) I could get the Air (and save quite a bit of money as well), but I don’t know if I’d be able to give up the extra power that a Pro provides.

Having said that, after using the new iPad for a couple of weeks, I increasingly feel that I could be able to skip the purchase of a new MacBook Pro/Air altogether. The iPad is just that good. I’m still learning he ropes with the typing experience, but it’s much better than I thought it would be. The autocorrect feature is a blast, although by no means perfect. One thing I’ve noticed, though: when typing on the iPad, I keep on watching the keyboard all the time, instead of looking at the text I’m producing. This is the complete opposite of what I do when typing on a real keyboard. It must be because of the lack of physical keys; I have no felling of which keys my fingers are on, so I need to constantly watch over them. The speed of typing (in this semi-awkward position of lying in bed) is actually surprisingly good. I must later assess my typing speed when sitting properly at a table.

I need my PC for playing games (Civilization 5 mostly), but it seems that at the moment I really don’t have a pressing need for a Mac laptop, at least not a new one. I do have, in addition to the aforementioned MBP, a Mac mini 2011 (2.5GHz), which I use sporadically, so I’m pretty well covered if I later want to do some iOS coding. Other than that, most of my time on a computer is nowadays spent on the iPad. I don’t know if there is going back. A laptop feels, by now, somehow old-fashioned. Physical keyboard has of course no parallel, but since I can do pretty much everything on this wonder slate, I ponder if I can now permanently move on to the post-PC era that Steve Jobs talked about when the first generation iPad was released.

By the way, when I purchased the iPad, I also grabbed the iPad Smart Cover (navy blue leather). It was a bit under 70 euros (a ridiculously high price), but at least it works quite well for what it is. I could have opted for a polycarbonate version, but they didn’t have one in my color, so I had to cough up 30 euros more (I can’t believe I just said that).