My life with Android: « it’s complicated »

Facebook screenshot: relationship status: it's complicated

Mobile development is difficult: there is not much memory, the CPU is low, network connection is limited, there are different screen sizes and hardware capabilities to take care of, etc. Android aims at helping on these topics, but the life of an Android developer is still not a paradise…

Some classes pretend to help, but just don’t

The framework encourages you to use classes that supposely simplify complex development.

For instance, AsyncTask « allows to perform background operations and publish results on the UI thread without having to manipulate threads and/or handlers. »

However, there are limitations or other problems virtually impossible to solve. For instance with AsyncTask, the application crash when the orientation is changed.

Activity has leaked window PhoneWindow$DecorView that was originally added here 
E/WindowManager(  244):

Eventually, I have found that only services can correctly handle long running operations. But they are more complicated to code.

The XML nightmare

With XML, you can build a software that perfectly compiles, and crash at runtime. Sometime not entering in your own code at all.

In the worse situation, it can crash the OS without letting a second to run a debugger. For instance, when I was going to Settings > Account and Sync > Add account, the phone crashed and rebooted. Why? Because I forgot the smallIcon attribute in the authentificator.xml (similar to this Resources$NotFoundException: String resource ID #0×0).

The recycling in adapters

A ListAdapter connects data to rows representing this data in a ListView. As I already mentioned, resources are limited, so it is a good practice to recycle a former view rather than creating a new one. As such, when the user scrolls down the list, instead of creating new views for the new rows, the views are recycled from rows that are not visible anymore. This is usually performed with this nippet of code:
[code]
if (convertView == null) {
view = mInflater.inflate(R.layout.mylayout, parent, false);
} else {
view = convertView;
}
[/code]

But this can lead to strange beahaviours or things difficult to debug. For instance, if a list view has a checkbox, this code is incorrect
[code]
checkBox.setChecked(myDataItem.isActve);
checkBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView,
boolean isChecked) {
myDataItem.isActive = isChecked)
}
});
[/code]

With this code, the checkboxes are checking and unchecking themselves randomly when the user scrolls the list. Whereas this code is correct. Can you spot the difference and explain what happens?

[code]
checkBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView,
boolean isChecked) {
myDataItem.isActive = isChecked)
}
});
checkBox.setChecked(myDataItem.isActve);
[/code]

In the first case setChecked() triggers the onClickListener defined in a a data element which is now hidden.

SyncAdapter requires AccountAuthentificator and ContentProvider

A SyncAdapter is used to synchronize Internet data with a ContentProvider. This is what gives you a synchronized address book, a synchronized list of emails, synchronized tweets, etc.

In all this examples, it is require to provide an AccountAuthentificator. However, I think this account authentificator is irrelevant for synchronizing public data, like weather forecast.

Well, the android framework thinks differently. It is mandatory to have these 3 pieces: SyncAdapter, AccountAuthentificator, ContentProvider. If one is missing, the android system might crash when you go in the Settings screen, and the phone will reboot without little to no debug message:

EXCEPTION IN SYSTEM PROCESS.  System will crash.
E AndroidRuntime: java.lang.NullPointerException

If you think this one sucks too, please star issue 5009.