The Long Journey (part 2)

Despite my past as a Java teacher, I am mostly involved in iOS development. I have dabbled here and there in Android, but it’s only been for short projects or maintenance. My first full fledged Android application now being behind me (mostly), I figured it might be helpful for other iOS devs out there with an understandable apprehension for Android development.

Basically it boils down to 3 fundamental observations:

  • Java is a lot stricter as a language than Objective-C, but allows for more “catching back”
  • Android projects should be thought like you would a web project, rather than monolithic as an iOS app
  • Yes, fragmentation of the device-scape sucks
Android projects as Web projects

This is not about technology and opposing app developers to web developers. Android, with its Intents and Activities, layouts and drawables, resources of many kinds, memory management schemes, etc, felt like web development should be, to me. Now, let me put it out there: as you can see from the surrounding pages, I am not a web developer. But the HTML/CSS/Javascript feels much closer to Android development than iOS techniques.

The basics of View Management

I’ll set aside the hardcore way of doing things (that also applies to iOS dev), with only code. I’m talking about the more standard XML layout + corresponding class here.

In the resources, there is a bunch of subfolders for supporting multiple screen sizes, ratios, input types, and languages. Think responsive design in CSS. Once the correct set of items has been selected, it is passed along to the Java class (think Javascript) which will then access each identified item to modify it.

In the Activity code, it translates to inflating resources, then assigning stuff to them, including contents, onClick (familiar, yet?) responders and the like. But If you don’t do anything, it’s just a static page.

public class MainActivity extends FragmentActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
 
        setContentView(R.layout.activity_main); // this will select the activity_main.xml in the most appropriate res folder
 
        TextView helloLbl = (TextView) findViewById(R.id.hello); // find me the view corresponding to that ID
        helloLbl.setText("Yay"); // replace the current contents with "Yay"
        // ...
    }
 
    // ...
}

Graphically, since devices have a somewhat big range of ratios and pixel sizes, having a design that “just works” is kind of difficult. In my opinion, which is the one from a non-designer developer, it’s a lot easier to decide early on that one of the dimensions is infinite like on a web page (otherwise, precisely tailored boxes change ratios on pretty much every device), or to have controls clustered on one end of the screen and a big scrollable “contents” area that will resize depending on the screen you’re on (kind of like a text editor). Any other arrangement is a bag of hurt…

Contents lifecycle

Maybe it’s just the project(s) I have been working on, but it feels as though the mechanics of the view resembles what I have done and seen in dynamic web apps built around HTML5 and Javascript, rather than a pure PHP one where the server outputs “static” HTML for the browser to handle:

  • The view is loaded from the XML. At that point, it’s “just” a structure on-screen.
  • The callback methods (onCreate, onResume, …) are called on the Java side
  • The Java code looks for graphical items with an id (or a class), and fills them, or moves/resizes them, or duplicates them…

Some will say that the iOS side of development works the same (with XIBs and IBOutlets etc), and maybe they are right, to a certain extent. It just feels that the listener approach gives a potentially much more varied way of doing things, and that they are called very often: for example, since a text label will resize according to its contents by default, it will trigger a resize/reorganizing of the layout, which will trigger other changes.

And since any object in the program can be a listener / actuator for these events, there’s a lot of competition and guesswork as to what will actually happen. The text label may respond a certain way (which can be overridden), its superview/layout engine another way (idem), all the way up the chain, which will trigger some changes down the branches again. During an ideal (and somewhat simple) load layout -> fill data boxes non repeating cycle, my onMeasure method (responsible for giving out the “final” size my control wishes to have depending on a bunch of parameters) was called up to 8 times in very close succession.

But that same listener mechanism, so pervasive in everything Java, also opens a lot of ways to catch anything that happens in your application, from any object:

  • you can detect layout changes from the buttons it contains
  • you can detect a tap on a control (usually non tappable) from its neighboring on a graphical point of view, thus extending the “tappable area”
  • you can react to content changes and limit/alter them on the fly

But so do the other views in the frame, not written by you!

View lifecycle

For memory-obsessed geeks such as myself, the view retain/release cycle was some work to get used to: They are kind of like the tabs in your mobile browser. Sometimes, you browse a website, open another tab, do some stuff, and when you get back to the first tab, it’s completely blank, and reloaded. Or not. It depends on the browser’s memory handling techniques and the available amount of RAM, processing power, and the page’s javascript running scripts.

Since the views might be re-created from scratch each and every time, the strategy to hold on to some data becomes critical. Do you keep them as instance variables of the controller, potentially hogging up the RAM, but being readily accessible instantly? Do you serialize them in the Bundle that the system uses for that kind of things (which I guess is written to disk when the RAM is full) every time the view goes away, and therefore test on all the restoring methods (onCreate, onViewStateRestored, …) that some data is present, deserialize it and put them where they belong? Do you reload it from whatever web service they are coming from? Do you serialize them yourself on disk?

All of these mechanisms require a lot of testing on various low memory devices, because there are out-of-view things happening that will destroy your data from memory if you’re not careful. And although you won’t find yourself having pointers that look ok, but have been freed, some data might be invalid at the time you’re trying to use them.

To Be Continued!

Next time, we’ll discuss the extremely varied range of android devices your app might be running on!

  

Leave a Reply