Thoughts on dealing with multiple Activities and UIViewControllers

In a typical model/view/controller implementation (setting aside, of course, the debate over what MVC really is), we implement a model (which maps to a document, file, or database), a controller (which manages the views), and a collection of views, generally contained within a window.

Now this model maps nicely into the iPhone API and the Android API: the basic controller class for the iPhone is UIViewController; for Android it is android.app.Activity. And of course the view hierarchy represents the UIViews and android.view.View objects, both built-in objects and custom objects. The controller object also makes the ideal target for iPhone delegates and data objects and for the various Android interfaces which do essentially the same thing.

On the desktop, most applications are built with either a single model and a single controller. Rarely do we have multiple controllers opened onto the same model, and when this happens, more often than not the multiple controllers are multiple instances of the same class declaration: multiple text editors opened onto the same text file, for example.

Mobile devices are different. On a mobile device you can have a top level screen with one controller drill down to a separate screen (with a separate controller) which displays an individual item, which drills down to a third screen showing information about that individual item, which drills down into a fourth showing the setting for a single field.

In this example, we have four (increasingly fine grained) views into the same model: in the first screen we have a top level view; in the next, a view of an item, and so forth. The original method I was using in order to code for this particular model was to create multiple model-like objects and pass them down to individual view controllers:

Now this model tends to be somewhat informal: my top-level model is (for example) an ArrayList of Items. When it’s time to edit an item, we pass the Item as the sub-model object into the sub-control display. And when it’s time to edit some piece of the Item, we pull that piece out and pass that to the next sub-control display.

The whole process becomes messy for a variety of reasons. First, it creates a strict dependency in the flow of views; even if we use interfaces and protocols in order to isolate a control (and its respective views), we still have a lot of work to do if we want to rearrange views. Second, it creates the problem that we somehow need to pass information about which sub-item was updated back to the previous view controller. This becomes problematic since the events for UIViewController and Activity don’t map well to the notion of “saving” or “marking dirty”: there is no single event we can easily grab that consistently means “You’re going away and the view above you is becoming active.”

Android presents a few twists on this as well. First, when your Android Activity goes into the background it can be deleted from memory in a low-memory situation. That is, you can find yourself in the situation where your Activity goes away and has to be rebuilt from scratch. This implies that you must strictly separate the sub-model from the controller (as opposed to the iPhone, where you can informally combine the model and view controller into the same UIViewController class). Second, well-factored activities can be set up to be brought up by external applications: it is possible your Item editor activity can be brought up by a separate application if it knows how to launch you with the correct Intent.

It strikes me that the proper way to handle this is to have a single unified model, and instead of passing sub-models, we instead pass a small record indicating what part of the model we are working on:

The idea is that the Δ object represents a small record which indicates to the sub-controller which part of the model it is working on. This has the advantage that updates are communicated to each of the controllers which are working on this model as the object updates. This also works well on Android, as individual control/view components can disappear and re-register themselves; the delta record is passed in the Intent which created that component, so when the Activity is reconstructed the Intent can be used to put the view controls back into the correct state.

I have a simple nutrition journal application I’ve been building for the iPhone which I was going to rewrite from the ground up using this model. In future posts I’ll update the post to indicate if this works well or not.

List View Context Menus

This was driving me nuts all weekend, because I became misguided.

On Google Android, I want to create a custom list view, and I want to handle context menus. Of course the right way to do this is:

(1) In your activity that contains your list, call setOnCreateContextMenu with a class that will be handling the context menu callbacks. (The activity already implements the interface, so you can just pass it your activity.)

        fListView.setOnCreateContextMenuListener(this);

(2) Implement the onCreateContextMenu and onContextItemSelect items as usual.

Where I ran into problems was with another suggestion from another web site that suggested in my custom list adapter that I call the view’s registerForContextMenu routine. The problem with that is that you don’t get the list view’s yellow highlight and animated fade effect.

KISS in practice.

I was having a conversation with a co-worker, where I complained that the biggest problem with some of the code we’re working on is that it was over-engineered. I reminded him of Gall’s Law:

“A complex system that works is invariably found to have evolved from a simple system that worked. The inverse proposition also appears to be true: A complex system designed from scratch never works and cannot be made to work. You have to start over, beginning with a working simple system.”

He asked me a question about client-server interaction, and rather than shooting off a 140 character reply it seems to make sense to answer the question more fully here.

To summarize, we are building an application that communicates to a remote server using JSON over HTTP. The remote system is built on top of Drupal. (Honestly it’s not how I would have done it, because there seems to be too many moving parts already–but the folks who built the server assure me that Drupal is God, and who am I to complain?)

Now on an error there are several things that can go wrong. The remote server can return a 4xx or a 5xx HTTP error. It can return a JSON error. Or it could return an HTML formatted error (I guess they have some flag turned on which translates all remote errors into human-readable error messages.) The client is hardened against all of these return possibilities, of course, and is also hardened against a network failure or against a server being unresponsive.

So here’s the question: how should the client respond to these wide variety of errors?

On the server side, of course, there needs to be logging. We even do some device-level logging, and a mechanism is in place on our iPhone client to transmit that log in the background to the server if there is a problem. Because clearly from a developer’s perspective a 404 is not a 501 is not a 505 is not a “server is unresponsive” is not an “illegal character in the API” is not a “network down” error. So clearly we need to know what is going on so we can fix it.

But what does the end user need to know?

In my mind, handling this is very simple: what can the user affect?

In the case of a mobile device, the user can retry again later, or he can make sure he’s got good network reception. Period.

So in the event of a failure, the client’s behavior should be simple: if a connection fails, then test to see if the network is up. If the network is down, tell the user “I’m unable to talk to the remote server because your network is down.” And if the network is up, tell the user “Sorry, a problem occurred while talking to the server.”

And that’s it.

If the network is down, the user can try to turn it on: he can take the device out of airplane mode, or move to where he has reception, or turn on the WiFi. But it’s up to the user–we just have to tell him “Um, the network is down.” And let him decide how he wants to handle the problem–or even if he wants to handle the problem: it could be he clicked on our application while at 38,000 feet over the Atlantic.

If we can’t hit the server, but the network is up, then there is nothing the user can do about it. All we can do as software developers is make sure whomever is maintaining the servers that they should investigate the outage. All we can tell the user, however, is “sorry, no dice; try again later.”

And hope to hell our servers are reliable enough we don’t drive users away.

Making it more complex is silly. It doesn’t serve the user who may be stressed out by messages he can do nothing about anyway.

Valid format values for declare-styleable/attr tags

Meh. Wasted an hour trying to sort this out.

The answer happened to be buried in some Android code. The fact that Android is open source is a cool thing–but I shouldn’t have to dig through that source kit just to figure out the answer to something that could be better documented.

When declaring a <declare-styleable> <attr> tag, you supply a name for the new attribute for your custom class, and you provide a format. Well, I couldn’t find the valid values for the format attribute in the documentation. But I did find them here.

And those values?

  • reference
  • string
  • color
  • dimension
  • boolean
  • integer
  • float
  • fraction
  • enum
  • flag

It also appears from the source code that this field is optional, and I presume if it is left blank, either one of two things will happen: this will default as a resource reference, or the format is only used for type checking, and this can be any value. I dunno; I haven’t tried it.

On the off-chance someone knows the answer, could they leave it in the comments?

Centering the contents of a component in a JScrollPane

When creating a drawing program it’s nice to be able to center the contents of your view if the content area of the JScrollPane is larger than the contents of your document. By default your contents are slammed to the upper-left; however, by using the Scrollable interface you can prevent the viewport containing your content view from shrinking smaller than the content area of the scroll pane, thus allowing you to do things like center your content.

Here is some code which I used to do this. I’m posting the code here so I can remember this in the future.

First, the class itself:

public class ContentView extends JComponent implements Scrollable
{
    private int width = 500;    // document width, height. (replace with whatever code you use to find these values.
    private int height = 400;
    private Rectangle offset;   // caching code; see discussion below.

I’m declaring a width and height inside my class for demo purposes., but you can obtain the visible width and height anyway you wish.

Now the centering code:

    /********************************************************************************/
    /*                                                                              */
    /*  Viewport Centering                                                          */
    /*                                                                              */
    /********************************************************************************/
    
    /**
     * Internal routine which computes the smallest rectangle size
     * encompassing the document area and the scroll viewport.
     */
    private Dimension getViewportSize()
    {
        Dimension size = getParent().getSize(); // get my viewport size

        int xsize = size.width;
        if (xsize < width) xsize = width;
        int ysize = size.height;
        if (ysize < height) ysize = height;
        
        return new Dimension(xsize,ysize);
    }
    
    /**
     * getMinimumSize returns the smallest acceptable size of this view. This
     * is then used resize
     */
    public Dimension getMinimumSize()
    {
        return new Dimension(300,200);
    }
    
    /**
     * The getPreferredSize routine returns my preferred size; this returns the
     * viewport size
     */
    public Dimension getPreferredSize()
    {
        return getViewportSize();
    }

    /**
     * The Scrollable.getPreferredScrollableViewportSize routine returns the suggested
     * size of the viewport. This will return the viewport size I want, which is
     * the larger of the view area size and the existing viewport size
     */
    public Dimension getPreferredScrollableViewportSize()
    {
        return getViewportSize();
    }


    public int getScrollableBlockIncrement(Rectangle visibleRect, int orientation, int direction)
    {
        int x;
        if (orientation == SwingConstants.VERTICAL) {
            x = visibleRect.width - 12;
        } else {
            x = visibleRect.height - 12;
        }
        if (x < 12) x = 12;
        return x;
    }

    public boolean getScrollableTracksViewportHeight()
    {
        return false;
    }

    public boolean getScrollableTracksViewportWidth()
    {
        return false;
    }

    public int getScrollableUnitIncrement(Rectangle visibleRect, int orientation, int direction)
    {
        return 12;
    }

The core of the code above is the getViewportSize() routine, which determines a size which contains the size of my content and the viewport size. This is then returned for the getPreferredSize and getPreferredScrollableViewportSize() routines–both are used by the JScrollPane to resize my view within the scroll view area.

The routine getMinimumSize() is used to return the minimum acceptable size. To make a long story short, in my custom LayoutManager, I call the JScrollPane’s getMinimumSize() routine to get the minimum area allowed for resizing my window; this makes sure the contents area of my scroll bar doesn’t shrink below the minimum size returned.

The other interface methods for the Scrollable are filled in with acceptable defaults for a drafting program: page scrolling scrolls almost the entire width or height of the visible area, and clicking the arrows steps 12 pixels.

Now to hang all this together you need to then draw the contents in the right place; this means you need a rectangle representing the content area of your document.

    /********************************************************************************/
    /*                                                                              */
    /*  Drawing Support                                                             */
    /*                                                                              */
    /********************************************************************************/

    /**
     * invalidate is called when the size or boundaries of this thing has been
     * invalidated. This resets my offset rectangle because I will need to recalculate
     * it.
     */
    public void invalidate()
    {
        super.invalidate();
        offset = null;
    }
    
    /**
     * getOffset calculates (if needed) and returns a rectangle which defines the
     * location of my drawing in my view. If the visible area of my view is larger
     * than my drawing, this will return a rectangle offset appropriately
     * @return
     */
    public Rectangle getOffset()
    {
        if (offset == null) {
            Dimension parentSize = getParent().getSize();
            int xoff = (parentSize.width - width) / 2;
            if (xoff < 0) xoff = 0;
            int yoff = (parentSize.height - height) / 2;
            if (yoff < 0) yoff = 0;
            
            offset = new Rectangle(xoff,yoff,width,height);
        }
        return offset;
    }
    
    protected void paintComponent(Graphics g)
    {
        Rectangle r = getOffset();
        Dimension size = getSize();
        
        // erase to background
        g.setColor(Color.lightGray);
        g.fillRect(0, 0, size.width, size.height);
        
        // erase my document area
        g.setColor(Color.WHITE);
        g.fillRect(r.x, r.y, r.width, r.height);
    }

The offset field above is used to cache the current offset and location of my contents in my drawing area; I cache this value so I’m not constantly recomputing this on a mouse down/move/up cycle. The calculation itself is handled in getOffset(). The invalidate() method is called by the OS whenever the size of my view is changed; this allows me the chance to dump the previously cached value to force a redraw.

And the paintComponent() routine will repaint the contents; here I draw the area as a white area within the content area.

As a footnote, if you write code to recalculate the location of the scroll bar and use that code to calculate the minimum acceptable size of your view, your LayoutManager should use getMinimumSize rather than getPreferredSize when determining the size for scrolling. (I’m lazy; my LayoutManagers use the same value for preferredLayoutSize and minimumLayoutSize.) Otherwise, you will find the window constantly resizing itself larger and larger as the custom getPreferredSize() above interacts poorly with the resize code.

Look; this is a hack. I make no promises this works correctly; standard disclaimers apply.

The lifespan of an object owned by NSMutableArray, or why Objective-C annoys me and Java makes me happy.

Hard to find memory bug on the iPhone.

I had to find it by (a) building the map file for the distribution of the iPhone product, and (b) walking for an hour around Santa Monica (pretty day, though a bit on the warm side) waiting for the map software component to crash.

I finally found it. It’s the sort of memory bug that Java programmers never have to concern themselves with.

So suppose you’re writing a queue, and you use an NSMutableArray. (In Java you’d use a LinkedList object, which would be faster, but I digress.) Removing the object from the NSMutableArray, I wrote:

MyObject *obj = [myMutableArray objectAtIndex:0];
[myMutableArray removeObjectAtIndex:0];
UseMyObject(obj);

And all is right in the world, correct?

Um, not quite.

See, there is thing thing called the autorelease pool. It’s quite clever: it holds a list of all the objects that, after this current event is finished being processed, the objects will be released and potentially deleted from the system. So when you get a return value back from some function, unless its a function which explicitly gives you ownership of the object, you can safely use that object until the end of the event processing loop, which certainly won’t happen until after your routine returns, right?

Um, not quite.

NSMutableArray notes in its documentation that on a call to the remove function removing that item from the array, release is called immediately on the object, which means my object obj above has been released. Now what makes this a hard to find bug is that while the object may have been deleted and its memory released, the object itself still lingers in memory unless you use a memory debugging library.

And unfortunately for me (1) the conditions causing this routine to be called is only triggered when walking around with our new software package, and (2) the various memory debugging libraries only work under the iPhone simulator.

The workaround?

MyObject *obj = [myMutableArray objectAtIndex:0];
[[obj retain] autorelease];  // before removeObjectAtIndex
[myMutableArray removeObjectAtIndex:0];
UseMyObject(obj);

Feh.

This is exactly the sort of stuff that garbage collection helps with, and is the primary reason why I like Java: no messing with object lifecycle management. Unfortunately garbage collected Objective C isn’t available on the iPhone, which means that so long as I’m trying to write Objective C code that runs on the iPhone and may also run on the Macintosh, I cannot use garbage collection in my Objective C development.

Software Development Tools

Many years ago I got a DSL connection with a fixed IP address. I paid a fortune per month to run that fixed IP address, but the nice thing was being able to put my server on-line so I could run my own e-mail server, my own web server, and my own source control system.

A couple of months ago I switched to a new ISP which was cheaper–but I gave up the fixed IP addresses in the process.

On the other hand, there is no need for having my own IP address when for less money I can sign up for the following services:

Google Apps: Free e-mail and shared documents.

SVN Hosting: I am using the $7/month level service at SVNRepository.com; this gives me theoretically unlimited repositories and users and a 2gig storage cap.

Web Hosting: I’m using the $7/month level basic service at LunarPages.com; I can park all of my different web sites on the same account (and even host different page collections from one account), and for an extra $2/month they’ll also host my JSP pages.

So I’m out $16/month on the above services–but the fixed IP address was running me $30/month, and it required me to maintain a separate computer, constantly update and maintain the software there. I don’t know how secure SVNRepository is: if I’m running something mission critical or creating software worth hundreds of millions of dollars I’d probably run my own SVN server. But for synchronizing my code across three different computers and providing me the ability to share code bases with other people, it’s pretty damned cool.

Updated ASN.1 Library

Well, I got an interesting correspondence yesterday and a follow-up today–and in investigating I realized that there were some primitives in my ASN.1 BER library which I failed to handle back when I wrote this two years ago.

Originally I wrote the library because I was interested in building my own LDAP engine. I had written parts of an engine, but I “borrowed” the Netscape LDAP library’s BER tag parsing code to handle incoming and outgoing messages. But the LDAP library wasn’t mine, nor was it robust, so I set out to write a replacement.

The problem was when I got enough to parse LDAP, I considered my replacement done. And it wasn’t. Far from it.

It turns out there are a couple of other primitive types that have been introduced elsewhere: RFC 3641 defines a couple of new constructs, and it turns out I completely skipped one of the primitives, the relative OID type, when I originally built my library.

I’ve corrected the problems, and uploaded a new version of the library, though the new types aren’t very well tested at this point.

Update: After spending the past few months writing Objective C++ code, it felt good to blow the dust off my mad Java sk|11z.

Update 2: Did I mention Fatih Batuk’s Java ASN.1 Compiler that uses my library? Go check it out.