Flag Attributes in Android — How to Use Them

JakobUlbrich
Follow

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 bitwiseoperator merging the two options into one single value.

The following will explain whatexactly Bit Flags are, how to declare custom XML flag attributes and how to read and work with them inthe code.


What Are Bit Flags?

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

In the binary system a bit has twostates:on and off. Now think about a rowof bits where every bit is an indicator for one of your options. When the option is set, the bit has thevalue 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 thebits for the second and third options are 1. This means they are set.

Every integer value has arepresentation 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 BitFlag 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 tocreate 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 usingan XML flag attribute.
I will not explain how to actually drawsomething, I will only explain how to work with flags.

We can declare XML flag attributeslike 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 haveset for the options.
We essentially have 4 options (top, right, bottom, left). The other twooptions are used to specify that no option is set or that all options are set.
The values for the 4options are chosen, so that when you write them in the binary system, these two statements arefulfilled:

  • Every value has exactlyone bit which is set to 1. All other bits are 0.
  • None of the values havethe 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 4options and indicates that all of the 4 options are set.

We can now use our custom attributelike 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 classfor our custom View. We should declare a constant for each of our options with an equal value asdeclared above. And a variable for the value that we get from reading the XML attribute. You can have alook 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 valuespecified in the XML layout file to the mDrawBordervariable. 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 ouroptions were set when we only get one value? That’s why we have defined the constants for our options.

There are bitwise operators we canuse to check if an option is contained in the current mDrawBorder valueand 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 theattribute 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 ofnone (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 valuesof bottom (3 =0011) and all (15 = 1111) get combined to (1111 = 15). The result still contains theflag for bottom since all enables the bits for all of the 4 options.

Check If a Flag is Contained inThe Set

Now we need to check which optionis contained in the value of the mDrawBordervariable. 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 theexisting flag-set and if the value of the flag-set does not change, we can combine that the flag wasalready contained.

Add a Flag to The Set

Adding a flag is pretty simple. Weuse 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 theflag-set already contains the flag that we want to add. When it is already contained, the value simplystays 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 thebits that are set in the flag when they are also already set in the flag-set. And it will add them ifthey 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 morecomplicated (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 wewant to remove. Then we combine this with the current flag-set. This means only where the bit in theflag was set, we now have a 0. And that’s why we also have a 0 at this position in the final result. Therest 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 goodalternative 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 defineyour own flag attributes and work with them in your application. You should also be able to use BitFlags as an alternative to a number of booleans.
When you found this tutorial useful feel free tohit the 💚.


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

Happy coding 💻.

Thanks to

Written by

Follow
See responses (5)

Discover

Welcome to a place where words matter. Onhref="https://medium.com/about?autoplay=1&source=post_page-----ac4ec8aee7d1----------------------"class="bb bc bd be bf bg bh bi bj bk bn bo hr hs ia">Watch

Make

Follow all the topics you care about, and we’lldeliver the best stories for you to your homepage and inbox.class="bb bc bd be bf bg bh bi bj bk bn bo hr hs ia">Explore

Become a member

Get unlimited access to the best stories onhref="https://medium.com/membership?source=post_page-----ac4ec8aee7d1----------------------"class="bb bc bd be bf bg bh bi bj bk bn bo hr hs ia">Upgrade
AboutHelpLegal