30 May 2016

Android Lambda

I've heard a lot about lambda recently and how amazing Java 8 is. I'm not really sure this will have a huge impact on Android as I fail to see the relevance, none the less I was interested and keen to experiment.

I thought I'd create a super simple example by changing the OnClickListener of a button and trying to replace it with a lambda. Nothing shocking here, just wanted to know if I could. So I created a brand new project and here's how I got it working.

Before we go any further you'll need to:

  • Donwload the Android N SDK, 
  • Download JDK 1.8 (and target it with Android Studio) 
  • You'll need an emulator or device capable of running Android N.

Android N

To use lambdas we have to target Android N so I've updated the compile version, build tools, min Sdk and target Sdk.

android {
    compileSdkVersion 'android-N'
    buildToolsVersion '24.0.0-rc3'

    defaultConfig {
        applicationId "eightest.test.com.eighttest"
        minSdkVersion 'N'
        targetSdkVersion 'N'
        versionCode 1
        versionName "1.0"
    }

The code

This is what we would normally do for a onClick
findViewById(R.id.activity_main_text).setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View view) {
        showToast()
    }
});

This is how a lambda makes it look a little cleaner
findViewById(R.id.activity_main_text).setOnClickListener((View v) -> {showToast();});

Target Java 8

We need to specifically target java 8 (do this inside the Android brackets, after buildTypes)
    compileOptions {
        targetCompatibility 1.8
        sourceCompatibility 1.8
    }

Utilise Jack compiler

Now we need to tell Android to use the Jack compiler which will allow us to utilise Java 8.
    defaultConfig {
        applicationId "eightest.test.com.eighttest"
        minSdkVersion 'N'
        targetSdkVersion 'N'
        versionCode 1
        versionName "1.0"
        jackOptions {
            enabled true
        }
    }

25 May 2016

Firebase Tutorial For Android Developers


I've sadly never had the chance to use Firebase in a production app. After Google talked about it so much at this year's IO I though it was about time I had a play and created a tutorial.

Firebase is primarily a real time database that makes data storage simple and easy. In the last few years it's been expanded to be an incredible fleet of tools that Android, iOS and Web developers can make use of.

The Firebase database is an inspired solution to data storage and syncing. The Firebase db is a NoSQL, cloud hosted database that allows for fast and easy sync across different devices. No more clumsy sync adapters or troublesome push notifications, Firebase handles all this for you with a simple API.

Also included in the suite is analytics, crash reporting, file storage, authentication, remote config and more.

I know I'm beginning to sound a bit like a marketing rep, but I really must say I'm flawed by how awesome Firebase is. The cloud sync database is really simple to set-up and it works incredibly well.

OK let's get into a tutorial. I wanted to link my app to Firebase and create a cloud db. Sounds easy! First you will be required to have a Google account, then we goto Firebase and create a new project:

https://console.firebase.google.com/

Now you have a Firebase app. Next we need to add it to Android, the wizard walks you through this process with a lovely little Material designed guide. You'll need the package name of your app and then to make some gradle and config changes.

Now we need to disable authentication. If you goto the Firebase console and click database on the left hand side you should see an empty data set. In the tabs above click on rules and change the json to match this:

{
  "rules": {
    ".read": true,
    ".write": true
  }
}

This basically disables all authentication giving anyone write and read access. For a real application you'd want to set-up proper user role based access, but for this tutorial will just turn authentication off.

Next you'll need to setup your Android project. You should already have the json config file and the gradle additions. Now you need to add the database gradle dependancy:

compile 'com.google.firebase:firebase-database:9.0.0'
That's it, you're pretty much ready to go. However there are a few important db constraints to get your head around before you launch your new app.

Data in Firebase is all JSON but it does support saving objects, lists, maps as well as simple data types such as strings, booleans, doubles etc. It seems to me largely based around a key value pair type of system. You put a value with it's corresponding key to Firebase and it syncs it. Then use the same key to retrieve that data.

SetValue

SetValue is an assignment method. At first I thought you could use it to create new db entries, but that is not the case. Instead you call

FirebaseDatabase database = FirebaseDatabase.getInstance();
DatabaseReference myRef = database.getReference("message");

myRef.setValue("Hello, World!");

This creates a key value pair with the key "message" and the value "Hello, World!". If you call setValue again on that key, the value is overwritten, a new pair is not created in this way.

ValueEventListener

The ValueEventListener gives you the ability to receive a callback when your data changes. This is useful when you create your UI so you can receive updates whenever the data changes. No more db listeners or broadcasts.

public void onDataChange(DataSnapshot dataSnapshot)

All you need to do is attatch the listener

myRef.addValueEventListener(this);

Push

Push allows create a list of data. Using this method generates a unique key instead of forcing you to create a new key for every object.

Save Data

Here's how I added a list of simple objects. Player is just a simple pojo. We use push to create a new child of the DB_KEY_PLAYERS type. We then get the key of that new child.
Using that key we can now update it's data. The second param to setValue is a callback so we can update the UI when the data has been updated successfully.

FirebaseDatabase database = FirebaseDatabase.getInstance();
DatabaseReference myplayers = database.getReference(DB_KEY_PLAYERS);

//Get key for a new player
String key = myplayers.push().getKey();
Player player = new Player(playername);
//set value of new player
myplayers.child(key).setValue(player, ActivityAddPlayer.this);


That's it, you should now have a working cloud synch'd database. You can now add analytics and crash reporting as well, super simple and very well designed. I really hope I get to put it into practice in a live app sometime soon.



16 May 2016

Android - There is a problem parsing the package

This was a head scratching problem I had. I copied an apk to my phone and tried to install it but immediately got an error

There is a problem parsing the package

So I opened up Android Studio, assembled it again and re-installed it. Same problem. I checked the manifest, checked gradle and a few million other things! Some hours later I tried:

adb install C:/folder/myapp.apk

Then I checked the ADB logcat and finally I had something to go on.

Installation error: INSTALL_PARSE_FAILED_MANIFEST_MALFORMED

How frustrating! Couldn't I have been told that during build? Well at least I had something. It turned out to be a missing provider authority for a specific flavour. Oh well, next time I'll know what to do first!

03 May 2016

Android n00b lessons

I've been training a couple of relatively junior Android developers recently and I've seen a few mistakes repeated. I thoughts I'd mention them here in the hope it will help someone else. This isn't supposed to be a laugh at anyone's expense, just a discussion about how to improve your code and become a better developer.
  1. Don't close a cursor properly
    I see this in on-line examples, in old code and in new code written by juniors. The fact is there are a lot of things that can go wrong when using a cursor, so you need to be a bit careful and make sure you don't throw an error or waste memory. 
    1. First and foremost close the cursor.
    2. Your cursor might be null
    3. Use finally to close your cursor, it works really well!

    Cursor data = context.getContentResolver().query(MyProvider.DETAILS, null, null, null, null);
    
    try {
        if (data != null && data.moveToFirst()) {
            retVal = data.getString(data.getColumnIndex(columnName));
        }
    } finally {
        if(data != null) {
            data.close();
        }
    }

  2. Catching an error badly
    Arrrg! I see this far too often. An empty catch block. Even if it's just a Log.e, that's better than nothing. OK I'll admit there are some situations where you just don't care if an error is thrown (like above), but all too often people just throw the try in to avoid compile errors and leave the catch empty. Don't do it!

            try {
                int a = 1;
            }catch(Exception e){
                    
            }
    

  3. Excessive use of RecyclerView
    RecyclerView is new, it's cool and it's heavily publicized. That doesn't mean you should use it ALL the time. If you've got a small simple app with one ListView that will show about three elements, please don't bring an entire new library into the project. A ListView is OK. If your ListView is small and your needs simple, don't panic, you can use a ListView. The world will not end, I promise. Yes the RecyclerView is efficient, especially when you want to use animations or change elements but sometimes it's like cutting the grass with a machine gun. I don't want to say RecyclerView is bad, it's a fantastic tool, but use your perspective and let's keep it simple people!

  4. Variables in a loop
    This one was really interesting. Conventional wisdom often states you should never create a variable in a loop, and to be honest I always held with this. However I did some research recently and it seems that it's actually most efficient to declare the variable in the smallest scope possible. If that means declaring it in the loop, then fine, as long as that's NOT then used outside the loop.

    for (Person person : people) {
        String desc = person.getDescription();
        ...
    }
    

If you've any more suggestions then I'd love to hear them.