Flag Attributes in Android — How to Use Them

I’m sure you have seen something like the following line very often while writing the XML attributes for your views or layouts.

attribute="option1|option2"

Notice the | between the options. It is not only a fancy separator, it is a bitwise operator merging the two options into one single value.

The following will explain what exactly Bit Flags are, how to declare custom XML flag attributes and how to read and work with them in the code.


What Are Bit Flags?

Generally you can see Bit Flags as a number of boolean values stored in one single value.

In the binary system a bit has two states: on and off. Now think about a row of bits where every bit is an indicator for one of your options. When the option is set, the bit has the value 1. If not, it has the value 0.

110

We read this from right to left. The bit for our first option is 0. That means the option is not set. Whereas the bits for the second and third options are 1. This means they are set.

Every integer value has a representation in the binary system and and vice versa.

0 = 0*2³ + 0*2² + 0*2¹ + 0*2⁰ = 0000
1 = 0*2³ + 0*2² + 0*2¹ + 1*2⁰ = 0001
2 = 0*2³ + 0*2² + 1*2¹ + 0*2⁰ = 0010
4 = 0*2³ + 1*2² + 0*2¹ + 0*2⁰ = 0100
8 = 1*2³ + 0*2² + 0*2¹ + 0*2⁰ = 1000

This means we can store our Bit Flag value as a plain integer value. And we can use the bitwise operators (more about them later) directly on integer values.


Declaring XML Flag Attributes

Now, let’s assume that we want to create a custom view called MyView which can draw a border around itself, and that we want to specify on which sites (top, right, bottom, left) it should draw the borders using an XML flag attribute. I will not explain how to actually draw something, I will only explain how to work with flags.

We can declare XML flag attributes like any other attribute. You can find an official documentation here.

In our values/attrs.xml file we declare the new attribute called drawBorder for our view called MyView.

<resources>
    <declare-styleable name="MyView">
        <attr name="drawBorder">
            <flag name="none" value="0" />
            <flag name="top" value="1" />
            <flag name="right" value="2" />
            <flag name="bottom" value="4" />
            <flag name="left" value="8" />
            <flag name="all" value="15" />
        </attr>
        ...
    </declare-styleable>
</resources>

Look exactly at the values we have set for the options. We essentially have 4 options (top, right, bottom, left). The other two options are used to specify that no option is set or that all options are set. The values for the 4 options are chosen, so that when you write them in the binary system, these two statements are fulfilled:

  • Every value has exactly one bit which is set to 1. All other bits are 0.
  • None of the values have the same bit set to 1.

The option none is used to indicate that none of the 4 options is set. And the option all is the sum of the values of the 4 options and indicates that all of the 4 options are set.

We can now use our custom attribute like this in our custom View:

<my.package.name.MyView
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    app:drawBorder="bottom|top" />

Read XML Flag Attributes

Let’s start with the basic class for our custom View. We should declare a constant for each of our options with an equal value as declared above. And a variable for the value that we get from reading the XML attribute. You can have a look about how to read attributes here.

public MyView extends View{    // Constants for the flags
    private static final int BORDER_NONE_DEFAULT = 0;
    private static final int BORDER_TOP = 1;
    private static final int BORDER_RIGHT = 2;
    private static final int BORDER_BOTTOM = 4;
    private static final int BORDER_LEFT = 8;    // Variable for the current value
    private int mDrawBorder = BORDER_NONE_DEFAULT;    public MyView(Context context){
        // Delegate to next constructor
        this(context, null);
    }    public MyView(Context context, AttributeSet attrs){
        // Delegate to next constructor
        this(context, attrs, 0); 
    }    public MyView(Context context, AttributeSet attrs,
            int defStyleAttr){
        super(context, attrs, defStyleAttr);        // Read attributes
        TypedArray a = context.getTheme().obtainStyledAttributes(
                attrs, R.styleable.MyView);        try {
            mDrawBorder = a.getInteger(
                    R.styleable.MyView_drawBorder,
                    BORDER_NONE_DEFAULT);
        } finally {
            a.recycle();
        }
    }
    ...
}

We have now assigned the value specified in the XML layout file to the mDrawBorder variable. If the attribute does not exists in the layout the BORDER_NONE_DEFAULT value is used.


Working With Bit Flags

Okay, how do we know which of our options were set when we only get one value? That’s why we have defined the constants for our options.

There are bitwise operators we can use to check if an option is contained in the current mDrawBorder value and to enable or disable or toggle an option. Let’s have a look at them:

| (bitwise logically or)
Example: 100 | 001 = 101
The result has a 1 on the position where at least one value has a 1.& (bitwise logically and)
Example: 100 & 101 = 100
The result has a 1 on the position where both values have a 1.~ (bitwise inverse)
Example: ~100 = 011
All bits get inverted.^ (bitwise exclusive or)
Example: 100^101 = 001
The result has a 1 on the position where one value has a 1 whereas the other value has a 0.

Let’s assume we have used the attribute in the following two ways. Yes, technically they are correct, but they may look weird 😵.

Example 1: app:drawBorder="none|top"

In this first example the values of none (0 = 000) and top (1 = 001) get combined by the logically or-operator | to the value (001 = 1). The result still contains the flag value for top (which is 1). And also for none (which is 0) because every flag-set contains the 0-flag at every time.

Example 2: app:drawBorder="bottom|all"

In this second example the values of bottom (3 =0011) and all (15 = 1111) get combined to (1111 = 15). The result still contains the flag for bottom since all enables the bits for all of the 4 options.

Check If a Flag is Contained in The Set

Now we need to check which option is contained in the value of the mDrawBorder variable. We do this by calling the following method:

private boolean containsFlag(int flagSet, int flag){
    return (flagSet|flag) == flagSet;
}// Method call
boolean drawBorderTop = containsFlag(mDrawBorder, BORDER_TOP);

We try to add the flag to the existing flag-set and if the value of the flag-set does not change, we can combine that the flag was already contained.

Add a Flag to The Set

Adding a flag is pretty simple. We use the same operator (The logically or-operator) like in the XML attributes:

private int addFlag(int flagSet, int flag){
    return flagSet|flag;
}// Method call
mDrawBorder = addFlag(mDrawBorder, BORDER_LEFT);

We do not need to check if the flag-set already contains the flag that we want to add. When it is already contained, the value simply stays the same.

Toggle a Flag in The Set

Toggling is also very simple.

private int toggleFlag(int flagSet, int flag){
    return flagSet^flag;
}// Method call
mDrawBorder = toggleFlag(mDrawBorder, BORDER_LEFT);

Since the exclusive or-operator ^ only keeps the bits where both bits are different, it will remove the bits that are set in the flag when they are also already set in the flag-set. And it will add them if they are not set in the flag-set.

Example 1: 110^010 = 100 (Binary)
            6 ^ 2  =  4  (Decimal)Example 2: 100^010 = 110 (Binary)
            4 ^ 2  =  6  (Decimal)

Remove a Flag From the Set

Removing a flag is a bit more complicated (we need two bitwise operators), but still easy.

private int removeFlag(int flagSet, int flag){
    return flagSet&(~flag);
}// Method call
mDrawBorder = removeFlag(mDrawBorder, BORDER_LEFT);

First we invert the flag that we want to remove. Then we combine this with the current flag-set. This means only where the bit in the flag was set, we now have a 0. And that’s why we also have a 0 at this position in the final result. The rest of the result is the same as in the original flag-set. Have a look at this example:

110&(~010) = 110&101 = 100 (Binary)
 6 &(~ 2 ) =  6 & 5  =  4  (Decimal)

Bit Flags are also a good alternative if you have a lot of boolean values and especially if you want to store them somehow. Instead of saving a lot of booleans you only need to save one integer value.

You should now be able to define your own flag attributes and work with them in your application. You should also be able to use Bit Flags as an alternative to a number of booleans. When you found this tutorial useful feel free to hit the 💚.


If you have any suggestions on how to improve this tutorial or found a mistake, you can leave a private note at the specific position.

Happy coding 💻.

402