The ViewHolder Pattern

As you develop your Android application, performance becomes more and more important. If your application appears slow, the user will get frustrated and not want to use it. One example of where this could happen is in the scrolling of a ListView. ListViews are a popular way to display information and can be done very poorly.

Each ListView has an adapter that is responsible for displaying the information in the list, and many times we’ll want to write a custom adapter to do something special. Within that adapter, the getView() method is responsible for figuring out how to display each cell in the list.  There are two main ways you’ll see developers implement this method–the right way and the wrong way.

The wrong way:

public View getView(int position, View convertView, ViewGroup parent) {
    LayoutInflater mInflater = mContext.getLayoutInflater();
    View convertView = mInflater.inflate(R.layout.buddy_list_item, null);
    Buddy buddy = getItem(position);

    ((TextView) convertView.findViewById(R.id.buddy_full_name)).setText(buddy.getFullName());
    ((TextView) convertView.findViewById(R.id.buddy_username)).setText(data.getUsername());
    return convertView;
}

In this example, each time a cell needs to be created, the ListView will need to find the View and its components (see where findViewById() is called?). This means the code will scan over all the layout resources and find this View and get its components to then populate in the cell. This is very expensive, and could lead to poor performance.

The correct way:

public static class ViewHolder {
    TextView fullName;
    TextView username;
}

Now, we use a ViewHolder which will represent a cell in our ListView. The ViewHolder will be attached to the tag field of our View. This will make it much easier for the ListView to recall the correct View and components, rather than calling findViewById() many times. Let’s see how it’s used in the getView() method.

@Override
public View getView(int position, View convertView, ViewGroup parent) {
    ViewHolder holder;
    if (convertView==null) {
        holder = new ViewHolder();
        convertView = mInflater.inflate(R.layout.list_item_buddy, null);
        holder.fullName = (TextView)convertView.findViewById(R.id.buddy_full_name);
        holder.username = (TextView)convertView.findViewById(R.id.buddy_username);
        convertView.setTag(holder);
    } else {
        holder = (ViewHolder) convertView.getTag();
    }

    final Buddy buddy = buddies.get(position);
    holder.fullName.setText(buddy.getFullName());
    holder.username.setText(buddy.getUsername());
    return convertView;
}

Here, we only inflate a View from scratch if convertView is null. Otherwise we have a reference to the View through the convertView’s tag, and we don’t need to call findViewById at all! This leads to great performance and smoother scrolling in our list.

Hopefully it’s clear why the ViewHolder pattern is superior. There are some great Android docs that touch on this. If you need clarity or have questions or suggestions, be sure to comment below!

Happy coding!
Brandon from The Bunch

iOS vs. Android: The Case for iOS

iphones

Last week my co-founder Brandon laid out the case for Android. While I agree that Android has some benefits like customizability, there are a few key factors that put the iPhone ahead.

Reliability & Smoothness

The iPhone is a reliable machine that runs at about the same performance throughout its lifetime. There’s a reason iPhone users rarely turn off their phone, and that’s because it performs reliably even after heavy usage. With reliability comes a consistent user experience, providing a smooth user interface. With Android, I’ve seen many phones start out zippy but degrade over time or lag periodically.

Updates

Apple has done a great service to developers and users alike by essentially forcing you to update your phone. Updates are simple on the iPhone, and users are quick to update iOS for new features. For developers, this means they don’t have to support the older versions of iOS, which increases time spent on things that matter. Android phones usually are customized on a phone-by-phone basis, meaning the version of Android they run becomes outdated and doesn’t get updated as frequently, which is bad for developers and users alike and probably only good for new phone sales.

Simplicity

iOS is very consistent and simple across apps. Apple’s design standard has made apps converge on “best” practices (sometimes they might not be the best, but they’re common). An example of this is swiping on an item in a list. The home screen on iOS is quite simple, where each app gets its own space. The counter-point for Android is customizability, but that comes at the expense of simplicity. Personally, I like an environment to be plug and play, where I can start using something and be productive in a matter of minutes and continue to be productive over time. iOS does this well.

Other Benefits

  • Quality of apps (largely due to Apple screening every app in the App Store)
  • Integration with Mac. If you use a MacBook, you’ll agree that some of the desktop apps don’t feel complete unless they’re used with the phone (i.e. Messages, Notes, etc.).
  • The lure of Android is always there to explore something unfamiliar, but I’m a “no-nonsense” user, so you can leave me here…I’ll be ok.

What are you favorite or least-favorite parts about owning an iPhone or an Android? Let us know in the comments below!

Sincerely,
Matt from the Bunch

iOS vs. Android: The Case for Android

android

Which is better: the iPhone or Android? Well, if we say iPhone vs. Android it’s actually as if we’re comparing apples and oranges. iPhone is the name of the device made by Apple. Android is an operating system (OS) made by Google. For the purposes of this blog post, let’s discuss iOS and Android, because there are too many devices that run Android to compare devices, and people usually argue about the OS, not the device it’s running on.

Both operating systems are pretty niche, in my opinion. I believe that’s why this argument can get so heated sometimes. iOS users are typically (in my experience) no-nonsense people who want a quality device that won’t slow them down in any way. This can range from cool hipsters who are more occupied with their other hobbies to worry about a cell phone to older people (like my grandparents) who just want a reliable device to handle the occasional call. Android users tend to be more into tinkering (with a few exceptions here and there). There’s the possibility of rooting the device (gaining root access to the device to bypass certain rules the OS has baked in), and there are undoubtedly more customizations to be made on the Android platform.

So, which is better? I’ve personally owned both. I’ve owned numerous Android devices but temporarily switched to an iPhone 5 for a few years. While there are great things about each, I would like to argue that the Android operating system is superior to iOS. But after you’ve heard my reasoning, you should comment below to let me know what you think!

iOS has a beautiful interface. I will never tell anybody differently. iOS is reliable and quick, all the time. There’s a reason no-nonsense users tend to find themselves on iPhones. iOS is simple. It’s clean. It’s very sexy. There’s no doubt about that. However, for me, this is where it ends. Its simplicity and beauty only go so far for me. I need more.

The Android platform can almost compete with iOS in terms of being clean and beautiful. I’ll admit that it’s not as fast and responsive and can get bogged down under heavy usage. However, this is rare and doesn’t at all ruin the system for me. Where it wins, though, is its customizability. I’m not talking about the ability to root and flash different system images on the devices. And I’m just talking about sheer customization and user experience. When you use an Android, you get the feeling that the phone was made for you. Google Now will tell you where you parked your car, what you wanted to buy at the store (via Wunderlist integration), what your schedule looks like today, how your stocks are doing, how your team did last night, and display articles of interest (that are actually relevant), all on the same screen! Oh, and saying ‘OK Google’ and searching the web actually returns super accurate results, unlike Siri. The great thing about Android is that if you don’t want to customize it or use all of its features, that’s totally fine. The phone still will deliver the same value that an iPhone does.

Also, you can get a phone running the latest Android version for a few hundred bucks, while iPhones cost an arm and a leg.

But this is just my opinion; what do I know? Let me know what you think–and why–by commenting below!

Sincerely,
Brandon from the Bunch

Android Push Notifications

Push notifications are important. Really important, actually.  When we released our first iteration of the LunchBunch, the most common feedback from users was that notifications didn’t act the way they were expected to.  A friend texted me saying, “I think something’s wrong with my phone, because notifications in your app don’t take me where I expect to go.” He thought it was a software issue on his phone’s part, not on ours! It was then that I realized we needed to focus our attention on notifications.

In this post, we’ll discuss two things: how the notifications get to our phones (specific to Google Cloud Messaging [GCM] notifications), and how we as developers parse them and notify the user. We’ll completely and intentionally ignore the aesthetics of the notification.  That’s actually an important discussion but out of the scope for this post. Check out Android’s Notification Design docs for more information.

Okay, first thing’s first–how do these great bundles of information reach my phone? Take this scenario for example: You just downloaded LunchBunch (congrats on the great decision, by the way), and you need some buddies to grab a meal with. So you add your best friend, Taylor. Well, Taylor is super psyched that you requested to be buddies and immediately accepts! Now, you won’t know that until we at LunchBunch send you a friendly notification. So what do we need to do?

Our application server, now knowing that you and Taylor just became buddies, will send a bit of data with the good news to Google’s servers. You, the user, having subscribed to receive notifications from LunchBunch (we’ll talk about this next), are now sent a notification from Google’s servers, and you can begin planning meals with Taylor. For all that to happen, our application servers need to be registered with Google to send them data, and you as a user need to subscribe to the notifications. I won’t walk you through the setup process (it’s boring, and Google does a good job with it here and here), so let’s get into the client-side code.

How do we subscribe to get notifications from LunchBunch? This all happens in an IntentService. When the app is installed, or when Google deems the last subscription stale, an Intent is kicked off to begin an IntentService (let’s call it CoolAppRegistrationIntentService). We kick it off from the MainActivity, the first activity that loads upon the app opening:

Intent intent = new Intent(this, CoolAppRegistrationIntentService.class);
    startService(intent);
}

The job of this IntentService is to get a token from Google to be sent to our Cool App application server. Here are the lines of code that do the magic:

InstanceID instanceID = InstanceID.getInstance(this);
String token = instanceID.getToken(getString(R.string.gcm_defaultSenderId),
        GoogleCloudMessaging.INSTANCE_ID_SCOPE, null);

After these lines, we have a token that will be sent to our application server for communication with the GCM servers. So, we have to get the token to our server. How you do that is up to you, but once you get confirmation from your server that it’s received the token, we’ll want to set some sort of Boolean that keeps the application from sending that token again for no reason, maybe in SharedPreferences:

if (status.equals("success")) {
    sharedPrefsHelper.setRegTokenSentToServer(true);
}

Sweet! Now we’re all set up to receive notifications. Snap, now we have to actually handle that, too!? No worries, it’s a piece of cake. There’s a GcmListenerService that does all the magic. What you’ll want to do is write your own class–let’s call it CoolAppListenerService–which extends GcmListenerService. You’ll implement a method called onMessageReceived, which has an important parameter–the data of the notification. Exciting, huh? That’s the data you’ll parse and (maybe) display to the user!

What’s been said so far is only bits and pieces–enough to get an understanding of the subscription process…But what I’m about to touch on is the nitty gritty application-specific stuff.

How you handle different notifications is totally up to you, but at some point you’ll want to display a message to the user. You can include this in the data, and extract it easily:

String frontFacingMessage = data.getString("message");
boolean sendNotification = !(TextUtils.isEmpty(frontFacingMessage));

Here we’ve included some message in the data if we want the user to see the change, and if that’s empty we don’t want the user to be privy.

Let’s go through two examples of actually parsing the notification data. First up, the story from before: Taylor just accepted you as a buddy, and LunchBunch is letting you know.

intent = new Intent(this, MainActivity.class);
intent.putExtra("action", "to_bunches");
notificationID = 0;
//Create a new buddy from data
String username = data.getString("username");
String firstName = data.getString("first_name");
String lastName = data.getString("last_name");
if (username!=null && firstName!=null && lastName!=null) {
    database.createBuddy(new Buddy(username, firstName, lastName, 0));
bus.post(new Event());
}

Whoa! That’s a big chunk of code. What does it all do? Not a whole lot, really. The first few lines create an intent that will be fired off when you click the notification. This one specifies the MainActivity and has an extra on it that will tell the MainActivity to send you to the Bunches page to see the new buddy. Below that, a notification ID is given to the notification, so we can dismiss it (or update it) manually in case the user doesn’t click on it or swipe it away. Finally, the end of this chunk mainly pertains to creating a new buddy to be added to our local database. We pull the username, first name, and last name from the data, and insert the buddy. Oh, and the last line is important–it posts a broadcast to our bunches page to update, in case you were looking at that page when the notification came in! Since the buddy was inserted into the database already, the adapter on the ListView would refresh, showing you the brand spankin’ new buddy in your list.

Now, a really simple and easy second example. The opposite of a new buddy, an ex-buddy. While we hope you never have any ex-LunchBunch-buddies, it’s a good way of seeing an example of when we wouldn’t want to notify you of a change.

String debuddyer = data.getString("username");
if (debuddyer!=null) {
    database.deleteBuddy(debuddyer); // Delete buddy from DB
}
bus.post(new Event());

In this instance, all we’ve done is parse for the username of our old friend, delete them from our database, and tell the Bunches Page to refresh. You don’t see any notification ID or Intent here, because there won’t be any actual visual notification.

Great! All done? Nope, not yet. You might have realized that we didn’t actually do anything to notify the user in our first example.  Good eyes, chief!

At the end of the parsing code, we check to see if we should send a notification (using our boolean from before), and if we should, we create one:

private void sendNotification(String message, Intent resultIntent, int notificationID) {
    // Notification attributes
    NotificationCompat.Builder mBuilder =
            new NotificationCompat.Builder(this)
                    .setSmallIcon(R.drawable.icon)
.setContentTitle("Cool App)
                    .setContentText(message)
    // Intent to start Activity
    TaskStackBuilder stackBuilder = TaskStackBuilder.create(this);
    // Adds the back stack
    stackBuilder.addParentStack(resultIntent.getComponent());
    // Adds the Intent to the top of the stack
    stackBuilder.addNextIntent(resultIntent);
    // Gets a PendingIntent containing the entire back stack
    PendingIntent resultPendingIntent =
            stackBuilder.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT);
    mBuilder.setContentIntent(resultPendingIntent);
    NotificationManager mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
    mNotificationManager.notify(notificationID, mBuilder.build());
}

This is just the basics, but it will do the trick.  We use the NotificationCompat.Builder to build a notification that will look sweet regardless of the API it’s being displayed on.  We set an icon, a title, and the content to be displayed.  Below that, you’ll see the intent that we defined in our new buddy example, which will fire off when the notification is clicked. In that same block of code, we define a back stack, so that the application will navigate the same as if the user had navigated to that place in the app himself, rather than having clicked on a notification.  Finally, we get an instance of NotificationManager and call notify(), using the notification ID we defined in our code.

And there you have it, the user has been notified! Congratulations, you’re well on your way to an app that meets everybody’s high expectations 🙂

How do you use push notifications in your applications? Interested in learning more about a specific concept? Let us know in the comments below!

Sincerely,
Brandon from The Bunch

Android Build Variants

One of the cool things about developing an application for the first time is learning something new at every step of the process.  Sometimes the learning is easy-peasy, and at other times you check the mirror every few minutes to see if you’ve sprouted any grey hairs.  But no matter the difficulty, getting through that obstacle is one of the best feelings a developer can experience.

Looking back, one of the most annoying obstacles I encountered was the creation of build variants for the application.  In order to explain build variants, it might help to understand why we need them in the first place.  Most applications today make network calls to servers to perform operations behind the scenes. In order to do that, an application needs a server that handles specific requests to store, retrieve, or change data.  So, when you pull up an application as a user, you’re probably doing some communication with a server somewhere! However, while you use the app, developers are out there working on that application to make it better.  They might be building a new feature into version 1.1 while you’re still on version 1.0.  In order to work with version 1.1, the server needs to be updated! Well, what if the developers changed the server you’re using to help them test their version? Chaos! That’s where a development server and a production server come in.  One is used by the development team and can be changed and messed with as much as they want, and one is always used for the application end-users, the people who need consistent functionality.

Still with me? Great. Now let’s think about the front-end, the application itself. You’re a developer, and you need to be able to use both aforementioned servers.  You need to be able to tell your phone to communicate with the development server to test new features but also quickly be able to tell it to talk with the production server to replicate bugs that are currently out there in the real-world.  How do you give the application this flexibility? You guessed it, build variants.

The phone and servers communicate using an Application Programming Interface (API).  For instance, an API might specify a method called /get_countries. The phone visits the API and specifies that method, and the server returns all the countries that are in its database.  Easy, right?  Usually this method is appended to a URL, like so: https://appproductionserver.com/get_countries. That might be the production URL, while the development URL is https://appdevelopmentserver.com/get_countries.  So, when I build my application to test, I need to make sure all calls go to the URL with development in it, and the production version calls must go to the URL without development! If there are just a few calls made in the entire application, it might be easy enough to make the change manually in the code. But most applications will have dozens and dozens of calls to different methods being made in different classes, and it’s just not efficient to do a manual change. So, how can I change ALL the calls in my codebase with the click of a button? Let’s find out!

In an Android project, the normal file path to the codebase is app/src/main/java/my/package/name. Inside your main package sit all of your classes.  Well, we can create different build variants using a few simple steps:

  1. In app/src, create two folders that will sit alongside the main folder–for example, prod and stage.
  2. Inside those two folders, create a file structure that replicates the one in the main folder. So if main contains java/my/package/name, then your prod and stage folder should contain java/my/package/name.
  3. Inside the last folder (in this case the “name” folder), create the class that needs to change based on the variant.  For example, maybe you have a URL.java class, which specifies ALL of the URLs for the application. In the stage version of the class, all of the URLs are to the test server, and in the prod version all the URLs hit the prod server.

Great, now we have the correct file setup. Next we need to tell Android Studio how to find them.

In our build.gradle file, we need to specify the product flavors:

productFlavors {
    prod {
        applicationId "my.application.prod"
        minSdkVersion 16
        targetSdkVersion 23
        versionCode 14
        versionName '0.3.6'
    }
    stage {
        applicationId "my.application.stage"
        minSdkVersion 16
        targetSdkVersion 23
        versionCode 15
        versionName '0.3.7'
    }
}

Once we do this, we can easily go to “Build” in the toolbar, and choose “Select Build Variant”. You’ll see four options there: prodDebug, prodRelease, stageDebug, and stageRelease.  You’ll mainly toggle between the debug options, and only use prodRelease when you’re ready to build and release a new production version! Don’t be worried if your compiler freaks out and throws a ton of errors when you switch variants, just do a project clean and they should resolve!

Hopefully this article has helped you to understand the need for build variants and how to implement them.  You can also use them to specify different names for the application like “MyApp – Dev” for development and “MyApp” for production.  I’ll leave you to figure out how to do that (Hint: You’ll want to replicate a strings.xml file like we did for our URL.java file)! That way, you can install both versions on your phone at the same time and tell which one is which!

Was this helpful? Have any other tips for build variants? Please let us know in the comments below!

Happy coding!

Sincerely,
Brandon from The Bunch