CategoriesJavaKotlinSoftware Development

What’s Wrong With Stack in Java and Kotlin?

This is a story about me accidentally crossing paths with the Stack API in Java and Kotlin. Whether you are a seasoned Java and/or Kotlin developer or are just beginning to test the waters. I promise you that by the end of this blog I will convince you to never touch the Stack class in Java/Kotlin even with a ten-foot poll.

Before we dive right in, let’s brush up our memory real quick so that we can enjoy the rest of the show.

What is a Stack?

In computer science, a Stack refers to a data structure for maintaining a collection of elements and it majorly supports these two operations:

  1. push, which allows you to add an element to the collection, and
  2. pop, which allows you to remove an element from the top of the collection.

Based on this information, we can say that it follows a LIFO (last in first out) strategy.

Next, let’s look at some common applications of stacks in real life.

Where are Stacks used?

Expression Evaluation & Conversion

We use stacks to evaluate infix, postfix and prefix expressions. Further, you can also convert from one type of expression to another using a stack.

Syntax Parsing

Compilers use a stack to parse the syntax of expressions in the source code.

Backtracking

If you are solving a problem to find a path in a maze. You can use a stack to backtrack the path if you hit a wall.

Parenthesis Checking

To validate if a parenthesis is opening and closing correctly, a Stack is pretty handy.

Now there are many more creative applications of stacks in real life but for the scope of this blog these should suffice.

Time to dive into some code.

Reverse a String

Now to keep the example simple to follow, let’s say we want to reverse a string.

Imagine we get “hello world” as the input. Our method should return “dlrow olleh“.

Here goes the code to do that

public class Main {
    public static void main(String[] args) {
        System.out.println(reverse("hello world"));
    }
    
    public static String reverse(String input) {
        Stack<Character> stack = new Stack();
        
        for (char c : input.toCharArray()) {
            stack.push(c);
        }
        
        StringBuilder sb = new StringBuilder();
        while (!stack.isEmpty()) {
            sb.append(stack.pop());
        }
        
        return sb.toString();
    }
    
}

Running the above code, should give you the following output

dlrow olleh

So far so good? 😎 From here on, things will only go south.

Randomly Accessing a Stack

What do you think will happen if you were to do this?

public class Main {
    public static void main(String[] args) {
    
        String input = "hello world";
        
        Stack<Character> stack = new Stack();
        
        for (char c : input.toCharArray()) {
            stack.push(c);
        }
        
        int top = stack.size() - 1;
        int bottom = 0;
        
        System.out.println("Char on top " + stack.get(top));
        System.out.println("Char at the bottom " + stack.get(bottom));
        
    }
    
}
  1. Do you think it fail to compile?
  2. Will it throw an exception at runtime?
  3. Or Do you think it will execute and output the following text:
    Char on top d
    Char at the bottom h

Now, before you try to answer the question. Let me make it clear that, I am trying to access the elements of the Stack by their position, as if it was an Array or an ArrayList in Java.

If you picked option 3, you are ✅. In Java and Kotlin, you can randomly access elements in a Stack.

Let’s make things more interesting. By trying to iterate over this stack.

Iterating Over a Stack

If you were to try to execute this piece of code, what do you think will happen?

public class Main {
    public static void main(String[] args) {
    
        String input = "hello world";
        
        Stack<Character> stack = new Stack();
        
        for (char c : input.toCharArray()) {
            stack.push(c);
        }
        
        Iterator it = stack.iterator();
        while (it.hasNext()) {
            System.out.print(it.next());    
        }

    }
    
}

Can you say which of the two following outputs, would this execution produce?

  1. hello world
  2. dlrow olleh

If you picked option 1, you are ✅. Even though your intuition would tell you otherwise, Java and Kotlin would print the elements in the FIFO (first in first out) order. 🙈

Why are Stacks Misbehaving?

Java like any other language was written by human engineers. Just like we do, they also made a bad design decision. The decision was to extend Stack class with Vector class.

This is the reason why we have random access in the Java and Kotlin Stacks and a FIFO strategy based iterator.

Also, this is not something new but a very old bug, which was actually reported back in 2001. However, it was closed with the following comment:

It was an incorrect design decision to have Stack extend Vector (“is-a” rather than “has-a”). We sympathize with the submitter but cannot fix this because of compatibility.

If you are interested in the bug ticket, here it is [JDK-4475301].

Stack is a Class and not an Interface!

Unlike most of the collections including but not limited to Lists, Maps and Queues, Stack is not an interface. This means that if you use it in your code, you are committing to the implementation itself. This can bite you at some point of time in future, should you feel a need to move away from it.

Before moving further, let’s quickly recall the problems with the Stack class in Java and Kotlin.

  • Stacks allow random access to the elements.
  • Iterator of the stack follows FIFO strategy and not LIFO strategy.
  • Stack exists as a Class and not an Interface in Java and Kotlin.

What Should You Use Instead?

Both Java and Kotlin offer an interface called Deque. It is short for “double ended queue” and is we usually pronounce it as “deck”.

It can be serve as a LIFO (last in first out) based collection, also referred to as a Stack. In fact the official java documentation recommends this interface over the legacy Stack class.

 This interface should be used in preference to the legacy Stack class.

Another consistency it brings along is that there is no random element access. The iterator also returns elements in the order from first (head) to last (tail).

So next time you encounter a problem where you want to use a Stack, remember not to use the Stack class directly but a Deque.

I was super amazed when I came across this information, especially because I have been writing Java code for over 7 years and I must confess I didn’t know this until very recently.


I am sure you and me aren’t the only ones who didn’t know this. Simply tweet this article out and tag as many people as you think may not know this and wait for their confessions 😄

For more such blogs you can follow me Twitter or connect with me on LinkedIn.

CategoriesAndroid

Working with In-App Updates in Android​

Do you know what’s one of the things that makes me envious of web developers? It is the fact that without relying on in-app updates they can release anything anytime and can be sure that all the users are going to see their new code almost instantly.

For software developers writing code for mobile apps the story is a bit different. The code we write for the mobile apps after every release has to go through the stores’ review process and then slowly gets on to the devices of our wonderful users.

 In-App updates by Google Play Core library are here to change the game.

Default Update Behaviour for Android Apps

In theory, updates on Android apps occur automatically, once the following constraints are met:

  • The device is connected to the Internet over Wi-Fi.
  • It is plugged in and charging.
  • The device is idle and not actively used.
  • The app that has to be updated is not running in the foreground.

As per Google Play’s help page, we know that devices check for updates once a day. This means that it will be at most 24 hours before an app update is added to the update queue.

Default Updates: The Reality

While we expect the users to be on the latest versions of our apps, the reality is a tad different. There may be too many apps in the update queue, automatic updates turned off, or the app may have been in the foreground when it was about to get the update.

Analysis of the app version adoption graphs of your releases will teach you you a number of interesting things:

  • Majority of your app versions are never adopted by 100% of your users. (Newly launched apps will be an anomaly in this case.)
  • Adoption acceleration tends to zero when you hit 75%-80% adoption rate.
  • You have to wait for several months if you want, say, 95% of your users to be off of legacy versions of your app.
App version adoption over last 90 Days
App version adoption

For minor changes, and regular updates it doesn’t really matter a lot and it is completely ok to have a slow and gradual adoption. The real need to get majority users on the latest version arises in case you have a critical fix, or if you want to deprecate a particular version due to any reason. That’s when you want to nudge your users to update the app if they haven’t.

How did we Force In-App Updates till now?

If you have been writing apps for at least a year, you might have found various creative solutions to ask your users to get the latest version of the app. Don’t judge me when I mention some that I have personally used:

  • Sending silent PUSH notifications to tell the clients that an update is available.
  • Using clients to POLL the backend to check if there is an update available?
  • Scraping Google Play web page in the app to see if the update is available.

If you or your company use another approach to solve this problem. I’d love to learn more about it. Hit me up on Twitter 👉 @droidchef

What’s new: The In-App Updates API?

In-App Updates is a feature of the Google Play Core Library which allows you to prompt your users to update the app when a new version is available. Minimum requirements for it to work, include:

  • Devices running Android 5.0 (API level 21) or higher.
  • Google Play Core library version 1.5.0 or higher.

Types of In-App Updates User Experience

Flexible Updates

This UX leads the user to a small dialog offering an update which can happen in the background and the user can continue using the app. Once the update has been downloaded and installed, user will be prompted to restart the app so that the changes can come into effect.

It is useful when you have a new feature that you’d want your users to try.

Immediate Updates

This UX leads the user into a full screen dialog, prompting the user to update the app in the foreground and prevent the user from using the app during this operation. In this flow, Google Play will handle the restart operation of the app as well.

They are useful when you have a critical update that you want your users to install.

Next we will learn how to implement Immediate Updates flow into your android apps.

Getting the dependency

If you don’t already use the Google Play Core library, you can add it to your app’s build.gradle file like this. As of writing this article, the latest version of the library is 1.7.1

implementation "com.google.android.play:core:1.7.1"

This dependency is downloaded from Google’s Maven Repository. So make sure you also include that repository in your project’s build.gradle file.

Checking for Update Availability

Before you can actually launch the update flow, you must check if there is an update available for the user. To do that, we will ask the AppUpdateManager about it.

Let us say we want to trigger the prompt from our MainActivity.

This could be a different entry point for your app so choose it as per your need. I will just refer to the MainActivity as our entry point for the purpose of this article.

Now, open your activity file and create an empty method called checkForAppUpdates()

	private fun checkForAppUpdates() {
		// Logic for checking and triggering updates goes here
	}

Logic for checking and triggering updates will go here, so let’s get started.

First, we need to get hold of the AppUpdateManager

	private fun checkForAppUpdates() {
    	val appUpdateManager = AppUpdateManagerFactory.create(context)
	}
    

Next, we ask the manager about the update information.

	private fun checkForAppUpdates() {
    	val appUpdateManager = AppUpdateManagerFactory.create(context)
		val appUpdateInfoTask = appUpdateManager.appUpdateInfo
    }
    

Now the appUpdateInfoTask that we got is an Intent that you will use to check for the update

	private fun checkForAppUpdates() {
    	val appUpdateManager = AppUpdateManagerFactory.create(context)
		val appUpdateInfoTask = appUpdateManager.appUpdateInfo
        appUpdateInfoTask.addOnSuccessListener { appUpdateInfo ->
          if (appUpdateInfo.updateAvailability() == UpdateAvailability.UPDATE_AVAILABLE) {
              // Request the update.
          }
    }
    

Starting an Update

In case there is an update available, we we will request android to start the activity for the update

	private fun checkForAppUpdates() {
    	val appUpdateManager = AppUpdateManagerFactory.create(context)
		val appUpdateInfoTask = appUpdateManager.appUpdateInfo
        appUpdateInfoTask.addOnSuccessListener { appUpdateInfo ->
          if (appUpdateInfo.updateAvailability() == UpdateAvailability.UPDATE_AVAILABLE) {
              appUpdateManager.startUpdateFlowForResult(
              	appUpdateInfo,
              	AppUpdateType.IMMEDIATE,
              	this,
              	7500) // REQUEST_CODE_IN_APP_UPDATE = 7500
         }
    }
    

7500 is a request code we are using for the activity we are starting for result. You can choose any number that is unique for your app and can store it in the place you aggregate your Constants.

Getting Ready for the Action

Next, call this method from the onCreate()of your activity.

  	override fun onCreate(savedInstanceState: Bundle?) {
    	super.onCreate(savedInstanceState)
        // ... existing logic
    	checkForAppUpdates()
  	}

With all this code so far, you should be able to get the ball rolling.

Building the APKs or app Bundles

Since we need to emulate a real release process, we need to build an APK or app bundles that we are going to use for testing. Installing the app straight away from Android Studio or command line will not work.

To assemble the release we can simply ask Gradle to do it. Make sure you are in the project directory and then run this command.

First build one version of the app.

Let’s call it 1.0.0 and version code 1.

Then build the second version of the app, which will act as an update for the previous one.

Let’s call it 1.0.1 and version code 2.

If you have a lot of flavours in your project you can also build a specific flavour in case that makes things faster for you to test.

For simplicity, I’ll just run this command.

./gradlew assembleRelease

Finally when this task finishes successfully. You should have your APKs or app bundles ready. I assume you know where to find your release APK or app bundles.

Testing In-App Updates

You need a Google Play Developer account for this step. We are going to leverage internal app sharing feature of the Google Play Console to test our in-app updates. If you’re not familiar with it, I’d highly recommend you to first look at it and then come back to the article. As that link contains some crucial steps related to adding accounts that have access to your test apps, and also how to enable internal app sharing in your Google Play app on your device.

Head over to the internal app sharing upload page. On this page you’ll see an option to upload the release assets.

Internal app sharing page in Google Play console
Internal app sharing page in Google Play console

Uploading APKs and app Bundles

Drag and drop the first version here and once the upload finishes you will have a download link below.

Now do the same thing with your second version and have a link ready before we move on to the next step. The download links on that page should look like this.

Download links section of Internal app sharing page.
Download links section of Internal app sharing page.

Finally make sure you don’t have any other versions of this app on your device.

Installing the First Version

Now carefully copy the link of version 1.0.0 and use it to install this app on your device.

Using this link on the device, will take you to a screen that looks something like this

in-app updates testing step 1

Click on install, to start the installation. Once the installation is finished. Open the app and head over to the activity where you put your in-app update logic.

Nothing should happen at this point. You might be wondering why am I not getting the update? 🤔

This is because Google Play still doesn’t know if an update is available or not.

Notifying Google Play

Next, copy the second version’s link and open that on your device. It should open a screen that looks like this. Please DO NOT click the update button here.

in-app updates testing step 1

This step ensures, Google Play knows that there is an update available.

Now make sure you kill your app from the background.

Updating the app

Start your app and head over to the activity that has your in-app update logic. You will see the in-app update screen soon after the activity appears.

in-app updates testing step 3

Finally you can click on the update button and let Google Play do its magic.

Once the update finishes, your app will restart automatically. You can verify the version name by looking into the app settings as well.

Handling a Stalled Update

As all users are not patient or there might be a scenario where the user closes or terminates your app during the update. Google Play is smart enough to make sure that the update will continue to download and install in the background, however we must ensure that it is applied correctly when the user returns to the foreground.

Fortunately, the library has us covered for that scenario too. Remember how we were able to check if there is an update available using UpdateAvailability.UPDATE_AVAILABLE state.

There is another state that you can compare the availability against which is called UpdateAvailability.DEVELOPER_TRIGGERED_UPDATE_IN_PROGRESS.

You can add an OR condition for checking this state too and you should be covered.

	private fun checkForAppUpdates() {
    	val appUpdateManager = AppUpdateManagerFactory.create(context)
		val appUpdateInfoTask = appUpdateManager.appUpdateInfo
        appUpdateInfoTask.addOnSuccessListener { appUpdateInfo ->
          if (appUpdateInfo.updateAvailability() == UpdateAvailability.UPDATE_AVAILABLE ||
              appUpdateInfo.updateAvailability() == UpdateAvailability.DEVELOPER_TRIGGERED_UPDATE_IN_PROGRESS) {
              appUpdateManager.startUpdateFlowForResult(
              	appUpdateInfo,
              	AppUpdateType.IMMEDIATE,
              	this,
              	REQUEST_CODE_IN_APP_UPDATE)
         }
    }
    

Since the user can just come back from the background without killing the app during the update, you might also want to call the update check from onResume() like this.

  
  	override fun onResume() {
    	super.onResume()
    	checkForAppUpdates()
  	}

Reacting to Update Status Callbacks

If you have a keen eye for the code, 🧐 you might have figured out that we are actually starting an activity for result. This leads us to our final piece of handling failed updates. For simplicity, we just check if the result was not ok, we try to prompt the user for the update again as we are dealing with immediate in-app updates right now.

  override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent) {
      if (requestCode == REQUEST_CODE_IN_APP_UPDATE) {
          if (resultCode != RESULT_OK) {
              checkForAppUpdates()
          }
      }
  }

Preventing Excessive Update Checks

As a smart developer that you are 😎, I am sure you have a question in your mind. Aren’t we going to check for updates too frequently? The answer is yes, with this approach you will end up checking for updates every time your activity’s onCreate() or onResume() is called.

As we are currently only dealing with Immediate updates, they should only be intended for critical updates. Ideally you should guard the check with some short-circuiting logic.

The way I work around this problem is by using a Feature Flag surrounding the checkForAppUpdates(). The way we intend to use it, is by targeting specific versions of the app. So the flag only returns true for specific version and otherwise false. Using this we can target our users on a specific version to perform an immediate in-app whenever there is a need for one.

  
  	override fun onCreate(savedInstanceState: Bundle?) {
    	super.onCreate(savedInstanceState)
        if (myFeatureFlagManager.isFlagEnabled(FeatureFlag.IN_APP_UPDATE) ) {
    		checkForAppUpdates()
        }
  	}

What did you learn today?

If you’ve followed the post till here, 👏 Congratulations, you’ve equipped yourself with some knowledge about how to use in-app updates from Google Play Core library in Android. If you manage to get this working in your app, I’d love to try it out as a user.

Tell me about your app here 👉 @droidchef

What is Coming Next?

In the next blog, we will learn how to implement and handle flexible in-app updates.

Where to Go From Here?

Want to learn more about the In-App Updates. You can head over to Google’s official documentation here.

If you are facing any problems with testing in-app updates, there is a specific troubleshooting section on the same page.

If you like this post, please show your support by sharing it and if you spot any issues here, don’t hesitate to shoot them my way. Let’s connect on LinkedIn and Twitter.

CategoriesAndroidFlutterTalks

Flutter Add-to-App in Production: A War Story

Are you planning to use Flutter Add-to-App feature in Production? Make sure you carefully listen to my story about using this in production.

Our team at Getaround did a thorough research investigating ways to integrate Flutter into our Native apps using Add-to-App. We successfully managed to ship a feature built completely in Flutter. There were a lot of hurdles we had to cross in our journey. This talk of mine throws light on them. In the end, I also share the future of Flutter at Getaround. What do you think it would be? Did we decide to go big or go home? Answers to all these questions in the video below 👇

Please remember that Flutter is under active development. A lot of things that I mention in the talk may have changed or would no longer be valid. The questions that I pose though, will still be valid for any cross-platform framework you or your team are evaluating.

Also, if you are interested in going over the slides again or referring to them please feel free to do so with proper attribution. ❤️

I have been speaking at conferences worldwide for over 6 years now. The full list of my talks is available here. If you’d like me to present a talk at your Meetup, Conference or at one of your organization’s private events please reach out to me on Twitter.

CategoriesAndroidTalks

Mobile Experimentation Talk at Droidcon

How do I run experiments in my mobile app? What does A/B testing on Android & iOS look like? If similar questions around mobile experimentation cross your mind, you’re in the right place.

Im this post, I present you with my talk from Droidcon Berlin 2019 that will teach you how to efficiently write & setup experiments (A/B tests). Further it will showcase a way to create apps that keep the customers at the centre of everything.

Having run over a 100 experiments alone in the last 2 years at Booking.com. I present some hard to believe facts related to user experience and design that developers often overlook while shipping features.

If you watch this talk you will first learn how to frame the hypothesis of an experiment. Then learn to calculate runtime of an experiment. Followed by tips to set up metrics to measure success. All this so that you can act as a product manager yourself in future!

Think of this talk as a crash course for Mobile Developers to become Product Owners 😄

I am always excited to discuss various aspects of mobile experimentation especially because there is no one way to do it correctly. Different types of mobile experiments pose different challenges. If you or your organisation are have an interesting challenge related to mobile experimentation I would love to hear it out, discuss and learn from.

Also, if you are interested in going over the slides again or referring to them please feel free to do so with proper attribution. ❤️

I have been speaking at conferences worldwide for over 6 years now. The full list of my talks is available here. If you’d like me to present a talk at your Meetup, Conference or at one of your organization’s private events please reach out to me on Twitter.

CategoriesAndroidAndroid StudioSoftware Development

Android Studio always modifying codeStyleSettings.xml – Fixed

Yesterday a colleague of mine started experiencing a weird issue with their android studio. Whenever they’d build the code, a change would be written to codeStyleSettings.xml file automatically.

The change at the first glance was clearly unrelated to something they had been working and hence they weren’t able to figure out what could be the cause of this issue.

What did the change look like?

<Objective-C-extensions>
  <option name="GENERATE_INSTANCE_VARIABLES_FOR_PROPERTIES" value="ASK" />
  <option name="RELEASE_STYLE" value="IVAR" />
  <option name="TYPE_QUALIFIERS_PLACEMENT" value="BEFORE" />
  <file>
    <option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Import" />
    <option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Macro" />
    <option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Typedef" />
    <option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Enum" />
    <option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Constant" />
    <option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Global" />
    <option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Struct" />
    <option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="FunctionPredecl" />
    <option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Function" />
  </file>
  <class>
    <option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Property" />
    <option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Synthesize" />
    <option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="InitMethod" />
    <option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="StaticMethod" />
    <option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="InstanceMethod" />
    <option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="DeallocMethod" />
  </class>
  <extensions>
    <pair source="cpp" header="h" />
    <pair source="c" header="h" />
  </extensions>
</Objective-C-extensions>

Clearly it wasn’t something related to our code since we aren’t doing anything with Objective-C in our android project. This made me want to check the android studio config on that machine, to see if some preferences were changed by mistake, or through an update or any other means.

Quickly searching for objective-c, I found that there were changes being written to the Inspections in the IDE. However, the dev denied making any such changes.

What do you think was the next obvious step for me? Google :]

Turns out, this was an old issue that someone asked about, on StackOverflow 3 years ago, and this, was the top rated and accepted answer that led us to the solution.

The <Objective-C-extensions> Section is added by the Android NDK Support Plugin. Which was added in 1.3 and is activated by default. 
If you have activated this plugin it adds the Section to your codeStyleSettings.xml. Otherwise it will be removed.

Answer by devtribe

Even though the dev had not activated this plugin on their own, maybe an update introduced this change and started causing this weird behaviour.

Here are the steps to fix the problem:

Step 1: Open Preferences in your Android Studio. Shortcut on Mac OS is Command + , (comma) and on Windows is Control + Alt + S
Step 2: Goto Plugins and find the Android NDK Support plugin
Step 3: Uncheck the box to deactivate this plugin, As soon as you do that, a warning dialog will appear asking you to disable Android APK Plugin, Click OK
Step 4: Once deactivated, click on Apply and restart your Android Studio!

Now you can remove the file from your git change log if it appears there, restart Android Studio and the problem would be fixed.

Warning: The solution requires you to disable two plugins which you might want to use at a later stage, so keep that in mind before you do that.

CategoriesUncategorized

When RecyclerView couldn’t hold onto the weights of our LinearLayouts

While testing our android app on tablets a while ago, a developer reported that the app had a glitch on the Search Results in landscape mode. After making a search, when we scroll on the search results page, the screen becomes unresponsive.

We immediately started investigation and were easily able to reproduce this behavior on multiple real devices as well as on emulators. So it was not device specific and the amount of memory on the device was for sure not a concern.

The first logical step that came to our mind was to profile and see if we can spot a bottleneck in the CPU Usage or Memory Usage monitors.

While memory profiler showed us a lot of things that we were tempted to look into, one of the devs said we must first look at the CPU usage because it seems some heavy computation is happening on the main thread that is rendering the app completely unusable. We moved to the CPU usage flame chart in unison. 

Here we found out that the RecyclerView was generating more Views than needed. It was then that we figured, for the initial load of the screen, we need 5 different types of views which the RecyclerView might want to already create and cache. What we saw didn’t look very nice. Here is the picture of the Call chart.

The first blue colored call that you see when viewing from top to bottom is the call to onCreateViewHolder method. Something kept on triggering the call to this method infinitely. 

We started playing with RecyclerView API to control view cache size but to no avail.

We also tried to look into our ViewHolder to find out if “maybe” we were doing something nasty there but couldn’t find anything that contributed to this problem.

While reading the code in the fragment, we stumbled upon an issue reported on Google, titled RecyclerView notifyItemChanged Prevent Scroll.

Here is the code snippet which led us to that link:

recyclerView.setHasFixedSize(true);
// In tablet landscape mode the RecyclerView inflated all views because of the bug :
// This was also cause by the upgrade to support library 23.3 and 23.4
// If this bug is fixed by Google we might use the default for setAutoMeasureEnabled to true again if that is better.
srLayoutManager.setAutoMeasureEnabled(false);

Apparently, due to some changes in the past releases of RecyclerView something changed again and even, this fix stopped working.

We then went to the XML file of the Activity in which the two fragments were being loaded on the tablet. 

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
   xmlns:android="http://schemas.android.com/apk/res/android"
   android:layout_width="match_parent"
   android:layout_height="match_parent"
   android:orientation="horizontal">
   <FrameLayout
      android:id="@+id/searchresults_list"
      android:layout_width="0px"
      android:layout_height="match_parent"
      android:layout_weight="1"/>
   <View
      android:layout_width="1dp"
      android:layout_height="match_parent"
      android:background="@color/bui_color_grayscale_light"/>
   <FrameLayout
      android:id="@+id/searchresults_map"
      android:layout_width="0px"
      android:layout_height="match_parent"
      android:layout_weight="1"/>
</LinearLayout>

A lot of you might have understood the problem by now, right? But I’ll still continue for those who haven’t.

RecyclerView’s parent was measuring it with unlimited width and height spec. So the parent was literally asking the RecyclerView to layout as many items as it can, which it did – well, at least tried to. 

The problem is that we were using weighted width on a horizontal weighted linear layout. To calculate the weight distribution, it measured both children with unlimited space, then distributed the remaining space. 
Even though our RecyclerView container was MATCH_PARENT because it was a horizontal linear layout and baseline align is set to true (by default, it is true), LinearLayout tried to measure children’s height to be able to align them, thus, measuring the child with unlimited height. 

Inferred from Official Android Documentation

This is not really a bug in the RecyclerView API. LinearLayout could be more clever not to do this when the child is match_parent but since we were setting baseline align in match_parent children, it was also inconsistent. 

We wrote another variant of the same screen using RelativeLayout which fixed the issue for us.

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
   xmlns:android="http://schemas.android.com/apk/res/android"
   android:layout_width="match_parent"
   android:layout_height="match_parent"
   android:orientation="vertical">
   <FrameLayout
      android:id="@+id/searchresults_list"
      android:layout_alignParentStart="true"
      android:layout_toStartOf="@+id/searchresults_tablet_divider"
      android:layout_width="match_parent"
      android:layout_height="wrap_content"/>
   <View
      android:id="@+id/searchresults_tablet_divider"
      android:layout_width="1dp"
      android:layout_height="match_parent"
      android:layout_centerInParent="true"
      android:background="@color/bui_color_grayscale_light"/>
   <FrameLayout
      android:id="@+id/searchresults_map"
      android:layout_width="match_parent"
      android:layout_height="wrap_content"
      android:layout_alignParentEnd="true"
      android:layout_toEndOf="@+id/searchresults_tablet_divider"/>
</RelativeLayout>

Here is the call chart we saw while running the app with the new variant of the Layout.

The number of calls to onCreateViewHolder reduced significantly and RecyclerView only drew what we expected it to.

This is how we solved this major bottleneck in the tablet version of the app.

In the end, I’d like to conclude that the Android Studio Monitors for Profiling CPU and Memory Usage can be very handy. Never underestimate the power of profiling your code, you’ll always find something to improve there. But be careful as it can be very tempting to fall into traps of code that doesn’t really need optimization. 

CategoriesAndroidTalks

Modularization in Android

We have all heard stories about modularization, faster builds, quicker iterations and all the good things we get through it. But when it comes to actually breaking your legacy into modules, your code can give you a serious run for money. In this talk I share how 60+ Android Devs at Booking got together to defeat the legacy and modularized the app to get 10 times faster builds. If you watch this talk you will be able to learn the best practices about modularizing your large code bases and avoid the pitfalls that we discovered in journey.

Also, if you are interested in going over the slides again or referring to them please feel free to do so with proper attribution.❤️

I have been speaking at conferences worldwide for over 6 years now. The full list of my talks is available here. If you’d like me to present a talk at your Meetup, Conference or at one of your organization’s private events please reach out to me on Twitter.

CategoriesUncategorized

Learn how to test your Android app for flaky connections!

Request timed out! But you didn’t expect it, did you? Of course not because while you were writing the app and testing the code you were always on your blazing fast WiFi connection or a 4G LTE network. But in the real world, all your users don’t have access to such a network connection at all times.

Would you want them to suffer?
Would you want your app to behave in a strange manner in that case?
Would you want to create a bad user experience?
Would you want to have an unsatisfied customer?
Do you always test all your features depended on network requests for flaky connections?

If your answer to all the above questions is “No”, then I have a simple solution for you, that’ll make your life a lot easier to test your features for these scenarios and have a failure mechanism in place to be more responsive to the user.


Implementation

The solution is pretty straight forward, create an Interceptor for your network requests and delay or fail them. Let’s look at how to implement this interceptor with OkHttp and provide easy access to it through a UI to all the stakeholders that are responsible or are willing to test your application.

public class NetworkThrottlingInterceptor implements Interceptor {

private static boolean failRequests;

private static final AtomicLong failRequestCount = new AtomicLong(Long.MAX_VALUE);

private static boolean delayAllRequests;

private static long minRequestDelay;

private static long maxRequestDelay;

private final Random random = new Random(4);

@Override
public Response intercept(Chain chain) throws IOException {
if(failRequests) {
long failC = failRequestCount.get();
if (failC > 0) {
failRequestCount.compareAndSet(failC, failC-1);
throw new IOException("FAIL ALL REQUESTS");
}
}
if(delayAllRequests) {
long delay = minRequestDelay;

if(minRequestDelay != maxRequestDelay) {
delay = (long) ((random.nextDouble() * (maxRequestDelay - minRequestDelay)) + minRequestDelay);
}
long end = System.currentTimeMillis() + delay;
long now = System.currentTimeMillis();
while(now < end) {
try {
Thread.sleep(end - now);
} catch (InterruptedException e) {
// Nothing to do here, timing controlled by outer loop.
}
now = System.currentTimeMillis();
}
}
try {
return chain.proceed(chain.request());
} catch (Exception ex) {
if (BuildConfig.DEBUG) {
Request request = chain.request();
Log.e("NETWORK", "Exception during request", ex);
Log.e("NETWORK", "Request was to: " + request.url().toString());
}
throw ex;
}
}

public static void delayAllRequests(long minRequestDelay, long maxRequestDelay) {
if(minRequestDelay == 0 && maxRequestDelay == 0) {
delayAllRequests = false;
} else {
NetworkThrottlingInterceptor.minRequestDelay = minRequestDelay;
NetworkThrottlingInterceptor.maxRequestDelay = maxRequestDelay;
delayAllRequests = true;
}
}

public static void failNextRequests(long failCount) {
if(failCount == 0) {
failRequests = false;
}
else {
failRequestCount.set(failCount);
failRequests = true;
}
}
}

The logic in the interceptor is quite simple, but for verbosity, I’ll still explain it here:

We have two scenarios that we deal with, through this interceptor:

  1. Delay a response for a given network request.
  2. Fail next n network requests.

Scenario 1: Delay a response for a given network request

For this scenario, we set a minimum and maximum value and for a given request we find a random value between this range and ask the thread to sleep for that time.

You can create a different combination of settings that you give access to, through your UI, for example:

  1. Good Network (min = 0, max = 0)
  2. Slow Network (min = 1 second, max =5 seconds)
  3. Very Slow Network (min = 5 seconds, max = 10 seconds)

By default, your app can always be set to work on the Good Network. And then the users can switch to other networks as and when needed.

Scenario 2: Cause next n network requests to fail

For this scenario, we maintain a fail counter that keeps decreasing on each request until it becomes zero. And while this happens we just throw an IO Exception to cause the network request to fail, you can even cause a failure by other means like creating a fake failure response with some status code 5xx.


Interceptor Integration

Injection of this interceptor is quite simple you can add it at the time of configuration of your OkHttp client instance like so.

OkHttpClient okHttpClient = new OkHttpClient.Builder()
.addNetworkInterceptor(new NetworkThrottlingInterceptor())
.build();

Interceptor Exposure

In our app, we do it through a debug screen that contains a simple Spinner widget that holds all these values that we can select and modify the interceptor configuration at runtime, the code for which looks like this

private void setupNetworkThrottler() {
spNetworkInterceptor = findViewById(R.id.sp_network_throttle);
ArrayAdapter<String> networkSpeedTypeAdapter = new ArrayAdapter<>(this, android.R.layout.simple_dropdown_item_1line,
new String[]{"Good network", "Moderate network 1-5s delay", "Poor network 5-10s delay"});
spNetworkInterceptor.setAdapter(networkSpeedTypeAdapter);
spNetworkInterceptor.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
switch (position) {
case 0: NetworkThrottlingInterceptor.delayAllRequests(0,0);
break;
case 1: NetworkThrottlingInterceptor.delayAllRequests(1000, 5000);
break;
case 2: NetworkThrottlingInterceptor.delayAllRequests(5000, 10000);
break;
}
}

@Override
public void onNothingSelected(AdapterView<?> parent) {
NetworkThrottlingInterceptor.delayAllRequests(0,0);
}
});
}

If you have other interesting solutions that you can leverage this interceptor for, please share them with me on Twitter where you can find me as @droidchef.

I’d like to give credits to Jonathan Farris, who originally came up with this solution.

CategoriesAndroidTalks

How to Love Your Developers Like Your Customers

Abstract:

In this talk I’ll show how you can increase developer productivity of your Android Teams by adding simple debug features to your app, hacking gradle and Android Studio to turn your Devs into Super Heroes who ship much better products faster than ever. Everybody talks about Design, Architectures, Libraries and what not, but, what we often forget is that most of the times quick wins for us as developers can be much more beneficial than tackling large refactors to use the latest technologies available so if we apply the 80-20 rule to our development workflow we can achieve so much more. People with any level of android experience can see this talk.

Also, if you are interested in going over the slides again or referring to them please feel free to do so with proper attribution. ❤️

I have been speaking at conferences worldwide for over 6 years now. The full list of my talks is available here. If you’d like me to present a talk at your Meetup, Conference or at one of your organization’s private events please reach out to me on Twitter.

CategoriesUncategorized

Making the most out of Android Studio Debugger

This is a trick I learnt very recently from a Senior Android Developer at my company and now I feel miserable about all the time I had spent waiting for Gradle builds to test my changes while writing Android Apps.

Here is a typical scenario every android developer would have come across at least once during their development lifetime. You have a List of items that you want to show in a ListView or RecyclerView.

Below is our beloved onBindViewHolder method that binds your model to your views of the RecyclerView.

    @Overridepublic void onBindViewHolder(ViewHolder holder, final int position) {final String name = values.get(position);        holder.txtHeader.setText(name);        holder.txtFooter.setText("Footer: " + name);    }

Now lets say you wanted to change the text color for every 3rd element in the list. So the code would look something like this

@Override
public void onBindViewHolder(ViewHolder holder, final int position) {

final String name = values.get(position);
holder.txtHeader.setText(name);
if (position % 3 == 0) {
holder.txtHeader.
setTextColor(Color.GREEN);
}
holder.txtFooter.setText("Footer: " + name);
}

Then you’d click on Run and wait for build to finish and see your changes, right?

Copied Image from Anand Shekhar Roy’s post on Speeding up your gradle builds.

Now you’d be thinking what other way could we achieve this?

Welcome Android Studio Debugger, yes we need no external plugin or tool to achieve the above task and more over, we won’t even have to build the project, you heard me, we will by pass Gradle 🙂 Here’s how !

Step 1 — We need to define a Run Config

This run config would allow us to launch our app and attach the debugger from android studio to it, alternatively you can also attach it to an already running process by your hand.

Click on Run -> Edit Configurations

On the Top-Left Corner of the Dialog, Click on the + icon and choose Android App

Now give it a name, I like to call it Run-Only, but you can call it anything.

Choose the module which has your app code, in the below screenshot it is called app.

Important step : 
In Installation Options, Choose Nothing for Deploy.
In Launch Options, Choose Default Activity
In Before Launch, Remove the Gradle-aware Make task.

So the config should look like this screenshot below

Now you can apply and save this config. It should be selected automatically by Android Studio now, if not just select it from the list.

Now apply a Breakpoint some close before the line you’d like to test a change, in our case we’ll put it where we set the text.

Right Click on the Break Point and Uncheck Suspend. Please write back to me on Twitter, if you have never seen this before, I’d very happy to know I showed you something new 🙂

As soon as you uncheck this dialog, you would see this dialog expand with a lot of options.

What we are interested right now is in Evaluate and log. We will write a statement there to test a change in our RecyclerView’s Item. Click on the small blue colored icon next to the dropdown arrow of the Evaluate and log text input box to expand it to a bigger editor and add your testing statement, like this and click Ok and then click on Done.

Now Click on Debug icon with Run-Only Config Selected and see the Magic.

The App Should start from your default activity and you should see the changes applied there, also if you pay close attention to the IDE, on the very bottom you’ll just see one task running that says Launching Activity.

Would love to hear your experiences when you try this trick !! My Twitter Handle is @droidchef