android

Multi-module Lint Rules 🤹‍♀️

I have been learning a LOT about Lint the past year. Our team has grown 5x since I joined more than three years ago, and it became really obvious really quickly that we should be letting robots do a lot of the mundane and repetitive enforcement of our team’s code conventions.

13 min read

Accurate Measurements With getTextBounds()

We have a few custom spans in our app and over the last few days I have been poring over one of them. I was trying to see if the implementation could be improved but before that could happen I needed to understand what it was trying to do first.

5 min read

On-Device Debugging Part V: Strut Your Stuff

Over the past year, my team have been steadily building a Developer Options screen for our app. It is a simple PreferenceScreen available on debug builds that help us:

  • figure out what’s going on without needing to be attached to a computer
  • test various configurations without re-installing
  • have a host for various experimentations we are trying to explore
2 min read

On-Device Debugging Part IV: Log All The Things!

Over the past year, my team have been steadily building a Developer Options screen for our app. It is a simple PreferenceScreen available on debug builds that help us:

  • figure out what’s going on without needing to be attached to a computer
  • test various configurations without re-installing
  • have a host for various experimentations we are trying to explore
3 min read

On-Device Debugging Part III: Inspect, Reset, Repeat

Over the past year, my team have been steadily building a Developer Options screen for our app. It is a simple PreferenceScreen available on debug builds that help us:

  • figure out what’s going on without needing to be attached to a computer
  • test various configurations without re-installing
  • have a host for various experimentations we are trying to explore
4 min read

On-Device Debugging Part II: Timbeeeeeeer!

Over the past year, my team have been steadily building a Developer Options screen for our app. It is a simple PreferenceScreen available on debug builds that aims to help us:

  • figure out what’s going on without needing to be attached to a computer
  • test various configurations without re-installing
  • have a host for various experimentations we are trying to explore
3 min read

On-Device Debugging Part I: Now It’s On, Now It’s Off

Over the past year, my team have been steadily building a Developer Options screen for our app. It is a simple PreferenceScreen available on debug builds that aims to help us:

  • figure out what’s going on without needing to be attached to a computer
  • test various configurations without re-installing
  • have a host for various experimentations we are trying to explore
4 min read

Shortcuts to Shortcuts

It has been a few years since I last looked at implementing app shortcuts, and lately I have been looking at them again. I remember implementing them the first time they were released for Android N, but as with life, things have changed a bit.

3 min read

Unwrapping Framework Binding Adapters

For the past year or so, my team has been all-in with data binding. And if you know me at all, it obviously makes me one happy duck!

3 min read

Ya Basic

Over the last year or so, we have been writing a lot of Kotlin at work. There is a consensus within the team that we all like working with the language. It really helps our productivity a lot by reducing a lot of boilerplate, we can actively enforce nullability rules that makes business logic obvious, and having the option to make extension functions offers a lot of flexibility.

2 min read

Selectively Resetting SharedPreferences

I have recently been working on a feature that has a bunch of pre-conditions. Things like the user must be logged in AND the feature flag has to be turned on AND it only appears the first time the user lands on the screen.

1 min read

Effectively Wrangling Together a Bunch of Views

One bit of task that I find myself doing over and over again is managing a bunch of Views and their visibility. In the olden days <insert old person handwave>, before there was ConstraintLayout, I have written my fair share of container_s to make this task manageable. Say we have to do something like this:

2 min read

Referencing IDs in Data Binding

Last week, I was talking to someone on my team and it became apparent that they weren’t aware of one super useful feature of data binding. If you know me at all, you know that I like love this library, and I would take every opportunity to spread the love around.

~1 min read

Parsing Data Binding Errors

Learning something new is always fun and exciting. That is, until seemingly cryptic error messages start creeping up.

1 min read

Binding to the H(eight)

As would probably be obvious by now, I have been investing a lot of time in learning and using data binding.

1 min read

I Like Walls

I have always been told I’m stubborn. And I am. So jumping off this post, I continued doing instant apps stuff and I learnt more things this week.

1 min read

Children, Respect Your Parent(s)

I was updating a bit of code the other day that involved dynamically inflating views into a LinearLayout using DataBindingUtil.inflate(LayoutInflater.from(context), R.layout.row_related_property, container, false).

1 min read

There is Always Room for Improvement

During the beginning of my Android career, one of the things I had to do was to save some data to somewhere. I found out that for my purposes, I had to use an SQLite database. Reading through the docs, I was afraid. Petrified, even.

5 min read

@{app.plaid}

I gave a talk this morning in the first ever Droidcon Vietnam! It is about two of the things I love in Android – Plaid and data binding.

~1 min read

:facepalm:

I just spent an hour debugging an issue that should have been a non-issue at all.

1 min read

Troubleshooting autoVerify

So you implement app links and you are 300% sure you have implemented everything correctly. The important thing to remember here is that verification is all or nothing. From the docs:

2 min read

The Quirks of Supporting SDK 25

The last developer preview of Android 7.1 has started shipping, which means APIs are (based on past experience) more or less stable. There is a very good write up on developer.android.com on how to get started with supporting these new features. I set about trying it out, and here’s what happened.

4 min read

A Little UX Love Goes A Long Way

Yesterday, my bank pushed a notification asking if I’m going to travel. Yes! I am! I filled up the form they asked me to fill up, and tapped Submit.

2 min read

Tools of the Trade: Unabridged

I gave an unabridged version of my last Android Meetup talk at this year’s YOW Conference. It has been an honour being part of this awesome conference!

~1 min read

String formatting and Lint

One piece of advice that we keep hearing over and over is to extract strings into resources. There really is no reason for you to hard code strings in code.

1 min read

A big step

Today was the day.

~1 min read

Stylish Dynamic Layouts

One of the things we are taught in Android is that we should gracefully handle different layouts based on screen sizes. With more and more things being not just screen size-specific but also OS version-specific, this is one thing I think a lot more devs need to pay attention to. Today was my turn to do just that.

2 min read

Using resource IDs in data binding layouts

I have been playing with data binding more and more over the last couple of weeks. This week, it’s all about creating a dialog with stuff dictated by a value from an enum.

2 min read

In which I was in a podcast

It has been a month since IO and in case you missed it, I got to chat with Kaushik of Fragmented. And by golly, I made it into an episode! At that point I was about to lose my voice, so I sound really husky. :p

~1 min read

Taking a closer look while debugging

One of the most common sources of bugs (at least of my bugs) is math. I have been working on dynamically resizing a View the past days, and it was driving me nuts! I needed to consider preserving aspect ratio, device density, original view size, etc etc. Math is hard guys!

4 min read

LinearLayouts, TextViews and Drawables

I sent out a series of tweets today about LinearLayouts and unexpectedly, quite a few people like them. I decided to get off my lazy ass and actually write it down in a post for easy reference.

2 min read

Squashing Bugs

This has been one hell of a busy week for me. I think you can sort of tell from my Tweets and G+ posts that I have been debugging A LOT.

1 min read

Annotating all (or most of) the things

If, like me, you are old and have been developing for Android for a while, you should, like me, appreciate the fact that the backwards compatibility of the OS has come a long way. Sure, they may toy with my feelings from time to time, but we all need a little excitement every now and then.

I have recently decided that I will invest more time into learning how all the tools at an Android developer’s disposal can make me code better, faster, cleaner, and less buggy (I initially said “buggier” because I want to rhyme but someone who supposedly does English better complained).

To start with, I have been trying recently to consistently use the Resource Type annotations. These annotations prevent code like this from exploding:
<pre class="brush:java">private void setThingsToTextView(int res1, int res2, int res3, int res4) {
// do stuff
}
</pre>
This will explode because:
1. Fields are named horrendously
2. Without reading what the method does, it is so easy to pass the wrong resource ID (I can only assume that it wants resource IDs)

Resource annotations help with reason #2 by letting you and the compiler know just what type of resource is expected. There are a lot of available annotations (Read the docs!) but I find that the things I use the most are, well, the things I use the most:
@StringRes - expects an R.string.*
@DrawableRes - expects an R.drawable.*
@IdRes - expects an R.id.*
@ColorRes - expects an R.color.*

I have updated my SDK Sandbox project with an Activity to illustrate use of these annotations. FAIR WARNING: IT USES ENUMS. If this annoys you, DO NOT click through.

So how do we stop the method above from exploding? Let’s fix all the things!
<pre class="brush:java">private void setThingsToTextView(@IdRes int textView, @StringRes int introText, @DrawableRes int heroImage, @ColorRes int backgroundColour) {
// do stuff
}
</pre>
Ahhh. Easy. And so much better.


1 min read

NOT another day at the office

We had another round of Innovation Day at Domain last month, and I wrote about it. We started out dreaming up this ambitious project – too ambitious for two days! Here’s a partial list of what we had to do:<div><ul><li>Build a wall</li><li>Stick devices on said wall</li><li>Make app that cycles through photos from listings</li><li>Load said app on those devices that we stuck to the wall</li><li>Figure out how to track people who get devices</li><li>What if someone just gets a device?!</li><li>Figure out how to let people give back devices</li><li>Oh! oh! oh! Wouldn’t it be cool if other devices cheer when one of them “comes home”?</li><li>How do we put new versions of the app on those devices?</li><li>Run tests, maybe?</li><li>What if the website team wants to test responsive designs?</li><li>Do they even charge????!!!</li></ul><div>It was a LOT of work. But it was awesome.</div></div>

~1 min read

Raising Activities From the Dead

One of the scenarios I admittedly almost always forget to test is “What happens when my app goes into the background, then the OS kills is to claim memory, then I try to resume?” Usually it’s “Well, I handle onSavedInstanceState not being null, so I am great!” It is fine and dandy for simple apps; but once your Activity or Fragment gets beefier and you start relying on state for more and more things, it can get complicated pretty quickly (In my case, the Fragment has setRetainInstance(true)).

This scenario in particular is kind of hard to reproduce willingly. I usually see this when I leave an app running, make my phone do some heavy work overnight, then resume the app the next day.
<div class="separator" style="clear: both; text-align: center;"></div><div class="separator" style="clear: both; text-align: left;">
</div><div class="separator" style="clear: both; text-align: left;">So what you gonna do?</div><div class="separator" style="clear: both; text-align: left;">
</div><div class="separator" style="clear: both; text-align: left;">It turns out that Android Studio has the answer! There is this magical tiny red button that allows you to simulate this exact scenario.</div><div class="separator" style="clear: both; text-align: left;">
</div><div class="separator" style="clear: both; text-align: left;">1. Open your app to the Activity you want to test (I use a very simple app here just for demo).</div><div class="separator" style="clear: both; text-align: center;">

</div><div class="separator" style="clear: both; text-align: center;">
</div><div class="separator" style="clear: both; text-align: left;">2. In Studio, go to Android Monitor (make sure that your app is selected). Note the process ID, in this case it is 25647.</div><div class="separator" style="clear: both; text-align: center;"></div>
3. Push your app to the background. Pressing the HOME button should be sufficient. This will call onSaveInstanceState, which is all that matters really. It is after all what we want to test.

4. Back in Studio, press the magical tiny red button pointed to in the previous image. Notice that Studio now appends [DEAD] to your app’s process. It is now gone. He’s dead, Jim!
<div class="separator" style="clear: both; text-align: center;"></div>
5. Resume your app. I usually just do this via recent apps.
<div class="separator" style="clear: both; text-align: center;"></div>
6. If you look at Studio, you’ll see that your app is now no longer dead, but has a new process ID, in this case 26742.
<div class="separator" style="clear: both; text-align: center;"></div><div class="separator" style="clear: both; text-align: center;">
</div><div class="separator" style="clear: both; text-align: left;">If at this point you step through your code, you will notice that your Activity will go through the whole (re-)creation process with the Bundle given the values you have saved in onSaveInstanceState. No more waiting overnight, yay!</div>

1 min read

Stringy strings


While we are on the subject of strings, here are more ways of dealing with them in Android Studio. We all know that we should not hardcode strings in code, right? But sometimes, we forget and tend to do code first before defining them in strings.xml.

There are a couple of ways that Android Studio/IntelliJ makes this easy for us. The gif below (which took me a while to figure out how to do, by the way), shows how to deal with:
1. Moving a hardcoded string into strings.xml
2. Giving a previously undefined string ID a value in strings.xml

<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody><tr><td style="text-align: center;"></td></tr><tr><td class="tr-caption" style="text-align: center;">(Click to embiggen)</td></tr></tbody></table>
Move hardcoded string into XML:
This is probably the more common scenario. You happily put in texts into your TextViews, and now you have to copy and paste them into strings.xml. Don’t! There is a shortcut for that.

Put your cursor somewhere in the string, press ALT+Enter to bring up the context menu, choose “Extract string resource” and give your string resource a name. This will create a new <string name=”my_string_name”>My string value</string> in strings.xml.

Studio magically also calls getString(R.string.xxxxx) for you. Neat, huh?


Make new string from ID:
This is for when you suddenly remember that you need a new string and want to sort of try to do it correctly so you type in the string ID. Only it hasn’t been defined yet, so Studio complains. But it’s fine. There is a shortcut for that.

Put your cursor somewhere in the as of yet undefined ID, press ALT+Enter to bring up the context menu, choose “Create string value for resource my_string_id”, and type in the actual string value you want. Again, this will create a new <string name=”my_string_id”>My other string value</string> in strings.xml.

Remember, in both of these cases, Studio will create the new strings in strings.xml, but you can modify it to put in whatever variant you want it to be in (for localisations, screen size support, etc).

1 min read

On being material

In case you missed it, I made a blog post about updating our app to material design. In it I talk about what material design is and what we did to adopt it. I hope you enjoy reading it as much as I did writing it. :) Head on over to Domain’s tech blog for the details.

~1 min read

SQLiteAssetHelper + ORMLite

I recently had cause to use Jeff Gilfelt’s SQLite Asset Helper library. For those unfamiliar, it is a library that can help with including a pre-populated SQLite database with your Android application. It is extremely convenient with unbundling a potentially huge database you would want to ship.

For the app I was working on, I also wanted to use ORMLite. This is another library that helps with persisting POJOs to SQLite databases. If you deal with a lot of persisted objects in your code, then this is probably something worth looking into.

I won’t deal here with how ORMLite does its stuff, I’ll leave it to you to go through the documentation. What I’ll write about today is how to make these two libraries work together.

Right. Moving on. If you look at ORMLite’s sample code, it mentions that your database helper class must extend OrmLiteSqliteOpenHelper. If you look at SQLite Asset Helper’s sample code, it mentions that your database helper class must extend SQLiteAssetHelper. What this means for us is that somehow, we need our database helper class to be able to talk to both of these libraries.

Since Android Studio is now the official IDE of choice, the sample code for this post is now AS-compatible. Yay!

First, gradle:
<pre class="brush:xml">compile ‘com.readystatesoftware.sqliteasset:sqliteassethelper:2.0.1’
compile ‘com.j256.ormlite:ormlite-android:4.48’</pre>
When dealing with anything database, I tend to create my POJOs first. For this sample, I will be using the infamous Northwind database. For simplicity, this app will simply get the first entry from the Employees table and dump the contents into a TextView.

Since SQLite Asset Helper is the one who is in charge of our database creation and upgrade operations, we have to let it do the setup. Follow Jeff’s example for that, BUT follow ORMLite’s example for setting up ORMLite with no helper. At the end of it, you should have something similar to this.

To actually use ORMLite, just do as you usually would:
<pre class="brush:java">mOrmDbHelper = getHelper();

try {

    Dao<Employee, Integer> employeeDao = mOrmDbHelper.getEmployeeDao();

    // Try to get the first entry in the table
    Employee employee = employeeDao.queryBuilder().queryForFirst();
    if(employee == null) {
        textView.setText(“No employees found!”);
    } else {
        textView.setText(employee.toString());
    }
} catch (SQLException e) {
    e.printStackTrace();
}</pre>
Here we just get the first entry we can from the table and dump. If all goes well when we run the app, we should see this in the logs:

<pre class="brush:xml">01-20 23:02:39.203  12555-12555/droidista.blogspot.com.ormsqliteassethelper W/SQLiteAssetHelper﹕ copying database from assets…
01-20 23:02:39.226  12555-12555/droidista.blogspot.com.ormsqliteassethelper W/SQLiteAssetHelper﹕ database copy complete
01-20 23:02:39.289  12555-12555/droidista.blogspot.com.ormsqliteassethelper I/SQLiteAssetHelper﹕ successfully opened database northwind.db</pre>
And we should see Nancy’s details displayed on screen in all it’s raw .toString() glory.

2 min read

AutoCompleteTextView Hell

Today, I ran into a weird “feature” of Android. I was working on an AutoCompleteTextView with the dropdown list having section dividers. It all works well in portrait mode, but gets all messed up in landscape.

I made a sample app to illustrate the point of this blog [Github repo]. Clone it, run it, rotate the phone, select an item from the suggested auto-complete results, and get your mind blown. Or your heart stabbed. Or your stomach sucker-punched. Your choice.

So what was happening? Here’s what.

When we tell the app to perform a filter, we construct an array of the resulting matches. The example is pretty straightforward, just look for countries that start with whatever the user has typed in.

<pre class="brush:java">// Filter by start of string
String country = mCountries.get(i);
if(country.toLowerCase().startsWith(constraint.toString().toLowerCase())) {
mFilteredData.add(country);
}</pre>You can make this filtering as complicated as you like or need, just make sure to pass in whatever the user needs to see.

To illustrate having section headers (aka disabled items), we insert dummy text every fifth place in the list. The sample app does not care if there are more results after a section header, we still insert anyway.

So. Let’s filter. Typing in “pa” will give us this set of data:
<pre class="brush:xml">10-11 02:45:46.028 16282-20011/com.blogspot.droidista.autocompletetextviewhell D/AutoCompleteFragment﹕ 
Filtered results: [Section!, Pakistan, Palestine, Panama, Papua New Guinea, Section!, Paraguay]</pre>
There are two sections and five countries. Remember this.
<table border="2" bordercolor="#AAAAAA"><tbody><tr><td>Position in list</td><td>Value</td></tr><tr><td>0</td><td>Section!</td></tr><tr><td>1</td><td>Pakistan</td></tr><tr><td>2</td><td>Palestine</td></tr><tr><td>3</td><td>Panama</td></tr><tr><td>4</td><td>Papua New Guinea</td></tr><tr><td>5</td><td>Section!</td></tr><tr><td>6</td><td>Paraguay</td></tr></tbody></table>
This screenshot shows how the results are rendered in portrait mode. So far, so good. Selecting an item from the list populates the EditText with the country’s name.
<div class="separator" style="clear: both; text-align: center;"></div>
Now let’s try rotating our phone. This is where things get juicy. First off, there are no section headers. Second, the results are not in alphabetical order anymore. If we debug all over the adapter, we see what is written on the screenshot: Item on the left is position = 1, item in the middle is position = 0, and item on the right is position = 2.

Remember the result set we have? “Pakistan” is definitely NOT in position = 0, it should have been a section header! If we go ahead and select “Pakistan” in the suggestions above the keyboard, the EditText will populate with the item in position = 0 of the result set, i.e. “Section!”. Definitely not good.

<div class="separator" style="clear: both; text-align: center;"></div>
The AutoCompleteTextView widget has been around since API level 1, but I haven’t messed around with it as much as I did today. Googling returns very, very sparse results on this topic.
<ul><li>Does this mean people do not have the same problem as I did?</li><li>No one uses section headers in AutoCompleteTextViews?</li><li>No one uses this screen mode (EditText in full screen) in landscape without setting IME flags?</li><li>Is there a secret trick to making this work out-of-the-box?</li></ul><div>Or the most plausible of all,</div><div><ul><li>Am I being stupid?</li></ul></div>

2 min read

Swipe, not Pull, to Refresh

I have recently came across this new View in the support library package that allows your app to have built-in support for pull swipe to refresh. This is pretty cool, since we don’t have to use any of the libraries out there. Admittedly, very little customization can be done, but then what else can we customize, right?

Anyway, here’s a short demo of using this nifty little view.
<div class="separator" style="clear: both; text-align: center;"></div><table><tbody><tr><td><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody><tr><td style="text-align: center;"></td></tr><tr><td class="tr-caption" style="text-align: center;">Initial list</td></tr></tbody></table></td><td><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody><tr><td style="text-align: center;"></td></tr><tr><td class="tr-caption" style="text-align: center;">While refreshing</td></tr></tbody></table></td><td><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody><tr><td style="text-align: center;"></td></tr><tr><td class="tr-caption" style="text-align: center;">After refreshing</td></tr></tbody></table></td></tr></tbody></table>
The app is a simple ListView that shows a list of countries. Swiping down on the list will simulate a long-running activity (like connecting to a server, for example) and afterwards updating the list with new data.

Adding support for swipe to refresh is pretty straightforward. You would have to wrap the swipe-able layout in a SwipeRefreshLayout. Here is my XML file:

<pre class="brush:xml"><android.support.v4.widget.SwipeRefreshLayout xmlns:android=”http://schemas.android.com/apk/res/android”
xmlns:tools=”http://schemas.android.com/tools”
android:id=”@+id/container”
android:layout_width=”match_parent”
android:layout_height=”match_parent”
tools:ignore=”MergeRootFrame” >

<ListView
android:id=”@android:id/list”
android:layout_width=”match_parent”
android:layout_height=”match_parent” />

</android.support.v4.widget.SwipeRefreshLayout>
</pre>
In your Fragment, you would then have to put an onRefreshListener on this SwipeRefreshLayout. In my Fragment’s onCreateView, I have this:

<pre class="brush:java">// Configure the swipe refresh layout
mSwipeRefreshLayout = (SwipeRefreshLayout) rootView.findViewById(R.id.container);
mSwipeRefreshLayout.setOnRefreshListener(this);
mSwipeRefreshLayout.setColorScheme(
R.color.swipe_color_1, R.color.swipe_color_2,
R.color.swipe_color_3, R.color.swipe_color_4);
</pre>
The colors are defined in a colors.xml file in my res/values folder. To show or hide the refresh animation, you would have to call setRefreshing(boolean). This means that if you have to kick off an AsyncTask when the user swipes down, call setRefreshing(true) in onPreExecute, and call setRefreshing(false) in onPostExecute.

The implementation of onRefresh in the demo app is pretty simple, it simply grabs the next bunch of countries from a pre-defined list.

<pre class="brush:java">@Override
public void onRefresh() {
// Start showing the refresh animation
mSwipeRefreshLayout.setRefreshing(true);

// Simulate a long running activity
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
updateCountries();
}
}, 5000);
}
</pre>
That’s it really.  Nice and short. The code for this demo is in Github.

1 min read

Quick Tip: Understanding Alternate Resources

Trying to support as many devices as possible the best way possible is a very daunting task indeed. You will usually need to provide a lot of different layouts, strings, or dimensions (among others) to make your app look great whatever the user’s device is. And then you start chaining resource qualifiers and testing which resource is being loaded by the OS can become a nightmare very quickly.

Here’s a trick I started using which seemed to work quite well. Create a string (the app name works well if you have an Action Bar) that you can display on-screen (or just throw into a Log or a Toast) that will quickly let you know from which of those very many /res folders your resources are being pulled out of.

For this demo, I have the following /res/values-xxxxx folders:
<div class="separator" style="clear: both; text-align: center;"></div>
As you can see, there are strings.xml files in each of the configurations I want to support. Each of these files will contain whatever description we want to see on the device or in the Logs. In my case, I have custom strings for each form factor and orientation, which allows me to validate things easier. But this is particularly useful if the changes per form factor and orientation is subtle, such as dimensions.

Here’s what it looks like for phones:

<table><tbody><tr><td></td><td></td></tr></tbody></table>
And here are the outputs for tablets:
<table><tbody><tr><td></td><td></td></tr></tbody></table>
Each of the strings.xml files contains just these two strings (sample taken from /res/values-sw800dp):
<pre class="brush:xml">

MultiDeviceSupport - Tablet Portrait
Hello world on a tablet!


</pre>Have fun debugging!

1 min read

Adding attributes to a custom view

There are times when using the default Android Views just doesn’t cut it and you need to create your own version of a View. So how exactly do you do that? It’s as simple as subclassing the View! But what if you want to add customizable attributes? Here’s how.

Let’s say I am creating a form-filling application and I want some of the EditTexts in the form to be required. However, I am so tired of having to implement the error checking for each and every one of those fields. What I will do is create my own EditText that will do the validation for me if that particular field is required. Let’s do it.

Step 1: Create your custom view and create fields for the attributes you want. In this case, I want an EditText that will show the default EditText error display if the user has not put in any value.
<pre class="brush:java">public class RequiredEditText extends EditText {
private boolean mRequired;
private String mErrorMessage;

public RequiredEditText(Context context) {
super(context);
}

/*
* Set this EditText’s requirement validation. The error message
* will be set to null by default if not provided.
*
* @param required
* @param errorMessage (optional)
*/
public void setRequired(boolean required, String errorMessage) {
this.mRequired = required;
this.mErrorMessage = errorMessage;

invalidate();
requestLayout();
}

public void setRequired(boolean required) {
setRequired(required, null);
}

/
* Lets you know if this field is set as required or not
* @return
*/
public boolean isRequiredField() {
return mRequired;
}
}</pre>Step 2: If a field is required, we want the default error message to appear (with our own error message, of course). If the user fills in the EditText, we want the error to disappear.
<pre class="brush:java">public class RequiredEditText extends EditText {
private boolean mRequired;
private String mErrorMessage;

public RequiredEditText(Context context) {
super(context);
}

/

* Set this EditText’s requirement validation. The error message
* will be set to null by default if not provided.
*
* @param required
* @param errorMessage (optional)
*/
public void setRequired(boolean required, String errorMessage) {
this.mRequired = required;
this.mErrorMessage = errorMessage;

manageRequiredField(required);

invalidate();
requestLayout();
}

public void setRequired(boolean required) {
setRequired(required, null);
}

private void manageRequiredField(boolean required) {
// If we are required, set the listeners
if(required) {
setOnFocusChangeListener(mFocusChangeListener);
addTextChangedListener(mTextWatcher);
} else {
// In case there is an error message already, clear it
setError(null);

// Remove the listeners
setOnFocusChangeListener(null);
removeTextChangedListener(mTextWatcher);
}
}

/**
* Lets you know if this field is set as required or not
* @return
*/
public boolean isRequiredField() {
return mRequired;
}

OnFocusChangeListener mFocusChangeListener = new OnFocusChangeListener() {

@Override
public void onFocusChange(View v, boolean hasFocus) {
// If the focus was removed from the field and it IS required,
// check if the user has put in something
if(!hasFocus && mRequired){
isRequiredFieldFilled();
}
}
};

TextWatcher mTextWatcher = new TextWatcher() {

@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
// Once the user types in something, remove the error
setError(null);
}

@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) { /
do nothing / }

@Override
public void afterTextChanged(Editable s) { /
do nothing */ }
};

private boolean isRequiredFieldFilled() {
// If the EditText is empty, show the error message
if(TextUtils.isEmpty(getText().toString().trim())){
showRequiredErrorDrawable();
return false;
}
return true;
}

private void showRequiredErrorDrawable() {
setError(mErrorMessage);
}
}</pre>Step 3: Now it’s time to add the fields to the Layout Editor. Create an attrs.xml file in /res if there isn’t one already. Declare a styleable and include the attributes you want to appear in the Layout Editor.
<pre class="brush:xml">





</pre>The name of the styleable does not need to match your custom view class name, but doing so makes it more readable and maintainable.

Step 4: Go back to your custom view implementation and add constructors that take in an AttributeSet.
<pre class="brush:java">public RequiredEditText(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init(attrs);
}

public RequiredEditText(Context context, AttributeSet attrs) {
super(context, attrs);
init(attrs);
}

private void init(AttributeSet attrs) {
TypedArray a=getContext().obtainStyledAttributes(
attrs,
R.styleable.RequiredEditText);

try {
setRequired(a.getBoolean(R.styleable.RequiredEditText_required, false),
a.getString(R.styleable.RequiredEditText_errorMessage));
} finally {
//Don’t forget this, we need to recycle
a.recycle();
}
}
</pre>Step 5: Go to the Layout Editor and look for “Custom & Library Views” in the Palette (you may have to click on “Refresh” several times before your custom view appears in the list). Add the custom view to your layout and check out the properties panel!
 

 As always, the code is in GitHub.

3 min read

Quick Tip: Updating the location update frequency

When using Google Play’s Location Services and you want to change the frequency of the updates, make sure to do these in order:

<pre class="brush:java">stopLocationUpdates();
// This method should implement mLocationClient.removeLocationUpdates()

// Set the new frequency in your location client
updateLocationClient(frequency);

startLocationUpdates();
// This method should implement mLocationClient.requestLocationUpdates()
// which means it should check for isConnected() as well!</pre>
If you do not remove the updates before updating the frequency, it looks like the old frequency update is still active BUT a new one is started.

~1 min read

Setting up the SeekBar

So we want to use the SeekBar. We want the minimum value to be 10 and the maximum value to be 100, and it should increment by 10.

Thing is, SeekBar by default always starts at 0, and the increment is always an int. It is definitely possible to get what we want, but we need to do some simple math first.

Compute how many increments you will need from your minimum up to your maximum:
<pre class="brush:xml">numberOfIncrements = maximum - minimum = 90</pre>
Then divide it by the amount of each increment we want:
<pre class="brush:xml">seekBarMaximum = numberOfIncrements / 10 = 9</pre>
This means we should set up the SeekBar to have max = 9 and increment = 1. Then in our code, we have to figure out how to get the actual progress that we want.
<pre class="brush:java">SeekBar.OnSeekBarChangeListener mSeekbarListener = new OnSeekBarChangeListener() {

@Override
public void onStopTrackingTouch(SeekBar seekBar) { /* Do nothing/ }

@Override
public void onStartTrackingTouch(SeekBar seekBar) { /
Do nothing*/ }

@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
mProgressDisplay.setText(“Seekbar is at: “ + getProgressToDisplay(progress));
}
};


private String getProgressToDisplay(int progress) {</pre><pre class="brush:java"> // We are multiplying by 10 since it is our actual increment
int actualProgress = (progress + 1) * 10;
return String.valueOf(actualProgress);
}</pre>
Another example:
<pre class="brush:xml">minimum = 1, maximum = 10, increment = 0.5
numberOfIncrements = 9
seekBarMaximum = 18</pre>
In this case, the contents of getProgressToDisplay() will change since the increment is not a whole number.
<pre class="brush:java">private String getProgressToDisplay(int progress) {
float actualProgress = (progress + 1) - (progress * 0.5f);
return String.valueOf(actualProgress);
}</pre>

1 min read

Quick Tip: Pulling an SQLite db file from device

I have always thought that you would need root access to pull an SQLite file from a non-rooted Android device. Turns out I thought wrong! Here’s how you do it:
<pre class="brush:shell">$ adb -d shell
$ run-as your.package.name
$ cat /data/data/your.package.name/databases/yourdatabasename >/sdcard/yourdatabasename</pre>This will copy your app’s SQLite db file to the SD card’s root directory. From there, you can copy the file to your computer any way you like.

Props to this SO answer!

~1 min read

I Can Haz Internetz!

Last week, I was exploring connectivity monitoring and came up with a small app for demo. The app listens for connectivity changes and sends a notification to the user informing them of the change.

First off, create a class (I named mine ConnectivityUpdate.java) and make it extend BroadcastReceiver. This class should do what you want when notified of connectivity changes. You will be asked to implement the onReceive() method. Now here’s what I want to happen when the system notifies me of changes:
1. Check what kind of change I am being notified of: did I get Internet? Or did I lose Internet?
2. Compare this to what connectivity I had before the notification so I can inform the user (and app-wise do whatever it is I’m supposed to do like start syncing or stop syncing).

In my implementation, this is done as:
<pre class="brush:java">@Override
public void onReceive(Context context, Intent intent) {

boolean hasInternet = false;
Log.d(LOG_TAG, “Received broadcast!”);

// Do I have Internet?
if(intent.getAction().equals(ConnectivityManager.CONNECTIVITY_ACTION)) {
hasInternet = (new NDUtils()).hasInternet(context);
}

// Did I use to have Internet?
SharedPrefsManager prefs = new SharedPrefsManager();
boolean prevValue = prefs.hasNetwork(context);

if(prevValue != hasInternet){
// Remember what we have now
(new SharedPrefsManager()).saveNetworkState(context, hasInternet);
sendNotification(hasInternet, context);
}
}
</pre>
The actual checking if we have Internet or not is done by a utility class: <pre class="brush:java">public boolean hasInternet(Context context){
NetworkInfo networkInfo = (NetworkInfo) ((ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE)).getActiveNetworkInfo();

// Check if we are connected to Wifi or mobile internet
// AND if we can actually send data
if(networkInfo!=null &&
(networkInfo.getType() == ConnectivityManager.TYPE_WIFI
  networkInfo.getType() == ConnectivityManager.TYPE_MOBILE)
&& networkInfo.isConnected()) {
return true;
}

return false;
}
</pre>
The Android javadoc on getActiveNetworkInfo() says it may return null, so we check first to avoid NullPointerExceptions, then we check if we have WiFi or mobile internet, THEN (and this is important) we check if we can send data through this network.

You can also refine this filter more by checking the type of mobile network the user has (we want 3G or faster) or by checking if the user is roaming (user should not be roaming). Here is a more complete method describing what I just said:<pre class="brush:java">public boolean hasInternet(Context context){
NetworkInfo networkInfo = (NetworkInfo) ((ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE)).getActiveNetworkInfo();
TelephonyManager telephony = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
if(networkInfo!=null && networkInfo.isConnected() &&
(networkInfo.getType() == ConnectivityManager.TYPE_WIFI
 
(networkInfo.getType() == ConnectivityManager.TYPE_MOBILE && networkInfo.getSubtype() > TelephonyManager.NETWORK_TYPE_UMTS &&
!telephony.isNetworkRoaming()))) {

return true;
}

return false;
}</pre>
I then compare the returned value of the utility method to the last value saved in my preferences file. That part of the code is straight up saving/getting a boolean value from a SharedPreferences file.

I then inform the user of the network change through a notification. When the user clicks on the expanded notification, I want to open the app. The app can then display details about the network, but right now what my sample app does is simply show the boolean value returned by the utility method. Anyway, here’s how I send the notification:
<pre class="brush:java">private void sendNotification(boolean hasInternet, Context context) {
NotificationManager notificationManager = (NotificationManager)context.getSystemService(Context.NOTIFICATION_SERVICE);

// The notification details seen by the user when the drawer is pulled down
String notificationTitle = “Change in data connection!”;
String notificationText = “We have internet?: “ + (hasInternet ? “YES!” : “NO :(“);

// The icon and the text to be displayed in the notification area
Notification myNotification = new Notification(R.drawable.ic_launcher, “Broadcast received!”, System.currentTimeMillis());

// Create a new intent to launch my app
Intent myIntent = new Intent(context.getApplicationContext(), NetworkDetector.class);
PendingIntent pendingIntent = PendingIntent.getActivity(context.getApplicationContext(), 0, myIntent, Intent.FLAG_ACTIVITY_NEW_TASK);

// Send that notification! MY_NOTIFICATION_ID is a value greater than 0.
myNotification.setLatestEventInfo(context,
notificationTitle,
notificationText,
pendingIntent);
notificationManager.notify(MY_NOTIFICATION_ID, myNotification);
}</pre>
So how do we tell the OS that we have made this receiver and please notify us when the connectivity changes, Mister Android please? We create a broadcast receiver in the app’s manifest! We listen to both CONNECTIVITY_CHANGE and WiFi STATE_CHANGE. The value for android:name is the name of the class containing the receiver implementation.
<pre class="brush:xml"><receiver
android:name=”.util.ConnectivityUpdate”
android:enabled=”true”
android:exported=”true”
android:label=”ConnectivityActionReceiver” >
<intent-filter>
<action android:name=”android.net.conn.CONNECTIVITY_CHANGE” />
<action android:name=”android.net.wifi.STATE_CHANGE” />
</intent-filter>
</receiver></pre>
And don’t forget to add the permissions to read the network state:
<pre class="brush:xml"><uses-permission android:name=”android.permission.ACCESS_WIFI_STATE” />
<uses-permission android:name=”android.permission.ACCESS_NETWORK_STATE” /></pre>
<div>The complete source code for this sample app is in github.</div>
3 min read

Making ActionBarSherlock and ViewPagerIndicator play nice

EDIT (20121227): I made a new post on changing the tab selector underline.
EDIT (20121014): I received feedback from the comments that rotating the device will cause the tab contents to revert to the default text. In essence, the adapter “loses” the contents of the tabs. I have corrected this in the example below as well as in github.
EDIT (20120905): The full sample source code is now in github.

So ViewPagerIndicator cheerfully claims that it works with ActionBarSherlock. I was trying to test this out today and I can’t find a noob-friendly, step-by-step tutorial on how I can do it. I spent almost half a day frantically opening tab after tab in Google Chrome, but nothing seems to straight out say what I should do. So here it is, collated from several StackOverflow answers, blog posts, etc.

Get the ViewPagerIndicator (hereafter referred to as VPI) and ActionBarSherlock (hereafter referred to as ABS) libraries. Create your Android application in Eclipse and add those two projects as dependency library projects. If you do not know how to do that, see here.

First, create a theme. This is required by ABS, and will also help in VPI. What I did was to make the VPI theme inherit from the ABS theme so I don’t lose any of the styles I use in other parts of the app. I just add or override items needed by the ViewPagerIndicator. In this example, I just changed the text size and color of the tab labels. You can go one step further and change the selected tab indicator (via state selectors), change how the selectors are drawn, etc.
<pre class="brush:xml"><resources xmlns:android=”http://schemas.android.com/apk/res/android”>
<!– This is our main ActionBarSherlock theme –>
<style name=”Theme.Styled” parent=”Theme.Sherlock.Light.DarkActionBar”>
<item name=”actionBarStyle”>@style/Widget.Styled.ActionBar</item>
<item name=”android:actionBarStyle”>@style/Widget.Styled.ActionBar</item>
</style><!– This is our ViewPagerIndicator theme. We inherit from the ABS theme –>
<style name=”Theme.VPI” parent=”Theme.Styled”>
<item name=”vpiTabPageIndicatorStyle”>@style/CustomTabPageIndicator</item>
</style>  
<!– “Implementation” of our ABS custom theme –>
<style name=”Widget.Styled.ActionBar” parent=”Widget.Sherlock.Light.ActionBar.Solid.Inverse”>
<item name=”titleTextStyle”>@style/TitleText</item>
<item name=”android:titleTextStyle”>@style/TitleText</item>
</style>

<!– “Implementation” of VPI theme. We just set the text size and color. –>
<style name=”CustomTabPageIndicator” parent=”Widget.TabPageIndicator”>
<item name=”android:textSize”>50dip</item>
<item name=”android:textColor”>#FFB33E3E</item>
</style>

<!– More customizations for ABS –>
<style name=”TitleText” >
<item name=”android:textColor”>@android:color/darker_gray</item>
<item name=”android:textSize”>17dip</item>
</style>
</resources></pre>
Then we create the fragment(s) we need to populate the viewpager. My fragment is a simple layout with just a TextView indicating which tab is being shown.
<pre class="brush:java">public class TestFragment extends SherlockFragment {
private String mContent = “???”;

public static TestFragment newInstance(String text) {
TestFragment fragment = new TestFragment();

// Supply num input as an argument.
Bundle args = new Bundle();
args.putString(KEY_TAB_NUM, text);
fragment.setArguments(args);

return fragment;
}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.activity_main, null);
String text = getString(R.string.tab_page_num) + mContent;
((TextView)view.findViewById(R.id.text)).setText(text);

return view;
}

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mContent = getArguments() != null ? getArguments().getString(KEY_TAB_NUM) : “???”;
}

}</pre>
Then we create the activity that will hold everything together.
<pre class="brush:java">public class VpiAbsTestActivity extends SherlockFragmentActivity {

private static final String[] TAB_TITLES = new String[] { “This”, “Is”, “A”, “ViewPager” };

TestFragmentAdapter mAdapter;
ViewPager mPager;
PageIndicator mIndicator;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);

setContentView(R.layout.simple_tabs);

mAdapter = new TestFragmentAdapter(getSupportFragmentManager());

mPager = (ViewPager)findViewById(R.id.pager);
mPager.setAdapter(mAdapter);

mIndicator = (TabPageIndicator)findViewById(R.id.indicator);
mIndicator.setViewPager(mPager);
}

class TestFragmentAdapter extends FragmentPagerAdapter {
private int mCount = TAB_TITLES.length;

public TestFragmentAdapter(FragmentManager fm) {
super(fm);
}

@Override
public Fragment getItem(int position) {
return TestFragment.newInstance(String.valueOf(position));
}

@Override
public int getCount() {
return mCount;
}

@Override
public CharSequence getPageTitle(int position) {
return TAB_TITLES[position];
}
}
}</pre>And lastly, we apply the ViewPagerIndicator theme to our activity in the manifest:
<pre class="brush:xml"><activity android:name=”VpiAbsTestActivity” android:theme=”@style/Theme.VPI”>
</activity></pre>
As it turns out, it IS pretty straightforward!

2 min read

Save Logcat contents to file

Note to self: to save the contents of Logcat to a text file:
<ol><li>Navigate to the SDK installation directory.</li><li>Go to the /platform-tools folder.</li><li>adb logcat -d > my_logcat_dump.txt</li></ol><div>If there is more than one device connected to adb, specify which device’s log to dump:</div><div><blockquote class="tr_bq">adb -s emulator-5558 logcat -d > my_logcat_dump.txt</blockquote></div>

~1 min read

Cloning a remote branch in git

My current project at work uses git, and I have always been a CVS/SVN baby so I’m still trying to find my way around it. Today I wanted to clone a remote branch to my local computer. This remote branch also has submodules, so I want to get those too.

This assumes that you use Git Bash. First, navigate to the folder in you local computer where you want git to clone the remote branch. Once there, we can start cloning the repo. The following steps do the dirty work:
<pre class="brush:bash">$ git init
$ git fetch <git url> <branch name>:refs/remotes/origin/<branch name>
$ git checkout -b <branch name> origin/<branch name></pre>
This retrieves the contents of the remote branch and copies it to our local computer in a local branch (confused yet?). To update our copy of the submodules, the following commands should work:
<pre class="brush:bash">$ git submodule init
$ git submodule update</pre>

~1 min read

Adding Preferences On-The-Fly

(Make appropriate whooshing sounds)

Today, I will show you how to add preferences to your SharedPreferences (confused yet?) programatically. In an app that I am doing, I wanted to present a ListPreference to the user from the SharedPreferences page. However, the values contained in this list is not known at compile time. (Think Facebook groups that differ per user, or Twitter lists, or things like such, and I want to set a default option.)

Anyway, here’s what I did to make this work. I added a preference in my PreferenceScreen, a sort of placeholder, if you will. Here is my ListPreference:
<pre class="brush:xml"><PreferenceScreen xmlns:android=”http://schemas.android.com/apk/res/android” >

<PreferenceCategory android:title=”@string/pref_settings_header”>
<ListPreference android:key=”@string/pref_key_default_group” android:title=”@string/pref_default_group”/>
</PreferenceCategory>

</PreferenceScreen></pre>And then in the class that handles the SharedPreferences, I get the values that I want displayed and plug them in to the placeholder preference. I will not bother to explain here, just heavily commenting the code:
<pre class="brush:java">public class UserPreferences extends PreferenceActivity {

private static final String LOG_TAG = “UserPreferences”;

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);

// Load the preferences from an XML resource
addPreferencesFromResource(R.xml.my_apps_prefs);

// Manage the “Default Group” preference
addDefaultGroupPrefs();
}


private void addDefaultGroupPrefs() {
// Get our “placeholder” preference. I prefer to use strings instead of hard-coding the preference key.
// The value passed into findPreference is the value in the android:key parameter in the preference XML file.
ListPreference groupsListPrefs = (ListPreference) findPreference(getString(R.string.pref_key_default_group));

// Get your groups, this may come from a utility class or wherever
// In this example, I have a custom object that has a “name” and an “id”
List<CustomGroup> myGroups = getMyGroups();
if (myGroups == null) {
// Disable the preference if we don’t have a list
groupsListPrefs.setEnabled(false);
} else {
// Enable the preference if we have a list
groupsListPrefs.setEnabled(true);

// We split the list into names and IDs
// We show the names in the list, and the values as the entries
List<String> groupNames = new ArrayList<String>();
List<String> groupIds = new ArrayList<String>();
for (CustomGroup group : myGroups){
groupIds.add(group.getId());
groupNames.add(group.getName());

// I guess you can add directly to a String[]
// just make sure the order is preserved (name1=id1, name2=id2, etc)
}

// These should be user-readable strings
groupsListPrefs.setEntries(groupNames.toArray(new String[groupNames.size()]));

// These are the actual values to be saved in the XML file
groupsListPrefs.setEntryValues(groupIds.toArray(new String[groupIds.size()]));
}
}

private List<customgroup> getMyGroups(){
// do work here, query server or db or whatever
// return the list of groups
}
}</pre>
And we’re done. :)

1 min read

Inspecting your Shared Preferences

Did you know that you can look at your SharedPreferences file?

If during development you want to inspect what your SharedPreferences now contain, you can pull a copy of the XML file from the emulator.

In Eclipse, you can do that by following these steps:

<ol><li>Open the DDMS perspective (Window > Open Perspective > Other > DDMS).</li><li>Click on the File Explorer tab and navigate to your app’s data folder (that’s under data/data/<your package name>/shared_prefs/).</li><li>Choose the file you want to download.</li><li>Click on the Pull file from device button.</li></ol><div class="separator" style="clear: both; text-align: center;"></div><div>
</div>

~1 min read

Adding a float value to your resources

Earlier today, I was trying to figure out how to add a float value to constants file. What I used to do was add a string value in my strings.xml, retrieve the string value, and convert it to float. <pre class="brush:java">float floatFromFile = Float.valueOf(getResources().getString(R.string.my_float));</pre> I was trying out something new but it wasn’t working, so I decided to look for a more accepted solution. Google led me to this StackOverflow question. I was on the right track after all! I think the accepted answer is incomplete, or not clear enough for my purposes. I ended up having this entry in my dimensions.xml file: <pre class="brush:xml"><item name="face_feature_marker_size" type="vals" format="float">2.0</item></pre> And then in my code, I retrieve the value as: <pre class="brush:java">TypedValue tempVal = new TypedValue();
getResources().getValue(R.vals.face_feature_marker_size, tempVal, true);
float markerSize = testVal.getFloat();</pre> I ended up having more lines of code with no idea if this is more optimized. Let me know what you think!

~1 min read

Where’s my R.java?

This afternoon, I tried importing an existing project into Eclipse. Doing a Project > Clean usually clears up the R.java not found errors, but this time it didn’t work. I tried re-importing the project, copy-and-pasting it into a new workspace, restarting Eclipse, but the error is still there.

Just a quick note to self: If there is an error in the layout files, resolve that first then Clean.

I find it weird that no more specific error message is presented. Oh well.

~1 min read

ADT 12: Not so shiny after all


For all the shininess that ADT 12 promised, it seems that it also broke one major feature of DDMS: Launching emulators.

After updating to ADT 12, I kept on seeing that error when launching an emulator instance. Restarting Eclipse doesn’t help any.

Anyway, the apparent cause of this error is that ADT 12 has some problems with the SDK location having spaces. If you have already forgotten, it’s in Window > Preferences > Android.

To work around this bug, it is either you move your SDK to a folder in a path without spaces; or, modify the existing path to either of the following:<div><ul><li>If your SDK is in Program Files: C:/PROGRA~1/<path_to_sdk></li><li>If your SDK is in Program Files(x86): C:/PROGRA~2/<path_to_sdk></li></ul><div>Edit (20110711 1943): A bug has already been filed for this issue. Star to be notified of updates.</div></div>

~1 min read

Passing complex objects to another Activity

Several months ago, I was faced with a problem of passing a complex object to another Activity. There are several ways of doing this:
<ul><li>“Deconstructing” the complex object to simple data types and passing them as extras through putExtra()</li><li>Making the object Parcelable</li><li>Making the object Serializable</li></ul>I don’t really understand the concepts behind an object being Parcelable or Serializable, so I was not comfortable using that approach. Deconstructing the object, on the other hand, is easier but it is quite hard to manage as the number of fields in the object increases.

And then I came across another solution: using Bundles. In this post, I will try to explain how to do that.

In this sample project, we want to pass an instance of an AttendeeObject from our main activity to another. To better illustrate how we can use this method for different data types, an AttendeeObject will hold three pieces of information: a String name, an integer age, and a boolean indicating the person’s presence.

First, we construct the AttendeeObject like any old POJO. Create all the fields you want the object to contain and generate getters and setters for each. We then create the methods we would need to be able to pass, and subsequently receive, this object between activities.

To pass an AttendeeObject, we would need to put it in a Bundle and pass it using Intent#putExtra(String key, Bundle bundle).
<pre class="brush:java">public Bundle bundleAttendee(AttendeeObject attendee){
Bundle bundle = new Bundle();
bundle.putString(NAME, attendee.getName());
bundle.putInt(AGE, attendee.getAge());
bundle.putBoolean(PRESENCE, attendee.isPresent());

return bundle;
}</pre>Here, we simply put into a Bundle the values in the object that we want to pass.

Next, we should be able to convert this bundle back to an AttendeeObject in the receiving Activity. This task is done by the following method:
<pre class="brush:java">public AttendeeObject unBundleAttendee(Bundle attendeeBundle){
AttendeeObject attendee = new AttendeeObject();
attendee.setName(attendeeBundle.getString(NAME));
attendee.setAge(attendeeBundle.getInt(AGE));
attendee.setIsPresent(attendeeBundle.getBoolean(PRESENCE));

return attendee;
}</pre>Now, we are ready to use this in our application. I created a simple app that asks the user for the three values we would need to populate AttendeeObject.
I won’t discuss the details of creating the layout file, but it might be worthy to note that the possible values for the Spinner are just “Yes” and “No”.

When the user clicks on the “Create Attendee” button, the application creates a new AttendeeObject based on the values in the form and adds this to an ArrayList of AttendeeObjects.
<pre class="brush:java">private void onCreateAttendee() {
// Create a new AttendeeObject
AttendeeObject attendee = new AttendeeObject();
attendee.setName(mNameText.getText().toString());
attendee.setAge(Integer.valueOf(mAgeText.getText().toString()));
attendee.setIsPresent(mCurrentPresence);

// You can then do whatever you want with this object
// like adding it to an ArrayList or saving it to a database
mAttendees.add(attendee);

Toast.makeText(ComplexObjectDemo.this, “Attendee added!”, Toast.LENGTH_SHORT).show();
}</pre>
When the user clicks on the “Submit Attendee” button, the app “packages” the chosen value into a Bundle and sets it as an extra to the Intent. For illustration purposes, the application always gets the second AttendeeObject in the ArrayList.
<pre class="brush:java">private void onSubmitObject() {
Intent intent = new Intent(ComplexObjectDemo.this, ComplexObjectReceiverDemo.class);

// For simplicity, we will always get the second value
Bundle value = createAttendeeBundle(1);

// In a “real” application, the Key should be defined in a constants file
intent.putExtra(“test.complex.attendee”, value);

startActivity(intent);
}

private Bundle createAttendeeBundle(int index) {
// Here, mAttendee is an instance of AttendeeObject
// and mAttendees is an ArrayList holding all the created attendees
return mAttendee.bundleAttendee(mAttendees.get(index));
}</pre>

Upon receiving the Intent, the new activity simply displays the values in the AttendeeObject passed into it. Here’s how we can “unbundle” the Bundle:
<pre class="brush:java">@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_complex_demo_receiver);

// Get the extras passed to this Activity
setUpViews(getIntent().getExtras());
}

private void setUpViews(Bundle extras) {
// Again, the key should be in a constants file!
Bundle extraAttendee = extras.getBundle(“test.complex.attendee”);

AttendeeObject attendee = new AttendeeObject();

// Deconstruct the Bundle into the AttendeeObject
attendee = attendee.unBundleAttendee(extraAttendee);

// The AttendeeObject fields are now populated, so we set the texts
((TextView) findViewById(R.id.attendee_age_value))
.setText(String.valueOf(attendee.getAge()));
((TextView) findViewById(R.id.attendee_name_value))
.setText(attendee.getName());
((TextView) findViewById(R.id.attendee_presence_value))
.setText(String.valueOf(attendee.isPresent()));
}</pre>Here’s how the receiving activity looks like:Here’s the complete AttendeeObject class.
<pre class="brush:java; collapse:true">package droidista.example;

import android.os.Bundle;

public class AttendeeObject {

public static final String NAME = “attendee.name”;
public static final String AGE = “attendee.age”;
public static final String PRESENCE = “attendee.presence”;


private String mName;
private int mAge;
private boolean mIsPresent;

public AttendeeObject(){

}

public Bundle bundleAttendee(AttendeeObject attendee){
Bundle bundle = new Bundle();
bundle.putString(NAME, attendee.getName());
bundle.putInt(AGE, attendee.getAge());
bundle.putBoolean(PRESENCE, attendee.isPresent());

return bundle;
}

public AttendeeObject unBundleAttendee(Bundle attendeeBundle){
AttendeeObject attendee = new AttendeeObject();
attendee.setName(attendeeBundle.getString(NAME));
attendee.setAge(attendeeBundle.getInt(AGE));
attendee.setIsPresent(attendeeBundle.getBoolean(PRESENCE));

return attendee;
}

public String getName() {
return mName;
}

public void setName(String name) {
this.mName = name;
}

public int getAge() {
return mAge;
}

public void setAge(int age) {
this.mAge = age;
}

public boolean isPresent() {
return mIsPresent;
}

public void setIsPresent(boolean isPresent) {
this.mIsPresent = isPresent;
}
}</pre>And our main activity:
<pre class="brush:java; collapse:true">package droidista.example;

import java.util.ArrayList;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Spinner;
import android.widget.Toast;
import android.widget.AdapterView.OnItemSelectedListener;

public class ComplexObjectDemo extends Activity implements OnClickListener {

private Button mGoToNextIntent, mCreateAttendee, mClearFields;
private EditText mNameText, mAgeText;
private Spinner mPresence;

AttendeeObject mAttendee = new AttendeeObject();

private boolean mCurrentPresence;

private ArrayList<AttendeeObject> mAttendees = new ArrayList<AttendeeObject>();

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_complex_demo);

setUpViews();
}

private void setUpViews() {
setUpSpinner();

mNameText = (EditText)findViewById(R.id.name_text_input);
mAgeText = (EditText)findViewById(R.id.age_text_input);

mGoToNextIntent = (Button)findViewById(R.id.btn_submit_object);
mGoToNextIntent.setOnClickListener(this);

mCreateAttendee = (Button)findViewById(R.id.btn_create_attendee);
mCreateAttendee.setOnClickListener(this);

mClearFields = (Button) findViewById(R.id.btn_clear_fields);
mClearFields.setOnClickListener(this);
}

private void setUpSpinner() {
mPresence = (Spinner) findViewById(R.id.presence_spinner);
ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(
this, R.array.is_present_values, android.R.layout.simple_spinner_item);
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
mPresence.setAdapter(adapter);
}


private Bundle createAttendeeBundle(int index) {
// Here, mAttendee is an instance of AttendeeObject
// and mAttendees is an ArrayList holding all the created attendees
return mAttendee.bundleAttendee(mAttendees.get(index));
}

public void onClick(View v) {
switch(v.getId()){
case R.id.btn_create_attendee:
onCreateAttendee();
break;
case R.id.btn_submit_object:
onSubmitObject();
break;
case R.id.btn_clear_fields:
onClearFields();
break;
}
}

private void onClearFields() {
mAgeText.setText(“”);
mNameText.setText(“”);
mPresence.setSelection(0);
}

private void onSubmitObject() {

// For simplicity, we will always get the second value
Bundle value = createAttendeeBundle(1);

// In a “real” application, the Key should be defined in a constants file
Intent intent = new Intent(ComplexObjectDemo.this, ComplexObjectReceiverDemo.class);
intent.putExtra(“test.complex.attendee”, value);

// Start the new activity
startActivity(intent);
}

private void onCreateAttendee() {
// Create a new AttendeeObject
AttendeeObject attendee = new AttendeeObject();
attendee.setName(mNameText.getText().toString());
attendee.setAge(Integer.valueOf(mAgeText.getText().toString()));
attendee.setIsPresent(mCurrentPresence);

// You can then do whatever you want with this object
// like adding it to an ArrayList or saving it to a database
mAttendees.add(attendee);

// Notify the user
Toast.makeText(ComplexObjectDemo.this, “Attendee added!”, Toast.LENGTH_SHORT).show();
}

public class MyOnItemSelectedListener implements OnItemSelectedListener {

public void onItemSelected(AdapterView parent, View view, int pos, long id) {
mCurrentPresence = (pos==0) ? true : false;
}

public void onNothingSelected(AdapterView parent) { /Do nothing./ }
}
}</pre>And here’s the second activity:
<pre class="brush:java; collapse:true">package droidista.example;

import android.app.Activity;
import android.os.Bundle;
import android.widget.TextView;

public class ComplexObjectReceiverDemo extends Activity {

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_complex_demo_receiver);

// Get the extras passed to this Activity
setUpViews(getIntent().getExtras());
}

private void setUpViews(Bundle extras) {
// Again, the key should be in a constants file!
Bundle extraAttendee = extras.getBundle(“test.complex.attendee”);
AttendeeObject attendee = new AttendeeObject();

// Deconstruct the Bundle into the AttendeeObject
attendee = attendee.unBundleAttendee(extraAttendee);

// The AttendeeObject fields are now populated, so we set the texts
((TextView) findViewById(R.id.attendee_age_value)).setText(String.valueOf(attendee.getAge()));
((TextView) findViewById(R.id.attendee_name_value)).setText(attendee.getName());
((TextView) findViewById(R.id.attendee_presence_value)).setText(String.valueOf(attendee.isPresent()));
}

}</pre>

5 min read

Dreaming of Google I/O: ADT preview

It is my dream to one day attend Google I/O. But seeing as I’m from a Third World country where everyday is a practice in cost-cutting, it is very unlikely that I would fulfill that dream anytime soon. I haven’t sat down and computed the actual cost, but thinking about it makes my head spin. Off the top of my head:<div><ul><li>US Visa application = P6500 (~USD150)</li><li>Round trip plane fare ticket = P90,000 (~USD2000, if I’m lucky)</li><li>Google I/O ticket = P21,000 (~USD450, if my research is correct)</li></ul><div>Then of course, there’s food, transportation, accommodations, and pocket money. sigh</div></div><div>
</div>For now, I would have to content myself with watching videos from the sessions. Yesterday, I watched Android SDK tech lead’s Xavier Ducrohet’s session on the Android Development Tools. I had a little interaction with Xavier on the Android developers Google group before, and it is refreshing to finally map a face to the name. I kinda feel bad too, because the few times that I talked to him in the groups, it is to complain about the problems I’m having whenever I update my ADT. Eclipse, the SDK and I have a love-hate relationship with each other. But that’s another story.<div>
</div><div>Anyway, I was watching the session while having lunch which turned out to be a mistake. I was so awestruck by the new tools that I totally forgot to eat and my chicken got cold! I was gushing about the tools, but of course no one can relate as I am the only Android developer in our company. I was applauding and cheering by myself. Oh well.</div><div>
</div><div>Needless to say, I am so impressed with the new version of ADT! (More exclamation marks should follow, but I’m trying to act mature) I used to hate making layout files. I am lightyears away from being artistic, I don’t have a strong background in XML, and I simply find all the available features overwhelming. It’s developer option paralysis, I would think. But the new ADT makes making layouts look like F-U-N! I love how it’s sleeker, seemingly more user-friendly (I’d retain the qualifier until I get to try it out), and more feature-packed. </div><div>
</div><div>Some of the reasons I’m already loving the new ADT:</div><div>1. Smarter extract to include</div><div>The current ADT already has an extract to include feature, but the new version looks smarter. When you choose to extract a layout stub as an include, the ADT looks for the exact same layout in all your other layout files and replaces them with the include tag! Brilliant, I say!</div><div>
</div><div>2. XML editors: attribute auto-complete</div><div>Oh. My. God. I have been ranting about this for so long! There are simply too many attributes available for each type of widget I find it impossible to remember everything! And then of course I have to make sure that I am putting the correct value formats into those attributes! I admit that it terrified me when I was starting out in Android; having this feature saves the newbies from a lot of heartache.</div><div>
</div><div>3. Layout actions toolbar</div><div>Easier to set attributes without having to scroll down a lot then finding out you put in the wrong value and then having to scroll down again. Nifty!</div><div>
</div><div>4. Widget Previews in the palette</div><div>One time I was creating a layout file, I wanted to put an indeterminate progress bar but I want it to use the small progress bar style. But then I lost my list of native Android styles so I have to Google for the correct style that I want (?android:attr/android:progressBarStyleSmall is a little hard to remember).</div><div>
</div><div>Soon I can choose precisely what I want before dragging widgets onto the canvas! The previews plus the attribute autocomplete feature would work wonders, I would guess. And it is wonderful that the previews change with the selected theme!</div><div>
</div><div>5. Support for more widgets</div><div>I used to think that I’m doing an include wrong, because the graphical editor doesn’t show the layout I’m including. It turns out that I have to put it inside a LinearLayout just to have the editor render it properly. But it looks like those days are behind us now!</div><div>
</div><div>Also gone are the days when the ADT cannot render TabHosts! I’m doing my happy dance now!</div><div>
</div><div>6. (Hopefully) easier drag-and-drop</div><div>Dragging-and-dropping in RelativeLayouts is a pain in the ass. The editor simply does not listen to me! But in the new ADT it looks like the new anchors are easier to understand than the current one, with squares all around.</div><div>
</div><div>I haven’t tried dragging a view directly into the outline in the current ADT, but knowing that I would have it soon makes me happy!</div><div>
</div><div><div>7. Custom views available in the GUI editor</div><div>And then Xavier’s team showed us how much they love us by including custom views in the widget palette. I haven’t really used that many custom views, but I guess a lot of developers who customize like crazy would love this feature.</div></div><div>
</div><div><hr width="50%">
</div><div>That being said, I would like to thank Xavier and his team for making sure that us developers continue to love doing what we do by making our jobs a little easier. I would like to think that they take time to listen to our opinions, and they for sure make it easy for us to talk to them. I love how accessible they are, and how very supportive of us. Sending good vibes to you and your team, Xavier!</div><div>
</div><div>I just hope that having this new ADT would not make developers lazy. I wish that we still make sure we understand how the XML file works, that we still read the documentation for the widgets, that we simply do not rely on automation to do the work for us. For starters, make sure you know how to change an EditText to accept passwords, or phone numbers, or only letters without relying on the palette.</div><div>
</div><div>I admit that I screech like a true fan girl when Romain Guy or Xavier answer my tweets. blush
<div>
</div><div>Here’s the session’s video. Gush with me!</div><div>
<div><iframe width="480" height="295" src="http://www.youtube.com/embed/Oq05KqjXTvs?fs=1" frameborder="0" allowfullscreen=""></iframe></div></div></div>

4 min read

Changing a button’s text color

There are times that when changing a button's background color, we also want to change the text's color. There is a method setTextColor(int color) specifically for this purpose. Seems pretty straightforward enough, but it took me a few tries to get it right the first time I tried using it. Documenting it here so that I wouldn't forget.

Here’s a screenshot of my button with its default settings.<div><div style="text-align: center;">
</div></div><div>What I’m trying to do is have the color of the text change to a shade of blue once the button is pressed. But look what I got.</div><div>That is no shade of blue! Far from it! I tried changing the alpha value of the #AARRGGBB value, but I still end up with the same gray shade. It turns out that you cannot pass a direct R.* id to the setTextColor() method.</div><div>
</div><div>Here’s how I finally managed to make it work:</div><div><pre class="brush:java">int newColor = getResources().getColor(R.color.button_new_color);
((Button)view).setTextColor(newColor);</pre>And tada!</div><div></div>

~1 min read

Using CWAC’s EndlessAdapter with a custom adapter

In one of my projects, the app has the potential to display a very, and I mean very, long list. To minimize the loading time of the app, I limit the number of items initially included in the list and then add to it as the user scrolls down.

For this purpose, Mark Murphy’s EndlessAdapter works wonders. I was trying to make it work with a CursorAdapter though, but due to time constraints, I was not able to continue with my experiment.

And then I found out that some of the items in my list are HTML-formatted. Huh. So I have to have a custom adapter to override getView(). I patterned my code on the demo included in the EndlessAdapter project and I was at a loss. Maybe it’s because I just came from a vacation and my mind refuses to work. Hmmm.

To cut a long and arduous journey short, I was able to figure it out. Here’s a sample activity that displays a list of countries from an array. To illustrate using a custom adapter, I add the list item number when setting the item text.

I will discuss the pertinent parts of the code in detail.
<pre class="brush:java">private void init() {
LIST_SIZE = COUNTRIES.length;
for (int i=0; i<=BATCH_SIZE; i++){
countriesSub.add(COUNTRIES[i]);
}

setLastOffset(BATCH_SIZE);
displayList(countriesSub);
}</pre>In this part of the code, I get the first 10 items in the list as the initial contents of the list. Of course, our current list is small and is peanuts for ListView. This is just to illustrate my point. In my app, I initially load 2,000 items. I also make sure to remember where I am in my source list. In my case, it is the offset in the original array. This might also be a row in the DB, or the ID in an RSS feed.

The ArrayList countriesSub holds the items that are currently in my list. As the user goes through the list, this array will grow.

To display my list, I set an instance of DemoAdapter as my list adapter. DemoAdapter inherits from EndlessAdapter and in its constructor, I give it an instance of my custom ArrayAdapter.
<pre class="brush:java">@Override
public View getView(int position, View convertView, ViewGroup parent) {

ViewHolder holder;

if(convertView==null){
LayoutInflater inflater = (LayoutInflater)
EndlessCustom.this.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = inflater.inflate(android.R.layout.simple_list_item_1, null);
holder = new ViewHolder();
holder.word = (TextView)convertView.findViewById(android.R.id.text1);

convertView.setTag(holder);
} else{
holder=(ViewHolder)convertView.getTag();
}

holder.word.setText(String.valueOf(position+1) + “. “ + countriesSub.get(position));
return convertView;
}</pre>
The important part in my custom ArrayAdapter is the getView() method. In this method, I tell the adapter to not simply display the .toString() value of the item, but to add a number before it.

Notice that I use the ViewHolder pattern as illustrated in the Android Developers site.
<pre class="brush:java; tab-size: 5">DemoAdapter() {
super(new CustomArrayAdapter(EndlessCustom.this,
android.R.layout.simple_list_item_1, android.R.id.text1, countriesSub));

rotate=new RotateAnimation(0f, 360f, Animation.RELATIVE_TO_SELF,
0.5f, Animation.RELATIVE_TO_SELF,
0.5f);
rotate.setDuration(600);
rotate.setRepeatMode(Animation.RESTART);
rotate.setRepeatCount(Animation.INFINITE);
}</pre>
So now we come to the EndlessAdapter part. In the constructor, I pass into it an instance of my custom ArrayAdapter, indicating the source of the list, the layout for each row, and the TextView ID from the layout. I also instantiated the animation that will be used while the list is loading the additional items.
<pre class="brush:java">@Override
protected boolean cacheInBackground() {
tempList.clear();
int lastOffset = getLastOffset();
if(lastOffset < LIST_SIZE){
int limit = lastOffset + BATCH_SIZE;
for(int i=(lastOffset+1); (i<=limit && i<LIST_SIZE); i++){
tempList.add(COUNTRIES[i]);
}

setLastOffset(limit);

if(limit<LIST_SIZE){
return true;
} else {
return false;
}
} else {
return false;
}
}</pre>We have to override cacheInBackground() for EndlessAdapter to work. Here we do the heavy lifting like querying the server, reading from the DB, etc. Here, I load the next 10 items from the original list and put them in a temporary ArrayList. I also check whether I have loaded all the data, and if so, tell the EndlessAdapter to not show the extra row at the bottom. I do this by returning false from the method.
<pre class="brush:java; tab-size: 5">@Override
protected void appendCachedData() {
@SuppressWarnings(“unchecked”)
ArrayAdapter<String> arrAdapterNew = (ArrayAdapter<String>)getWrappedAdapter();

int listLen = tempList.size();
for(int i=0; i<listLen; i++){
arrAdapterNew.add(tempList.get(i));
}
}</pre>Finally, I add the newly retrieved rows to my current list. And that’s it.

The complete Java file for this activity follows:
<pre class="brush:java; collapse: true">package com.test.example;

import java.util.ArrayList;
import java.util.List;

import android.app.ListActivity;
import android.content.Context;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.Animation;
import android.view.animation.RotateAnimation;
import android.widget.ArrayAdapter;
import android.widget.TextView;

import com.commonsware.cwac.endless.EndlessAdapter;

public class EndlessCustom extends ListActivity {

static int LIST_SIZE;
private int mLastOffset = 0;

static final int BATCH_SIZE = 10;

ArrayList<String> countriesSub = new ArrayList<String>();

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.lib_activity_dictionary);
init();
}

private void init() {
LIST_SIZE = COUNTRIES.length;
for (int i=0; i<=BATCH_SIZE; i++){
countriesSub.add(COUNTRIES[i]);
}
setLastOffset(BATCH_SIZE);
displayList(countriesSub);
}

private void setLastOffset(int i) {
mLastOffset = i;
}

private int getLastOffset(){
return mLastOffset;
}

private void displayList(ArrayList<String> countriesSub) {
setListAdapter(new DemoAdapter());
}

private class CustomArrayAdapter extends ArrayAdapter<String>{

public CustomArrayAdapter(Context context, int resource,
int textViewResourceId, List<String> objects) {
super(context, resource, textViewResourceId, objects);
}

@Override
public View getView(int position, View convertView, ViewGroup parent) {

ViewHolder holder;

if(convertView==null){
LayoutInflater inflater = (LayoutInflater)
EndlessCustom.this.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = inflater.inflate(android.R.layout.simple_list_item_1, null);
holder = new ViewHolder();
holder.word = (TextView)convertView.findViewById(android.R.id.text1);

convertView.setTag(holder);
} else{
holder=(ViewHolder)convertView.getTag();
}

holder.word.setText(String.valueOf(position+1) + “. “ + countriesSub.get(position));
return convertView;
}

public class ViewHolder{
public TextView word;
}
}

class DemoAdapter extends EndlessAdapter {
private RotateAnimation rotate=null;
ArrayList<String> tempList = new ArrayList<String>();

DemoAdapter() {
super(new CustomArrayAdapter(EndlessCustom.this,
android.R.layout.simple_list_item_1, android.R.id.text1, countriesSub));

rotate=new RotateAnimation(0f, 360f, Animation.RELATIVE_TO_SELF,
0.5f, Animation.RELATIVE_TO_SELF,
0.5f);
rotate.setDuration(600);
rotate.setRepeatMode(Animation.RESTART);
rotate.setRepeatCount(Animation.INFINITE);
}

@Override
protected View getPendingView(ViewGroup parent) {
View row=getLayoutInflater().inflate(R.layout.row, null);

View child=row.findViewById(android.R.id.text1);
child.setVisibility(View.GONE);
child=row.findViewById(R.id.throbber);
child.setVisibility(View.VISIBLE);
child.startAnimation(rotate);

return(row);
}

@Override
protected boolean cacheInBackground() {
tempList.clear();
int lastOffset = getLastOffset();
if(lastOffset < LIST_SIZE){
int limit = lastOffset + BATCH_SIZE;
for(int i=(lastOffset+1); (i<=limit && i<LIST_SIZE); i++){
tempList.add(COUNTRIES[i]);
}
setLastOffset(limit);

if(limit<LIST_SIZE){
return true;
} else {
return false;
}
} else {
return false;
}
}


@Override
protected void appendCachedData() {

@SuppressWarnings(“unchecked”)
ArrayAdapter<String> arrAdapterNew = (ArrayAdapter<String>)getWrappedAdapter();

int listLen = tempList.size();
for(int i=0; i<listLen; i++){
arrAdapterNew.add(tempList.get(i));
}
}
}


static final String[] COUNTRIES = new String[] {
“Afghanistan”, “Albania”, “Algeria”, “American Samoa”, “Andorra”,
“Angola”, “Anguilla”, “Antarctica”, “Antigua and Barbuda”, “Argentina”,
“Armenia”, “Aruba”, “Australia”, “Austria”, “Azerbaijan”,
“Bahrain”, “Bangladesh”, “Barbados”, “Belarus”, “Belgium”,
“Belize”, “Benin”, “Bermuda”, “Bhutan”, “Bolivia”,
“Bosnia and Herzegovina”, “Botswana”, “Bouvet Island”, “Brazil”, “British Indian Ocean Territory”,
“British Virgin Islands”, “Brunei”, “Bulgaria”, “Burkina Faso”, “Burundi”,
“Cote d’Ivoire”, “Cambodia”, “Cameroon”, “Canada”, “Cape Verde”,
“Cayman Islands”, “Central African Republic”, “Chad”, “Chile”, “China”,
“Christmas Island”, “Cocos (Keeling) Islands”, “Colombia”, “Comoros”, “Congo”,
“Cook Islands”, “Costa Rica”, “Croatia”, “Cuba”, “Cyprus”, “Czech Republic”,
“Democratic Republic of the Congo”, “Denmark”, “Djibouti”, “Dominica”, “Dominican Republic”,
“East Timor”, “Ecuador”, “Egypt”, “El Salvador”, “Equatorial Guinea”, “Eritrea”,
“Estonia”, “Ethiopia”, “Faeroe Islands”, “Falkland Islands”, “Fiji”, “Finland”,
“Former Yugoslav Republic of Macedonia”, “France”, “French Guiana”, “French Polynesia”,
“French Southern Territories”, “Gabon”, “Georgia”, “Germany”, “Ghana”, “Gibraltar”,
“Greece”, “Greenland”, “Grenada”, “Guadeloupe”, “Guam”, “Guatemala”, “Guinea”, “Guinea-Bissau”,
“Guyana”, “Haiti”, “Heard Island and McDonald Islands”, “Honduras”, “Hong Kong”, “Hungary”,
“Iceland”, “India”, “Indonesia”, “Iran”, “Iraq”, “Ireland”, “Israel”, “Italy”, “Jamaica”,
“Japan”, “Jordan”, “Kazakhstan”, “Kenya”, “Kiribati”, “Kuwait”, “Kyrgyzstan”, “Laos”,
“Latvia”, “Lebanon”, “Lesotho”, “Liberia”, “Libya”, “Liechtenstein”, “Lithuania”, “Luxembourg”,
“Macau”, “Madagascar”, “Malawi”, “Malaysia”, “Maldives”, “Mali”, “Malta”, “Marshall Islands”,
“Martinique”, “Mauritania”, “Mauritius”, “Mayotte”, “Mexico”, “Micronesia”, “Moldova”,
“Monaco”, “Mongolia”, “Montserrat”, “Morocco”, “Mozambique”, “Myanmar”, “Namibia”,
“Nauru”, “Nepal”, “Netherlands”, “Netherlands Antilles”, “New Caledonia”, “New Zealand”,
“Nicaragua”, “Niger”, “Nigeria”, “Niue”, “Norfolk Island”, “North Korea”, “Northern Marianas”,
“Norway”, “Oman”, “Pakistan”, “Palau”, “Panama”, “Papua New Guinea”, “Paraguay”, “Peru”,
“Philippines”, “Pitcairn Islands”, “Poland”, “Portugal”, “Puerto Rico”, “Qatar”,
“Reunion”, “Romania”, “Russia”, “Rwanda”, “Sqo Tome and Principe”, “Saint Helena”,
“Saint Kitts and Nevis”, “Saint Lucia”, “Saint Pierre and Miquelon”,
“Saint Vincent and the Grenadines”, “Samoa”, “San Marino”, “Saudi Arabia”, “Senegal”,
“Seychelles”, “Sierra Leone”, “Singapore”, “Slovakia”, “Slovenia”, “Solomon Islands”,
“Somalia”, “South Africa”, “South Georgia and the South Sandwich Islands”, “South Korea”,
“Spain”, “Sri Lanka”, “Sudan”, “Suriname”, “Svalbard and Jan Mayen”, “Swaziland”, “Sweden”,
“Switzerland”, “Syria”, “Taiwan”, “Tajikistan”, “Tanzania”, “Thailand”, “The Bahamas”,
“The Gambia”, “Togo”, “Tokelau”, “Tonga”, “Trinidad and Tobago”, “Tunisia”, “Turkey”,
“Turkmenistan”, “Turks and Caicos Islands”, “Tuvalu”, “Virgin Islands”, “Uganda”,
“Ukraine”, “United Arab Emirates”, “United Kingdom”,
“United States”, “United States Minor Outlying Islands”, “Uruguay”, “Uzbekistan”,
“Vanuatu”, “Vatican City”, “Venezuela”, “Vietnam”, “Wallis and Futuna”, “Western Sahara”,
“Yemen”, “Yugoslavia”, “Zambia”, “Zimbabwe”
};
}</pre>
If you know of a more efficient way to do this, please do not hesitate to let me know! :)

6 min read

My EditText is cut off by the on-screen keyboard!

With clients demanding left and right that my app should look like an iPhone app, I tend to be unappreciative of the way Android natively handles UI interactions and such. Notice how the screen automagically scrolls up when you click on an EditText? It turns out that in iPhone development, the developer does this manually (indicate how much the view should scroll when the on-screen keyboard appears, then scroll it back down afterwards). HA!

But even magic fails sometimes. Has this ever happened to you?
<img style=”display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 134px; height: 200px;” src=”http://3.bp.blogspot.com/-JftkETrkB2c/TZlrHJOji5I/AAAAAAAAA4I/cX4jSBJRiGY/s200/edittext_hidden.png” border=”0” alt=”“id=”BLOGGER_PHOTO_ID_5591618182837406610” />
The bottommost EditText is cut off. And we don’t want that!

So what do we do? Do we programmatically scroll the view up? I don’t want to do that! It turns out that we can just wrap the whole view in a ScrollView and it will scroll up properly!
<img style=”display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 134px; height: 200px;” src=”http://1.bp.blogspot.com/-J2UCMLF_E3k/TZlrk_lKBdI/AAAAAAAAA4Q/c7G321XalBo/s200/edittext_shown.png” border=”0” alt=”“id=”BLOGGER_PHOTO_ID_5591618695643923922” />

The only downside to this is that you might want to hide the scrollbar when the view moves up to accommodate the on-screen keyboard. And to do that, I was trying to set the android:scrollbars=”none” attribute but for one reason or another the scrollbar is still being drawn. To make the scrollbar disappear, we can do it from code as such:<pre class="brush:java">((ScrollView)findViewById(R.id.my_scrollview))
.setVerticalScrollBarEnabled(false);</pre>And we’re done!

~1 min read

Using a custom font in WebView

In one of my projects, I needed to display some special characters that the Android OS by itself cannot seem to render. I figured that I would need to provide a custom font that includes the characters that I needed.

If I was using a TextView, I could use TextView#setTypeFace. But I was using a WebView and I feared that things would be more complicated than that. So how do I do this?

Here’s how we can make it work.

Step 1: We would need to have our font face included in our project’s /assets folder. So look for a TTF file that you can use freely, make sure the author/creator allows you to re-distribute it!

Step 2: Edit your HTML file to include some CSS stuff, just so the WebView would know what font you want to use. Here’s a sample file: <pre class="brush:xml"><html><head><link href=”YourCssFile.css” rel=”stylesheet” type=”text/css” /></head><body><span class=”phon”>This string contains special characters: əˈpåstrəfi </span></body></html></pre>Make sure that the href references are correct. In this case, my CSS file, HTML file and font file are in the same folder.

Step 3: Define your CSS file. In this case, our YourCssFile.css would be:<pre class="brush:css">@font-face {
font-family: “My font”;
src: url(‘MyFontFile.TTF’);
}

.phon, .unicode {
display: inline;
font-family: ‘My font’, Verdana, sans-serif;
font-size: 14pt;
font-weight: 500;
font-style:normal;
color: black;
}</pre>Step 4: Load the file in your WebView! You can use <pre class="brush:java">WebView webView = (WebView) findViewById(R.id.myWebview);
webView.loadUrl(“path/to/html/file”);</pre> or <pre class="brush:java">webView.loadDataWithBaseURL(“file:///android_asset/”,
article, “text/html”, Encoding.UTF_8.toString(), null);</pre>If you will use the second option, your article variable would contain the HTML string. Just make sure that you escape your quotation marks with a backslash ().
<blockquote><blockquote>IMPORTANT NOTE: This feature seems to be broken in Android 2.0 and 2.1, as reported here.</blockquote></blockquote>

1 min read

It never ends!

Been ultra super busy the past few weeks. Also learning a lot of new things. And renewing my battle with orientation change, AsyncTasks and dialog boxes.

So, I have been thinking of what to document here next. Here are my choices:
- Loading HTML pages stored in the SD card in a WebView
- Managing your SharedPreferences
- Using a ViewStub

I had a long list in my mind yesterday, but I managed to not write it down. facepalm

~1 min read

stealth ninja mode on

Over the past couple of weeks, this blog has been getting unusually high traffic. Which means I get more than one hit per week.

So if it isn’t too much to ask, can I please know how you got here, and what you were looking for. And please please let me know if I said anything wrong, or if you know of a better/easier/more optimized way to do the stuff I’m trying to talk about. Thanks! :)

~1 min read

That damn seekbar thumb

If you have ever needed to use a SeekBar, you definitely would have noticed how hard it is to move the slider (aka thumb) when it is set to the minimum or maximum value. The slider tends to be cut in half, and fitting your finger into it to press it becomes a test of patience.<div></div>
See how small the slider becomes when it reaches the far ends of the SeekBar? Crazy!

Luckily, I found a way (just today!) to move the slider just a little tiny bit to make it easier to press. Apparently, there is a method called setThumbOffset() that allows us to nudge the slider by a number of pixels.

It’s pretty easy to use, aside from the fact that it accepts pixels and not dip measurements. Anyway, here’s how to do it:<pre class="brush:java">int pixels = convertDipToPixels(8f);
SeekBar mySeekBar = (SeekBar) findViewById(R.id.quiz_settings_seekbar);
mySeekBar.setOnSeekBarChangeListener(mySeekBarListener);
mySeekBar.setThumbOffset(pixels);</pre>I convert dip measurements to pixels to better manage the growing number of resolutions of screen sizes present. Here’s the code to do that:<pre class="brush:java">private int convertDipToPixels(float dip) {
DisplayMetrics metrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(metrics);
float density = metrics.density;
return (int)(dip * density);
}</pre>Aaaaaaaand this is now how our slider looks:Applause! Confetti! Applause!

~1 min read

Enabling/disabling menu items on the fly

In one of my applications, I want to disable some menu entries if the database is not valid or is not present at all. To do that, I make use of the onPrepareOptionsMenu() API.

Let’s say the user is on the Quiz activity. When the user presses the MENU button, the Quiz item should not be there anymore; and until the application validates the presence of a database, I want the Books item to be unclickable.

So I inflate my menu as usual from the XML file:<pre class="brush:java">@Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.my_menu, menu);

removeSomeItems(menu);
return true;
}

private void removeSomeItems(Menu menu){
MenuItem books = menu.findItem(R.id.menu_books);
books.setEnabled(false); // I want this item to be available eventually

menu.removeItem(R.id.menu_quiz); // I want this item to be unavailable for this activity
}</pre>
You have to remember though, that this method is called only ONCE, the very first time the user opens the menu.

The activity does its business as usual. When I am done checking if the database is there already, I want the user to be able to use the Books item. I have a boolean field that I set when the database is validated, and so now I can enable the menu.<pre class="brush:java">@Override
public boolean onPrepareOptionsMenu (Menu menu){
super.onPrepareOptionsMenu(menu);

if(mIsDbValid){
MenuItem books = menu.findItem(R.id.menu_books);
books.setEnabled(true);
}

return true;
}</pre>

You can change the contents of the menu as often as you want using onPrepareOptionsMenu() because that method is called each and every time the user presses the MENU button.

And that’s it!

1 min read

Quick tip: Quick Formatting of Android XML Files

One of the most useful tools in Android’s Eclipse plug-in is the Layout Editor. It is easy to experiment with layouts using the drag-and-drop enabled editor without having to worry about the correct syntax or if you are using the correct attribute name.

After creating your layout this way, however, you can end up with a messy XML file. I say “messy” in the sense that elements can run on in one veeeeeeeeeeeery long line, and if you are about to edit the XML file manually, this can be a nightmare.

I used to format the XML file by hand, putting in line breaks and correcting indentation. But one edit using the graphical layout editor and it’s messed up again. And then I had a light bulb moment. Eclipse allows auto-formatting of code, but what about XML files? AHA!

It turns out that auto-formatting works for XML files too! Simply select all the contents of the XML file (CTRL-A) and then press the ultra magical shortcut CTRL-I and your XML file is clean and orderly as can be! YAY!

~1 min read

What happened to my layout editor?

There you are, happily creating your layout files in the Eclipse plug-in’s layout editor. Dragging and dropping is a breeze. But then one day, you open a layout XML file and boom! No UI! All you see is the XML tree with all the nodes and attributes. What happened?

This happened to me and I was in a panic for a few seconds. Why do things like these have to happen to me? I tried opening a layout file from another project in the same workspace, and it has the UI! What happened?

It probably has something to do with the interpreter you used to open the XML file, a voice in my head said. So I tried right-clicking on the XML file, and lo and behold, I found it. I may have accidentally clicked on some file in one of my mad-clicking moments and changed the setting.

So anyway, to bring back the Layout UI Editor, right click on an XML file > Choose Open With > Android Layout Editor.

I would say that everything is handy dandy, but apparently, the engineers at Google decided that we developers need a little less help and removed the very useful up and down arrow keys in the Outline View when editing XML layouts. Why do they hurt us like this?

I WANT MY UP/DOWN KEYS BACK!

1 min read

What grammar?

My OC side was alarmed when suddenly, my Problems view in Eclipse was filled with warnings on my XML files. Each of my XML files had a warning with it, and that little yellow exclamation mark on the side:<div>No grammar constraints (DTD or XML schema) detected for the document</div><div>
</div><div>So how do you get rid of it? Go to Window > Preferences > XML > XML Files > Validation then set Indicate when no grammar is specified to Ignore. Click on Apply.</div><div>
</div><div>Clean up your project (Project > Clean). </div><div>
</div><div>If the problem doesn’t go away, you may need to re-validate the XML files. Right click on the file then choose Validate from the popup menu. You can also right click on the folder (such as your res folder) and validate from there.</div>

~1 min read

TextView and MaxLines

I have a TextView (who doesn’t?) and I want to adjust its height automatically, depending on the length of the text it will contain. Should be easy. It was, but it took me a couple of minutes to figure it out.<div>
</div><div>So I want my TextView to be by default one line tall, but be able to expand up to two lines. My initial set up was to set lines=1 and maxLines=2, but it was making the TextView always two lines. Not what I wanted! I went through the documentation again, read each word carefully, and then:
<pre class="brush:xml"><TextView android:id=”@+id/title”
android:layout_height=”wrap_content”
android:layout_width=”fill_parent”
android:ellipsize=”end”
android:maxLines=”2”
android:minLines=”1”
android:text=”This is the text” /></pre>So it turned out that you have to set both minLines and maxLines. TADA!</div>

~1 min read

Missing hierarchyviewer in SDK 7

If you have SDK version 7, you are most probably missing the hierarchyviewer from your /tools folder. To check your SDK version, launch the SDK manager UI from your installation path, usually C:\android-sdk-windows, then click About.
To run hierarchyviewer, you need to manually create the </code>hierarchyviewer.bat</code> file and add it to your <install_path>/tools directory. The text of the batch file can be copied from here.

And so, you can now run hierarchyviewer as you would if the SDK release isn’t effed up. Don’t know how to run it? Follow these steps:
a. In Windows, open up a terminal by running cmd.
b. Navigate to your SDK’s install path. Since I installed mine in C:\, I would have to type in cd C:\android-sdk-windows\tools
c. Type in hierarchyviewer at the prompt.

~1 min read

More plurals: decimal values

In my previous post, I showed you how to set string plurals. If you noticed, the methods to get the plurals strings only accept ints. What if (like me) you want to display a decimal value? I am getting my raw value from a progress bar with a range of 1-10, with 0.1 increments.

1 min read

String Pluralization

Last week, I discovered Android’s support for plural strings by accident. And a good accident it was since I am working on an app that will display a float to the user. I used to display:

1 min read

Quick string resource formatting

Sooner or later, you would want to display a message to your user with dynamic content. This may be the number of results, the user’s name, etc.

~1 min read

A test, a test

I was thinking of starting a quick-tips style blog for software development (mostly for myself, since I tend to forget stuff a lot recently).

~1 min read
Back to Top ↑

android studio

Enforcing Team Rules with Lint: Tests 🧐

A few months ago, my team came upon an agreement that when leaving a TODO anywhere in our code, we need to always provide several things:

  • the person who is expected to address the TODO
  • date when the TODO was left
  • a comment or explanation on what needs to be done
4 min read

Enforcing Team Rules with Lint: Detectors 🕵️

A few months ago, my team came upon an agreement that when leaving a TODO anywhere in our code, we need to always provide several things:

  • the person who is expected to address the TODO
  • date when the TODO was left
  • a comment or explanation on what needs to be done
12 min read

Enforcing Team Rules with Lint 👩‍🔧

A few months ago, my team came upon an agreement that when leaving a TODO anywhere in our code, we need to always provide several things:

  • the person who is expected to address the TODO
  • date when the TODO was left
  • a comment or explanation on what needs to be done
4 min read

Easy Navigation with Bookmarks

One of the things I find most challenging when learning a new part of a codebase is navigating through the data flow. In some areas of our app, following RX streams can be particularly… draining.

1 min read

//TODO Live Templates

Throughout my career, I have worked in projects of all sizes. I have taken part in greenfield projects and some that are a few years old. One of the lessons I have learned over the years is that no one ever goes back to fix the TODOs.

2 min read

Which is Which: Named Breakpoints

I have always believed that one of the biggest factors that influence a person’s enjoyment and delight in doing their job are the tools. Having the right tools and using them the best way possible helps direct our energy on the what rather than the how.

1 min read

Scratch That Itch

One of the most useful things for me whilst I was learning Kotlin was TryKotlin. It gave me a quick way to test concepts, try new APIs, or just to get familiar with the syntax.

2 min read

Tools of the Trade: Unabridged

I gave an unabridged version of my last Android Meetup talk at this year’s YOW Conference. It has been an honour being part of this awesome conference!

~1 min read

Snazzy git blaming

Sometimes, you can’t help it. You need to look at what happened in the past to understand what is happening in the present (wow).

1 min read

Squashing Bugs

This has been one hell of a busy week for me. I think you can sort of tell from my Tweets and G+ posts that I have been debugging A LOT.

1 min read

Raising Activities From the Dead

One of the scenarios I admittedly almost always forget to test is “What happens when my app goes into the background, then the OS kills is to claim memory, then I try to resume?” Usually it’s “Well, I handle onSavedInstanceState not being null, so I am great!” It is fine and dandy for simple apps; but once your Activity or Fragment gets beefier and you start relying on state for more and more things, it can get complicated pretty quickly (In my case, the Fragment has setRetainInstance(true)).

This scenario in particular is kind of hard to reproduce willingly. I usually see this when I leave an app running, make my phone do some heavy work overnight, then resume the app the next day.
<div class="separator" style="clear: both; text-align: center;"></div><div class="separator" style="clear: both; text-align: left;">
</div><div class="separator" style="clear: both; text-align: left;">So what you gonna do?</div><div class="separator" style="clear: both; text-align: left;">
</div><div class="separator" style="clear: both; text-align: left;">It turns out that Android Studio has the answer! There is this magical tiny red button that allows you to simulate this exact scenario.</div><div class="separator" style="clear: both; text-align: left;">
</div><div class="separator" style="clear: both; text-align: left;">1. Open your app to the Activity you want to test (I use a very simple app here just for demo).</div><div class="separator" style="clear: both; text-align: center;">

</div><div class="separator" style="clear: both; text-align: center;">
</div><div class="separator" style="clear: both; text-align: left;">2. In Studio, go to Android Monitor (make sure that your app is selected). Note the process ID, in this case it is 25647.</div><div class="separator" style="clear: both; text-align: center;"></div>
3. Push your app to the background. Pressing the HOME button should be sufficient. This will call onSaveInstanceState, which is all that matters really. It is after all what we want to test.

4. Back in Studio, press the magical tiny red button pointed to in the previous image. Notice that Studio now appends [DEAD] to your app’s process. It is now gone. He’s dead, Jim!
<div class="separator" style="clear: both; text-align: center;"></div>
5. Resume your app. I usually just do this via recent apps.
<div class="separator" style="clear: both; text-align: center;"></div>
6. If you look at Studio, you’ll see that your app is now no longer dead, but has a new process ID, in this case 26742.
<div class="separator" style="clear: both; text-align: center;"></div><div class="separator" style="clear: both; text-align: center;">
</div><div class="separator" style="clear: both; text-align: left;">If at this point you step through your code, you will notice that your Activity will go through the whole (re-)creation process with the Bundle given the values you have saved in onSaveInstanceState. No more waiting overnight, yay!</div>

1 min read

Lies I’ve been told today

So I played around with data binding today. And these are the lies that the dev guide told me (explicitly or inferred):

<ul><li>There is a method DataBindingUtil.bindTo(viewRoot, layoutId)</li><li>That this will work MyLayoutBinding.bind(viewRoot);</li><li>Android Studio has auto-complete</li></ul>

~1 min read

Pasting and Extracting Stuff

A lot of times, but especially when I am implementing some new logic, coding for me takes several steps:
1. Write down what I have to do as comments
2. Implement what I have written down
3. Refactor and improve what I have implemented

More often than not, step 3 means moving stuff around, copy-pasting things, extracting variables, defining constants, etc. I am not a hardcode never-using-my-mouse developer. If anything, I think my brain is limited to holding a limited number of shortcuts for everything I use in my life. Android Studio has the perfect shortcuts for making this easier for me. Luckily, these shortcuts made it to the list of things my brain remembers.

How many times have I copied (or even cut!) text but instead of pasting, I press ⌘+V (CMD+V) again! ARGH. I used to do ⌘+Z (CMD+Z) any number of times until I get back what I wanted. That is, until I learned about ⌘+⇧+V (CMD+SHIFT+V)! This key combo shows the clipboard history, which means no more fretting. Yay!

Refactoring also mostly involves extracting variables. I have already shown how to extract strings into strings.xml, and here I show how to extract things into methods, variables, fields, or constants.

It is fairly easy to remember them. Just combine ⌘+⌥ (CMD+OPTION) with the first letter of what you want to extract to. Time for a handy table!

<table style="border-collapse: collapse; border: 1px solid black;"><tbody><tr><th style="border: 1px solid black; padding: 5px;">Shortcut </th><th></th></tr><tr><td style="border: 1px solid black; padding: 5px;">⌘+⌥+M </td><td style="border: 1px solid black; padding: 5px;">Method </td></tr><tr><td style="border: 1px solid black; padding: 5px;">⌘+⌥+V </td><td style="border: 1px solid black; padding: 5px;">Variable </td></tr><tr><td style="border: 1px solid black; padding: 5px;">⌘+⌥+F </td><td style="border: 1px solid black; padding: 5px;">Field </td></tr><tr><td style="border: 1px solid black; padding: 5px;">⌘+⌥+C </td><td style="border: 1px solid black; padding: 5px;">Constant </td></tr></tbody></table>
This video might do a better job of showing what I’m trying to say. Code from Chris Banes’s Cheesesquare demo.
<iframe allowfullscreen="" frameborder="0" height="315" src="https://www.youtube.com/embed/bgzPRX9zC30" width="420"></iframe>

1 min read

Super lightning talk: Tinkering with Tools

If you are just starting Android development or migrating from Eclipse to Android Studio, I gave a lightning talk on setting up some tools: <iframe src="https://docs.google.com/presentation/d/1UqyM9ZjMGjREdyaAoduTT6wY8NnfylR39fohlp3eg7k/embed?start=false&loop=false&delayms=60000" frameborder="0" width="480" height="299" allowfullscreen="true" mozallowfullscreen="true" webkitallowfullscreen="true"></iframe>

~1 min read

Stringy strings


While we are on the subject of strings, here are more ways of dealing with them in Android Studio. We all know that we should not hardcode strings in code, right? But sometimes, we forget and tend to do code first before defining them in strings.xml.

There are a couple of ways that Android Studio/IntelliJ makes this easy for us. The gif below (which took me a while to figure out how to do, by the way), shows how to deal with:
1. Moving a hardcoded string into strings.xml
2. Giving a previously undefined string ID a value in strings.xml

<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody><tr><td style="text-align: center;"></td></tr><tr><td class="tr-caption" style="text-align: center;">(Click to embiggen)</td></tr></tbody></table>
Move hardcoded string into XML:
This is probably the more common scenario. You happily put in texts into your TextViews, and now you have to copy and paste them into strings.xml. Don’t! There is a shortcut for that.

Put your cursor somewhere in the string, press ALT+Enter to bring up the context menu, choose “Extract string resource” and give your string resource a name. This will create a new <string name=”my_string_name”>My string value</string> in strings.xml.

Studio magically also calls getString(R.string.xxxxx) for you. Neat, huh?


Make new string from ID:
This is for when you suddenly remember that you need a new string and want to sort of try to do it correctly so you type in the string ID. Only it hasn’t been defined yet, so Studio complains. But it’s fine. There is a shortcut for that.

Put your cursor somewhere in the as of yet undefined ID, press ALT+Enter to bring up the context menu, choose “Create string value for resource my_string_id”, and type in the actual string value you want. Again, this will create a new <string name=”my_string_id”>My other string value</string> in strings.xml.

Remember, in both of these cases, Studio will create the new strings in strings.xml, but you can modify it to put in whatever variant you want it to be in (for localisations, screen size support, etc).

1 min read
Back to Top ↑

quick tips

:facepalm:

I just spent an hour debugging an issue that should have been a non-issue at all.

1 min read

Troubleshooting autoVerify

So you implement app links and you are 300% sure you have implemented everything correctly. The important thing to remember here is that verification is all or nothing. From the docs:

2 min read

Stringy strings


While we are on the subject of strings, here are more ways of dealing with them in Android Studio. We all know that we should not hardcode strings in code, right? But sometimes, we forget and tend to do code first before defining them in strings.xml.

There are a couple of ways that Android Studio/IntelliJ makes this easy for us. The gif below (which took me a while to figure out how to do, by the way), shows how to deal with:
1. Moving a hardcoded string into strings.xml
2. Giving a previously undefined string ID a value in strings.xml

<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody><tr><td style="text-align: center;"></td></tr><tr><td class="tr-caption" style="text-align: center;">(Click to embiggen)</td></tr></tbody></table>
Move hardcoded string into XML:
This is probably the more common scenario. You happily put in texts into your TextViews, and now you have to copy and paste them into strings.xml. Don’t! There is a shortcut for that.

Put your cursor somewhere in the string, press ALT+Enter to bring up the context menu, choose “Extract string resource” and give your string resource a name. This will create a new <string name=”my_string_name”>My string value</string> in strings.xml.

Studio magically also calls getString(R.string.xxxxx) for you. Neat, huh?


Make new string from ID:
This is for when you suddenly remember that you need a new string and want to sort of try to do it correctly so you type in the string ID. Only it hasn’t been defined yet, so Studio complains. But it’s fine. There is a shortcut for that.

Put your cursor somewhere in the as of yet undefined ID, press ALT+Enter to bring up the context menu, choose “Create string value for resource my_string_id”, and type in the actual string value you want. Again, this will create a new <string name=”my_string_id”>My other string value</string> in strings.xml.

Remember, in both of these cases, Studio will create the new strings in strings.xml, but you can modify it to put in whatever variant you want it to be in (for localisations, screen size support, etc).

1 min read

Quick Tip: Understanding Alternate Resources

Trying to support as many devices as possible the best way possible is a very daunting task indeed. You will usually need to provide a lot of different layouts, strings, or dimensions (among others) to make your app look great whatever the user’s device is. And then you start chaining resource qualifiers and testing which resource is being loaded by the OS can become a nightmare very quickly.

Here’s a trick I started using which seemed to work quite well. Create a string (the app name works well if you have an Action Bar) that you can display on-screen (or just throw into a Log or a Toast) that will quickly let you know from which of those very many /res folders your resources are being pulled out of.

For this demo, I have the following /res/values-xxxxx folders:
<div class="separator" style="clear: both; text-align: center;"></div>
As you can see, there are strings.xml files in each of the configurations I want to support. Each of these files will contain whatever description we want to see on the device or in the Logs. In my case, I have custom strings for each form factor and orientation, which allows me to validate things easier. But this is particularly useful if the changes per form factor and orientation is subtle, such as dimensions.

Here’s what it looks like for phones:

<table><tbody><tr><td></td><td></td></tr></tbody></table>
And here are the outputs for tablets:
<table><tbody><tr><td></td><td></td></tr></tbody></table>
Each of the strings.xml files contains just these two strings (sample taken from /res/values-sw800dp):
<pre class="brush:xml">

MultiDeviceSupport - Tablet Portrait
Hello world on a tablet!


</pre>Have fun debugging!

1 min read

Quick Tip: Updating the location update frequency

When using Google Play’s Location Services and you want to change the frequency of the updates, make sure to do these in order:

<pre class="brush:java">stopLocationUpdates();
// This method should implement mLocationClient.removeLocationUpdates()

// Set the new frequency in your location client
updateLocationClient(frequency);

startLocationUpdates();
// This method should implement mLocationClient.requestLocationUpdates()
// which means it should check for isConnected() as well!</pre>
If you do not remove the updates before updating the frequency, it looks like the old frequency update is still active BUT a new one is started.

~1 min read

Quick Tip: Pulling an SQLite db file from device

I have always thought that you would need root access to pull an SQLite file from a non-rooted Android device. Turns out I thought wrong! Here’s how you do it:
<pre class="brush:shell">$ adb -d shell
$ run-as your.package.name
$ cat /data/data/your.package.name/databases/yourdatabasename >/sdcard/yourdatabasename</pre>This will copy your app’s SQLite db file to the SD card’s root directory. From there, you can copy the file to your computer any way you like.

Props to this SO answer!

~1 min read

Save Logcat contents to file

Note to self: to save the contents of Logcat to a text file:
<ol><li>Navigate to the SDK installation directory.</li><li>Go to the /platform-tools folder.</li><li>adb logcat -d > my_logcat_dump.txt</li></ol><div>If there is more than one device connected to adb, specify which device’s log to dump:</div><div><blockquote class="tr_bq">adb -s emulator-5558 logcat -d > my_logcat_dump.txt</blockquote></div>

~1 min read

Adding a float value to your resources

Earlier today, I was trying to figure out how to add a float value to constants file. What I used to do was add a string value in my strings.xml, retrieve the string value, and convert it to float. <pre class="brush:java">float floatFromFile = Float.valueOf(getResources().getString(R.string.my_float));</pre> I was trying out something new but it wasn’t working, so I decided to look for a more accepted solution. Google led me to this StackOverflow question. I was on the right track after all! I think the accepted answer is incomplete, or not clear enough for my purposes. I ended up having this entry in my dimensions.xml file: <pre class="brush:xml"><item name="face_feature_marker_size" type="vals" format="float">2.0</item></pre> And then in my code, I retrieve the value as: <pre class="brush:java">TypedValue tempVal = new TypedValue();
getResources().getValue(R.vals.face_feature_marker_size, tempVal, true);
float markerSize = testVal.getFloat();</pre> I ended up having more lines of code with no idea if this is more optimized. Let me know what you think!

~1 min read

Quick Tip: git cloning

A user-friendly way of cloning a git repo is through the eGit plug-in in Eclipse. But sometimes, especially on Windows machines, Eclipse has trouble cleaning up after itself after completing a clone operation. The best workaround for this is to clone the repo from git bash and then import the repo in Eclipse.
<pre class="brush:bash">default@ZDOMINGUEZ-T420 ~
$ git clone git@github.com:<your git repo> <local folder to check out to></pre>When git finishes cloning your repo, import it to Eclipse.
<div class="separator" style="clear: both; text-align: center;"></div>Browse to the folder you checked out to, click OK, and the newly-cloned repo should now appear on the Git Repositories view.

~1 min read
Back to Top ↑

data binding

Unwrapping Framework Binding Adapters

For the past year or so, my team has been all-in with data binding. And if you know me at all, it obviously makes me one happy duck!

3 min read

Effectively Wrangling Together a Bunch of Views

One bit of task that I find myself doing over and over again is managing a bunch of Views and their visibility. In the olden days <insert old person handwave>, before there was ConstraintLayout, I have written my fair share of container_s to make this task manageable. Say we have to do something like this:

2 min read

Referencing IDs in Data Binding

Last week, I was talking to someone on my team and it became apparent that they weren’t aware of one super useful feature of data binding. If you know me at all, you know that I like love this library, and I would take every opportunity to spread the love around.

~1 min read

Parsing Data Binding Errors

Learning something new is always fun and exciting. That is, until seemingly cryptic error messages start creeping up.

1 min read

Binding to the H(eight)

As would probably be obvious by now, I have been investing a lot of time in learning and using data binding.

1 min read

@{app.plaid}

I gave a talk this morning in the first ever Droidcon Vietnam! It is about two of the things I love in Android – Plaid and data binding.

~1 min read

Using resource IDs in data binding layouts

I have been playing with data binding more and more over the last couple of weeks. This week, it’s all about creating a dialog with stuff dictated by a value from an enum.

2 min read

Lies I’ve been told today

So I played around with data binding today. And these are the lies that the dev guide told me (explicitly or inferred):

<ul><li>There is a method DataBindingUtil.bindTo(viewRoot, layoutId)</li><li>That this will work MyLayoutBinding.bind(viewRoot);</li><li>Android Studio has auto-complete</li></ul>

~1 min read
Back to Top ↑

eclipse

Eclipse-ception

Guys!! Eclipse just went all Inception on me!
<div class="separator" style="clear: both; text-align: center;"></div>

~1 min read

Quick Tip: git cloning

A user-friendly way of cloning a git repo is through the eGit plug-in in Eclipse. But sometimes, especially on Windows machines, Eclipse has trouble cleaning up after itself after completing a clone operation. The best workaround for this is to clone the repo from git bash and then import the repo in Eclipse.
<pre class="brush:bash">default@ZDOMINGUEZ-T420 ~
$ git clone git@github.com:<your git repo> <local folder to check out to></pre>When git finishes cloning your repo, import it to Eclipse.
<div class="separator" style="clear: both; text-align: center;"></div>Browse to the folder you checked out to, click OK, and the newly-cloned repo should now appear on the Git Repositories view.

~1 min read

Where’s my R.java?

This afternoon, I tried importing an existing project into Eclipse. Doing a Project > Clean usually clears up the R.java not found errors, but this time it didn’t work. I tried re-importing the project, copy-and-pasting it into a new workspace, restarting Eclipse, but the error is still there.

Just a quick note to self: If there is an error in the layout files, resolve that first then Clean.

I find it weird that no more specific error message is presented. Oh well.

~1 min read

ADT 12: Not so shiny after all


For all the shininess that ADT 12 promised, it seems that it also broke one major feature of DDMS: Launching emulators.

After updating to ADT 12, I kept on seeing that error when launching an emulator instance. Restarting Eclipse doesn’t help any.

Anyway, the apparent cause of this error is that ADT 12 has some problems with the SDK location having spaces. If you have already forgotten, it’s in Window > Preferences > Android.

To work around this bug, it is either you move your SDK to a folder in a path without spaces; or, modify the existing path to either of the following:<div><ul><li>If your SDK is in Program Files: C:/PROGRA~1/<path_to_sdk></li><li>If your SDK is in Program Files(x86): C:/PROGRA~2/<path_to_sdk></li></ul><div>Edit (20110711 1943): A bug has already been filed for this issue. Star to be notified of updates.</div></div>

~1 min read

Quick tip: Quick Formatting of Android XML Files

One of the most useful tools in Android’s Eclipse plug-in is the Layout Editor. It is easy to experiment with layouts using the drag-and-drop enabled editor without having to worry about the correct syntax or if you are using the correct attribute name.

After creating your layout this way, however, you can end up with a messy XML file. I say “messy” in the sense that elements can run on in one veeeeeeeeeeeery long line, and if you are about to edit the XML file manually, this can be a nightmare.

I used to format the XML file by hand, putting in line breaks and correcting indentation. But one edit using the graphical layout editor and it’s messed up again. And then I had a light bulb moment. Eclipse allows auto-formatting of code, but what about XML files? AHA!

It turns out that auto-formatting works for XML files too! Simply select all the contents of the XML file (CTRL-A) and then press the ultra magical shortcut CTRL-I and your XML file is clean and orderly as can be! YAY!

~1 min read

What happened to my layout editor?

There you are, happily creating your layout files in the Eclipse plug-in’s layout editor. Dragging and dropping is a breeze. But then one day, you open a layout XML file and boom! No UI! All you see is the XML tree with all the nodes and attributes. What happened?

This happened to me and I was in a panic for a few seconds. Why do things like these have to happen to me? I tried opening a layout file from another project in the same workspace, and it has the UI! What happened?

It probably has something to do with the interpreter you used to open the XML file, a voice in my head said. So I tried right-clicking on the XML file, and lo and behold, I found it. I may have accidentally clicked on some file in one of my mad-clicking moments and changed the setting.

So anyway, to bring back the Layout UI Editor, right click on an XML file > Choose Open With > Android Layout Editor.

I would say that everything is handy dandy, but apparently, the engineers at Google decided that we developers need a little less help and removed the very useful up and down arrow keys in the Outline View when editing XML layouts. Why do they hurt us like this?

I WANT MY UP/DOWN KEYS BACK!

1 min read

What grammar?

My OC side was alarmed when suddenly, my Problems view in Eclipse was filled with warnings on my XML files. Each of my XML files had a warning with it, and that little yellow exclamation mark on the side:<div>No grammar constraints (DTD or XML schema) detected for the document</div><div>
</div><div>So how do you get rid of it? Go to Window > Preferences > XML > XML Files > Validation then set Indicate when no grammar is specified to Ignore. Click on Apply.</div><div>
</div><div>Clean up your project (Project > Clean). </div><div>
</div><div>If the problem doesn’t go away, you may need to re-validate the XML files. Right click on the file then choose Validate from the popup menu. You can also right click on the folder (such as your res folder) and validate from there.</div>

~1 min read
Back to Top ↑

git

That Thing About Commit Messages

Last week, I was giving feedback to someone about improving the commit messages they write. I was very taken aback by their response – “it does not matter what the commit messages are”. Now this is confusing for me, mainly because I know from years of experience that having relevant commit messages is important.

1 min read

Snazzy git blaming

Sometimes, you can’t help it. You need to look at what happened in the past to understand what is happening in the present (wow).

1 min read

Fixing a mistake in your git history

I have been using git for about five years now, but I definitely get stumped by it a lot. It is so powerful it’s daunting. There has been a couple lot of times where I had been too careless and reliant on my fingers’ add-commit-push muscle memory that I realised I have made a mistake too late. I have always been a proponent of clean, atomic commits, and when I find my commits all messed up, I hit myself in the head.

So, to stop myself from pulling my hair out looking for all the right StackOverflow answers that I KNOW I’VE SEEN THE SOLUTION BEFORE WHERE THE HELL IS IT???, I am writing the steps down to remind myself.

SCENARIO:
- I have committed some files in a previous commit that should not be there
- I want to REMOVE those files from that commit
- I want to preserve all other commits after that bad commit

CAVEATS:
- I am working in a local branch
- I will be removing those files forever
- I AM WORKING IN A LOCAL BRANCH

SOLUTION:
1. Find out which commit you want to go back to.
$ git log

This should give you something like:
<pre class="brush:shell">zarah.dominguez@R5003334 swipe-to-refresh-demo (master) $ git log
commit a6c00638b3d466a61e3381a98e6b44cf2d085164
Author: Zarah Dominguez
Date: Tue Jun 17 16:34:50 2014 +0800

Removed dependency on ButterKnife.

commit e25c6862a79270921a24d6bf2a9eb07cc3f03b36
Author: Zarah Dominguez
Date: Tue Jun 17 16:07:33 2014 +0800

First commit</pre>
If you just want the commit messages:
$ git log --oneline


2. Create a new branch based on the bad commit.
$ git checkout -b fix-that-shit e25c686

What this does is create a new branch named fix-that-shit, whose HEAD points to commit e25c686. The -b switch tells git to go to that newly-created branch.

3. Do your thing. In this case, I want to remove files.
$ git rm BadFile.java
rm ‘BadFile.java’
$ git rm AnotherBadFile.java
rm ‘AnotherBadFile.java’

4. Let git know that you’ve overcome your stupidity and are now saying sorry.
$ git commit –amend

An editor will open, and here you can edit the commit message.

5. Go back to the original branch. In my case, it is master.
$ git checkout master

6. Give this branch your changes.
$ git rebase fix-that-shit

7. Check your log. git might try and do it’s thing, and do funny merges. So you might end up with a new commit in your history, something like:
<pre class="brush:shell">zarah.dominguez@R5003334 swipe-to-refresh-demo (master) $ git log
commit 3e08701339c35301caf269058eab6359c9d87ecd
Author: Zarah Dominguez
Date: Tue Jun 17 16:34:50 2014 +0800

Removed dependency on ButterKnife.

commit ca57ac7974d7a422a2225612404cb6bd555acfc4
Author: Zarah Dominguez
Date: Tue Jun 17 16:07:33 2014 +0800

First commit

commit 679ad41bedb2d61fbea36e39e334074b7de66dcd
Author: Zarah Dominguez
Date: Tue Jun 17 16:07:33 2014 +0800

First commit</pre>

7b. Examine the two commits, and you’ll notice that the second in the list contains the file we just removed. I want to chuck that out completely, so I will do a rebase. This will take me back to the first commit in interactive mode:
$ git rebase -i --root

Now I can trash that bad commit by adding a pound sign (or fine, hashtag) before that commit’s SHA:
pick 679ad41 First commit
#pick ca57ac7 First commit
pick 3e08701 Removed dependency on ButterKnife.

8. Check your logs again, and verify that the file is now nowhere to be found.
<pre class="brush:shell">zarah.dominguez@R5003334 swipe-to-refresh-demo (master) $ git log
commit a6c00638b3d466a61e3381a98e6b44cf2d085164
Author: Zarah Dominguez
Date: Tue Jun 17 16:34:50 2014 +0800

Removed dependency on ButterKnife.

commit e25c6862a79270921a24d6bf2a9eb07cc3f03b36
Author: Zarah Dominguez
Date: Tue Jun 17 16:07:33 2014 +0800

First commit</pre>

9. Now kill and bury that shit:
$ git branch -d fix-that-shit

10. You will then need to force-push your changes if you have a remote branch. Hence the DO NOT DO UNLESS YOU ARE THE ONLY ONE USING THE BRANCH.
$ git push master –force



I am sure there is a more concise way to do this, but doing the verbose solution here for posterity.


———–
I cannot stress this enough. DO NOT DO THIS IF YOU ARE SHARING YOUR BRANCH WITH SOMEBODY ELSE. If you do, you automatically give them license to punch you in the face. (It can be a remote branch, as long as YOU ARE NOT SHARING IT WITH SOMEBODY ELSE)

3 min read

Quick Tip: git Auto-complete

When I started using git, it peeved me that there is no auto-complete. More so when you have to manually do a git add manually.

Thank heavens I found this little gem. Making auto-complete work for git:

In terminal:
<pre class="brush:shell">curl https://raw.github.com/git/git/master/contrib/completion/git-completion.bash -o ~/.git-completion.bash</pre>

And then you’d need to “activate” it in your .bash_profile:
<pre class="brush:shell">if [ -f ~/.git-completion.bash ]; then
. ~/.git-completion.bash
fi</pre>

~1 min read

Cloning a remote branch in git

My current project at work uses git, and I have always been a CVS/SVN baby so I’m still trying to find my way around it. Today I wanted to clone a remote branch to my local computer. This remote branch also has submodules, so I want to get those too.

This assumes that you use Git Bash. First, navigate to the folder in you local computer where you want git to clone the remote branch. Once there, we can start cloning the repo. The following steps do the dirty work:
<pre class="brush:bash">$ git init
$ git fetch <git url> <branch name>:refs/remotes/origin/<branch name>
$ git checkout -b <branch name> origin/<branch name></pre>
This retrieves the contents of the remote branch and copies it to our local computer in a local branch (confused yet?). To update our copy of the submodules, the following commands should work:
<pre class="brush:bash">$ git submodule init
$ git submodule update</pre>

~1 min read

Quick Tip: git cloning

A user-friendly way of cloning a git repo is through the eGit plug-in in Eclipse. But sometimes, especially on Windows machines, Eclipse has trouble cleaning up after itself after completing a clone operation. The best workaround for this is to clone the repo from git bash and then import the repo in Eclipse.
<pre class="brush:bash">default@ZDOMINGUEZ-T420 ~
$ git clone git@github.com:<your git repo> <local folder to check out to></pre>When git finishes cloning your repo, import it to Eclipse.
<div class="separator" style="clear: both; text-align: center;"></div>Browse to the folder you checked out to, click OK, and the newly-cloned repo should now appear on the Git Repositories view.

~1 min read
Back to Top ↑

layout

Stylish Dynamic Layouts

One of the things we are taught in Android is that we should gracefully handle different layouts based on screen sizes. With more and more things being not just screen size-specific but also OS version-specific, this is one thing I think a lot more devs need to pay attention to. Today was my turn to do just that.

2 min read

LinearLayouts, TextViews and Drawables

I sent out a series of tweets today about LinearLayouts and unexpectedly, quite a few people like them. I decided to get off my lazy ass and actually write it down in a post for easy reference.

2 min read

Quick Tip: Understanding Alternate Resources

Trying to support as many devices as possible the best way possible is a very daunting task indeed. You will usually need to provide a lot of different layouts, strings, or dimensions (among others) to make your app look great whatever the user’s device is. And then you start chaining resource qualifiers and testing which resource is being loaded by the OS can become a nightmare very quickly.

Here’s a trick I started using which seemed to work quite well. Create a string (the app name works well if you have an Action Bar) that you can display on-screen (or just throw into a Log or a Toast) that will quickly let you know from which of those very many /res folders your resources are being pulled out of.

For this demo, I have the following /res/values-xxxxx folders:
<div class="separator" style="clear: both; text-align: center;"></div>
As you can see, there are strings.xml files in each of the configurations I want to support. Each of these files will contain whatever description we want to see on the device or in the Logs. In my case, I have custom strings for each form factor and orientation, which allows me to validate things easier. But this is particularly useful if the changes per form factor and orientation is subtle, such as dimensions.

Here’s what it looks like for phones:

<table><tbody><tr><td></td><td></td></tr></tbody></table>
And here are the outputs for tablets:
<table><tbody><tr><td></td><td></td></tr></tbody></table>
Each of the strings.xml files contains just these two strings (sample taken from /res/values-sw800dp):
<pre class="brush:xml">

MultiDeviceSupport - Tablet Portrait
Hello world on a tablet!


</pre>Have fun debugging!

1 min read

Adding attributes to a custom view

There are times when using the default Android Views just doesn’t cut it and you need to create your own version of a View. So how exactly do you do that? It’s as simple as subclassing the View! But what if you want to add customizable attributes? Here’s how.

Let’s say I am creating a form-filling application and I want some of the EditTexts in the form to be required. However, I am so tired of having to implement the error checking for each and every one of those fields. What I will do is create my own EditText that will do the validation for me if that particular field is required. Let’s do it.

Step 1: Create your custom view and create fields for the attributes you want. In this case, I want an EditText that will show the default EditText error display if the user has not put in any value.
<pre class="brush:java">public class RequiredEditText extends EditText {
private boolean mRequired;
private String mErrorMessage;

public RequiredEditText(Context context) {
super(context);
}

/*
* Set this EditText’s requirement validation. The error message
* will be set to null by default if not provided.
*
* @param required
* @param errorMessage (optional)
*/
public void setRequired(boolean required, String errorMessage) {
this.mRequired = required;
this.mErrorMessage = errorMessage;

invalidate();
requestLayout();
}

public void setRequired(boolean required) {
setRequired(required, null);
}

/
* Lets you know if this field is set as required or not
* @return
*/
public boolean isRequiredField() {
return mRequired;
}
}</pre>Step 2: If a field is required, we want the default error message to appear (with our own error message, of course). If the user fills in the EditText, we want the error to disappear.
<pre class="brush:java">public class RequiredEditText extends EditText {
private boolean mRequired;
private String mErrorMessage;

public RequiredEditText(Context context) {
super(context);
}

/

* Set this EditText’s requirement validation. The error message
* will be set to null by default if not provided.
*
* @param required
* @param errorMessage (optional)
*/
public void setRequired(boolean required, String errorMessage) {
this.mRequired = required;
this.mErrorMessage = errorMessage;

manageRequiredField(required);

invalidate();
requestLayout();
}

public void setRequired(boolean required) {
setRequired(required, null);
}

private void manageRequiredField(boolean required) {
// If we are required, set the listeners
if(required) {
setOnFocusChangeListener(mFocusChangeListener);
addTextChangedListener(mTextWatcher);
} else {
// In case there is an error message already, clear it
setError(null);

// Remove the listeners
setOnFocusChangeListener(null);
removeTextChangedListener(mTextWatcher);
}
}

/**
* Lets you know if this field is set as required or not
* @return
*/
public boolean isRequiredField() {
return mRequired;
}

OnFocusChangeListener mFocusChangeListener = new OnFocusChangeListener() {

@Override
public void onFocusChange(View v, boolean hasFocus) {
// If the focus was removed from the field and it IS required,
// check if the user has put in something
if(!hasFocus && mRequired){
isRequiredFieldFilled();
}
}
};

TextWatcher mTextWatcher = new TextWatcher() {

@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
// Once the user types in something, remove the error
setError(null);
}

@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) { /
do nothing / }

@Override
public void afterTextChanged(Editable s) { /
do nothing */ }
};

private boolean isRequiredFieldFilled() {
// If the EditText is empty, show the error message
if(TextUtils.isEmpty(getText().toString().trim())){
showRequiredErrorDrawable();
return false;
}
return true;
}

private void showRequiredErrorDrawable() {
setError(mErrorMessage);
}
}</pre>Step 3: Now it’s time to add the fields to the Layout Editor. Create an attrs.xml file in /res if there isn’t one already. Declare a styleable and include the attributes you want to appear in the Layout Editor.
<pre class="brush:xml">





</pre>The name of the styleable does not need to match your custom view class name, but doing so makes it more readable and maintainable.

Step 4: Go back to your custom view implementation and add constructors that take in an AttributeSet.
<pre class="brush:java">public RequiredEditText(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init(attrs);
}

public RequiredEditText(Context context, AttributeSet attrs) {
super(context, attrs);
init(attrs);
}

private void init(AttributeSet attrs) {
TypedArray a=getContext().obtainStyledAttributes(
attrs,
R.styleable.RequiredEditText);

try {
setRequired(a.getBoolean(R.styleable.RequiredEditText_required, false),
a.getString(R.styleable.RequiredEditText_errorMessage));
} finally {
//Don’t forget this, we need to recycle
a.recycle();
}
}
</pre>Step 5: Go to the Layout Editor and look for “Custom & Library Views” in the Palette (you may have to click on “Refresh” several times before your custom view appears in the list). Add the custom view to your layout and check out the properties panel!
 

 As always, the code is in GitHub.

3 min read

Styling tab selectors for ActionBarSherlock

This post builds on the previous post for ABS + VPI.

I have gotten a lot of questions on styling the ABS, specifically the tab selected indicators. This task may seem daunting, but in reality it is relatively simple. I am also quite confused why I didn’t find any straightforward tutorials when I tried googling this. Anyway, this post will hopefully help developers who aim to style their action bars.

We will need to use Jeff Gilfelt’s awesome styling tool. To use it, just input in your app’s color scheme for the highlights and what-not then download the generated zip file. If you want to just change the tab underline color, change the value under “Accent color”. To make the change obvious from the default settings, I have used a shade of orange for the tab selected indicators. Here are the settings I used for this demo.

Jeff’s tool conveniently generates all the XML files and drawables and organizes them into the correct /res/drawable folders. Unzip the file and just drag the generated files into your project, or merge the contents if you already have such existing files.

See how easy it was? Seriously, we should all lie prostrate at Jeff Gilfelt’s and Jake Wharton’s feet. These guys are AWESOME.

The two photos below show the difference between the old app and the styled app. As you can see, I only changed the tab selected color. You can explore what happens if you use the other styles you can get from Jeff’s tool.
<table align="center" cellpadding="10" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody><tr><td style="text-align: center;"></td><td style="text-align: center;"></td></tr><tr><td class="tr-caption" style="text-align: center;">Default</td><td class="tr-caption" style="text-align: center;">Styled</td></tr></tbody></table>The hard work is done, let’s now try to understand the automagically generated configurations we did.

First, we have to configure the theme to use custom tab indicators. We do this by changing the tab styles in themes.xml. In my sample app, these lines customize the tabs we are using.
<pre class="brush:xml"><!– Styling the tabs –>
<style name=”CustomTabPageIndicator” parent=”Widget.TabPageIndicator”>
 <!– Tab text –>
<item name=”android:textSize”>15dip</item>
<item name=”android:textColor”>#FFB33E3E</item>

<!– Lines under tabs –>
<item name=”background”>@drawable/tab_indicator_ab_styling_abs</item>
<item name=”android:background”>@drawable/tab_indicator_ab_styling_abs</item>
</style></pre>
The “drawable” tab_indicator_ab_styling_abs is actually a state list drawable that provides different images for each state of a tab – focused and non-focused, pressed and not pressed.

You can see part of this in action in the image above. Try long pressing on a tab and you can see the tab’s background change to use the unselected-pressed drawable.

Again, HUGE thanks to Jeff Gilfelt and Jake Wharton for creating tools that make our lives easier. :)

I have pushed a new branch in github that uses this style. The master branch of that repo still uses the default tab selectors.

2 min read

My EditText is cut off by the on-screen keyboard!

With clients demanding left and right that my app should look like an iPhone app, I tend to be unappreciative of the way Android natively handles UI interactions and such. Notice how the screen automagically scrolls up when you click on an EditText? It turns out that in iPhone development, the developer does this manually (indicate how much the view should scroll when the on-screen keyboard appears, then scroll it back down afterwards). HA!

But even magic fails sometimes. Has this ever happened to you?
<img style=”display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 134px; height: 200px;” src=”http://3.bp.blogspot.com/-JftkETrkB2c/TZlrHJOji5I/AAAAAAAAA4I/cX4jSBJRiGY/s200/edittext_hidden.png” border=”0” alt=”“id=”BLOGGER_PHOTO_ID_5591618182837406610” />
The bottommost EditText is cut off. And we don’t want that!

So what do we do? Do we programmatically scroll the view up? I don’t want to do that! It turns out that we can just wrap the whole view in a ScrollView and it will scroll up properly!
<img style=”display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 134px; height: 200px;” src=”http://1.bp.blogspot.com/-J2UCMLF_E3k/TZlrk_lKBdI/AAAAAAAAA4Q/c7G321XalBo/s200/edittext_shown.png” border=”0” alt=”“id=”BLOGGER_PHOTO_ID_5591618695643923922” />

The only downside to this is that you might want to hide the scrollbar when the view moves up to accommodate the on-screen keyboard. And to do that, I was trying to set the android:scrollbars=”none” attribute but for one reason or another the scrollbar is still being drawn. To make the scrollbar disappear, we can do it from code as such:<pre class="brush:java">((ScrollView)findViewById(R.id.my_scrollview))
.setVerticalScrollBarEnabled(false);</pre>And we’re done!

~1 min read

What happened to my layout editor?

There you are, happily creating your layout files in the Eclipse plug-in’s layout editor. Dragging and dropping is a breeze. But then one day, you open a layout XML file and boom! No UI! All you see is the XML tree with all the nodes and attributes. What happened?

This happened to me and I was in a panic for a few seconds. Why do things like these have to happen to me? I tried opening a layout file from another project in the same workspace, and it has the UI! What happened?

It probably has something to do with the interpreter you used to open the XML file, a voice in my head said. So I tried right-clicking on the XML file, and lo and behold, I found it. I may have accidentally clicked on some file in one of my mad-clicking moments and changed the setting.

So anyway, to bring back the Layout UI Editor, right click on an XML file > Choose Open With > Android Layout Editor.

I would say that everything is handy dandy, but apparently, the engineers at Google decided that we developers need a little less help and removed the very useful up and down arrow keys in the Outline View when editing XML layouts. Why do they hurt us like this?

I WANT MY UP/DOWN KEYS BACK!

1 min read
Back to Top ↑

hello

A note on giving back

Recently, there has been a spate of tweets about developers admitting their weaknesses. A bunch of people I know even made into the Moment created by @ThePracticalDev. And then there’s this tweet:

1 min read

Hello, it’s me again.


To my two readers out there, hello! It’s been a while since I posted here. I was transferred to another (non-Android) project and lost all my Internet privileges, hence the silence. I still can’t believe almost every other site is blocked by the office firewall! Makes software development ten times harder. Ugh.

Anyway, as of the last three months, I have been working on backend development (J2EE). I don’t know a lot about it, and the past months have been a great journey of learning. It is quite a shock being exposed all in one go to so many technologies and tools, I’m lucky my head didn’t explode.

Happy as I am to learn new things, I am quite sad to leave Android development behind. I’m still hoping though that I would be given the chance to go back to it, and pick up where I left off. Hopefully the Android train won’t be too far off by then.

In the meantime, I will be posting stuff that I’ve learned while working on J2EE, and hopefully somebody can learn from my mistakes. :)

~1 min read

stealth ninja mode on

Over the past couple of weeks, this blog has been getting unusually high traffic. Which means I get more than one hit per week.

So if it isn’t too much to ask, can I please know how you got here, and what you were looking for. And please please let me know if I said anything wrong, or if you know of a better/easier/more optimized way to do the stuff I’m trying to talk about. Thanks! :)

~1 min read

A test, a test

I was thinking of starting a quick-tips style blog for software development (mostly for myself, since I tend to forget stuff a lot recently).

~1 min read
Back to Top ↑

debugging

Taking a closer look while debugging

One of the most common sources of bugs (at least of my bugs) is math. I have been working on dynamically resizing a View the past days, and it was driving me nuts! I needed to consider preserving aspect ratio, device density, original view size, etc etc. Math is hard guys!

4 min read

Squashing Bugs

This has been one hell of a busy week for me. I think you can sort of tell from my Tweets and G+ posts that I have been debugging A LOT.

1 min read

Raising Activities From the Dead

One of the scenarios I admittedly almost always forget to test is “What happens when my app goes into the background, then the OS kills is to claim memory, then I try to resume?” Usually it’s “Well, I handle onSavedInstanceState not being null, so I am great!” It is fine and dandy for simple apps; but once your Activity or Fragment gets beefier and you start relying on state for more and more things, it can get complicated pretty quickly (In my case, the Fragment has setRetainInstance(true)).

This scenario in particular is kind of hard to reproduce willingly. I usually see this when I leave an app running, make my phone do some heavy work overnight, then resume the app the next day.
<div class="separator" style="clear: both; text-align: center;"></div><div class="separator" style="clear: both; text-align: left;">
</div><div class="separator" style="clear: both; text-align: left;">So what you gonna do?</div><div class="separator" style="clear: both; text-align: left;">
</div><div class="separator" style="clear: both; text-align: left;">It turns out that Android Studio has the answer! There is this magical tiny red button that allows you to simulate this exact scenario.</div><div class="separator" style="clear: both; text-align: left;">
</div><div class="separator" style="clear: both; text-align: left;">1. Open your app to the Activity you want to test (I use a very simple app here just for demo).</div><div class="separator" style="clear: both; text-align: center;">

</div><div class="separator" style="clear: both; text-align: center;">
</div><div class="separator" style="clear: both; text-align: left;">2. In Studio, go to Android Monitor (make sure that your app is selected). Note the process ID, in this case it is 25647.</div><div class="separator" style="clear: both; text-align: center;"></div>
3. Push your app to the background. Pressing the HOME button should be sufficient. This will call onSaveInstanceState, which is all that matters really. It is after all what we want to test.

4. Back in Studio, press the magical tiny red button pointed to in the previous image. Notice that Studio now appends [DEAD] to your app’s process. It is now gone. He’s dead, Jim!
<div class="separator" style="clear: both; text-align: center;"></div>
5. Resume your app. I usually just do this via recent apps.
<div class="separator" style="clear: both; text-align: center;"></div>
6. If you look at Studio, you’ll see that your app is now no longer dead, but has a new process ID, in this case 26742.
<div class="separator" style="clear: both; text-align: center;"></div><div class="separator" style="clear: both; text-align: center;">
</div><div class="separator" style="clear: both; text-align: left;">If at this point you step through your code, you will notice that your Activity will go through the whole (re-)creation process with the Bundle given the values you have saved in onSaveInstanceState. No more waiting overnight, yay!</div>

1 min read

Quick Tip: Pulling an SQLite db file from device

I have always thought that you would need root access to pull an SQLite file from a non-rooted Android device. Turns out I thought wrong! Here’s how you do it:
<pre class="brush:shell">$ adb -d shell
$ run-as your.package.name
$ cat /data/data/your.package.name/databases/yourdatabasename >/sdcard/yourdatabasename</pre>This will copy your app’s SQLite db file to the SD card’s root directory. From there, you can copy the file to your computer any way you like.

Props to this SO answer!

~1 min read

Inspecting your Shared Preferences

Did you know that you can look at your SharedPreferences file?

If during development you want to inspect what your SharedPreferences now contain, you can pull a copy of the XML file from the emulator.

In Eclipse, you can do that by following these steps:

<ol><li>Open the DDMS perspective (Window > Open Perspective > Other > DDMS).</li><li>Click on the File Explorer tab and navigate to your app’s data folder (that’s under data/data/<your package name>/shared_prefs/).</li><li>Choose the file you want to download.</li><li>Click on the Pull file from device button.</li></ol><div class="separator" style="clear: both; text-align: center;"></div><div>
</div>

~1 min read
Back to Top ↑

lint

Multi-module Lint Rules 🤹‍♀️

I have been learning a LOT about Lint the past year. Our team has grown 5x since I joined more than three years ago, and it became really obvious really quickly that we should be letting robots do a lot of the mundane and repetitive enforcement of our team’s code conventions.

13 min read

Enforcing Team Rules with Lint: Tests 🧐

A few months ago, my team came upon an agreement that when leaving a TODO anywhere in our code, we need to always provide several things:

  • the person who is expected to address the TODO
  • date when the TODO was left
  • a comment or explanation on what needs to be done
4 min read

Enforcing Team Rules with Lint: Detectors 🕵️

A few months ago, my team came upon an agreement that when leaving a TODO anywhere in our code, we need to always provide several things:

  • the person who is expected to address the TODO
  • date when the TODO was left
  • a comment or explanation on what needs to be done
12 min read

Enforcing Team Rules with Lint 👩‍🔧

A few months ago, my team came upon an agreement that when leaving a TODO anywhere in our code, we need to always provide several things:

  • the person who is expected to address the TODO
  • date when the TODO was left
  • a comment or explanation on what needs to be done
4 min read
Back to Top ↑

tools

Which is Which: Named Breakpoints

I have always believed that one of the biggest factors that influence a person’s enjoyment and delight in doing their job are the tools. Having the right tools and using them the best way possible helps direct our energy on the what rather than the how.

1 min read

Scratch That Itch

One of the most useful things for me whilst I was learning Kotlin was TryKotlin. It gave me a quick way to test concepts, try new APIs, or just to get familiar with the syntax.

2 min read

Tools of the Trade

Here are the slides to my talk at the Android Meetup tonight.

~1 min read

Super lightning talk: Tinkering with Tools

If you are just starting Android development or migrating from Eclipse to Android Studio, I gave a lightning talk on setting up some tools: <iframe src="https://docs.google.com/presentation/d/1UqyM9ZjMGjREdyaAoduTT6wY8NnfylR39fohlp3eg7k/embed?start=false&loop=false&delayms=60000" frameborder="0" width="480" height="299" allowfullscreen="true" mozallowfullscreen="true" webkitallowfullscreen="true"></iframe>

~1 min read
Back to Top ↑

strings

String formatting and Lint

One piece of advice that we keep hearing over and over is to extract strings into resources. There really is no reason for you to hard code strings in code.

1 min read

Stringy strings


While we are on the subject of strings, here are more ways of dealing with them in Android Studio. We all know that we should not hardcode strings in code, right? But sometimes, we forget and tend to do code first before defining them in strings.xml.

There are a couple of ways that Android Studio/IntelliJ makes this easy for us. The gif below (which took me a while to figure out how to do, by the way), shows how to deal with:
1. Moving a hardcoded string into strings.xml
2. Giving a previously undefined string ID a value in strings.xml

<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody><tr><td style="text-align: center;"></td></tr><tr><td class="tr-caption" style="text-align: center;">(Click to embiggen)</td></tr></tbody></table>
Move hardcoded string into XML:
This is probably the more common scenario. You happily put in texts into your TextViews, and now you have to copy and paste them into strings.xml. Don’t! There is a shortcut for that.

Put your cursor somewhere in the string, press ALT+Enter to bring up the context menu, choose “Extract string resource” and give your string resource a name. This will create a new <string name=”my_string_name”>My string value</string> in strings.xml.

Studio magically also calls getString(R.string.xxxxx) for you. Neat, huh?


Make new string from ID:
This is for when you suddenly remember that you need a new string and want to sort of try to do it correctly so you type in the string ID. Only it hasn’t been defined yet, so Studio complains. But it’s fine. There is a shortcut for that.

Put your cursor somewhere in the as of yet undefined ID, press ALT+Enter to bring up the context menu, choose “Create string value for resource my_string_id”, and type in the actual string value you want. Again, this will create a new <string name=”my_string_id”>My other string value</string> in strings.xml.

Remember, in both of these cases, Studio will create the new strings in strings.xml, but you can modify it to put in whatever variant you want it to be in (for localisations, screen size support, etc).

1 min read

More plurals: decimal values

In my previous post, I showed you how to set string plurals. If you noticed, the methods to get the plurals strings only accept ints. What if (like me) you want to display a decimal value? I am getting my raw value from a progress bar with a range of 1-10, with 0.1 increments.

1 min read

String Pluralization

Last week, I discovered Android’s support for plural strings by accident. And a good accident it was since I am working on an app that will display a float to the user. I used to display:

1 min read
Back to Top ↑

wtfSDK

Eclipse-ception

Guys!! Eclipse just went all Inception on me!
<div class="separator" style="clear: both; text-align: center;"></div>

~1 min read

ADT 12: Not so shiny after all


For all the shininess that ADT 12 promised, it seems that it also broke one major feature of DDMS: Launching emulators.

After updating to ADT 12, I kept on seeing that error when launching an emulator instance. Restarting Eclipse doesn’t help any.

Anyway, the apparent cause of this error is that ADT 12 has some problems with the SDK location having spaces. If you have already forgotten, it’s in Window > Preferences > Android.

To work around this bug, it is either you move your SDK to a folder in a path without spaces; or, modify the existing path to either of the following:<div><ul><li>If your SDK is in Program Files: C:/PROGRA~1/<path_to_sdk></li><li>If your SDK is in Program Files(x86): C:/PROGRA~2/<path_to_sdk></li></ul><div>Edit (20110711 1943): A bug has already been filed for this issue. Star to be notified of updates.</div></div>

~1 min read

Missing hierarchyviewer in SDK 7

If you have SDK version 7, you are most probably missing the hierarchyviewer from your /tools folder. To check your SDK version, launch the SDK manager UI from your installation path, usually C:\android-sdk-windows, then click About.
To run hierarchyviewer, you need to manually create the </code>hierarchyviewer.bat</code> file and add it to your <install_path>/tools directory. The text of the batch file can be copied from here.

And so, you can now run hierarchyviewer as you would if the SDK release isn’t effed up. Don’t know how to run it? Follow these steps:
a. In Windows, open up a terminal by running cmd.
b. Navigate to your SDK’s install path. Since I installed mine in C:\, I would have to type in cd C:\android-sdk-windows\tools
c. Type in hierarchyviewer at the prompt.

~1 min read
Back to Top ↑

XML

Quick tip: Quick Formatting of Android XML Files

One of the most useful tools in Android’s Eclipse plug-in is the Layout Editor. It is easy to experiment with layouts using the drag-and-drop enabled editor without having to worry about the correct syntax or if you are using the correct attribute name.

After creating your layout this way, however, you can end up with a messy XML file. I say “messy” in the sense that elements can run on in one veeeeeeeeeeeery long line, and if you are about to edit the XML file manually, this can be a nightmare.

I used to format the XML file by hand, putting in line breaks and correcting indentation. But one edit using the graphical layout editor and it’s messed up again. And then I had a light bulb moment. Eclipse allows auto-formatting of code, but what about XML files? AHA!

It turns out that auto-formatting works for XML files too! Simply select all the contents of the XML file (CTRL-A) and then press the ultra magical shortcut CTRL-I and your XML file is clean and orderly as can be! YAY!

~1 min read

What happened to my layout editor?

There you are, happily creating your layout files in the Eclipse plug-in’s layout editor. Dragging and dropping is a breeze. But then one day, you open a layout XML file and boom! No UI! All you see is the XML tree with all the nodes and attributes. What happened?

This happened to me and I was in a panic for a few seconds. Why do things like these have to happen to me? I tried opening a layout file from another project in the same workspace, and it has the UI! What happened?

It probably has something to do with the interpreter you used to open the XML file, a voice in my head said. So I tried right-clicking on the XML file, and lo and behold, I found it. I may have accidentally clicked on some file in one of my mad-clicking moments and changed the setting.

So anyway, to bring back the Layout UI Editor, right click on an XML file > Choose Open With > Android Layout Editor.

I would say that everything is handy dandy, but apparently, the engineers at Google decided that we developers need a little less help and removed the very useful up and down arrow keys in the Outline View when editing XML layouts. Why do they hurt us like this?

I WANT MY UP/DOWN KEYS BACK!

1 min read

What grammar?

My OC side was alarmed when suddenly, my Problems view in Eclipse was filled with warnings on my XML files. Each of my XML files had a warning with it, and that little yellow exclamation mark on the side:<div>No grammar constraints (DTD or XML schema) detected for the document</div><div>
</div><div>So how do you get rid of it? Go to Window > Preferences > XML > XML Files > Validation then set Indicate when no grammar is specified to Ignore. Click on Apply.</div><div>
</div><div>Clean up your project (Project > Clean). </div><div>
</div><div>If the problem doesn’t go away, you may need to re-validate the XML files. Right click on the file then choose Validate from the popup menu. You can also right click on the folder (such as your res folder) and validate from there.</div>

~1 min read
Back to Top ↑

EditText

AutoCompleteTextView Hell

Today, I ran into a weird “feature” of Android. I was working on an AutoCompleteTextView with the dropdown list having section dividers. It all works well in portrait mode, but gets all messed up in landscape.

I made a sample app to illustrate the point of this blog [Github repo]. Clone it, run it, rotate the phone, select an item from the suggested auto-complete results, and get your mind blown. Or your heart stabbed. Or your stomach sucker-punched. Your choice.

So what was happening? Here’s what.

When we tell the app to perform a filter, we construct an array of the resulting matches. The example is pretty straightforward, just look for countries that start with whatever the user has typed in.

<pre class="brush:java">// Filter by start of string
String country = mCountries.get(i);
if(country.toLowerCase().startsWith(constraint.toString().toLowerCase())) {
mFilteredData.add(country);
}</pre>You can make this filtering as complicated as you like or need, just make sure to pass in whatever the user needs to see.

To illustrate having section headers (aka disabled items), we insert dummy text every fifth place in the list. The sample app does not care if there are more results after a section header, we still insert anyway.

So. Let’s filter. Typing in “pa” will give us this set of data:
<pre class="brush:xml">10-11 02:45:46.028 16282-20011/com.blogspot.droidista.autocompletetextviewhell D/AutoCompleteFragment﹕ 
Filtered results: [Section!, Pakistan, Palestine, Panama, Papua New Guinea, Section!, Paraguay]</pre>
There are two sections and five countries. Remember this.
<table border="2" bordercolor="#AAAAAA"><tbody><tr><td>Position in list</td><td>Value</td></tr><tr><td>0</td><td>Section!</td></tr><tr><td>1</td><td>Pakistan</td></tr><tr><td>2</td><td>Palestine</td></tr><tr><td>3</td><td>Panama</td></tr><tr><td>4</td><td>Papua New Guinea</td></tr><tr><td>5</td><td>Section!</td></tr><tr><td>6</td><td>Paraguay</td></tr></tbody></table>
This screenshot shows how the results are rendered in portrait mode. So far, so good. Selecting an item from the list populates the EditText with the country’s name.
<div class="separator" style="clear: both; text-align: center;"></div>
Now let’s try rotating our phone. This is where things get juicy. First off, there are no section headers. Second, the results are not in alphabetical order anymore. If we debug all over the adapter, we see what is written on the screenshot: Item on the left is position = 1, item in the middle is position = 0, and item on the right is position = 2.

Remember the result set we have? “Pakistan” is definitely NOT in position = 0, it should have been a section header! If we go ahead and select “Pakistan” in the suggestions above the keyboard, the EditText will populate with the item in position = 0 of the result set, i.e. “Section!”. Definitely not good.

<div class="separator" style="clear: both; text-align: center;"></div>
The AutoCompleteTextView widget has been around since API level 1, but I haven’t messed around with it as much as I did today. Googling returns very, very sparse results on this topic.
<ul><li>Does this mean people do not have the same problem as I did?</li><li>No one uses section headers in AutoCompleteTextViews?</li><li>No one uses this screen mode (EditText in full screen) in landscape without setting IME flags?</li><li>Is there a secret trick to making this work out-of-the-box?</li></ul><div>Or the most plausible of all,</div><div><ul><li>Am I being stupid?</li></ul></div>

2 min read

Adding attributes to a custom view

There are times when using the default Android Views just doesn’t cut it and you need to create your own version of a View. So how exactly do you do that? It’s as simple as subclassing the View! But what if you want to add customizable attributes? Here’s how.

Let’s say I am creating a form-filling application and I want some of the EditTexts in the form to be required. However, I am so tired of having to implement the error checking for each and every one of those fields. What I will do is create my own EditText that will do the validation for me if that particular field is required. Let’s do it.

Step 1: Create your custom view and create fields for the attributes you want. In this case, I want an EditText that will show the default EditText error display if the user has not put in any value.
<pre class="brush:java">public class RequiredEditText extends EditText {
private boolean mRequired;
private String mErrorMessage;

public RequiredEditText(Context context) {
super(context);
}

/*
* Set this EditText’s requirement validation. The error message
* will be set to null by default if not provided.
*
* @param required
* @param errorMessage (optional)
*/
public void setRequired(boolean required, String errorMessage) {
this.mRequired = required;
this.mErrorMessage = errorMessage;

invalidate();
requestLayout();
}

public void setRequired(boolean required) {
setRequired(required, null);
}

/
* Lets you know if this field is set as required or not
* @return
*/
public boolean isRequiredField() {
return mRequired;
}
}</pre>Step 2: If a field is required, we want the default error message to appear (with our own error message, of course). If the user fills in the EditText, we want the error to disappear.
<pre class="brush:java">public class RequiredEditText extends EditText {
private boolean mRequired;
private String mErrorMessage;

public RequiredEditText(Context context) {
super(context);
}

/

* Set this EditText’s requirement validation. The error message
* will be set to null by default if not provided.
*
* @param required
* @param errorMessage (optional)
*/
public void setRequired(boolean required, String errorMessage) {
this.mRequired = required;
this.mErrorMessage = errorMessage;

manageRequiredField(required);

invalidate();
requestLayout();
}

public void setRequired(boolean required) {
setRequired(required, null);
}

private void manageRequiredField(boolean required) {
// If we are required, set the listeners
if(required) {
setOnFocusChangeListener(mFocusChangeListener);
addTextChangedListener(mTextWatcher);
} else {
// In case there is an error message already, clear it
setError(null);

// Remove the listeners
setOnFocusChangeListener(null);
removeTextChangedListener(mTextWatcher);
}
}

/**
* Lets you know if this field is set as required or not
* @return
*/
public boolean isRequiredField() {
return mRequired;
}

OnFocusChangeListener mFocusChangeListener = new OnFocusChangeListener() {

@Override
public void onFocusChange(View v, boolean hasFocus) {
// If the focus was removed from the field and it IS required,
// check if the user has put in something
if(!hasFocus && mRequired){
isRequiredFieldFilled();
}
}
};

TextWatcher mTextWatcher = new TextWatcher() {

@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
// Once the user types in something, remove the error
setError(null);
}

@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) { /
do nothing / }

@Override
public void afterTextChanged(Editable s) { /
do nothing */ }
};

private boolean isRequiredFieldFilled() {
// If the EditText is empty, show the error message
if(TextUtils.isEmpty(getText().toString().trim())){
showRequiredErrorDrawable();
return false;
}
return true;
}

private void showRequiredErrorDrawable() {
setError(mErrorMessage);
}
}</pre>Step 3: Now it’s time to add the fields to the Layout Editor. Create an attrs.xml file in /res if there isn’t one already. Declare a styleable and include the attributes you want to appear in the Layout Editor.
<pre class="brush:xml">





</pre>The name of the styleable does not need to match your custom view class name, but doing so makes it more readable and maintainable.

Step 4: Go back to your custom view implementation and add constructors that take in an AttributeSet.
<pre class="brush:java">public RequiredEditText(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init(attrs);
}

public RequiredEditText(Context context, AttributeSet attrs) {
super(context, attrs);
init(attrs);
}

private void init(AttributeSet attrs) {
TypedArray a=getContext().obtainStyledAttributes(
attrs,
R.styleable.RequiredEditText);

try {
setRequired(a.getBoolean(R.styleable.RequiredEditText_required, false),
a.getString(R.styleable.RequiredEditText_errorMessage));
} finally {
//Don’t forget this, we need to recycle
a.recycle();
}
}
</pre>Step 5: Go to the Layout Editor and look for “Custom & Library Views” in the Palette (you may have to click on “Refresh” several times before your custom view appears in the list). Add the custom view to your layout and check out the properties panel!
 

 As always, the code is in GitHub.

3 min read

My EditText is cut off by the on-screen keyboard!

With clients demanding left and right that my app should look like an iPhone app, I tend to be unappreciative of the way Android natively handles UI interactions and such. Notice how the screen automagically scrolls up when you click on an EditText? It turns out that in iPhone development, the developer does this manually (indicate how much the view should scroll when the on-screen keyboard appears, then scroll it back down afterwards). HA!

But even magic fails sometimes. Has this ever happened to you?
<img style=”display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 134px; height: 200px;” src=”http://3.bp.blogspot.com/-JftkETrkB2c/TZlrHJOji5I/AAAAAAAAA4I/cX4jSBJRiGY/s200/edittext_hidden.png” border=”0” alt=”“id=”BLOGGER_PHOTO_ID_5591618182837406610” />
The bottommost EditText is cut off. And we don’t want that!

So what do we do? Do we programmatically scroll the view up? I don’t want to do that! It turns out that we can just wrap the whole view in a ScrollView and it will scroll up properly!
<img style=”display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 134px; height: 200px;” src=”http://1.bp.blogspot.com/-J2UCMLF_E3k/TZlrk_lKBdI/AAAAAAAAA4Q/c7G321XalBo/s200/edittext_shown.png” border=”0” alt=”“id=”BLOGGER_PHOTO_ID_5591618695643923922” />

The only downside to this is that you might want to hide the scrollbar when the view moves up to accommodate the on-screen keyboard. And to do that, I was trying to set the android:scrollbars=”none” attribute but for one reason or another the scrollbar is still being drawn. To make the scrollbar disappear, we can do it from code as such:<pre class="brush:java">((ScrollView)findViewById(R.id.my_scrollview))
.setVerticalScrollBarEnabled(false);</pre>And we’re done!

~1 min read
Back to Top ↑

shared preferences

Selectively Resetting SharedPreferences

I have recently been working on a feature that has a bunch of pre-conditions. Things like the user must be logged in AND the feature flag has to be turned on AND it only appears the first time the user lands on the screen.

1 min read

Adding Preferences On-The-Fly

(Make appropriate whooshing sounds)

Today, I will show you how to add preferences to your SharedPreferences (confused yet?) programatically. In an app that I am doing, I wanted to present a ListPreference to the user from the SharedPreferences page. However, the values contained in this list is not known at compile time. (Think Facebook groups that differ per user, or Twitter lists, or things like such, and I want to set a default option.)

Anyway, here’s what I did to make this work. I added a preference in my PreferenceScreen, a sort of placeholder, if you will. Here is my ListPreference:
<pre class="brush:xml"><PreferenceScreen xmlns:android=”http://schemas.android.com/apk/res/android” >

<PreferenceCategory android:title=”@string/pref_settings_header”>
<ListPreference android:key=”@string/pref_key_default_group” android:title=”@string/pref_default_group”/>
</PreferenceCategory>

</PreferenceScreen></pre>And then in the class that handles the SharedPreferences, I get the values that I want displayed and plug them in to the placeholder preference. I will not bother to explain here, just heavily commenting the code:
<pre class="brush:java">public class UserPreferences extends PreferenceActivity {

private static final String LOG_TAG = “UserPreferences”;

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);

// Load the preferences from an XML resource
addPreferencesFromResource(R.xml.my_apps_prefs);

// Manage the “Default Group” preference
addDefaultGroupPrefs();
}


private void addDefaultGroupPrefs() {
// Get our “placeholder” preference. I prefer to use strings instead of hard-coding the preference key.
// The value passed into findPreference is the value in the android:key parameter in the preference XML file.
ListPreference groupsListPrefs = (ListPreference) findPreference(getString(R.string.pref_key_default_group));

// Get your groups, this may come from a utility class or wherever
// In this example, I have a custom object that has a “name” and an “id”
List<CustomGroup> myGroups = getMyGroups();
if (myGroups == null) {
// Disable the preference if we don’t have a list
groupsListPrefs.setEnabled(false);
} else {
// Enable the preference if we have a list
groupsListPrefs.setEnabled(true);

// We split the list into names and IDs
// We show the names in the list, and the values as the entries
List<String> groupNames = new ArrayList<String>();
List<String> groupIds = new ArrayList<String>();
for (CustomGroup group : myGroups){
groupIds.add(group.getId());
groupNames.add(group.getName());

// I guess you can add directly to a String[]
// just make sure the order is preserved (name1=id1, name2=id2, etc)
}

// These should be user-readable strings
groupsListPrefs.setEntries(groupNames.toArray(new String[groupNames.size()]));

// These are the actual values to be saved in the XML file
groupsListPrefs.setEntryValues(groupIds.toArray(new String[groupIds.size()]));
}
}

private List<customgroup> getMyGroups(){
// do work here, query server or db or whatever
// return the list of groups
}
}</pre>
And we’re done. :)

1 min read

Inspecting your Shared Preferences

Did you know that you can look at your SharedPreferences file?

If during development you want to inspect what your SharedPreferences now contain, you can pull a copy of the XML file from the emulator.

In Eclipse, you can do that by following these steps:

<ol><li>Open the DDMS perspective (Window > Open Perspective > Other > DDMS).</li><li>Click on the File Explorer tab and navigate to your app’s data folder (that’s under data/data/<your package name>/shared_prefs/).</li><li>Choose the file you want to download.</li><li>Click on the Pull file from device button.</li></ol><div class="separator" style="clear: both; text-align: center;"></div><div>
</div>

~1 min read
Back to Top ↑

resources

A big step

Today was the day.

~1 min read

Using resource IDs in data binding layouts

I have been playing with data binding more and more over the last couple of weeks. This week, it’s all about creating a dialog with stuff dictated by a value from an enum.

2 min read

Quick Tip: Understanding Alternate Resources

Trying to support as many devices as possible the best way possible is a very daunting task indeed. You will usually need to provide a lot of different layouts, strings, or dimensions (among others) to make your app look great whatever the user’s device is. And then you start chaining resource qualifiers and testing which resource is being loaded by the OS can become a nightmare very quickly.

Here’s a trick I started using which seemed to work quite well. Create a string (the app name works well if you have an Action Bar) that you can display on-screen (or just throw into a Log or a Toast) that will quickly let you know from which of those very many /res folders your resources are being pulled out of.

For this demo, I have the following /res/values-xxxxx folders:
<div class="separator" style="clear: both; text-align: center;"></div>
As you can see, there are strings.xml files in each of the configurations I want to support. Each of these files will contain whatever description we want to see on the device or in the Logs. In my case, I have custom strings for each form factor and orientation, which allows me to validate things easier. But this is particularly useful if the changes per form factor and orientation is subtle, such as dimensions.

Here’s what it looks like for phones:

<table><tbody><tr><td></td><td></td></tr></tbody></table>
And here are the outputs for tablets:
<table><tbody><tr><td></td><td></td></tr></tbody></table>
Each of the strings.xml files contains just these two strings (sample taken from /res/values-sw800dp):
<pre class="brush:xml">

MultiDeviceSupport - Tablet Portrait
Hello world on a tablet!


</pre>Have fun debugging!

1 min read
Back to Top ↑

instant apps

I Like Walls

I have always been told I’m stubborn. And I am. So jumping off this post, I continued doing instant apps stuff and I learnt more things this week.

1 min read
Back to Top ↑

formatter

Using a custom font in WebView

In one of my projects, I needed to display some special characters that the Android OS by itself cannot seem to render. I figured that I would need to provide a custom font that includes the characters that I needed.

If I was using a TextView, I could use TextView#setTypeFace. But I was using a WebView and I feared that things would be more complicated than that. So how do I do this?

Here’s how we can make it work.

Step 1: We would need to have our font face included in our project’s /assets folder. So look for a TTF file that you can use freely, make sure the author/creator allows you to re-distribute it!

Step 2: Edit your HTML file to include some CSS stuff, just so the WebView would know what font you want to use. Here’s a sample file: <pre class="brush:xml"><html><head><link href=”YourCssFile.css” rel=”stylesheet” type=”text/css” /></head><body><span class=”phon”>This string contains special characters: əˈpåstrəfi </span></body></html></pre>Make sure that the href references are correct. In this case, my CSS file, HTML file and font file are in the same folder.

Step 3: Define your CSS file. In this case, our YourCssFile.css would be:<pre class="brush:css">@font-face {
font-family: “My font”;
src: url(‘MyFontFile.TTF’);
}

.phon, .unicode {
display: inline;
font-family: ‘My font’, Verdana, sans-serif;
font-size: 14pt;
font-weight: 500;
font-style:normal;
color: black;
}</pre>Step 4: Load the file in your WebView! You can use <pre class="brush:java">WebView webView = (WebView) findViewById(R.id.myWebview);
webView.loadUrl(“path/to/html/file”);</pre> or <pre class="brush:java">webView.loadDataWithBaseURL(“file:///android_asset/”,
article, “text/html”, Encoding.UTF_8.toString(), null);</pre>If you will use the second option, your article variable would contain the HTML string. Just make sure that you escape your quotation marks with a backslash ().
<blockquote><blockquote>IMPORTANT NOTE: This feature seems to be broken in Android 2.0 and 2.1, as reported here.</blockquote></blockquote>

1 min read

Quick string resource formatting

Sooner or later, you would want to display a message to your user with dynamic content. This may be the number of results, the user’s name, etc.

~1 min read
Back to Top ↑

textview

TextView and MaxLines

I have a TextView (who doesn’t?) and I want to adjust its height automatically, depending on the length of the text it will contain. Should be easy. It was, but it took me a couple of minutes to figure it out.<div>
</div><div>So I want my TextView to be by default one line tall, but be able to expand up to two lines. My initial set up was to set lines=1 and maxLines=2, but it was making the TextView always two lines. Not what I wanted! I went through the documentation again, read each word carefully, and then:
<pre class="brush:xml"><TextView android:id=”@+id/title”
android:layout_height=”wrap_content”
android:layout_width=”fill_parent”
android:ellipsize=”end”
android:maxLines=”2”
android:minLines=”1”
android:text=”This is the text” /></pre>So it turned out that you have to set both minLines and maxLines. TADA!</div>

~1 min read

Quick string resource formatting

Sooner or later, you would want to display a message to your user with dynamic content. This may be the number of results, the user’s name, etc.

~1 min read
Back to Top ↑

despicable

It never ends!

Been ultra super busy the past few weeks. Also learning a lot of new things. And renewing my battle with orientation change, AsyncTasks and dialog boxes.

So, I have been thinking of what to document here next. Here are my choices:
- Loading HTML pages stored in the SD card in a WebView
- Managing your SharedPreferences
- Using a ViewStub

I had a long list in my mind yesterday, but I managed to not write it down. facepalm

~1 min read

It’s so fluffyyyyyyyyy!!!

<img src=http://www.despicable.me/pops/minionMaker/userpics/910156207.jpg width=”380” height=”473” alt=”I’ve created a Minion to join Gru’s Minion army.” />

~1 min read
Back to Top ↑

plurals

More plurals: decimal values

In my previous post, I showed you how to set string plurals. If you noticed, the methods to get the plurals strings only accept ints. What if (like me) you want to display a decimal value? I am getting my raw value from a progress bar with a range of 1-10, with 0.1 increments.

1 min read

String Pluralization

Last week, I discovered Android’s support for plural strings by accident. And a good accident it was since I am working on an app that will display a float to the user. I used to display:

1 min read
Back to Top ↑

shortcut

Pasting and Extracting Stuff

A lot of times, but especially when I am implementing some new logic, coding for me takes several steps:
1. Write down what I have to do as comments
2. Implement what I have written down
3. Refactor and improve what I have implemented

More often than not, step 3 means moving stuff around, copy-pasting things, extracting variables, defining constants, etc. I am not a hardcode never-using-my-mouse developer. If anything, I think my brain is limited to holding a limited number of shortcuts for everything I use in my life. Android Studio has the perfect shortcuts for making this easier for me. Luckily, these shortcuts made it to the list of things my brain remembers.

How many times have I copied (or even cut!) text but instead of pasting, I press ⌘+V (CMD+V) again! ARGH. I used to do ⌘+Z (CMD+Z) any number of times until I get back what I wanted. That is, until I learned about ⌘+⇧+V (CMD+SHIFT+V)! This key combo shows the clipboard history, which means no more fretting. Yay!

Refactoring also mostly involves extracting variables. I have already shown how to extract strings into strings.xml, and here I show how to extract things into methods, variables, fields, or constants.

It is fairly easy to remember them. Just combine ⌘+⌥ (CMD+OPTION) with the first letter of what you want to extract to. Time for a handy table!

<table style="border-collapse: collapse; border: 1px solid black;"><tbody><tr><th style="border: 1px solid black; padding: 5px;">Shortcut </th><th></th></tr><tr><td style="border: 1px solid black; padding: 5px;">⌘+⌥+M </td><td style="border: 1px solid black; padding: 5px;">Method </td></tr><tr><td style="border: 1px solid black; padding: 5px;">⌘+⌥+V </td><td style="border: 1px solid black; padding: 5px;">Variable </td></tr><tr><td style="border: 1px solid black; padding: 5px;">⌘+⌥+F </td><td style="border: 1px solid black; padding: 5px;">Field </td></tr><tr><td style="border: 1px solid black; padding: 5px;">⌘+⌥+C </td><td style="border: 1px solid black; padding: 5px;">Constant </td></tr></tbody></table>
This video might do a better job of showing what I’m trying to say. Code from Chris Banes’s Cheesesquare demo.
<iframe allowfullscreen="" frameborder="0" height="315" src="https://www.youtube.com/embed/bgzPRX9zC30" width="420"></iframe>

1 min read

Quick tip: Quick Formatting of Android XML Files

One of the most useful tools in Android’s Eclipse plug-in is the Layout Editor. It is easy to experiment with layouts using the drag-and-drop enabled editor without having to worry about the correct syntax or if you are using the correct attribute name.

After creating your layout this way, however, you can end up with a messy XML file. I say “messy” in the sense that elements can run on in one veeeeeeeeeeeery long line, and if you are about to edit the XML file manually, this can be a nightmare.

I used to format the XML file by hand, putting in line breaks and correcting indentation. But one edit using the graphical layout editor and it’s messed up again. And then I had a light bulb moment. Eclipse allows auto-formatting of code, but what about XML files? AHA!

It turns out that auto-formatting works for XML files too! Simply select all the contents of the XML file (CTRL-A) and then press the ultra magical shortcut CTRL-I and your XML file is clean and orderly as can be! YAY!

~1 min read
Back to Top ↑

seekbar

Setting up the SeekBar

So we want to use the SeekBar. We want the minimum value to be 10 and the maximum value to be 100, and it should increment by 10.

Thing is, SeekBar by default always starts at 0, and the increment is always an int. It is definitely possible to get what we want, but we need to do some simple math first.

Compute how many increments you will need from your minimum up to your maximum:
<pre class="brush:xml">numberOfIncrements = maximum - minimum = 90</pre>
Then divide it by the amount of each increment we want:
<pre class="brush:xml">seekBarMaximum = numberOfIncrements / 10 = 9</pre>
This means we should set up the SeekBar to have max = 9 and increment = 1. Then in our code, we have to figure out how to get the actual progress that we want.
<pre class="brush:java">SeekBar.OnSeekBarChangeListener mSeekbarListener = new OnSeekBarChangeListener() {

@Override
public void onStopTrackingTouch(SeekBar seekBar) { /* Do nothing/ }

@Override
public void onStartTrackingTouch(SeekBar seekBar) { /
Do nothing*/ }

@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
mProgressDisplay.setText(“Seekbar is at: “ + getProgressToDisplay(progress));
}
};


private String getProgressToDisplay(int progress) {</pre><pre class="brush:java"> // We are multiplying by 10 since it is our actual increment
int actualProgress = (progress + 1) * 10;
return String.valueOf(actualProgress);
}</pre>
Another example:
<pre class="brush:xml">minimum = 1, maximum = 10, increment = 0.5
numberOfIncrements = 9
seekBarMaximum = 18</pre>
In this case, the contents of getProgressToDisplay() will change since the increment is not a whole number.
<pre class="brush:java">private String getProgressToDisplay(int progress) {
float actualProgress = (progress + 1) - (progress * 0.5f);
return String.valueOf(actualProgress);
}</pre>

1 min read

That damn seekbar thumb

If you have ever needed to use a SeekBar, you definitely would have noticed how hard it is to move the slider (aka thumb) when it is set to the minimum or maximum value. The slider tends to be cut in half, and fitting your finger into it to press it becomes a test of patience.<div></div>
See how small the slider becomes when it reaches the far ends of the SeekBar? Crazy!

Luckily, I found a way (just today!) to move the slider just a little tiny bit to make it easier to press. Apparently, there is a method called setThumbOffset() that allows us to nudge the slider by a number of pixels.

It’s pretty easy to use, aside from the fact that it accepts pixels and not dip measurements. Anyway, here’s how to do it:<pre class="brush:java">int pixels = convertDipToPixels(8f);
SeekBar mySeekBar = (SeekBar) findViewById(R.id.quiz_settings_seekbar);
mySeekBar.setOnSeekBarChangeListener(mySeekBarListener);
mySeekBar.setThumbOffset(pixels);</pre>I convert dip measurements to pixels to better manage the growing number of resolutions of screen sizes present. Here’s the code to do that:<pre class="brush:java">private int convertDipToPixels(float dip) {
DisplayMetrics metrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(metrics);
float density = metrics.density;
return (int)(dip * density);
}</pre>Aaaaaaaand this is now how our slider looks:Applause! Confetti! Applause!

~1 min read
Back to Top ↑

listview

Swipe, not Pull, to Refresh

I have recently came across this new View in the support library package that allows your app to have built-in support for pull swipe to refresh. This is pretty cool, since we don’t have to use any of the libraries out there. Admittedly, very little customization can be done, but then what else can we customize, right?

Anyway, here’s a short demo of using this nifty little view.
<div class="separator" style="clear: both; text-align: center;"></div><table><tbody><tr><td><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody><tr><td style="text-align: center;"></td></tr><tr><td class="tr-caption" style="text-align: center;">Initial list</td></tr></tbody></table></td><td><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody><tr><td style="text-align: center;"></td></tr><tr><td class="tr-caption" style="text-align: center;">While refreshing</td></tr></tbody></table></td><td><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody><tr><td style="text-align: center;"></td></tr><tr><td class="tr-caption" style="text-align: center;">After refreshing</td></tr></tbody></table></td></tr></tbody></table>
The app is a simple ListView that shows a list of countries. Swiping down on the list will simulate a long-running activity (like connecting to a server, for example) and afterwards updating the list with new data.

Adding support for swipe to refresh is pretty straightforward. You would have to wrap the swipe-able layout in a SwipeRefreshLayout. Here is my XML file:

<pre class="brush:xml"><android.support.v4.widget.SwipeRefreshLayout xmlns:android=”http://schemas.android.com/apk/res/android”
xmlns:tools=”http://schemas.android.com/tools”
android:id=”@+id/container”
android:layout_width=”match_parent”
android:layout_height=”match_parent”
tools:ignore=”MergeRootFrame” >

<ListView
android:id=”@android:id/list”
android:layout_width=”match_parent”
android:layout_height=”match_parent” />

</android.support.v4.widget.SwipeRefreshLayout>
</pre>
In your Fragment, you would then have to put an onRefreshListener on this SwipeRefreshLayout. In my Fragment’s onCreateView, I have this:

<pre class="brush:java">// Configure the swipe refresh layout
mSwipeRefreshLayout = (SwipeRefreshLayout) rootView.findViewById(R.id.container);
mSwipeRefreshLayout.setOnRefreshListener(this);
mSwipeRefreshLayout.setColorScheme(
R.color.swipe_color_1, R.color.swipe_color_2,
R.color.swipe_color_3, R.color.swipe_color_4);
</pre>
The colors are defined in a colors.xml file in my res/values folder. To show or hide the refresh animation, you would have to call setRefreshing(boolean). This means that if you have to kick off an AsyncTask when the user swipes down, call setRefreshing(true) in onPreExecute, and call setRefreshing(false) in onPostExecute.

The implementation of onRefresh in the demo app is pretty simple, it simply grabs the next bunch of countries from a pre-defined list.

<pre class="brush:java">@Override
public void onRefresh() {
// Start showing the refresh animation
mSwipeRefreshLayout.setRefreshing(true);

// Simulate a long running activity
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
updateCountries();
}
}, 5000);
}
</pre>
That’s it really.  Nice and short. The code for this demo is in Github.

1 min read

Using CWAC’s EndlessAdapter with a custom adapter

In one of my projects, the app has the potential to display a very, and I mean very, long list. To minimize the loading time of the app, I limit the number of items initially included in the list and then add to it as the user scrolls down.

For this purpose, Mark Murphy’s EndlessAdapter works wonders. I was trying to make it work with a CursorAdapter though, but due to time constraints, I was not able to continue with my experiment.

And then I found out that some of the items in my list are HTML-formatted. Huh. So I have to have a custom adapter to override getView(). I patterned my code on the demo included in the EndlessAdapter project and I was at a loss. Maybe it’s because I just came from a vacation and my mind refuses to work. Hmmm.

To cut a long and arduous journey short, I was able to figure it out. Here’s a sample activity that displays a list of countries from an array. To illustrate using a custom adapter, I add the list item number when setting the item text.

I will discuss the pertinent parts of the code in detail.
<pre class="brush:java">private void init() {
LIST_SIZE = COUNTRIES.length;
for (int i=0; i<=BATCH_SIZE; i++){
countriesSub.add(COUNTRIES[i]);
}

setLastOffset(BATCH_SIZE);
displayList(countriesSub);
}</pre>In this part of the code, I get the first 10 items in the list as the initial contents of the list. Of course, our current list is small and is peanuts for ListView. This is just to illustrate my point. In my app, I initially load 2,000 items. I also make sure to remember where I am in my source list. In my case, it is the offset in the original array. This might also be a row in the DB, or the ID in an RSS feed.

The ArrayList countriesSub holds the items that are currently in my list. As the user goes through the list, this array will grow.

To display my list, I set an instance of DemoAdapter as my list adapter. DemoAdapter inherits from EndlessAdapter and in its constructor, I give it an instance of my custom ArrayAdapter.
<pre class="brush:java">@Override
public View getView(int position, View convertView, ViewGroup parent) {

ViewHolder holder;

if(convertView==null){
LayoutInflater inflater = (LayoutInflater)
EndlessCustom.this.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = inflater.inflate(android.R.layout.simple_list_item_1, null);
holder = new ViewHolder();
holder.word = (TextView)convertView.findViewById(android.R.id.text1);

convertView.setTag(holder);
} else{
holder=(ViewHolder)convertView.getTag();
}

holder.word.setText(String.valueOf(position+1) + “. “ + countriesSub.get(position));
return convertView;
}</pre>
The important part in my custom ArrayAdapter is the getView() method. In this method, I tell the adapter to not simply display the .toString() value of the item, but to add a number before it.

Notice that I use the ViewHolder pattern as illustrated in the Android Developers site.
<pre class="brush:java; tab-size: 5">DemoAdapter() {
super(new CustomArrayAdapter(EndlessCustom.this,
android.R.layout.simple_list_item_1, android.R.id.text1, countriesSub));

rotate=new RotateAnimation(0f, 360f, Animation.RELATIVE_TO_SELF,
0.5f, Animation.RELATIVE_TO_SELF,
0.5f);
rotate.setDuration(600);
rotate.setRepeatMode(Animation.RESTART);
rotate.setRepeatCount(Animation.INFINITE);
}</pre>
So now we come to the EndlessAdapter part. In the constructor, I pass into it an instance of my custom ArrayAdapter, indicating the source of the list, the layout for each row, and the TextView ID from the layout. I also instantiated the animation that will be used while the list is loading the additional items.
<pre class="brush:java">@Override
protected boolean cacheInBackground() {
tempList.clear();
int lastOffset = getLastOffset();
if(lastOffset < LIST_SIZE){
int limit = lastOffset + BATCH_SIZE;
for(int i=(lastOffset+1); (i<=limit && i<LIST_SIZE); i++){
tempList.add(COUNTRIES[i]);
}

setLastOffset(limit);

if(limit<LIST_SIZE){
return true;
} else {
return false;
}
} else {
return false;
}
}</pre>We have to override cacheInBackground() for EndlessAdapter to work. Here we do the heavy lifting like querying the server, reading from the DB, etc. Here, I load the next 10 items from the original list and put them in a temporary ArrayList. I also check whether I have loaded all the data, and if so, tell the EndlessAdapter to not show the extra row at the bottom. I do this by returning false from the method.
<pre class="brush:java; tab-size: 5">@Override
protected void appendCachedData() {
@SuppressWarnings(“unchecked”)
ArrayAdapter<String> arrAdapterNew = (ArrayAdapter<String>)getWrappedAdapter();

int listLen = tempList.size();
for(int i=0; i<listLen; i++){
arrAdapterNew.add(tempList.get(i));
}
}</pre>Finally, I add the newly retrieved rows to my current list. And that’s it.

The complete Java file for this activity follows:
<pre class="brush:java; collapse: true">package com.test.example;

import java.util.ArrayList;
import java.util.List;

import android.app.ListActivity;
import android.content.Context;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.Animation;
import android.view.animation.RotateAnimation;
import android.widget.ArrayAdapter;
import android.widget.TextView;

import com.commonsware.cwac.endless.EndlessAdapter;

public class EndlessCustom extends ListActivity {

static int LIST_SIZE;
private int mLastOffset = 0;

static final int BATCH_SIZE = 10;

ArrayList<String> countriesSub = new ArrayList<String>();

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.lib_activity_dictionary);
init();
}

private void init() {
LIST_SIZE = COUNTRIES.length;
for (int i=0; i<=BATCH_SIZE; i++){
countriesSub.add(COUNTRIES[i]);
}
setLastOffset(BATCH_SIZE);
displayList(countriesSub);
}

private void setLastOffset(int i) {
mLastOffset = i;
}

private int getLastOffset(){
return mLastOffset;
}

private void displayList(ArrayList<String> countriesSub) {
setListAdapter(new DemoAdapter());
}

private class CustomArrayAdapter extends ArrayAdapter<String>{

public CustomArrayAdapter(Context context, int resource,
int textViewResourceId, List<String> objects) {
super(context, resource, textViewResourceId, objects);
}

@Override
public View getView(int position, View convertView, ViewGroup parent) {

ViewHolder holder;

if(convertView==null){
LayoutInflater inflater = (LayoutInflater)
EndlessCustom.this.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = inflater.inflate(android.R.layout.simple_list_item_1, null);
holder = new ViewHolder();
holder.word = (TextView)convertView.findViewById(android.R.id.text1);

convertView.setTag(holder);
} else{
holder=(ViewHolder)convertView.getTag();
}

holder.word.setText(String.valueOf(position+1) + “. “ + countriesSub.get(position));
return convertView;
}

public class ViewHolder{
public TextView word;
}
}

class DemoAdapter extends EndlessAdapter {
private RotateAnimation rotate=null;
ArrayList<String> tempList = new ArrayList<String>();

DemoAdapter() {
super(new CustomArrayAdapter(EndlessCustom.this,
android.R.layout.simple_list_item_1, android.R.id.text1, countriesSub));

rotate=new RotateAnimation(0f, 360f, Animation.RELATIVE_TO_SELF,
0.5f, Animation.RELATIVE_TO_SELF,
0.5f);
rotate.setDuration(600);
rotate.setRepeatMode(Animation.RESTART);
rotate.setRepeatCount(Animation.INFINITE);
}

@Override
protected View getPendingView(ViewGroup parent) {
View row=getLayoutInflater().inflate(R.layout.row, null);

View child=row.findViewById(android.R.id.text1);
child.setVisibility(View.GONE);
child=row.findViewById(R.id.throbber);
child.setVisibility(View.VISIBLE);
child.startAnimation(rotate);

return(row);
}

@Override
protected boolean cacheInBackground() {
tempList.clear();
int lastOffset = getLastOffset();
if(lastOffset < LIST_SIZE){
int limit = lastOffset + BATCH_SIZE;
for(int i=(lastOffset+1); (i<=limit && i<LIST_SIZE); i++){
tempList.add(COUNTRIES[i]);
}
setLastOffset(limit);

if(limit<LIST_SIZE){
return true;
} else {
return false;
}
} else {
return false;
}
}


@Override
protected void appendCachedData() {

@SuppressWarnings(“unchecked”)
ArrayAdapter<String> arrAdapterNew = (ArrayAdapter<String>)getWrappedAdapter();

int listLen = tempList.size();
for(int i=0; i<listLen; i++){
arrAdapterNew.add(tempList.get(i));
}
}
}


static final String[] COUNTRIES = new String[] {
“Afghanistan”, “Albania”, “Algeria”, “American Samoa”, “Andorra”,
“Angola”, “Anguilla”, “Antarctica”, “Antigua and Barbuda”, “Argentina”,
“Armenia”, “Aruba”, “Australia”, “Austria”, “Azerbaijan”,
“Bahrain”, “Bangladesh”, “Barbados”, “Belarus”, “Belgium”,
“Belize”, “Benin”, “Bermuda”, “Bhutan”, “Bolivia”,
“Bosnia and Herzegovina”, “Botswana”, “Bouvet Island”, “Brazil”, “British Indian Ocean Territory”,
“British Virgin Islands”, “Brunei”, “Bulgaria”, “Burkina Faso”, “Burundi”,
“Cote d’Ivoire”, “Cambodia”, “Cameroon”, “Canada”, “Cape Verde”,
“Cayman Islands”, “Central African Republic”, “Chad”, “Chile”, “China”,
“Christmas Island”, “Cocos (Keeling) Islands”, “Colombia”, “Comoros”, “Congo”,
“Cook Islands”, “Costa Rica”, “Croatia”, “Cuba”, “Cyprus”, “Czech Republic”,
“Democratic Republic of the Congo”, “Denmark”, “Djibouti”, “Dominica”, “Dominican Republic”,
“East Timor”, “Ecuador”, “Egypt”, “El Salvador”, “Equatorial Guinea”, “Eritrea”,
“Estonia”, “Ethiopia”, “Faeroe Islands”, “Falkland Islands”, “Fiji”, “Finland”,
“Former Yugoslav Republic of Macedonia”, “France”, “French Guiana”, “French Polynesia”,
“French Southern Territories”, “Gabon”, “Georgia”, “Germany”, “Ghana”, “Gibraltar”,
“Greece”, “Greenland”, “Grenada”, “Guadeloupe”, “Guam”, “Guatemala”, “Guinea”, “Guinea-Bissau”,
“Guyana”, “Haiti”, “Heard Island and McDonald Islands”, “Honduras”, “Hong Kong”, “Hungary”,
“Iceland”, “India”, “Indonesia”, “Iran”, “Iraq”, “Ireland”, “Israel”, “Italy”, “Jamaica”,
“Japan”, “Jordan”, “Kazakhstan”, “Kenya”, “Kiribati”, “Kuwait”, “Kyrgyzstan”, “Laos”,
“Latvia”, “Lebanon”, “Lesotho”, “Liberia”, “Libya”, “Liechtenstein”, “Lithuania”, “Luxembourg”,
“Macau”, “Madagascar”, “Malawi”, “Malaysia”, “Maldives”, “Mali”, “Malta”, “Marshall Islands”,
“Martinique”, “Mauritania”, “Mauritius”, “Mayotte”, “Mexico”, “Micronesia”, “Moldova”,
“Monaco”, “Mongolia”, “Montserrat”, “Morocco”, “Mozambique”, “Myanmar”, “Namibia”,
“Nauru”, “Nepal”, “Netherlands”, “Netherlands Antilles”, “New Caledonia”, “New Zealand”,
“Nicaragua”, “Niger”, “Nigeria”, “Niue”, “Norfolk Island”, “North Korea”, “Northern Marianas”,
“Norway”, “Oman”, “Pakistan”, “Palau”, “Panama”, “Papua New Guinea”, “Paraguay”, “Peru”,
“Philippines”, “Pitcairn Islands”, “Poland”, “Portugal”, “Puerto Rico”, “Qatar”,
“Reunion”, “Romania”, “Russia”, “Rwanda”, “Sqo Tome and Principe”, “Saint Helena”,
“Saint Kitts and Nevis”, “Saint Lucia”, “Saint Pierre and Miquelon”,
“Saint Vincent and the Grenadines”, “Samoa”, “San Marino”, “Saudi Arabia”, “Senegal”,
“Seychelles”, “Sierra Leone”, “Singapore”, “Slovakia”, “Slovenia”, “Solomon Islands”,
“Somalia”, “South Africa”, “South Georgia and the South Sandwich Islands”, “South Korea”,
“Spain”, “Sri Lanka”, “Sudan”, “Suriname”, “Svalbard and Jan Mayen”, “Swaziland”, “Sweden”,
“Switzerland”, “Syria”, “Taiwan”, “Tajikistan”, “Tanzania”, “Thailand”, “The Bahamas”,
“The Gambia”, “Togo”, “Tokelau”, “Tonga”, “Trinidad and Tobago”, “Tunisia”, “Turkey”,
“Turkmenistan”, “Turks and Caicos Islands”, “Tuvalu”, “Virgin Islands”, “Uganda”,
“Ukraine”, “United Arab Emirates”, “United Kingdom”,
“United States”, “United States Minor Outlying Islands”, “Uruguay”, “Uzbekistan”,
“Vanuatu”, “Vatican City”, “Venezuela”, “Vietnam”, “Wallis and Futuna”, “Western Sahara”,
“Yemen”, “Yugoslavia”, “Zambia”, “Zimbabwe”
};
}</pre>
If you know of a more efficient way to do this, please do not hesitate to let me know! :)

6 min read
Back to Top ↑

extras

ADT 12: Not so shiny after all


For all the shininess that ADT 12 promised, it seems that it also broke one major feature of DDMS: Launching emulators.

After updating to ADT 12, I kept on seeing that error when launching an emulator instance. Restarting Eclipse doesn’t help any.

Anyway, the apparent cause of this error is that ADT 12 has some problems with the SDK location having spaces. If you have already forgotten, it’s in Window > Preferences > Android.

To work around this bug, it is either you move your SDK to a folder in a path without spaces; or, modify the existing path to either of the following:<div><ul><li>If your SDK is in Program Files: C:/PROGRA~1/<path_to_sdk></li><li>If your SDK is in Program Files(x86): C:/PROGRA~2/<path_to_sdk></li></ul><div>Edit (20110711 1943): A bug has already been filed for this issue. Star to be notified of updates.</div></div>

~1 min read

Passing complex objects to another Activity

Several months ago, I was faced with a problem of passing a complex object to another Activity. There are several ways of doing this:
<ul><li>“Deconstructing” the complex object to simple data types and passing them as extras through putExtra()</li><li>Making the object Parcelable</li><li>Making the object Serializable</li></ul>I don’t really understand the concepts behind an object being Parcelable or Serializable, so I was not comfortable using that approach. Deconstructing the object, on the other hand, is easier but it is quite hard to manage as the number of fields in the object increases.

And then I came across another solution: using Bundles. In this post, I will try to explain how to do that.

In this sample project, we want to pass an instance of an AttendeeObject from our main activity to another. To better illustrate how we can use this method for different data types, an AttendeeObject will hold three pieces of information: a String name, an integer age, and a boolean indicating the person’s presence.

First, we construct the AttendeeObject like any old POJO. Create all the fields you want the object to contain and generate getters and setters for each. We then create the methods we would need to be able to pass, and subsequently receive, this object between activities.

To pass an AttendeeObject, we would need to put it in a Bundle and pass it using Intent#putExtra(String key, Bundle bundle).
<pre class="brush:java">public Bundle bundleAttendee(AttendeeObject attendee){
Bundle bundle = new Bundle();
bundle.putString(NAME, attendee.getName());
bundle.putInt(AGE, attendee.getAge());
bundle.putBoolean(PRESENCE, attendee.isPresent());

return bundle;
}</pre>Here, we simply put into a Bundle the values in the object that we want to pass.

Next, we should be able to convert this bundle back to an AttendeeObject in the receiving Activity. This task is done by the following method:
<pre class="brush:java">public AttendeeObject unBundleAttendee(Bundle attendeeBundle){
AttendeeObject attendee = new AttendeeObject();
attendee.setName(attendeeBundle.getString(NAME));
attendee.setAge(attendeeBundle.getInt(AGE));
attendee.setIsPresent(attendeeBundle.getBoolean(PRESENCE));

return attendee;
}</pre>Now, we are ready to use this in our application. I created a simple app that asks the user for the three values we would need to populate AttendeeObject.
I won’t discuss the details of creating the layout file, but it might be worthy to note that the possible values for the Spinner are just “Yes” and “No”.

When the user clicks on the “Create Attendee” button, the application creates a new AttendeeObject based on the values in the form and adds this to an ArrayList of AttendeeObjects.
<pre class="brush:java">private void onCreateAttendee() {
// Create a new AttendeeObject
AttendeeObject attendee = new AttendeeObject();
attendee.setName(mNameText.getText().toString());
attendee.setAge(Integer.valueOf(mAgeText.getText().toString()));
attendee.setIsPresent(mCurrentPresence);

// You can then do whatever you want with this object
// like adding it to an ArrayList or saving it to a database
mAttendees.add(attendee);

Toast.makeText(ComplexObjectDemo.this, “Attendee added!”, Toast.LENGTH_SHORT).show();
}</pre>
When the user clicks on the “Submit Attendee” button, the app “packages” the chosen value into a Bundle and sets it as an extra to the Intent. For illustration purposes, the application always gets the second AttendeeObject in the ArrayList.
<pre class="brush:java">private void onSubmitObject() {
Intent intent = new Intent(ComplexObjectDemo.this, ComplexObjectReceiverDemo.class);

// For simplicity, we will always get the second value
Bundle value = createAttendeeBundle(1);

// In a “real” application, the Key should be defined in a constants file
intent.putExtra(“test.complex.attendee”, value);

startActivity(intent);
}

private Bundle createAttendeeBundle(int index) {
// Here, mAttendee is an instance of AttendeeObject
// and mAttendees is an ArrayList holding all the created attendees
return mAttendee.bundleAttendee(mAttendees.get(index));
}</pre>

Upon receiving the Intent, the new activity simply displays the values in the AttendeeObject passed into it. Here’s how we can “unbundle” the Bundle:
<pre class="brush:java">@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_complex_demo_receiver);

// Get the extras passed to this Activity
setUpViews(getIntent().getExtras());
}

private void setUpViews(Bundle extras) {
// Again, the key should be in a constants file!
Bundle extraAttendee = extras.getBundle(“test.complex.attendee”);

AttendeeObject attendee = new AttendeeObject();

// Deconstruct the Bundle into the AttendeeObject
attendee = attendee.unBundleAttendee(extraAttendee);

// The AttendeeObject fields are now populated, so we set the texts
((TextView) findViewById(R.id.attendee_age_value))
.setText(String.valueOf(attendee.getAge()));
((TextView) findViewById(R.id.attendee_name_value))
.setText(attendee.getName());
((TextView) findViewById(R.id.attendee_presence_value))
.setText(String.valueOf(attendee.isPresent()));
}</pre>Here’s how the receiving activity looks like:Here’s the complete AttendeeObject class.
<pre class="brush:java; collapse:true">package droidista.example;

import android.os.Bundle;

public class AttendeeObject {

public static final String NAME = “attendee.name”;
public static final String AGE = “attendee.age”;
public static final String PRESENCE = “attendee.presence”;


private String mName;
private int mAge;
private boolean mIsPresent;

public AttendeeObject(){

}

public Bundle bundleAttendee(AttendeeObject attendee){
Bundle bundle = new Bundle();
bundle.putString(NAME, attendee.getName());
bundle.putInt(AGE, attendee.getAge());
bundle.putBoolean(PRESENCE, attendee.isPresent());

return bundle;
}

public AttendeeObject unBundleAttendee(Bundle attendeeBundle){
AttendeeObject attendee = new AttendeeObject();
attendee.setName(attendeeBundle.getString(NAME));
attendee.setAge(attendeeBundle.getInt(AGE));
attendee.setIsPresent(attendeeBundle.getBoolean(PRESENCE));

return attendee;
}

public String getName() {
return mName;
}

public void setName(String name) {
this.mName = name;
}

public int getAge() {
return mAge;
}

public void setAge(int age) {
this.mAge = age;
}

public boolean isPresent() {
return mIsPresent;
}

public void setIsPresent(boolean isPresent) {
this.mIsPresent = isPresent;
}
}</pre>And our main activity:
<pre class="brush:java; collapse:true">package droidista.example;

import java.util.ArrayList;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Spinner;
import android.widget.Toast;
import android.widget.AdapterView.OnItemSelectedListener;

public class ComplexObjectDemo extends Activity implements OnClickListener {

private Button mGoToNextIntent, mCreateAttendee, mClearFields;
private EditText mNameText, mAgeText;
private Spinner mPresence;

AttendeeObject mAttendee = new AttendeeObject();

private boolean mCurrentPresence;

private ArrayList<AttendeeObject> mAttendees = new ArrayList<AttendeeObject>();

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_complex_demo);

setUpViews();
}

private void setUpViews() {
setUpSpinner();

mNameText = (EditText)findViewById(R.id.name_text_input);
mAgeText = (EditText)findViewById(R.id.age_text_input);

mGoToNextIntent = (Button)findViewById(R.id.btn_submit_object);
mGoToNextIntent.setOnClickListener(this);

mCreateAttendee = (Button)findViewById(R.id.btn_create_attendee);
mCreateAttendee.setOnClickListener(this);

mClearFields = (Button) findViewById(R.id.btn_clear_fields);
mClearFields.setOnClickListener(this);
}

private void setUpSpinner() {
mPresence = (Spinner) findViewById(R.id.presence_spinner);
ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(
this, R.array.is_present_values, android.R.layout.simple_spinner_item);
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
mPresence.setAdapter(adapter);
}


private Bundle createAttendeeBundle(int index) {
// Here, mAttendee is an instance of AttendeeObject
// and mAttendees is an ArrayList holding all the created attendees
return mAttendee.bundleAttendee(mAttendees.get(index));
}

public void onClick(View v) {
switch(v.getId()){
case R.id.btn_create_attendee:
onCreateAttendee();
break;
case R.id.btn_submit_object:
onSubmitObject();
break;
case R.id.btn_clear_fields:
onClearFields();
break;
}
}

private void onClearFields() {
mAgeText.setText(“”);
mNameText.setText(“”);
mPresence.setSelection(0);
}

private void onSubmitObject() {

// For simplicity, we will always get the second value
Bundle value = createAttendeeBundle(1);

// In a “real” application, the Key should be defined in a constants file
Intent intent = new Intent(ComplexObjectDemo.this, ComplexObjectReceiverDemo.class);
intent.putExtra(“test.complex.attendee”, value);

// Start the new activity
startActivity(intent);
}

private void onCreateAttendee() {
// Create a new AttendeeObject
AttendeeObject attendee = new AttendeeObject();
attendee.setName(mNameText.getText().toString());
attendee.setAge(Integer.valueOf(mAgeText.getText().toString()));
attendee.setIsPresent(mCurrentPresence);

// You can then do whatever you want with this object
// like adding it to an ArrayList or saving it to a database
mAttendees.add(attendee);

// Notify the user
Toast.makeText(ComplexObjectDemo.this, “Attendee added!”, Toast.LENGTH_SHORT).show();
}

public class MyOnItemSelectedListener implements OnItemSelectedListener {

public void onItemSelected(AdapterView parent, View view, int pos, long id) {
mCurrentPresence = (pos==0) ? true : false;
}

public void onNothingSelected(AdapterView parent) { /Do nothing./ }
}
}</pre>And here’s the second activity:
<pre class="brush:java; collapse:true">package droidista.example;

import android.app.Activity;
import android.os.Bundle;
import android.widget.TextView;

public class ComplexObjectReceiverDemo extends Activity {

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_complex_demo_receiver);

// Get the extras passed to this Activity
setUpViews(getIntent().getExtras());
}

private void setUpViews(Bundle extras) {
// Again, the key should be in a constants file!
Bundle extraAttendee = extras.getBundle(“test.complex.attendee”);
AttendeeObject attendee = new AttendeeObject();

// Deconstruct the Bundle into the AttendeeObject
attendee = attendee.unBundleAttendee(extraAttendee);

// The AttendeeObject fields are now populated, so we set the texts
((TextView) findViewById(R.id.attendee_age_value)).setText(String.valueOf(attendee.getAge()));
((TextView) findViewById(R.id.attendee_name_value)).setText(attendee.getName());
((TextView) findViewById(R.id.attendee_presence_value)).setText(String.valueOf(attendee.isPresent()));
}

}</pre>

5 min read
Back to Top ↑

intents

Passing complex objects to another Activity

Several months ago, I was faced with a problem of passing a complex object to another Activity. There are several ways of doing this:
<ul><li>“Deconstructing” the complex object to simple data types and passing them as extras through putExtra()</li><li>Making the object Parcelable</li><li>Making the object Serializable</li></ul>I don’t really understand the concepts behind an object being Parcelable or Serializable, so I was not comfortable using that approach. Deconstructing the object, on the other hand, is easier but it is quite hard to manage as the number of fields in the object increases.

And then I came across another solution: using Bundles. In this post, I will try to explain how to do that.

In this sample project, we want to pass an instance of an AttendeeObject from our main activity to another. To better illustrate how we can use this method for different data types, an AttendeeObject will hold three pieces of information: a String name, an integer age, and a boolean indicating the person’s presence.

First, we construct the AttendeeObject like any old POJO. Create all the fields you want the object to contain and generate getters and setters for each. We then create the methods we would need to be able to pass, and subsequently receive, this object between activities.

To pass an AttendeeObject, we would need to put it in a Bundle and pass it using Intent#putExtra(String key, Bundle bundle).
<pre class="brush:java">public Bundle bundleAttendee(AttendeeObject attendee){
Bundle bundle = new Bundle();
bundle.putString(NAME, attendee.getName());
bundle.putInt(AGE, attendee.getAge());
bundle.putBoolean(PRESENCE, attendee.isPresent());

return bundle;
}</pre>Here, we simply put into a Bundle the values in the object that we want to pass.

Next, we should be able to convert this bundle back to an AttendeeObject in the receiving Activity. This task is done by the following method:
<pre class="brush:java">public AttendeeObject unBundleAttendee(Bundle attendeeBundle){
AttendeeObject attendee = new AttendeeObject();
attendee.setName(attendeeBundle.getString(NAME));
attendee.setAge(attendeeBundle.getInt(AGE));
attendee.setIsPresent(attendeeBundle.getBoolean(PRESENCE));

return attendee;
}</pre>Now, we are ready to use this in our application. I created a simple app that asks the user for the three values we would need to populate AttendeeObject.
I won’t discuss the details of creating the layout file, but it might be worthy to note that the possible values for the Spinner are just “Yes” and “No”.

When the user clicks on the “Create Attendee” button, the application creates a new AttendeeObject based on the values in the form and adds this to an ArrayList of AttendeeObjects.
<pre class="brush:java">private void onCreateAttendee() {
// Create a new AttendeeObject
AttendeeObject attendee = new AttendeeObject();
attendee.setName(mNameText.getText().toString());
attendee.setAge(Integer.valueOf(mAgeText.getText().toString()));
attendee.setIsPresent(mCurrentPresence);

// You can then do whatever you want with this object
// like adding it to an ArrayList or saving it to a database
mAttendees.add(attendee);

Toast.makeText(ComplexObjectDemo.this, “Attendee added!”, Toast.LENGTH_SHORT).show();
}</pre>
When the user clicks on the “Submit Attendee” button, the app “packages” the chosen value into a Bundle and sets it as an extra to the Intent. For illustration purposes, the application always gets the second AttendeeObject in the ArrayList.
<pre class="brush:java">private void onSubmitObject() {
Intent intent = new Intent(ComplexObjectDemo.this, ComplexObjectReceiverDemo.class);

// For simplicity, we will always get the second value
Bundle value = createAttendeeBundle(1);

// In a “real” application, the Key should be defined in a constants file
intent.putExtra(“test.complex.attendee”, value);

startActivity(intent);
}

private Bundle createAttendeeBundle(int index) {
// Here, mAttendee is an instance of AttendeeObject
// and mAttendees is an ArrayList holding all the created attendees
return mAttendee.bundleAttendee(mAttendees.get(index));
}</pre>

Upon receiving the Intent, the new activity simply displays the values in the AttendeeObject passed into it. Here’s how we can “unbundle” the Bundle:
<pre class="brush:java">@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_complex_demo_receiver);

// Get the extras passed to this Activity
setUpViews(getIntent().getExtras());
}

private void setUpViews(Bundle extras) {
// Again, the key should be in a constants file!
Bundle extraAttendee = extras.getBundle(“test.complex.attendee”);

AttendeeObject attendee = new AttendeeObject();

// Deconstruct the Bundle into the AttendeeObject
attendee = attendee.unBundleAttendee(extraAttendee);

// The AttendeeObject fields are now populated, so we set the texts
((TextView) findViewById(R.id.attendee_age_value))
.setText(String.valueOf(attendee.getAge()));
((TextView) findViewById(R.id.attendee_name_value))
.setText(attendee.getName());
((TextView) findViewById(R.id.attendee_presence_value))
.setText(String.valueOf(attendee.isPresent()));
}</pre>Here’s how the receiving activity looks like:Here’s the complete AttendeeObject class.
<pre class="brush:java; collapse:true">package droidista.example;

import android.os.Bundle;

public class AttendeeObject {

public static final String NAME = “attendee.name”;
public static final String AGE = “attendee.age”;
public static final String PRESENCE = “attendee.presence”;


private String mName;
private int mAge;
private boolean mIsPresent;

public AttendeeObject(){

}

public Bundle bundleAttendee(AttendeeObject attendee){
Bundle bundle = new Bundle();
bundle.putString(NAME, attendee.getName());
bundle.putInt(AGE, attendee.getAge());
bundle.putBoolean(PRESENCE, attendee.isPresent());

return bundle;
}

public AttendeeObject unBundleAttendee(Bundle attendeeBundle){
AttendeeObject attendee = new AttendeeObject();
attendee.setName(attendeeBundle.getString(NAME));
attendee.setAge(attendeeBundle.getInt(AGE));
attendee.setIsPresent(attendeeBundle.getBoolean(PRESENCE));

return attendee;
}

public String getName() {
return mName;
}

public void setName(String name) {
this.mName = name;
}

public int getAge() {
return mAge;
}

public void setAge(int age) {
this.mAge = age;
}

public boolean isPresent() {
return mIsPresent;
}

public void setIsPresent(boolean isPresent) {
this.mIsPresent = isPresent;
}
}</pre>And our main activity:
<pre class="brush:java; collapse:true">package droidista.example;

import java.util.ArrayList;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Spinner;
import android.widget.Toast;
import android.widget.AdapterView.OnItemSelectedListener;

public class ComplexObjectDemo extends Activity implements OnClickListener {

private Button mGoToNextIntent, mCreateAttendee, mClearFields;
private EditText mNameText, mAgeText;
private Spinner mPresence;

AttendeeObject mAttendee = new AttendeeObject();

private boolean mCurrentPresence;

private ArrayList<AttendeeObject> mAttendees = new ArrayList<AttendeeObject>();

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_complex_demo);

setUpViews();
}

private void setUpViews() {
setUpSpinner();

mNameText = (EditText)findViewById(R.id.name_text_input);
mAgeText = (EditText)findViewById(R.id.age_text_input);

mGoToNextIntent = (Button)findViewById(R.id.btn_submit_object);
mGoToNextIntent.setOnClickListener(this);

mCreateAttendee = (Button)findViewById(R.id.btn_create_attendee);
mCreateAttendee.setOnClickListener(this);

mClearFields = (Button) findViewById(R.id.btn_clear_fields);
mClearFields.setOnClickListener(this);
}

private void setUpSpinner() {
mPresence = (Spinner) findViewById(R.id.presence_spinner);
ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(
this, R.array.is_present_values, android.R.layout.simple_spinner_item);
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
mPresence.setAdapter(adapter);
}


private Bundle createAttendeeBundle(int index) {
// Here, mAttendee is an instance of AttendeeObject
// and mAttendees is an ArrayList holding all the created attendees
return mAttendee.bundleAttendee(mAttendees.get(index));
}

public void onClick(View v) {
switch(v.getId()){
case R.id.btn_create_attendee:
onCreateAttendee();
break;
case R.id.btn_submit_object:
onSubmitObject();
break;
case R.id.btn_clear_fields:
onClearFields();
break;
}
}

private void onClearFields() {
mAgeText.setText(“”);
mNameText.setText(“”);
mPresence.setSelection(0);
}

private void onSubmitObject() {

// For simplicity, we will always get the second value
Bundle value = createAttendeeBundle(1);

// In a “real” application, the Key should be defined in a constants file
Intent intent = new Intent(ComplexObjectDemo.this, ComplexObjectReceiverDemo.class);
intent.putExtra(“test.complex.attendee”, value);

// Start the new activity
startActivity(intent);
}

private void onCreateAttendee() {
// Create a new AttendeeObject
AttendeeObject attendee = new AttendeeObject();
attendee.setName(mNameText.getText().toString());
attendee.setAge(Integer.valueOf(mAgeText.getText().toString()));
attendee.setIsPresent(mCurrentPresence);

// You can then do whatever you want with this object
// like adding it to an ArrayList or saving it to a database
mAttendees.add(attendee);

// Notify the user
Toast.makeText(ComplexObjectDemo.this, “Attendee added!”, Toast.LENGTH_SHORT).show();
}

public class MyOnItemSelectedListener implements OnItemSelectedListener {

public void onItemSelected(AdapterView parent, View view, int pos, long id) {
mCurrentPresence = (pos==0) ? true : false;
}

public void onNothingSelected(AdapterView parent) { /Do nothing./ }
}
}</pre>And here’s the second activity:
<pre class="brush:java; collapse:true">package droidista.example;

import android.app.Activity;
import android.os.Bundle;
import android.widget.TextView;

public class ComplexObjectReceiverDemo extends Activity {

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_complex_demo_receiver);

// Get the extras passed to this Activity
setUpViews(getIntent().getExtras());
}

private void setUpViews(Bundle extras) {
// Again, the key should be in a constants file!
Bundle extraAttendee = extras.getBundle(“test.complex.attendee”);
AttendeeObject attendee = new AttendeeObject();

// Deconstruct the Bundle into the AttendeeObject
attendee = attendee.unBundleAttendee(extraAttendee);

// The AttendeeObject fields are now populated, so we set the texts
((TextView) findViewById(R.id.attendee_age_value)).setText(String.valueOf(attendee.getAge()));
((TextView) findViewById(R.id.attendee_name_value)).setText(attendee.getName());
((TextView) findViewById(R.id.attendee_presence_value)).setText(String.valueOf(attendee.isPresent()));
}

}</pre>

5 min read
Back to Top ↑

adt

Where’s my R.java?

This afternoon, I tried importing an existing project into Eclipse. Doing a Project > Clean usually clears up the R.java not found errors, but this time it didn’t work. I tried re-importing the project, copy-and-pasting it into a new workspace, restarting Eclipse, but the error is still there.

Just a quick note to self: If there is an error in the layout files, resolve that first then Clean.

I find it weird that no more specific error message is presented. Oh well.

~1 min read

ADT 12: Not so shiny after all


For all the shininess that ADT 12 promised, it seems that it also broke one major feature of DDMS: Launching emulators.

After updating to ADT 12, I kept on seeing that error when launching an emulator instance. Restarting Eclipse doesn’t help any.

Anyway, the apparent cause of this error is that ADT 12 has some problems with the SDK location having spaces. If you have already forgotten, it’s in Window > Preferences > Android.

To work around this bug, it is either you move your SDK to a folder in a path without spaces; or, modify the existing path to either of the following:<div><ul><li>If your SDK is in Program Files: C:/PROGRA~1/<path_to_sdk></li><li>If your SDK is in Program Files(x86): C:/PROGRA~2/<path_to_sdk></li></ul><div>Edit (20110711 1943): A bug has already been filed for this issue. Star to be notified of updates.</div></div>

~1 min read
Back to Top ↑

R.java

Adding a float value to your resources

Earlier today, I was trying to figure out how to add a float value to constants file. What I used to do was add a string value in my strings.xml, retrieve the string value, and convert it to float. <pre class="brush:java">float floatFromFile = Float.valueOf(getResources().getString(R.string.my_float));</pre> I was trying out something new but it wasn’t working, so I decided to look for a more accepted solution. Google led me to this StackOverflow question. I was on the right track after all! I think the accepted answer is incomplete, or not clear enough for my purposes. I ended up having this entry in my dimensions.xml file: <pre class="brush:xml"><item name="face_feature_marker_size" type="vals" format="float">2.0</item></pre> And then in my code, I retrieve the value as: <pre class="brush:java">TypedValue tempVal = new TypedValue();
getResources().getValue(R.vals.face_feature_marker_size, tempVal, true);
float markerSize = testVal.getFloat();</pre> I ended up having more lines of code with no idea if this is more optimized. Let me know what you think!

~1 min read

Where’s my R.java?

This afternoon, I tried importing an existing project into Eclipse. Doing a Project > Clean usually clears up the R.java not found errors, but this time it didn’t work. I tried re-importing the project, copy-and-pasting it into a new workspace, restarting Eclipse, but the error is still there.

Just a quick note to self: If there is an error in the layout files, resolve that first then Clean.

I find it weird that no more specific error message is presented. Oh well.

~1 min read
Back to Top ↑

adb

Tools of the Trade: Unabridged

I gave an unabridged version of my last Android Meetup talk at this year’s YOW Conference. It has been an honour being part of this awesome conference!

~1 min read

Save Logcat contents to file

Note to self: to save the contents of Logcat to a text file:
<ol><li>Navigate to the SDK installation directory.</li><li>Go to the /platform-tools folder.</li><li>adb logcat -d > my_logcat_dump.txt</li></ol><div>If there is more than one device connected to adb, specify which device’s log to dump:</div><div><blockquote class="tr_bq">adb -s emulator-5558 logcat -d > my_logcat_dump.txt</blockquote></div>

~1 min read
Back to Top ↑

viewpagerindicator

Styling tab selectors for ActionBarSherlock

This post builds on the previous post for ABS + VPI.

I have gotten a lot of questions on styling the ABS, specifically the tab selected indicators. This task may seem daunting, but in reality it is relatively simple. I am also quite confused why I didn’t find any straightforward tutorials when I tried googling this. Anyway, this post will hopefully help developers who aim to style their action bars.

We will need to use Jeff Gilfelt’s awesome styling tool. To use it, just input in your app’s color scheme for the highlights and what-not then download the generated zip file. If you want to just change the tab underline color, change the value under “Accent color”. To make the change obvious from the default settings, I have used a shade of orange for the tab selected indicators. Here are the settings I used for this demo.

Jeff’s tool conveniently generates all the XML files and drawables and organizes them into the correct /res/drawable folders. Unzip the file and just drag the generated files into your project, or merge the contents if you already have such existing files.

See how easy it was? Seriously, we should all lie prostrate at Jeff Gilfelt’s and Jake Wharton’s feet. These guys are AWESOME.

The two photos below show the difference between the old app and the styled app. As you can see, I only changed the tab selected color. You can explore what happens if you use the other styles you can get from Jeff’s tool.
<table align="center" cellpadding="10" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody><tr><td style="text-align: center;"></td><td style="text-align: center;"></td></tr><tr><td class="tr-caption" style="text-align: center;">Default</td><td class="tr-caption" style="text-align: center;">Styled</td></tr></tbody></table>The hard work is done, let’s now try to understand the automagically generated configurations we did.

First, we have to configure the theme to use custom tab indicators. We do this by changing the tab styles in themes.xml. In my sample app, these lines customize the tabs we are using.
<pre class="brush:xml"><!– Styling the tabs –>
<style name=”CustomTabPageIndicator” parent=”Widget.TabPageIndicator”>
 <!– Tab text –>
<item name=”android:textSize”>15dip</item>
<item name=”android:textColor”>#FFB33E3E</item>

<!– Lines under tabs –>
<item name=”background”>@drawable/tab_indicator_ab_styling_abs</item>
<item name=”android:background”>@drawable/tab_indicator_ab_styling_abs</item>
</style></pre>
The “drawable” tab_indicator_ab_styling_abs is actually a state list drawable that provides different images for each state of a tab – focused and non-focused, pressed and not pressed.

You can see part of this in action in the image above. Try long pressing on a tab and you can see the tab’s background change to use the unselected-pressed drawable.

Again, HUGE thanks to Jeff Gilfelt and Jake Wharton for creating tools that make our lives easier. :)

I have pushed a new branch in github that uses this style. The master branch of that repo still uses the default tab selectors.

2 min read

Making ActionBarSherlock and ViewPagerIndicator play nice

EDIT (20121227): I made a new post on changing the tab selector underline.
EDIT (20121014): I received feedback from the comments that rotating the device will cause the tab contents to revert to the default text. In essence, the adapter “loses” the contents of the tabs. I have corrected this in the example below as well as in github.
EDIT (20120905): The full sample source code is now in github.

So ViewPagerIndicator cheerfully claims that it works with ActionBarSherlock. I was trying to test this out today and I can’t find a noob-friendly, step-by-step tutorial on how I can do it. I spent almost half a day frantically opening tab after tab in Google Chrome, but nothing seems to straight out say what I should do. So here it is, collated from several StackOverflow answers, blog posts, etc.

Get the ViewPagerIndicator (hereafter referred to as VPI) and ActionBarSherlock (hereafter referred to as ABS) libraries. Create your Android application in Eclipse and add those two projects as dependency library projects. If you do not know how to do that, see here.

First, create a theme. This is required by ABS, and will also help in VPI. What I did was to make the VPI theme inherit from the ABS theme so I don’t lose any of the styles I use in other parts of the app. I just add or override items needed by the ViewPagerIndicator. In this example, I just changed the text size and color of the tab labels. You can go one step further and change the selected tab indicator (via state selectors), change how the selectors are drawn, etc.
<pre class="brush:xml"><resources xmlns:android=”http://schemas.android.com/apk/res/android”>
<!– This is our main ActionBarSherlock theme –>
<style name=”Theme.Styled” parent=”Theme.Sherlock.Light.DarkActionBar”>
<item name=”actionBarStyle”>@style/Widget.Styled.ActionBar</item>
<item name=”android:actionBarStyle”>@style/Widget.Styled.ActionBar</item>
</style><!– This is our ViewPagerIndicator theme. We inherit from the ABS theme –>
<style name=”Theme.VPI” parent=”Theme.Styled”>
<item name=”vpiTabPageIndicatorStyle”>@style/CustomTabPageIndicator</item>
</style>  
<!– “Implementation” of our ABS custom theme –>
<style name=”Widget.Styled.ActionBar” parent=”Widget.Sherlock.Light.ActionBar.Solid.Inverse”>
<item name=”titleTextStyle”>@style/TitleText</item>
<item name=”android:titleTextStyle”>@style/TitleText</item>
</style>

<!– “Implementation” of VPI theme. We just set the text size and color. –>
<style name=”CustomTabPageIndicator” parent=”Widget.TabPageIndicator”>
<item name=”android:textSize”>50dip</item>
<item name=”android:textColor”>#FFB33E3E</item>
</style>

<!– More customizations for ABS –>
<style name=”TitleText” >
<item name=”android:textColor”>@android:color/darker_gray</item>
<item name=”android:textSize”>17dip</item>
</style>
</resources></pre>
Then we create the fragment(s) we need to populate the viewpager. My fragment is a simple layout with just a TextView indicating which tab is being shown.
<pre class="brush:java">public class TestFragment extends SherlockFragment {
private String mContent = “???”;

public static TestFragment newInstance(String text) {
TestFragment fragment = new TestFragment();

// Supply num input as an argument.
Bundle args = new Bundle();
args.putString(KEY_TAB_NUM, text);
fragment.setArguments(args);

return fragment;
}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.activity_main, null);
String text = getString(R.string.tab_page_num) + mContent;
((TextView)view.findViewById(R.id.text)).setText(text);

return view;
}

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mContent = getArguments() != null ? getArguments().getString(KEY_TAB_NUM) : “???”;
}

}</pre>
Then we create the activity that will hold everything together.
<pre class="brush:java">public class VpiAbsTestActivity extends SherlockFragmentActivity {

private static final String[] TAB_TITLES = new String[] { “This”, “Is”, “A”, “ViewPager” };

TestFragmentAdapter mAdapter;
ViewPager mPager;
PageIndicator mIndicator;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);

setContentView(R.layout.simple_tabs);

mAdapter = new TestFragmentAdapter(getSupportFragmentManager());

mPager = (ViewPager)findViewById(R.id.pager);
mPager.setAdapter(mAdapter);

mIndicator = (TabPageIndicator)findViewById(R.id.indicator);
mIndicator.setViewPager(mPager);
}

class TestFragmentAdapter extends FragmentPagerAdapter {
private int mCount = TAB_TITLES.length;

public TestFragmentAdapter(FragmentManager fm) {
super(fm);
}

@Override
public Fragment getItem(int position) {
return TestFragment.newInstance(String.valueOf(position));
}

@Override
public int getCount() {
return mCount;
}

@Override
public CharSequence getPageTitle(int position) {
return TAB_TITLES[position];
}
}
}</pre>And lastly, we apply the ViewPagerIndicator theme to our activity in the manifest:
<pre class="brush:xml"><activity android:name=”VpiAbsTestActivity” android:theme=”@style/Theme.VPI”>
</activity></pre>
As it turns out, it IS pretty straightforward!

2 min read
Back to Top ↑

actionbarsherlock

Styling tab selectors for ActionBarSherlock

This post builds on the previous post for ABS + VPI.

I have gotten a lot of questions on styling the ABS, specifically the tab selected indicators. This task may seem daunting, but in reality it is relatively simple. I am also quite confused why I didn’t find any straightforward tutorials when I tried googling this. Anyway, this post will hopefully help developers who aim to style their action bars.

We will need to use Jeff Gilfelt’s awesome styling tool. To use it, just input in your app’s color scheme for the highlights and what-not then download the generated zip file. If you want to just change the tab underline color, change the value under “Accent color”. To make the change obvious from the default settings, I have used a shade of orange for the tab selected indicators. Here are the settings I used for this demo.

Jeff’s tool conveniently generates all the XML files and drawables and organizes them into the correct /res/drawable folders. Unzip the file and just drag the generated files into your project, or merge the contents if you already have such existing files.

See how easy it was? Seriously, we should all lie prostrate at Jeff Gilfelt’s and Jake Wharton’s feet. These guys are AWESOME.

The two photos below show the difference between the old app and the styled app. As you can see, I only changed the tab selected color. You can explore what happens if you use the other styles you can get from Jeff’s tool.
<table align="center" cellpadding="10" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody><tr><td style="text-align: center;"></td><td style="text-align: center;"></td></tr><tr><td class="tr-caption" style="text-align: center;">Default</td><td class="tr-caption" style="text-align: center;">Styled</td></tr></tbody></table>The hard work is done, let’s now try to understand the automagically generated configurations we did.

First, we have to configure the theme to use custom tab indicators. We do this by changing the tab styles in themes.xml. In my sample app, these lines customize the tabs we are using.
<pre class="brush:xml"><!– Styling the tabs –>
<style name=”CustomTabPageIndicator” parent=”Widget.TabPageIndicator”>
 <!– Tab text –>
<item name=”android:textSize”>15dip</item>
<item name=”android:textColor”>#FFB33E3E</item>

<!– Lines under tabs –>
<item name=”background”>@drawable/tab_indicator_ab_styling_abs</item>
<item name=”android:background”>@drawable/tab_indicator_ab_styling_abs</item>
</style></pre>
The “drawable” tab_indicator_ab_styling_abs is actually a state list drawable that provides different images for each state of a tab – focused and non-focused, pressed and not pressed.

You can see part of this in action in the image above. Try long pressing on a tab and you can see the tab’s background change to use the unselected-pressed drawable.

Again, HUGE thanks to Jeff Gilfelt and Jake Wharton for creating tools that make our lives easier. :)

I have pushed a new branch in github that uses this style. The master branch of that repo still uses the default tab selectors.

2 min read

Making ActionBarSherlock and ViewPagerIndicator play nice

EDIT (20121227): I made a new post on changing the tab selector underline.
EDIT (20121014): I received feedback from the comments that rotating the device will cause the tab contents to revert to the default text. In essence, the adapter “loses” the contents of the tabs. I have corrected this in the example below as well as in github.
EDIT (20120905): The full sample source code is now in github.

So ViewPagerIndicator cheerfully claims that it works with ActionBarSherlock. I was trying to test this out today and I can’t find a noob-friendly, step-by-step tutorial on how I can do it. I spent almost half a day frantically opening tab after tab in Google Chrome, but nothing seems to straight out say what I should do. So here it is, collated from several StackOverflow answers, blog posts, etc.

Get the ViewPagerIndicator (hereafter referred to as VPI) and ActionBarSherlock (hereafter referred to as ABS) libraries. Create your Android application in Eclipse and add those two projects as dependency library projects. If you do not know how to do that, see here.

First, create a theme. This is required by ABS, and will also help in VPI. What I did was to make the VPI theme inherit from the ABS theme so I don’t lose any of the styles I use in other parts of the app. I just add or override items needed by the ViewPagerIndicator. In this example, I just changed the text size and color of the tab labels. You can go one step further and change the selected tab indicator (via state selectors), change how the selectors are drawn, etc.
<pre class="brush:xml"><resources xmlns:android=”http://schemas.android.com/apk/res/android”>
<!– This is our main ActionBarSherlock theme –>
<style name=”Theme.Styled” parent=”Theme.Sherlock.Light.DarkActionBar”>
<item name=”actionBarStyle”>@style/Widget.Styled.ActionBar</item>
<item name=”android:actionBarStyle”>@style/Widget.Styled.ActionBar</item>
</style><!– This is our ViewPagerIndicator theme. We inherit from the ABS theme –>
<style name=”Theme.VPI” parent=”Theme.Styled”>
<item name=”vpiTabPageIndicatorStyle”>@style/CustomTabPageIndicator</item>
</style>  
<!– “Implementation” of our ABS custom theme –>
<style name=”Widget.Styled.ActionBar” parent=”Widget.Sherlock.Light.ActionBar.Solid.Inverse”>
<item name=”titleTextStyle”>@style/TitleText</item>
<item name=”android:titleTextStyle”>@style/TitleText</item>
</style>

<!– “Implementation” of VPI theme. We just set the text size and color. –>
<style name=”CustomTabPageIndicator” parent=”Widget.TabPageIndicator”>
<item name=”android:textSize”>50dip</item>
<item name=”android:textColor”>#FFB33E3E</item>
</style>

<!– More customizations for ABS –>
<style name=”TitleText” >
<item name=”android:textColor”>@android:color/darker_gray</item>
<item name=”android:textSize”>17dip</item>
</style>
</resources></pre>
Then we create the fragment(s) we need to populate the viewpager. My fragment is a simple layout with just a TextView indicating which tab is being shown.
<pre class="brush:java">public class TestFragment extends SherlockFragment {
private String mContent = “???”;

public static TestFragment newInstance(String text) {
TestFragment fragment = new TestFragment();

// Supply num input as an argument.
Bundle args = new Bundle();
args.putString(KEY_TAB_NUM, text);
fragment.setArguments(args);

return fragment;
}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.activity_main, null);
String text = getString(R.string.tab_page_num) + mContent;
((TextView)view.findViewById(R.id.text)).setText(text);

return view;
}

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mContent = getArguments() != null ? getArguments().getString(KEY_TAB_NUM) : “???”;
}

}</pre>
Then we create the activity that will hold everything together.
<pre class="brush:java">public class VpiAbsTestActivity extends SherlockFragmentActivity {

private static final String[] TAB_TITLES = new String[] { “This”, “Is”, “A”, “ViewPager” };

TestFragmentAdapter mAdapter;
ViewPager mPager;
PageIndicator mIndicator;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);

setContentView(R.layout.simple_tabs);

mAdapter = new TestFragmentAdapter(getSupportFragmentManager());

mPager = (ViewPager)findViewById(R.id.pager);
mPager.setAdapter(mAdapter);

mIndicator = (TabPageIndicator)findViewById(R.id.indicator);
mIndicator.setViewPager(mPager);
}

class TestFragmentAdapter extends FragmentPagerAdapter {
private int mCount = TAB_TITLES.length;

public TestFragmentAdapter(FragmentManager fm) {
super(fm);
}

@Override
public Fragment getItem(int position) {
return TestFragment.newInstance(String.valueOf(position));
}

@Override
public int getCount() {
return mCount;
}

@Override
public CharSequence getPageTitle(int position) {
return TAB_TITLES[position];
}
}
}</pre>And lastly, we apply the ViewPagerIndicator theme to our activity in the manifest:
<pre class="brush:xml"><activity android:name=”VpiAbsTestActivity” android:theme=”@style/Theme.VPI”>
</activity></pre>
As it turns out, it IS pretty straightforward!

2 min read
Back to Top ↑

style

Stylish Dynamic Layouts

One of the things we are taught in Android is that we should gracefully handle different layouts based on screen sizes. With more and more things being not just screen size-specific but also OS version-specific, this is one thing I think a lot more devs need to pay attention to. Today was my turn to do just that.

2 min read

Styling tab selectors for ActionBarSherlock

This post builds on the previous post for ABS + VPI.

I have gotten a lot of questions on styling the ABS, specifically the tab selected indicators. This task may seem daunting, but in reality it is relatively simple. I am also quite confused why I didn’t find any straightforward tutorials when I tried googling this. Anyway, this post will hopefully help developers who aim to style their action bars.

We will need to use Jeff Gilfelt’s awesome styling tool. To use it, just input in your app’s color scheme for the highlights and what-not then download the generated zip file. If you want to just change the tab underline color, change the value under “Accent color”. To make the change obvious from the default settings, I have used a shade of orange for the tab selected indicators. Here are the settings I used for this demo.

Jeff’s tool conveniently generates all the XML files and drawables and organizes them into the correct /res/drawable folders. Unzip the file and just drag the generated files into your project, or merge the contents if you already have such existing files.

See how easy it was? Seriously, we should all lie prostrate at Jeff Gilfelt’s and Jake Wharton’s feet. These guys are AWESOME.

The two photos below show the difference between the old app and the styled app. As you can see, I only changed the tab selected color. You can explore what happens if you use the other styles you can get from Jeff’s tool.
<table align="center" cellpadding="10" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody><tr><td style="text-align: center;"></td><td style="text-align: center;"></td></tr><tr><td class="tr-caption" style="text-align: center;">Default</td><td class="tr-caption" style="text-align: center;">Styled</td></tr></tbody></table>The hard work is done, let’s now try to understand the automagically generated configurations we did.

First, we have to configure the theme to use custom tab indicators. We do this by changing the tab styles in themes.xml. In my sample app, these lines customize the tabs we are using.
<pre class="brush:xml"><!– Styling the tabs –>
<style name=”CustomTabPageIndicator” parent=”Widget.TabPageIndicator”>
 <!– Tab text –>
<item name=”android:textSize”>15dip</item>
<item name=”android:textColor”>#FFB33E3E</item>

<!– Lines under tabs –>
<item name=”background”>@drawable/tab_indicator_ab_styling_abs</item>
<item name=”android:background”>@drawable/tab_indicator_ab_styling_abs</item>
</style></pre>
The “drawable” tab_indicator_ab_styling_abs is actually a state list drawable that provides different images for each state of a tab – focused and non-focused, pressed and not pressed.

You can see part of this in action in the image above. Try long pressing on a tab and you can see the tab’s background change to use the unselected-pressed drawable.

Again, HUGE thanks to Jeff Gilfelt and Jake Wharton for creating tools that make our lives easier. :)

I have pushed a new branch in github that uses this style. The master branch of that repo still uses the default tab selectors.

2 min read
Back to Top ↑

ux

Troubleshooting autoVerify

So you implement app links and you are 300% sure you have implemented everything correctly. The important thing to remember here is that verification is all or nothing. From the docs:

2 min read

A Little UX Love Goes A Long Way

Yesterday, my bank pushed a notification asking if I’m going to travel. Yes! I am! I filled up the form they asked me to fill up, and tapped Submit.

2 min read
Back to Top ↑

speaking

Back to Top ↑

conference

Back to Top ↑

anti-stress

It’s so fluffyyyyyyyyy!!!

<img src=http://www.despicable.me/pops/minionMaker/userpics/910156207.jpg width=”380” height=”473” alt=”I’ve created a Minion to join Gru’s Minion army.” />

~1 min read
Back to Top ↑

import project

Back to Top ↑

decimal

More plurals: decimal values

In my previous post, I showed you how to set string plurals. If you noticed, the methods to get the plurals strings only accept ints. What if (like me) you want to display a decimal value? I am getting my raw value from a progress bar with a range of 1-10, with 0.1 increments.

1 min read
Back to Top ↑

hierarchyviewer

Missing hierarchyviewer in SDK 7

If you have SDK version 7, you are most probably missing the hierarchyviewer from your /tools folder. To check your SDK version, launch the SDK manager UI from your installation path, usually C:\android-sdk-windows, then click About.
To run hierarchyviewer, you need to manually create the </code>hierarchyviewer.bat</code> file and add it to your <install_path>/tools directory. The text of the batch file can be copied from here.

And so, you can now run hierarchyviewer as you would if the SDK release isn’t effed up. Don’t know how to run it? Follow these steps:
a. In Windows, open up a terminal by running cmd.
b. Navigate to your SDK’s install path. Since I installed mine in C:\, I would have to type in cd C:\android-sdk-windows\tools
c. Type in hierarchyviewer at the prompt.

~1 min read
Back to Top ↑

autoadjust

TextView and MaxLines

I have a TextView (who doesn’t?) and I want to adjust its height automatically, depending on the length of the text it will contain. Should be easy. It was, but it took me a couple of minutes to figure it out.<div>
</div><div>So I want my TextView to be by default one line tall, but be able to expand up to two lines. My initial set up was to set lines=1 and maxLines=2, but it was making the TextView always two lines. Not what I wanted! I went through the documentation again, read each word carefully, and then:
<pre class="brush:xml"><TextView android:id=”@+id/title”
android:layout_height=”wrap_content”
android:layout_width=”fill_parent”
android:ellipsize=”end”
android:maxLines=”2”
android:minLines=”1”
android:text=”This is the text” /></pre>So it turned out that you have to set both minLines and maxLines. TADA!</div>

~1 min read
Back to Top ↑

maxlines

TextView and MaxLines

I have a TextView (who doesn’t?) and I want to adjust its height automatically, depending on the length of the text it will contain. Should be easy. It was, but it took me a couple of minutes to figure it out.<div>
</div><div>So I want my TextView to be by default one line tall, but be able to expand up to two lines. My initial set up was to set lines=1 and maxLines=2, but it was making the TextView always two lines. Not what I wanted! I went through the documentation again, read each word carefully, and then:
<pre class="brush:xml"><TextView android:id=”@+id/title”
android:layout_height=”wrap_content”
android:layout_width=”fill_parent”
android:ellipsize=”end”
android:maxLines=”2”
android:minLines=”1”
android:text=”This is the text” /></pre>So it turned out that you have to set both minLines and maxLines. TADA!</div>

~1 min read
Back to Top ↑

grammar error

What grammar?

My OC side was alarmed when suddenly, my Problems view in Eclipse was filled with warnings on my XML files. Each of my XML files had a warning with it, and that little yellow exclamation mark on the side:<div>No grammar constraints (DTD or XML schema) detected for the document</div><div>
</div><div>So how do you get rid of it? Go to Window > Preferences > XML > XML Files > Validation then set Indicate when no grammar is specified to Ignore. Click on Apply.</div><div>
</div><div>Clean up your project (Project > Clean). </div><div>
</div><div>If the problem doesn’t go away, you may need to re-validate the XML files. Right click on the file then choose Validate from the popup menu. You can also right click on the folder (such as your res folder) and validate from there.</div>

~1 min read
Back to Top ↑

thumboffset

That damn seekbar thumb

If you have ever needed to use a SeekBar, you definitely would have noticed how hard it is to move the slider (aka thumb) when it is set to the minimum or maximum value. The slider tends to be cut in half, and fitting your finger into it to press it becomes a test of patience.<div></div>
See how small the slider becomes when it reaches the far ends of the SeekBar? Crazy!

Luckily, I found a way (just today!) to move the slider just a little tiny bit to make it easier to press. Apparently, there is a method called setThumbOffset() that allows us to nudge the slider by a number of pixels.

It’s pretty easy to use, aside from the fact that it accepts pixels and not dip measurements. Anyway, here’s how to do it:<pre class="brush:java">int pixels = convertDipToPixels(8f);
SeekBar mySeekBar = (SeekBar) findViewById(R.id.quiz_settings_seekbar);
mySeekBar.setOnSeekBarChangeListener(mySeekBarListener);
mySeekBar.setThumbOffset(pixels);</pre>I convert dip measurements to pixels to better manage the growing number of resolutions of screen sizes present. Here’s the code to do that:<pre class="brush:java">private int convertDipToPixels(float dip) {
DisplayMetrics metrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(metrics);
float density = metrics.density;
return (int)(dip * density);
}</pre>Aaaaaaaand this is now how our slider looks:Applause! Confetti! Applause!

~1 min read
Back to Top ↑

slider

That damn seekbar thumb

If you have ever needed to use a SeekBar, you definitely would have noticed how hard it is to move the slider (aka thumb) when it is set to the minimum or maximum value. The slider tends to be cut in half, and fitting your finger into it to press it becomes a test of patience.<div></div>
See how small the slider becomes when it reaches the far ends of the SeekBar? Crazy!

Luckily, I found a way (just today!) to move the slider just a little tiny bit to make it easier to press. Apparently, there is a method called setThumbOffset() that allows us to nudge the slider by a number of pixels.

It’s pretty easy to use, aside from the fact that it accepts pixels and not dip measurements. Anyway, here’s how to do it:<pre class="brush:java">int pixels = convertDipToPixels(8f);
SeekBar mySeekBar = (SeekBar) findViewById(R.id.quiz_settings_seekbar);
mySeekBar.setOnSeekBarChangeListener(mySeekBarListener);
mySeekBar.setThumbOffset(pixels);</pre>I convert dip measurements to pixels to better manage the growing number of resolutions of screen sizes present. Here’s the code to do that:<pre class="brush:java">private int convertDipToPixels(float dip) {
DisplayMetrics metrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(metrics);
float density = metrics.density;
return (int)(dip * density);
}</pre>Aaaaaaaand this is now how our slider looks:Applause! Confetti! Applause!

~1 min read
Back to Top ↑

css

Using a custom font in WebView

In one of my projects, I needed to display some special characters that the Android OS by itself cannot seem to render. I figured that I would need to provide a custom font that includes the characters that I needed.

If I was using a TextView, I could use TextView#setTypeFace. But I was using a WebView and I feared that things would be more complicated than that. So how do I do this?

Here’s how we can make it work.

Step 1: We would need to have our font face included in our project’s /assets folder. So look for a TTF file that you can use freely, make sure the author/creator allows you to re-distribute it!

Step 2: Edit your HTML file to include some CSS stuff, just so the WebView would know what font you want to use. Here’s a sample file: <pre class="brush:xml"><html><head><link href=”YourCssFile.css” rel=”stylesheet” type=”text/css” /></head><body><span class=”phon”>This string contains special characters: əˈpåstrəfi </span></body></html></pre>Make sure that the href references are correct. In this case, my CSS file, HTML file and font file are in the same folder.

Step 3: Define your CSS file. In this case, our YourCssFile.css would be:<pre class="brush:css">@font-face {
font-family: “My font”;
src: url(‘MyFontFile.TTF’);
}

.phon, .unicode {
display: inline;
font-family: ‘My font’, Verdana, sans-serif;
font-size: 14pt;
font-weight: 500;
font-style:normal;
color: black;
}</pre>Step 4: Load the file in your WebView! You can use <pre class="brush:java">WebView webView = (WebView) findViewById(R.id.myWebview);
webView.loadUrl(“path/to/html/file”);</pre> or <pre class="brush:java">webView.loadDataWithBaseURL(“file:///android_asset/”,
article, “text/html”, Encoding.UTF_8.toString(), null);</pre>If you will use the second option, your article variable would contain the HTML string. Just make sure that you escape your quotation marks with a backslash ().
<blockquote><blockquote>IMPORTANT NOTE: This feature seems to be broken in Android 2.0 and 2.1, as reported here.</blockquote></blockquote>

1 min read
Back to Top ↑

font

Using a custom font in WebView

In one of my projects, I needed to display some special characters that the Android OS by itself cannot seem to render. I figured that I would need to provide a custom font that includes the characters that I needed.

If I was using a TextView, I could use TextView#setTypeFace. But I was using a WebView and I feared that things would be more complicated than that. So how do I do this?

Here’s how we can make it work.

Step 1: We would need to have our font face included in our project’s /assets folder. So look for a TTF file that you can use freely, make sure the author/creator allows you to re-distribute it!

Step 2: Edit your HTML file to include some CSS stuff, just so the WebView would know what font you want to use. Here’s a sample file: <pre class="brush:xml"><html><head><link href=”YourCssFile.css” rel=”stylesheet” type=”text/css” /></head><body><span class=”phon”>This string contains special characters: əˈpåstrəfi </span></body></html></pre>Make sure that the href references are correct. In this case, my CSS file, HTML file and font file are in the same folder.

Step 3: Define your CSS file. In this case, our YourCssFile.css would be:<pre class="brush:css">@font-face {
font-family: “My font”;
src: url(‘MyFontFile.TTF’);
}

.phon, .unicode {
display: inline;
font-family: ‘My font’, Verdana, sans-serif;
font-size: 14pt;
font-weight: 500;
font-style:normal;
color: black;
}</pre>Step 4: Load the file in your WebView! You can use <pre class="brush:java">WebView webView = (WebView) findViewById(R.id.myWebview);
webView.loadUrl(“path/to/html/file”);</pre> or <pre class="brush:java">webView.loadDataWithBaseURL(“file:///android_asset/”,
article, “text/html”, Encoding.UTF_8.toString(), null);</pre>If you will use the second option, your article variable would contain the HTML string. Just make sure that you escape your quotation marks with a backslash ().
<blockquote><blockquote>IMPORTANT NOTE: This feature seems to be broken in Android 2.0 and 2.1, as reported here.</blockquote></blockquote>

1 min read
Back to Top ↑

webview

Using a custom font in WebView

In one of my projects, I needed to display some special characters that the Android OS by itself cannot seem to render. I figured that I would need to provide a custom font that includes the characters that I needed.

If I was using a TextView, I could use TextView#setTypeFace. But I was using a WebView and I feared that things would be more complicated than that. So how do I do this?

Here’s how we can make it work.

Step 1: We would need to have our font face included in our project’s /assets folder. So look for a TTF file that you can use freely, make sure the author/creator allows you to re-distribute it!

Step 2: Edit your HTML file to include some CSS stuff, just so the WebView would know what font you want to use. Here’s a sample file: <pre class="brush:xml"><html><head><link href=”YourCssFile.css” rel=”stylesheet” type=”text/css” /></head><body><span class=”phon”>This string contains special characters: əˈpåstrəfi </span></body></html></pre>Make sure that the href references are correct. In this case, my CSS file, HTML file and font file are in the same folder.

Step 3: Define your CSS file. In this case, our YourCssFile.css would be:<pre class="brush:css">@font-face {
font-family: “My font”;
src: url(‘MyFontFile.TTF’);
}

.phon, .unicode {
display: inline;
font-family: ‘My font’, Verdana, sans-serif;
font-size: 14pt;
font-weight: 500;
font-style:normal;
color: black;
}</pre>Step 4: Load the file in your WebView! You can use <pre class="brush:java">WebView webView = (WebView) findViewById(R.id.myWebview);
webView.loadUrl(“path/to/html/file”);</pre> or <pre class="brush:java">webView.loadDataWithBaseURL(“file:///android_asset/”,
article, “text/html”, Encoding.UTF_8.toString(), null);</pre>If you will use the second option, your article variable would contain the HTML string. Just make sure that you escape your quotation marks with a backslash ().
<blockquote><blockquote>IMPORTANT NOTE: This feature seems to be broken in Android 2.0 and 2.1, as reported here.</blockquote></blockquote>

1 min read
Back to Top ↑

ScrollView

My EditText is cut off by the on-screen keyboard!

With clients demanding left and right that my app should look like an iPhone app, I tend to be unappreciative of the way Android natively handles UI interactions and such. Notice how the screen automagically scrolls up when you click on an EditText? It turns out that in iPhone development, the developer does this manually (indicate how much the view should scroll when the on-screen keyboard appears, then scroll it back down afterwards). HA!

But even magic fails sometimes. Has this ever happened to you?
<img style=”display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 134px; height: 200px;” src=”http://3.bp.blogspot.com/-JftkETrkB2c/TZlrHJOji5I/AAAAAAAAA4I/cX4jSBJRiGY/s200/edittext_hidden.png” border=”0” alt=”“id=”BLOGGER_PHOTO_ID_5591618182837406610” />
The bottommost EditText is cut off. And we don’t want that!

So what do we do? Do we programmatically scroll the view up? I don’t want to do that! It turns out that we can just wrap the whole view in a ScrollView and it will scroll up properly!
<img style=”display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 134px; height: 200px;” src=”http://1.bp.blogspot.com/-J2UCMLF_E3k/TZlrk_lKBdI/AAAAAAAAA4Q/c7G321XalBo/s200/edittext_shown.png” border=”0” alt=”“id=”BLOGGER_PHOTO_ID_5591618695643923922” />

The only downside to this is that you might want to hide the scrollbar when the view moves up to accommodate the on-screen keyboard. And to do that, I was trying to set the android:scrollbars=”none” attribute but for one reason or another the scrollbar is still being drawn. To make the scrollbar disappear, we can do it from code as such:<pre class="brush:java">((ScrollView)findViewById(R.id.my_scrollview))
.setVerticalScrollBarEnabled(false);</pre>And we’re done!

~1 min read
Back to Top ↑

custom adapter

Using CWAC’s EndlessAdapter with a custom adapter

In one of my projects, the app has the potential to display a very, and I mean very, long list. To minimize the loading time of the app, I limit the number of items initially included in the list and then add to it as the user scrolls down.

For this purpose, Mark Murphy’s EndlessAdapter works wonders. I was trying to make it work with a CursorAdapter though, but due to time constraints, I was not able to continue with my experiment.

And then I found out that some of the items in my list are HTML-formatted. Huh. So I have to have a custom adapter to override getView(). I patterned my code on the demo included in the EndlessAdapter project and I was at a loss. Maybe it’s because I just came from a vacation and my mind refuses to work. Hmmm.

To cut a long and arduous journey short, I was able to figure it out. Here’s a sample activity that displays a list of countries from an array. To illustrate using a custom adapter, I add the list item number when setting the item text.

I will discuss the pertinent parts of the code in detail.
<pre class="brush:java">private void init() {
LIST_SIZE = COUNTRIES.length;
for (int i=0; i<=BATCH_SIZE; i++){
countriesSub.add(COUNTRIES[i]);
}

setLastOffset(BATCH_SIZE);
displayList(countriesSub);
}</pre>In this part of the code, I get the first 10 items in the list as the initial contents of the list. Of course, our current list is small and is peanuts for ListView. This is just to illustrate my point. In my app, I initially load 2,000 items. I also make sure to remember where I am in my source list. In my case, it is the offset in the original array. This might also be a row in the DB, or the ID in an RSS feed.

The ArrayList countriesSub holds the items that are currently in my list. As the user goes through the list, this array will grow.

To display my list, I set an instance of DemoAdapter as my list adapter. DemoAdapter inherits from EndlessAdapter and in its constructor, I give it an instance of my custom ArrayAdapter.
<pre class="brush:java">@Override
public View getView(int position, View convertView, ViewGroup parent) {

ViewHolder holder;

if(convertView==null){
LayoutInflater inflater = (LayoutInflater)
EndlessCustom.this.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = inflater.inflate(android.R.layout.simple_list_item_1, null);
holder = new ViewHolder();
holder.word = (TextView)convertView.findViewById(android.R.id.text1);

convertView.setTag(holder);
} else{
holder=(ViewHolder)convertView.getTag();
}

holder.word.setText(String.valueOf(position+1) + “. “ + countriesSub.get(position));
return convertView;
}</pre>
The important part in my custom ArrayAdapter is the getView() method. In this method, I tell the adapter to not simply display the .toString() value of the item, but to add a number before it.

Notice that I use the ViewHolder pattern as illustrated in the Android Developers site.
<pre class="brush:java; tab-size: 5">DemoAdapter() {
super(new CustomArrayAdapter(EndlessCustom.this,
android.R.layout.simple_list_item_1, android.R.id.text1, countriesSub));

rotate=new RotateAnimation(0f, 360f, Animation.RELATIVE_TO_SELF,
0.5f, Animation.RELATIVE_TO_SELF,
0.5f);
rotate.setDuration(600);
rotate.setRepeatMode(Animation.RESTART);
rotate.setRepeatCount(Animation.INFINITE);
}</pre>
So now we come to the EndlessAdapter part. In the constructor, I pass into it an instance of my custom ArrayAdapter, indicating the source of the list, the layout for each row, and the TextView ID from the layout. I also instantiated the animation that will be used while the list is loading the additional items.
<pre class="brush:java">@Override
protected boolean cacheInBackground() {
tempList.clear();
int lastOffset = getLastOffset();
if(lastOffset < LIST_SIZE){
int limit = lastOffset + BATCH_SIZE;
for(int i=(lastOffset+1); (i<=limit && i<LIST_SIZE); i++){
tempList.add(COUNTRIES[i]);
}

setLastOffset(limit);

if(limit<LIST_SIZE){
return true;
} else {
return false;
}
} else {
return false;
}
}</pre>We have to override cacheInBackground() for EndlessAdapter to work. Here we do the heavy lifting like querying the server, reading from the DB, etc. Here, I load the next 10 items from the original list and put them in a temporary ArrayList. I also check whether I have loaded all the data, and if so, tell the EndlessAdapter to not show the extra row at the bottom. I do this by returning false from the method.
<pre class="brush:java; tab-size: 5">@Override
protected void appendCachedData() {
@SuppressWarnings(“unchecked”)
ArrayAdapter<String> arrAdapterNew = (ArrayAdapter<String>)getWrappedAdapter();

int listLen = tempList.size();
for(int i=0; i<listLen; i++){
arrAdapterNew.add(tempList.get(i));
}
}</pre>Finally, I add the newly retrieved rows to my current list. And that’s it.

The complete Java file for this activity follows:
<pre class="brush:java; collapse: true">package com.test.example;

import java.util.ArrayList;
import java.util.List;

import android.app.ListActivity;
import android.content.Context;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.Animation;
import android.view.animation.RotateAnimation;
import android.widget.ArrayAdapter;
import android.widget.TextView;

import com.commonsware.cwac.endless.EndlessAdapter;

public class EndlessCustom extends ListActivity {

static int LIST_SIZE;
private int mLastOffset = 0;

static final int BATCH_SIZE = 10;

ArrayList<String> countriesSub = new ArrayList<String>();

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.lib_activity_dictionary);
init();
}

private void init() {
LIST_SIZE = COUNTRIES.length;
for (int i=0; i<=BATCH_SIZE; i++){
countriesSub.add(COUNTRIES[i]);
}
setLastOffset(BATCH_SIZE);
displayList(countriesSub);
}

private void setLastOffset(int i) {
mLastOffset = i;
}

private int getLastOffset(){
return mLastOffset;
}

private void displayList(ArrayList<String> countriesSub) {
setListAdapter(new DemoAdapter());
}

private class CustomArrayAdapter extends ArrayAdapter<String>{

public CustomArrayAdapter(Context context, int resource,
int textViewResourceId, List<String> objects) {
super(context, resource, textViewResourceId, objects);
}

@Override
public View getView(int position, View convertView, ViewGroup parent) {

ViewHolder holder;

if(convertView==null){
LayoutInflater inflater = (LayoutInflater)
EndlessCustom.this.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = inflater.inflate(android.R.layout.simple_list_item_1, null);
holder = new ViewHolder();
holder.word = (TextView)convertView.findViewById(android.R.id.text1);

convertView.setTag(holder);
} else{
holder=(ViewHolder)convertView.getTag();
}

holder.word.setText(String.valueOf(position+1) + “. “ + countriesSub.get(position));
return convertView;
}

public class ViewHolder{
public TextView word;
}
}

class DemoAdapter extends EndlessAdapter {
private RotateAnimation rotate=null;
ArrayList<String> tempList = new ArrayList<String>();

DemoAdapter() {
super(new CustomArrayAdapter(EndlessCustom.this,
android.R.layout.simple_list_item_1, android.R.id.text1, countriesSub));

rotate=new RotateAnimation(0f, 360f, Animation.RELATIVE_TO_SELF,
0.5f, Animation.RELATIVE_TO_SELF,
0.5f);
rotate.setDuration(600);
rotate.setRepeatMode(Animation.RESTART);
rotate.setRepeatCount(Animation.INFINITE);
}

@Override
protected View getPendingView(ViewGroup parent) {
View row=getLayoutInflater().inflate(R.layout.row, null);

View child=row.findViewById(android.R.id.text1);
child.setVisibility(View.GONE);
child=row.findViewById(R.id.throbber);
child.setVisibility(View.VISIBLE);
child.startAnimation(rotate);

return(row);
}

@Override
protected boolean cacheInBackground() {
tempList.clear();
int lastOffset = getLastOffset();
if(lastOffset < LIST_SIZE){
int limit = lastOffset + BATCH_SIZE;
for(int i=(lastOffset+1); (i<=limit && i<LIST_SIZE); i++){
tempList.add(COUNTRIES[i]);
}
setLastOffset(limit);

if(limit<LIST_SIZE){
return true;
} else {
return false;
}
} else {
return false;
}
}


@Override
protected void appendCachedData() {

@SuppressWarnings(“unchecked”)
ArrayAdapter<String> arrAdapterNew = (ArrayAdapter<String>)getWrappedAdapter();

int listLen = tempList.size();
for(int i=0; i<listLen; i++){
arrAdapterNew.add(tempList.get(i));
}
}
}


static final String[] COUNTRIES = new String[] {
“Afghanistan”, “Albania”, “Algeria”, “American Samoa”, “Andorra”,
“Angola”, “Anguilla”, “Antarctica”, “Antigua and Barbuda”, “Argentina”,
“Armenia”, “Aruba”, “Australia”, “Austria”, “Azerbaijan”,
“Bahrain”, “Bangladesh”, “Barbados”, “Belarus”, “Belgium”,
“Belize”, “Benin”, “Bermuda”, “Bhutan”, “Bolivia”,
“Bosnia and Herzegovina”, “Botswana”, “Bouvet Island”, “Brazil”, “British Indian Ocean Territory”,
“British Virgin Islands”, “Brunei”, “Bulgaria”, “Burkina Faso”, “Burundi”,
“Cote d’Ivoire”, “Cambodia”, “Cameroon”, “Canada”, “Cape Verde”,
“Cayman Islands”, “Central African Republic”, “Chad”, “Chile”, “China”,
“Christmas Island”, “Cocos (Keeling) Islands”, “Colombia”, “Comoros”, “Congo”,
“Cook Islands”, “Costa Rica”, “Croatia”, “Cuba”, “Cyprus”, “Czech Republic”,
“Democratic Republic of the Congo”, “Denmark”, “Djibouti”, “Dominica”, “Dominican Republic”,
“East Timor”, “Ecuador”, “Egypt”, “El Salvador”, “Equatorial Guinea”, “Eritrea”,
“Estonia”, “Ethiopia”, “Faeroe Islands”, “Falkland Islands”, “Fiji”, “Finland”,
“Former Yugoslav Republic of Macedonia”, “France”, “French Guiana”, “French Polynesia”,
“French Southern Territories”, “Gabon”, “Georgia”, “Germany”, “Ghana”, “Gibraltar”,
“Greece”, “Greenland”, “Grenada”, “Guadeloupe”, “Guam”, “Guatemala”, “Guinea”, “Guinea-Bissau”,
“Guyana”, “Haiti”, “Heard Island and McDonald Islands”, “Honduras”, “Hong Kong”, “Hungary”,
“Iceland”, “India”, “Indonesia”, “Iran”, “Iraq”, “Ireland”, “Israel”, “Italy”, “Jamaica”,
“Japan”, “Jordan”, “Kazakhstan”, “Kenya”, “Kiribati”, “Kuwait”, “Kyrgyzstan”, “Laos”,
“Latvia”, “Lebanon”, “Lesotho”, “Liberia”, “Libya”, “Liechtenstein”, “Lithuania”, “Luxembourg”,
“Macau”, “Madagascar”, “Malawi”, “Malaysia”, “Maldives”, “Mali”, “Malta”, “Marshall Islands”,
“Martinique”, “Mauritania”, “Mauritius”, “Mayotte”, “Mexico”, “Micronesia”, “Moldova”,
“Monaco”, “Mongolia”, “Montserrat”, “Morocco”, “Mozambique”, “Myanmar”, “Namibia”,
“Nauru”, “Nepal”, “Netherlands”, “Netherlands Antilles”, “New Caledonia”, “New Zealand”,
“Nicaragua”, “Niger”, “Nigeria”, “Niue”, “Norfolk Island”, “North Korea”, “Northern Marianas”,
“Norway”, “Oman”, “Pakistan”, “Palau”, “Panama”, “Papua New Guinea”, “Paraguay”, “Peru”,
“Philippines”, “Pitcairn Islands”, “Poland”, “Portugal”, “Puerto Rico”, “Qatar”,
“Reunion”, “Romania”, “Russia”, “Rwanda”, “Sqo Tome and Principe”, “Saint Helena”,
“Saint Kitts and Nevis”, “Saint Lucia”, “Saint Pierre and Miquelon”,
“Saint Vincent and the Grenadines”, “Samoa”, “San Marino”, “Saudi Arabia”, “Senegal”,
“Seychelles”, “Sierra Leone”, “Singapore”, “Slovakia”, “Slovenia”, “Solomon Islands”,
“Somalia”, “South Africa”, “South Georgia and the South Sandwich Islands”, “South Korea”,
“Spain”, “Sri Lanka”, “Sudan”, “Suriname”, “Svalbard and Jan Mayen”, “Swaziland”, “Sweden”,
“Switzerland”, “Syria”, “Taiwan”, “Tajikistan”, “Tanzania”, “Thailand”, “The Bahamas”,
“The Gambia”, “Togo”, “Tokelau”, “Tonga”, “Trinidad and Tobago”, “Tunisia”, “Turkey”,
“Turkmenistan”, “Turks and Caicos Islands”, “Tuvalu”, “Virgin Islands”, “Uganda”,
“Ukraine”, “United Arab Emirates”, “United Kingdom”,
“United States”, “United States Minor Outlying Islands”, “Uruguay”, “Uzbekistan”,
“Vanuatu”, “Vatican City”, “Venezuela”, “Vietnam”, “Wallis and Futuna”, “Western Sahara”,
“Yemen”, “Yugoslavia”, “Zambia”, “Zimbabwe”
};
}</pre>
If you know of a more efficient way to do this, please do not hesitate to let me know! :)

6 min read
Back to Top ↑

endless adapter

Using CWAC’s EndlessAdapter with a custom adapter

In one of my projects, the app has the potential to display a very, and I mean very, long list. To minimize the loading time of the app, I limit the number of items initially included in the list and then add to it as the user scrolls down.

For this purpose, Mark Murphy’s EndlessAdapter works wonders. I was trying to make it work with a CursorAdapter though, but due to time constraints, I was not able to continue with my experiment.

And then I found out that some of the items in my list are HTML-formatted. Huh. So I have to have a custom adapter to override getView(). I patterned my code on the demo included in the EndlessAdapter project and I was at a loss. Maybe it’s because I just came from a vacation and my mind refuses to work. Hmmm.

To cut a long and arduous journey short, I was able to figure it out. Here’s a sample activity that displays a list of countries from an array. To illustrate using a custom adapter, I add the list item number when setting the item text.

I will discuss the pertinent parts of the code in detail.
<pre class="brush:java">private void init() {
LIST_SIZE = COUNTRIES.length;
for (int i=0; i<=BATCH_SIZE; i++){
countriesSub.add(COUNTRIES[i]);
}

setLastOffset(BATCH_SIZE);
displayList(countriesSub);
}</pre>In this part of the code, I get the first 10 items in the list as the initial contents of the list. Of course, our current list is small and is peanuts for ListView. This is just to illustrate my point. In my app, I initially load 2,000 items. I also make sure to remember where I am in my source list. In my case, it is the offset in the original array. This might also be a row in the DB, or the ID in an RSS feed.

The ArrayList countriesSub holds the items that are currently in my list. As the user goes through the list, this array will grow.

To display my list, I set an instance of DemoAdapter as my list adapter. DemoAdapter inherits from EndlessAdapter and in its constructor, I give it an instance of my custom ArrayAdapter.
<pre class="brush:java">@Override
public View getView(int position, View convertView, ViewGroup parent) {

ViewHolder holder;

if(convertView==null){
LayoutInflater inflater = (LayoutInflater)
EndlessCustom.this.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = inflater.inflate(android.R.layout.simple_list_item_1, null);
holder = new ViewHolder();
holder.word = (TextView)convertView.findViewById(android.R.id.text1);

convertView.setTag(holder);
} else{
holder=(ViewHolder)convertView.getTag();
}

holder.word.setText(String.valueOf(position+1) + “. “ + countriesSub.get(position));
return convertView;
}</pre>
The important part in my custom ArrayAdapter is the getView() method. In this method, I tell the adapter to not simply display the .toString() value of the item, but to add a number before it.

Notice that I use the ViewHolder pattern as illustrated in the Android Developers site.
<pre class="brush:java; tab-size: 5">DemoAdapter() {
super(new CustomArrayAdapter(EndlessCustom.this,
android.R.layout.simple_list_item_1, android.R.id.text1, countriesSub));

rotate=new RotateAnimation(0f, 360f, Animation.RELATIVE_TO_SELF,
0.5f, Animation.RELATIVE_TO_SELF,
0.5f);
rotate.setDuration(600);
rotate.setRepeatMode(Animation.RESTART);
rotate.setRepeatCount(Animation.INFINITE);
}</pre>
So now we come to the EndlessAdapter part. In the constructor, I pass into it an instance of my custom ArrayAdapter, indicating the source of the list, the layout for each row, and the TextView ID from the layout. I also instantiated the animation that will be used while the list is loading the additional items.
<pre class="brush:java">@Override
protected boolean cacheInBackground() {
tempList.clear();
int lastOffset = getLastOffset();
if(lastOffset < LIST_SIZE){
int limit = lastOffset + BATCH_SIZE;
for(int i=(lastOffset+1); (i<=limit && i<LIST_SIZE); i++){
tempList.add(COUNTRIES[i]);
}

setLastOffset(limit);

if(limit<LIST_SIZE){
return true;
} else {
return false;
}
} else {
return false;
}
}</pre>We have to override cacheInBackground() for EndlessAdapter to work. Here we do the heavy lifting like querying the server, reading from the DB, etc. Here, I load the next 10 items from the original list and put them in a temporary ArrayList. I also check whether I have loaded all the data, and if so, tell the EndlessAdapter to not show the extra row at the bottom. I do this by returning false from the method.
<pre class="brush:java; tab-size: 5">@Override
protected void appendCachedData() {
@SuppressWarnings(“unchecked”)
ArrayAdapter<String> arrAdapterNew = (ArrayAdapter<String>)getWrappedAdapter();

int listLen = tempList.size();
for(int i=0; i<listLen; i++){
arrAdapterNew.add(tempList.get(i));
}
}</pre>Finally, I add the newly retrieved rows to my current list. And that’s it.

The complete Java file for this activity follows:
<pre class="brush:java; collapse: true">package com.test.example;

import java.util.ArrayList;
import java.util.List;

import android.app.ListActivity;
import android.content.Context;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.Animation;
import android.view.animation.RotateAnimation;
import android.widget.ArrayAdapter;
import android.widget.TextView;

import com.commonsware.cwac.endless.EndlessAdapter;

public class EndlessCustom extends ListActivity {

static int LIST_SIZE;
private int mLastOffset = 0;

static final int BATCH_SIZE = 10;

ArrayList<String> countriesSub = new ArrayList<String>();

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.lib_activity_dictionary);
init();
}

private void init() {
LIST_SIZE = COUNTRIES.length;
for (int i=0; i<=BATCH_SIZE; i++){
countriesSub.add(COUNTRIES[i]);
}
setLastOffset(BATCH_SIZE);
displayList(countriesSub);
}

private void setLastOffset(int i) {
mLastOffset = i;
}

private int getLastOffset(){
return mLastOffset;
}

private void displayList(ArrayList<String> countriesSub) {
setListAdapter(new DemoAdapter());
}

private class CustomArrayAdapter extends ArrayAdapter<String>{

public CustomArrayAdapter(Context context, int resource,
int textViewResourceId, List<String> objects) {
super(context, resource, textViewResourceId, objects);
}

@Override
public View getView(int position, View convertView, ViewGroup parent) {

ViewHolder holder;

if(convertView==null){
LayoutInflater inflater = (LayoutInflater)
EndlessCustom.this.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = inflater.inflate(android.R.layout.simple_list_item_1, null);
holder = new ViewHolder();
holder.word = (TextView)convertView.findViewById(android.R.id.text1);

convertView.setTag(holder);
} else{
holder=(ViewHolder)convertView.getTag();
}

holder.word.setText(String.valueOf(position+1) + “. “ + countriesSub.get(position));
return convertView;
}

public class ViewHolder{
public TextView word;
}
}

class DemoAdapter extends EndlessAdapter {
private RotateAnimation rotate=null;
ArrayList<String> tempList = new ArrayList<String>();

DemoAdapter() {
super(new CustomArrayAdapter(EndlessCustom.this,
android.R.layout.simple_list_item_1, android.R.id.text1, countriesSub));

rotate=new RotateAnimation(0f, 360f, Animation.RELATIVE_TO_SELF,
0.5f, Animation.RELATIVE_TO_SELF,
0.5f);
rotate.setDuration(600);
rotate.setRepeatMode(Animation.RESTART);
rotate.setRepeatCount(Animation.INFINITE);
}

@Override
protected View getPendingView(ViewGroup parent) {
View row=getLayoutInflater().inflate(R.layout.row, null);

View child=row.findViewById(android.R.id.text1);
child.setVisibility(View.GONE);
child=row.findViewById(R.id.throbber);
child.setVisibility(View.VISIBLE);
child.startAnimation(rotate);

return(row);
}

@Override
protected boolean cacheInBackground() {
tempList.clear();
int lastOffset = getLastOffset();
if(lastOffset < LIST_SIZE){
int limit = lastOffset + BATCH_SIZE;
for(int i=(lastOffset+1); (i<=limit && i<LIST_SIZE); i++){
tempList.add(COUNTRIES[i]);
}
setLastOffset(limit);

if(limit<LIST_SIZE){
return true;
} else {
return false;
}
} else {
return false;
}
}


@Override
protected void appendCachedData() {

@SuppressWarnings(“unchecked”)
ArrayAdapter<String> arrAdapterNew = (ArrayAdapter<String>)getWrappedAdapter();

int listLen = tempList.size();
for(int i=0; i<listLen; i++){
arrAdapterNew.add(tempList.get(i));
}
}
}


static final String[] COUNTRIES = new String[] {
“Afghanistan”, “Albania”, “Algeria”, “American Samoa”, “Andorra”,
“Angola”, “Anguilla”, “Antarctica”, “Antigua and Barbuda”, “Argentina”,
“Armenia”, “Aruba”, “Australia”, “Austria”, “Azerbaijan”,
“Bahrain”, “Bangladesh”, “Barbados”, “Belarus”, “Belgium”,
“Belize”, “Benin”, “Bermuda”, “Bhutan”, “Bolivia”,
“Bosnia and Herzegovina”, “Botswana”, “Bouvet Island”, “Brazil”, “British Indian Ocean Territory”,
“British Virgin Islands”, “Brunei”, “Bulgaria”, “Burkina Faso”, “Burundi”,
“Cote d’Ivoire”, “Cambodia”, “Cameroon”, “Canada”, “Cape Verde”,
“Cayman Islands”, “Central African Republic”, “Chad”, “Chile”, “China”,
“Christmas Island”, “Cocos (Keeling) Islands”, “Colombia”, “Comoros”, “Congo”,
“Cook Islands”, “Costa Rica”, “Croatia”, “Cuba”, “Cyprus”, “Czech Republic”,
“Democratic Republic of the Congo”, “Denmark”, “Djibouti”, “Dominica”, “Dominican Republic”,
“East Timor”, “Ecuador”, “Egypt”, “El Salvador”, “Equatorial Guinea”, “Eritrea”,
“Estonia”, “Ethiopia”, “Faeroe Islands”, “Falkland Islands”, “Fiji”, “Finland”,
“Former Yugoslav Republic of Macedonia”, “France”, “French Guiana”, “French Polynesia”,
“French Southern Territories”, “Gabon”, “Georgia”, “Germany”, “Ghana”, “Gibraltar”,
“Greece”, “Greenland”, “Grenada”, “Guadeloupe”, “Guam”, “Guatemala”, “Guinea”, “Guinea-Bissau”,
“Guyana”, “Haiti”, “Heard Island and McDonald Islands”, “Honduras”, “Hong Kong”, “Hungary”,
“Iceland”, “India”, “Indonesia”, “Iran”, “Iraq”, “Ireland”, “Israel”, “Italy”, “Jamaica”,
“Japan”, “Jordan”, “Kazakhstan”, “Kenya”, “Kiribati”, “Kuwait”, “Kyrgyzstan”, “Laos”,
“Latvia”, “Lebanon”, “Lesotho”, “Liberia”, “Libya”, “Liechtenstein”, “Lithuania”, “Luxembourg”,
“Macau”, “Madagascar”, “Malawi”, “Malaysia”, “Maldives”, “Mali”, “Malta”, “Marshall Islands”,
“Martinique”, “Mauritania”, “Mauritius”, “Mayotte”, “Mexico”, “Micronesia”, “Moldova”,
“Monaco”, “Mongolia”, “Montserrat”, “Morocco”, “Mozambique”, “Myanmar”, “Namibia”,
“Nauru”, “Nepal”, “Netherlands”, “Netherlands Antilles”, “New Caledonia”, “New Zealand”,
“Nicaragua”, “Niger”, “Nigeria”, “Niue”, “Norfolk Island”, “North Korea”, “Northern Marianas”,
“Norway”, “Oman”, “Pakistan”, “Palau”, “Panama”, “Papua New Guinea”, “Paraguay”, “Peru”,
“Philippines”, “Pitcairn Islands”, “Poland”, “Portugal”, “Puerto Rico”, “Qatar”,
“Reunion”, “Romania”, “Russia”, “Rwanda”, “Sqo Tome and Principe”, “Saint Helena”,
“Saint Kitts and Nevis”, “Saint Lucia”, “Saint Pierre and Miquelon”,
“Saint Vincent and the Grenadines”, “Samoa”, “San Marino”, “Saudi Arabia”, “Senegal”,
“Seychelles”, “Sierra Leone”, “Singapore”, “Slovakia”, “Slovenia”, “Solomon Islands”,
“Somalia”, “South Africa”, “South Georgia and the South Sandwich Islands”, “South Korea”,
“Spain”, “Sri Lanka”, “Sudan”, “Suriname”, “Svalbard and Jan Mayen”, “Swaziland”, “Sweden”,
“Switzerland”, “Syria”, “Taiwan”, “Tajikistan”, “Tanzania”, “Thailand”, “The Bahamas”,
“The Gambia”, “Togo”, “Tokelau”, “Tonga”, “Trinidad and Tobago”, “Tunisia”, “Turkey”,
“Turkmenistan”, “Turks and Caicos Islands”, “Tuvalu”, “Virgin Islands”, “Uganda”,
“Ukraine”, “United Arab Emirates”, “United Kingdom”,
“United States”, “United States Minor Outlying Islands”, “Uruguay”, “Uzbekistan”,
“Vanuatu”, “Vatican City”, “Venezuela”, “Vietnam”, “Wallis and Futuna”, “Western Sahara”,
“Yemen”, “Yugoslavia”, “Zambia”, “Zimbabwe”
};
}</pre>
If you know of a more efficient way to do this, please do not hesitate to let me know! :)

6 min read
Back to Top ↑

text color

Changing a button’s text color

There are times that when changing a button's background color, we also want to change the text's color. There is a method setTextColor(int color) specifically for this purpose. Seems pretty straightforward enough, but it took me a few tries to get it right the first time I tried using it. Documenting it here so that I wouldn't forget.

Here’s a screenshot of my button with its default settings.<div><div style="text-align: center;">
</div></div><div>What I’m trying to do is have the color of the text change to a shade of blue once the button is pressed. But look what I got.</div><div>That is no shade of blue! Far from it! I tried changing the alpha value of the #AARRGGBB value, but I still end up with the same gray shade. It turns out that you cannot pass a direct R.* id to the setTextColor() method.</div><div>
</div><div>Here’s how I finally managed to make it work:</div><div><pre class="brush:java">int newColor = getResources().getColor(R.color.button_new_color);
((Button)view).setTextColor(newColor);</pre>And tada!</div><div></div>

~1 min read
Back to Top ↑

button

Changing a button’s text color

There are times that when changing a button's background color, we also want to change the text's color. There is a method setTextColor(int color) specifically for this purpose. Seems pretty straightforward enough, but it took me a few tries to get it right the first time I tried using it. Documenting it here so that I wouldn't forget.

Here’s a screenshot of my button with its default settings.<div><div style="text-align: center;">
</div></div><div>What I’m trying to do is have the color of the text change to a shade of blue once the button is pressed. But look what I got.</div><div>That is no shade of blue! Far from it! I tried changing the alpha value of the #AARRGGBB value, but I still end up with the same gray shade. It turns out that you cannot pass a direct R.* id to the setTextColor() method.</div><div>
</div><div>Here’s how I finally managed to make it work:</div><div><pre class="brush:java">int newColor = getResources().getColor(R.color.button_new_color);
((Button)view).setTextColor(newColor);</pre>And tada!</div><div></div>

~1 min read
Back to Top ↑

wishful thinking

Dreaming of Google I/O: ADT preview

It is my dream to one day attend Google I/O. But seeing as I’m from a Third World country where everyday is a practice in cost-cutting, it is very unlikely that I would fulfill that dream anytime soon. I haven’t sat down and computed the actual cost, but thinking about it makes my head spin. Off the top of my head:<div><ul><li>US Visa application = P6500 (~USD150)</li><li>Round trip plane fare ticket = P90,000 (~USD2000, if I’m lucky)</li><li>Google I/O ticket = P21,000 (~USD450, if my research is correct)</li></ul><div>Then of course, there’s food, transportation, accommodations, and pocket money. sigh</div></div><div>
</div>For now, I would have to content myself with watching videos from the sessions. Yesterday, I watched Android SDK tech lead’s Xavier Ducrohet’s session on the Android Development Tools. I had a little interaction with Xavier on the Android developers Google group before, and it is refreshing to finally map a face to the name. I kinda feel bad too, because the few times that I talked to him in the groups, it is to complain about the problems I’m having whenever I update my ADT. Eclipse, the SDK and I have a love-hate relationship with each other. But that’s another story.<div>
</div><div>Anyway, I was watching the session while having lunch which turned out to be a mistake. I was so awestruck by the new tools that I totally forgot to eat and my chicken got cold! I was gushing about the tools, but of course no one can relate as I am the only Android developer in our company. I was applauding and cheering by myself. Oh well.</div><div>
</div><div>Needless to say, I am so impressed with the new version of ADT! (More exclamation marks should follow, but I’m trying to act mature) I used to hate making layout files. I am lightyears away from being artistic, I don’t have a strong background in XML, and I simply find all the available features overwhelming. It’s developer option paralysis, I would think. But the new ADT makes making layouts look like F-U-N! I love how it’s sleeker, seemingly more user-friendly (I’d retain the qualifier until I get to try it out), and more feature-packed. </div><div>
</div><div>Some of the reasons I’m already loving the new ADT:</div><div>1. Smarter extract to include</div><div>The current ADT already has an extract to include feature, but the new version looks smarter. When you choose to extract a layout stub as an include, the ADT looks for the exact same layout in all your other layout files and replaces them with the include tag! Brilliant, I say!</div><div>
</div><div>2. XML editors: attribute auto-complete</div><div>Oh. My. God. I have been ranting about this for so long! There are simply too many attributes available for each type of widget I find it impossible to remember everything! And then of course I have to make sure that I am putting the correct value formats into those attributes! I admit that it terrified me when I was starting out in Android; having this feature saves the newbies from a lot of heartache.</div><div>
</div><div>3. Layout actions toolbar</div><div>Easier to set attributes without having to scroll down a lot then finding out you put in the wrong value and then having to scroll down again. Nifty!</div><div>
</div><div>4. Widget Previews in the palette</div><div>One time I was creating a layout file, I wanted to put an indeterminate progress bar but I want it to use the small progress bar style. But then I lost my list of native Android styles so I have to Google for the correct style that I want (?android:attr/android:progressBarStyleSmall is a little hard to remember).</div><div>
</div><div>Soon I can choose precisely what I want before dragging widgets onto the canvas! The previews plus the attribute autocomplete feature would work wonders, I would guess. And it is wonderful that the previews change with the selected theme!</div><div>
</div><div>5. Support for more widgets</div><div>I used to think that I’m doing an include wrong, because the graphical editor doesn’t show the layout I’m including. It turns out that I have to put it inside a LinearLayout just to have the editor render it properly. But it looks like those days are behind us now!</div><div>
</div><div>Also gone are the days when the ADT cannot render TabHosts! I’m doing my happy dance now!</div><div>
</div><div>6. (Hopefully) easier drag-and-drop</div><div>Dragging-and-dropping in RelativeLayouts is a pain in the ass. The editor simply does not listen to me! But in the new ADT it looks like the new anchors are easier to understand than the current one, with squares all around.</div><div>
</div><div>I haven’t tried dragging a view directly into the outline in the current ADT, but knowing that I would have it soon makes me happy!</div><div>
</div><div><div>7. Custom views available in the GUI editor</div><div>And then Xavier’s team showed us how much they love us by including custom views in the widget palette. I haven’t really used that many custom views, but I guess a lot of developers who customize like crazy would love this feature.</div></div><div>
</div><div><hr width="50%">
</div><div>That being said, I would like to thank Xavier and his team for making sure that us developers continue to love doing what we do by making our jobs a little easier. I would like to think that they take time to listen to our opinions, and they for sure make it easy for us to talk to them. I love how accessible they are, and how very supportive of us. Sending good vibes to you and your team, Xavier!</div><div>
</div><div>I just hope that having this new ADT would not make developers lazy. I wish that we still make sure we understand how the XML file works, that we still read the documentation for the widgets, that we simply do not rely on automation to do the work for us. For starters, make sure you know how to change an EditText to accept passwords, or phone numbers, or only letters without relying on the palette.</div><div>
</div><div>I admit that I screech like a true fan girl when Romain Guy or Xavier answer my tweets. blush
<div>
</div><div>Here’s the session’s video. Gush with me!</div><div>
<div><iframe width="480" height="295" src="http://www.youtube.com/embed/Oq05KqjXTvs?fs=1" frameborder="0" allowfullscreen=""></iframe></div></div></div>

4 min read
Back to Top ↑

Google I/O

Dreaming of Google I/O: ADT preview

It is my dream to one day attend Google I/O. But seeing as I’m from a Third World country where everyday is a practice in cost-cutting, it is very unlikely that I would fulfill that dream anytime soon. I haven’t sat down and computed the actual cost, but thinking about it makes my head spin. Off the top of my head:<div><ul><li>US Visa application = P6500 (~USD150)</li><li>Round trip plane fare ticket = P90,000 (~USD2000, if I’m lucky)</li><li>Google I/O ticket = P21,000 (~USD450, if my research is correct)</li></ul><div>Then of course, there’s food, transportation, accommodations, and pocket money. sigh</div></div><div>
</div>For now, I would have to content myself with watching videos from the sessions. Yesterday, I watched Android SDK tech lead’s Xavier Ducrohet’s session on the Android Development Tools. I had a little interaction with Xavier on the Android developers Google group before, and it is refreshing to finally map a face to the name. I kinda feel bad too, because the few times that I talked to him in the groups, it is to complain about the problems I’m having whenever I update my ADT. Eclipse, the SDK and I have a love-hate relationship with each other. But that’s another story.<div>
</div><div>Anyway, I was watching the session while having lunch which turned out to be a mistake. I was so awestruck by the new tools that I totally forgot to eat and my chicken got cold! I was gushing about the tools, but of course no one can relate as I am the only Android developer in our company. I was applauding and cheering by myself. Oh well.</div><div>
</div><div>Needless to say, I am so impressed with the new version of ADT! (More exclamation marks should follow, but I’m trying to act mature) I used to hate making layout files. I am lightyears away from being artistic, I don’t have a strong background in XML, and I simply find all the available features overwhelming. It’s developer option paralysis, I would think. But the new ADT makes making layouts look like F-U-N! I love how it’s sleeker, seemingly more user-friendly (I’d retain the qualifier until I get to try it out), and more feature-packed. </div><div>
</div><div>Some of the reasons I’m already loving the new ADT:</div><div>1. Smarter extract to include</div><div>The current ADT already has an extract to include feature, but the new version looks smarter. When you choose to extract a layout stub as an include, the ADT looks for the exact same layout in all your other layout files and replaces them with the include tag! Brilliant, I say!</div><div>
</div><div>2. XML editors: attribute auto-complete</div><div>Oh. My. God. I have been ranting about this for so long! There are simply too many attributes available for each type of widget I find it impossible to remember everything! And then of course I have to make sure that I am putting the correct value formats into those attributes! I admit that it terrified me when I was starting out in Android; having this feature saves the newbies from a lot of heartache.</div><div>
</div><div>3. Layout actions toolbar</div><div>Easier to set attributes without having to scroll down a lot then finding out you put in the wrong value and then having to scroll down again. Nifty!</div><div>
</div><div>4. Widget Previews in the palette</div><div>One time I was creating a layout file, I wanted to put an indeterminate progress bar but I want it to use the small progress bar style. But then I lost my list of native Android styles so I have to Google for the correct style that I want (?android:attr/android:progressBarStyleSmall is a little hard to remember).</div><div>
</div><div>Soon I can choose precisely what I want before dragging widgets onto the canvas! The previews plus the attribute autocomplete feature would work wonders, I would guess. And it is wonderful that the previews change with the selected theme!</div><div>
</div><div>5. Support for more widgets</div><div>I used to think that I’m doing an include wrong, because the graphical editor doesn’t show the layout I’m including. It turns out that I have to put it inside a LinearLayout just to have the editor render it properly. But it looks like those days are behind us now!</div><div>
</div><div>Also gone are the days when the ADT cannot render TabHosts! I’m doing my happy dance now!</div><div>
</div><div>6. (Hopefully) easier drag-and-drop</div><div>Dragging-and-dropping in RelativeLayouts is a pain in the ass. The editor simply does not listen to me! But in the new ADT it looks like the new anchors are easier to understand than the current one, with squares all around.</div><div>
</div><div>I haven’t tried dragging a view directly into the outline in the current ADT, but knowing that I would have it soon makes me happy!</div><div>
</div><div><div>7. Custom views available in the GUI editor</div><div>And then Xavier’s team showed us how much they love us by including custom views in the widget palette. I haven’t really used that many custom views, but I guess a lot of developers who customize like crazy would love this feature.</div></div><div>
</div><div><hr width="50%">
</div><div>That being said, I would like to thank Xavier and his team for making sure that us developers continue to love doing what we do by making our jobs a little easier. I would like to think that they take time to listen to our opinions, and they for sure make it easy for us to talk to them. I love how accessible they are, and how very supportive of us. Sending good vibes to you and your team, Xavier!</div><div>
</div><div>I just hope that having this new ADT would not make developers lazy. I wish that we still make sure we understand how the XML file works, that we still read the documentation for the widgets, that we simply do not rely on automation to do the work for us. For starters, make sure you know how to change an EditText to accept passwords, or phone numbers, or only letters without relying on the palette.</div><div>
</div><div>I admit that I screech like a true fan girl when Romain Guy or Xavier answer my tweets. blush
<div>
</div><div>Here’s the session’s video. Gush with me!</div><div>
<div><iframe width="480" height="295" src="http://www.youtube.com/embed/Oq05KqjXTvs?fs=1" frameborder="0" allowfullscreen=""></iframe></div></div></div>

4 min read
Back to Top ↑

complex values

Passing complex objects to another Activity

Several months ago, I was faced with a problem of passing a complex object to another Activity. There are several ways of doing this:
<ul><li>“Deconstructing” the complex object to simple data types and passing them as extras through putExtra()</li><li>Making the object Parcelable</li><li>Making the object Serializable</li></ul>I don’t really understand the concepts behind an object being Parcelable or Serializable, so I was not comfortable using that approach. Deconstructing the object, on the other hand, is easier but it is quite hard to manage as the number of fields in the object increases.

And then I came across another solution: using Bundles. In this post, I will try to explain how to do that.

In this sample project, we want to pass an instance of an AttendeeObject from our main activity to another. To better illustrate how we can use this method for different data types, an AttendeeObject will hold three pieces of information: a String name, an integer age, and a boolean indicating the person’s presence.

First, we construct the AttendeeObject like any old POJO. Create all the fields you want the object to contain and generate getters and setters for each. We then create the methods we would need to be able to pass, and subsequently receive, this object between activities.

To pass an AttendeeObject, we would need to put it in a Bundle and pass it using Intent#putExtra(String key, Bundle bundle).
<pre class="brush:java">public Bundle bundleAttendee(AttendeeObject attendee){
Bundle bundle = new Bundle();
bundle.putString(NAME, attendee.getName());
bundle.putInt(AGE, attendee.getAge());
bundle.putBoolean(PRESENCE, attendee.isPresent());

return bundle;
}</pre>Here, we simply put into a Bundle the values in the object that we want to pass.

Next, we should be able to convert this bundle back to an AttendeeObject in the receiving Activity. This task is done by the following method:
<pre class="brush:java">public AttendeeObject unBundleAttendee(Bundle attendeeBundle){
AttendeeObject attendee = new AttendeeObject();
attendee.setName(attendeeBundle.getString(NAME));
attendee.setAge(attendeeBundle.getInt(AGE));
attendee.setIsPresent(attendeeBundle.getBoolean(PRESENCE));

return attendee;
}</pre>Now, we are ready to use this in our application. I created a simple app that asks the user for the three values we would need to populate AttendeeObject.
I won’t discuss the details of creating the layout file, but it might be worthy to note that the possible values for the Spinner are just “Yes” and “No”.

When the user clicks on the “Create Attendee” button, the application creates a new AttendeeObject based on the values in the form and adds this to an ArrayList of AttendeeObjects.
<pre class="brush:java">private void onCreateAttendee() {
// Create a new AttendeeObject
AttendeeObject attendee = new AttendeeObject();
attendee.setName(mNameText.getText().toString());
attendee.setAge(Integer.valueOf(mAgeText.getText().toString()));
attendee.setIsPresent(mCurrentPresence);

// You can then do whatever you want with this object
// like adding it to an ArrayList or saving it to a database
mAttendees.add(attendee);

Toast.makeText(ComplexObjectDemo.this, “Attendee added!”, Toast.LENGTH_SHORT).show();
}</pre>
When the user clicks on the “Submit Attendee” button, the app “packages” the chosen value into a Bundle and sets it as an extra to the Intent. For illustration purposes, the application always gets the second AttendeeObject in the ArrayList.
<pre class="brush:java">private void onSubmitObject() {
Intent intent = new Intent(ComplexObjectDemo.this, ComplexObjectReceiverDemo.class);

// For simplicity, we will always get the second value
Bundle value = createAttendeeBundle(1);

// In a “real” application, the Key should be defined in a constants file
intent.putExtra(“test.complex.attendee”, value);

startActivity(intent);
}

private Bundle createAttendeeBundle(int index) {
// Here, mAttendee is an instance of AttendeeObject
// and mAttendees is an ArrayList holding all the created attendees
return mAttendee.bundleAttendee(mAttendees.get(index));
}</pre>

Upon receiving the Intent, the new activity simply displays the values in the AttendeeObject passed into it. Here’s how we can “unbundle” the Bundle:
<pre class="brush:java">@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_complex_demo_receiver);

// Get the extras passed to this Activity
setUpViews(getIntent().getExtras());
}

private void setUpViews(Bundle extras) {
// Again, the key should be in a constants file!
Bundle extraAttendee = extras.getBundle(“test.complex.attendee”);

AttendeeObject attendee = new AttendeeObject();

// Deconstruct the Bundle into the AttendeeObject
attendee = attendee.unBundleAttendee(extraAttendee);

// The AttendeeObject fields are now populated, so we set the texts
((TextView) findViewById(R.id.attendee_age_value))
.setText(String.valueOf(attendee.getAge()));
((TextView) findViewById(R.id.attendee_name_value))
.setText(attendee.getName());
((TextView) findViewById(R.id.attendee_presence_value))
.setText(String.valueOf(attendee.isPresent()));
}</pre>Here’s how the receiving activity looks like:Here’s the complete AttendeeObject class.
<pre class="brush:java; collapse:true">package droidista.example;

import android.os.Bundle;

public class AttendeeObject {

public static final String NAME = “attendee.name”;
public static final String AGE = “attendee.age”;
public static final String PRESENCE = “attendee.presence”;


private String mName;
private int mAge;
private boolean mIsPresent;

public AttendeeObject(){

}

public Bundle bundleAttendee(AttendeeObject attendee){
Bundle bundle = new Bundle();
bundle.putString(NAME, attendee.getName());
bundle.putInt(AGE, attendee.getAge());
bundle.putBoolean(PRESENCE, attendee.isPresent());

return bundle;
}

public AttendeeObject unBundleAttendee(Bundle attendeeBundle){
AttendeeObject attendee = new AttendeeObject();
attendee.setName(attendeeBundle.getString(NAME));
attendee.setAge(attendeeBundle.getInt(AGE));
attendee.setIsPresent(attendeeBundle.getBoolean(PRESENCE));

return attendee;
}

public String getName() {
return mName;
}

public void setName(String name) {
this.mName = name;
}

public int getAge() {
return mAge;
}

public void setAge(int age) {
this.mAge = age;
}

public boolean isPresent() {
return mIsPresent;
}

public void setIsPresent(boolean isPresent) {
this.mIsPresent = isPresent;
}
}</pre>And our main activity:
<pre class="brush:java; collapse:true">package droidista.example;

import java.util.ArrayList;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Spinner;
import android.widget.Toast;
import android.widget.AdapterView.OnItemSelectedListener;

public class ComplexObjectDemo extends Activity implements OnClickListener {

private Button mGoToNextIntent, mCreateAttendee, mClearFields;
private EditText mNameText, mAgeText;
private Spinner mPresence;

AttendeeObject mAttendee = new AttendeeObject();

private boolean mCurrentPresence;

private ArrayList<AttendeeObject> mAttendees = new ArrayList<AttendeeObject>();

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_complex_demo);

setUpViews();
}

private void setUpViews() {
setUpSpinner();

mNameText = (EditText)findViewById(R.id.name_text_input);
mAgeText = (EditText)findViewById(R.id.age_text_input);

mGoToNextIntent = (Button)findViewById(R.id.btn_submit_object);
mGoToNextIntent.setOnClickListener(this);

mCreateAttendee = (Button)findViewById(R.id.btn_create_attendee);
mCreateAttendee.setOnClickListener(this);

mClearFields = (Button) findViewById(R.id.btn_clear_fields);
mClearFields.setOnClickListener(this);
}

private void setUpSpinner() {
mPresence = (Spinner) findViewById(R.id.presence_spinner);
ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(
this, R.array.is_present_values, android.R.layout.simple_spinner_item);
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
mPresence.setAdapter(adapter);
}


private Bundle createAttendeeBundle(int index) {
// Here, mAttendee is an instance of AttendeeObject
// and mAttendees is an ArrayList holding all the created attendees
return mAttendee.bundleAttendee(mAttendees.get(index));
}

public void onClick(View v) {
switch(v.getId()){
case R.id.btn_create_attendee:
onCreateAttendee();
break;
case R.id.btn_submit_object:
onSubmitObject();
break;
case R.id.btn_clear_fields:
onClearFields();
break;
}
}

private void onClearFields() {
mAgeText.setText(“”);
mNameText.setText(“”);
mPresence.setSelection(0);
}

private void onSubmitObject() {

// For simplicity, we will always get the second value
Bundle value = createAttendeeBundle(1);

// In a “real” application, the Key should be defined in a constants file
Intent intent = new Intent(ComplexObjectDemo.this, ComplexObjectReceiverDemo.class);
intent.putExtra(“test.complex.attendee”, value);

// Start the new activity
startActivity(intent);
}

private void onCreateAttendee() {
// Create a new AttendeeObject
AttendeeObject attendee = new AttendeeObject();
attendee.setName(mNameText.getText().toString());
attendee.setAge(Integer.valueOf(mAgeText.getText().toString()));
attendee.setIsPresent(mCurrentPresence);

// You can then do whatever you want with this object
// like adding it to an ArrayList or saving it to a database
mAttendees.add(attendee);

// Notify the user
Toast.makeText(ComplexObjectDemo.this, “Attendee added!”, Toast.LENGTH_SHORT).show();
}

public class MyOnItemSelectedListener implements OnItemSelectedListener {

public void onItemSelected(AdapterView parent, View view, int pos, long id) {
mCurrentPresence = (pos==0) ? true : false;
}

public void onNothingSelected(AdapterView parent) { /Do nothing./ }
}
}</pre>And here’s the second activity:
<pre class="brush:java; collapse:true">package droidista.example;

import android.app.Activity;
import android.os.Bundle;
import android.widget.TextView;

public class ComplexObjectReceiverDemo extends Activity {

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_complex_demo_receiver);

// Get the extras passed to this Activity
setUpViews(getIntent().getExtras());
}

private void setUpViews(Bundle extras) {
// Again, the key should be in a constants file!
Bundle extraAttendee = extras.getBundle(“test.complex.attendee”);
AttendeeObject attendee = new AttendeeObject();

// Deconstruct the Bundle into the AttendeeObject
attendee = attendee.unBundleAttendee(extraAttendee);

// The AttendeeObject fields are now populated, so we set the texts
((TextView) findViewById(R.id.attendee_age_value)).setText(String.valueOf(attendee.getAge()));
((TextView) findViewById(R.id.attendee_name_value)).setText(attendee.getName());
((TextView) findViewById(R.id.attendee_presence_value)).setText(String.valueOf(attendee.isPresent()));
}

}</pre>

5 min read
Back to Top ↑

the 90s rule

A break: When I grow up

Tearing my hair out on my latest project. So here’s some Garbage to cheer me up.

<iframe width="425" height="349" src="http://www.youtube.com/embed/Alo6_rMLGik" frameborder="0" allowfullscreen></iframe>

~1 min read
Back to Top ↑

authentication

MongoDB and Authentication

By default, MongoDB allows access to the database without authentication. Adding a user with a username/password is easy, but authenticating might be a bit tricky since the official documentation does not say the command directly.
First, we add an admin account. Navigate to the MongoDB directory on your machine then start the database.
<pre class="brush:java">$ ./mongo
> use admin
> db.addUser(adminuser, adminpassword)</pre>Switch to the database of your choice and add users to it.
<pre class="brush:java">> use foo
> db.addUser(myuser, userpassword)</pre>This adds a user myuser that has read and write access to the database. If we want a user with read-only access, set the third parameter for addUser().
<pre class="brush:java">> db.addUser(guest, guestpassword, true)</pre>You can check for users with access to a particular database like thus:
<pre class="brush:bash">> db.system.users.find().pretty()
{
“_id” : ObjectId(“4ee9863d954eb7168e07089d”),
“user” : “zarah”,
“readOnly” : false,
“pwd” : “70581bfb1e32e2286df11fe119addc7a”
}
{
“_id” : ObjectId(“4ee98658954eb7168e07089e”),
“user” : “guest”,
“readOnly” : true,
“pwd” : “88558f1ece63fa0b528012b9840bd9de”
}</pre>
Now stop the MongoDB server and restart it with authentication enabled.
<pre class="brush:java">$ ./mongod –auth
> mongo foo -u myuser -p userpassword</pre>where foo is the database that myuser has access to.
You can now read and write into database foo. Notice however that querying for databases would result to an error:
<pre class="brush:java">> show dbs
Mon Dec 19 17:21:20 uncaught exception: listDatabases failed:{ “errmsg” : “need to login”, “ok” : 0 }</pre>
Exit MongoDB and login again, this time using the read-only account. If we try inserting a document, an error should appear:
<pre class="brush:bash">> db.foo.insert({“title”,”MongoDB Authentication Test”})
unauthorized</pre>The read-only account can query for collections and use find() and its variations. It can’t, however, query for databases.

1 min read
Back to Top ↑

mongodb

MongoDB and Authentication

By default, MongoDB allows access to the database without authentication. Adding a user with a username/password is easy, but authenticating might be a bit tricky since the official documentation does not say the command directly.
First, we add an admin account. Navigate to the MongoDB directory on your machine then start the database.
<pre class="brush:java">$ ./mongo
> use admin
> db.addUser(adminuser, adminpassword)</pre>Switch to the database of your choice and add users to it.
<pre class="brush:java">> use foo
> db.addUser(myuser, userpassword)</pre>This adds a user myuser that has read and write access to the database. If we want a user with read-only access, set the third parameter for addUser().
<pre class="brush:java">> db.addUser(guest, guestpassword, true)</pre>You can check for users with access to a particular database like thus:
<pre class="brush:bash">> db.system.users.find().pretty()
{
“_id” : ObjectId(“4ee9863d954eb7168e07089d”),
“user” : “zarah”,
“readOnly” : false,
“pwd” : “70581bfb1e32e2286df11fe119addc7a”
}
{
“_id” : ObjectId(“4ee98658954eb7168e07089e”),
“user” : “guest”,
“readOnly” : true,
“pwd” : “88558f1ece63fa0b528012b9840bd9de”
}</pre>
Now stop the MongoDB server and restart it with authentication enabled.
<pre class="brush:java">$ ./mongod –auth
> mongo foo -u myuser -p userpassword</pre>where foo is the database that myuser has access to.
You can now read and write into database foo. Notice however that querying for databases would result to an error:
<pre class="brush:java">> show dbs
Mon Dec 19 17:21:20 uncaught exception: listDatabases failed:{ “errmsg” : “need to login”, “ok” : 0 }</pre>
Exit MongoDB and login again, this time using the read-only account. If we try inserting a document, an error should appear:
<pre class="brush:bash">> db.foo.insert({“title”,”MongoDB Authentication Test”})
unauthorized</pre>The read-only account can query for collections and use find() and its variations. It can’t, however, query for databases.

1 min read
Back to Top ↑

selenium

Selenium and File Downloads

Lately, one of my tasks has been to automate regression tests on one of our apps. Since this is a web app, we are using Selenium. Here, I enumerate the steps to configure Firefox for file downloading using Selenium and JUnit by foregoing the downloads dialog box.

Setting up the profile
We will create a new profile to be used for testing. A profile is simply a set of configuration that Firefox will use when you start it. You can use your existing profile as well, but I opted to create a new one so that the Firefox instance for testing will be as pristine as possible (i.e. no unnecessary plugins, no bookmarks, etc). A note: I am working on a Windows machine.
<ol><li>Bring up the command prompt and start the profile chooser by typing in firefox.exe -ProfileManager -no-remote</li><li>Click on Create Profile.</li><li>Enter the profile name you wish to use. I suggest you include the name of your project instead of just naming it “Test”.</li><li>Click on Choose Folder and navigate to the folder where you wish to store the profile files. Make sure you can access that folder easily; write the path down because you will need this in JUnit.</li><li>Click on Finish.</li><li>You will be brought back to the profile chooser dialog. Click on the Don't ask at start-up checkbox.</li></ol><div>Note: To make Firefox use your original configurations when you are browsing, bring up the profile chooser dialog, choose the profile named default, and start Firefox.</div><div>
</div><div>Configuring Firefox</div><div>Now we will configure Firefox to behave like how we want it to.
<ol><li>From the profile chooser dialog, highlight your test profile and click the Start Firefox button.</li><li>(Optional if Firefox is not your default browser) Uncheck "Always perform this check when starting Firefox".</li><li>Click on Tools > Options. We will go through the steps for each tab in the Options dialog box.</li><li>General tab</li><ul><li>Under Startup, choose Show a blank page from the When Firefox starts dropdown.</li><li>Under Downloads, uncheck the Show the Downloads window when downloading a file checkbox.</li><li>Still under Downloads, click on Browse for the Save files to option. Navigate to the folder where you want Firefox to put downloaded files. Take note of this folder as well because we will use this in JUnit.</li></ul><li>Tabs tab</li><ul><li>Uncheck Open new windows in a new tab instead and uncheck all warnings.</li></ul><li>Content tab</li><ul><li>Uncheck Block pop-up windows.</li></ul><li>(Optional) Privacy tab</li><ul><li>Under History, choose Never remember history from the Firefox will: dropdown.</li></ul><li>Advanced tab</li><ul><li>Under the General sub-tab, uncheck Use autoscrolling and uncheck Always check to see if Firefox is the default browser on startup.</li><li>If you will be using a proxy server, choose the Network sub-tab and input your proxy settings there.</li></ul></ol><div>Adding MIME Types</div></div><div>Now we need to tell Firefox how to handle downloading each specific type of file.</div><div><ol><li>Navigate to the folder where you saved your custom profile and open the mimeTypes.rdf file in a text editor.</li><li>Add the following lines towards the end of the file, right above the closing </RDF:RDF> tag.</li><pre class="brush:xml"><RDF:Seq RDF:about=”urn:mimetypes:root”>
<RDF:li RDF:resource=”urn:mimetype:text/plain”/>
</RDF:Seq>

<RDF:Description RDF:about=”urn:mimetype:handler:text/plain” NC:alwaysAsk=”false” NC:saveToDisk=”true”>
<NC:externalApplication RDF:resource=”urn:mimetype:externalApplication:text/plain”/>
</RDF:Description>

<RDF:Description RDF:about=”urn:mimetype:text/plain” NC:value=”text/plain” NC:editable=”true” NC:fileExtensions=”txt” NC:description=”Text Document”>
<NC:handlerProp RDF:resource=”urn:mimetype:handler:text/plain”/>
</RDF:Description></pre>
What we did there is we told Firefox to directly download files with MIME type text/plain. If you need to test downloading other file types like .doc or .pdf, you would need to add their MIME types to this file too.
<li>There are two ways to add MIME types to the mimeTypes.rdf file.</li><ul><li>Via the Firefox Applications GUI</li><ul><li>From Firefox, choose Tools > Options > Applications</li><li>If you have previously downloaded a file of the required MIME type, look for it in the list. In the dropdown menu on the right, under Action choose Save File.</li><li>If the MIME type you want is not in the list, you would need to go to a website that allows you to download a sample file. If the file downloads automatically without showing the download pop-up, you would not have to do anything. If the pop-up shows up, activate the Save File radio button and check the Do this automatically for files like this from now on checkbox and click Okay.</li></ul><li>Manually editing the file</li> Note: This is generally not the advised way to edit the file due to its complexity. Care is required! <ul><li>Open the mimeTypes.rdf file.</li><li>Look for the RDF:Seq node and add your desired MIME type.</li><pre class="brush:xml"><RDF:Seq RDF:about=”urn:mimetypes:root”>
<RDF:li RDF:resource=”urn:mimetype:text/plain”/>
<RDF:li RDF:resource=”urn:mimetype:application/pdf”/>
</RDF:Seq></pre><li>Add the RDF: Description nodes for that MIME type.</li><pre class="brush:xml"><RDF:Description RDF:about=”urn:mimetype:application/pdf” NC:fileExtensions=”pdf” NC:description=”Adobe Acrobat Document” NC:value=”application/pdf” NC:editable=”true”>
<NC:handlerProp RDF:resource=”urn:mimetype:handler:application/pdf”/>
</RDF:Description>

<RDF:Description RDF:about=”urn:mimetype:handler:application/pdf” NC:saveToDisk=”true” NC:alwaysAsk=”false” /></pre></ul></ul></ol>To use this profile in our Selenium test:
<pre class="brush:java">FirefoxProfile profile = new FirefoxProfile(new File(“path/to/your/profile”));

// We can also set the download folder via code
File testFile = new File(“path/to/download/folder”);
String downloadFolder = testFile.getAbsolutePath();
profile.setPreference(“browser.download.dir”, downloadFolder);

WebDriver driver = new FirefoxDriver(profile);</pre> And you’re done. :) </div>

3 min read
Back to Top ↑

JUnit

Selenium and File Downloads

Lately, one of my tasks has been to automate regression tests on one of our apps. Since this is a web app, we are using Selenium. Here, I enumerate the steps to configure Firefox for file downloading using Selenium and JUnit by foregoing the downloads dialog box.

Setting up the profile
We will create a new profile to be used for testing. A profile is simply a set of configuration that Firefox will use when you start it. You can use your existing profile as well, but I opted to create a new one so that the Firefox instance for testing will be as pristine as possible (i.e. no unnecessary plugins, no bookmarks, etc). A note: I am working on a Windows machine.
<ol><li>Bring up the command prompt and start the profile chooser by typing in firefox.exe -ProfileManager -no-remote</li><li>Click on Create Profile.</li><li>Enter the profile name you wish to use. I suggest you include the name of your project instead of just naming it “Test”.</li><li>Click on Choose Folder and navigate to the folder where you wish to store the profile files. Make sure you can access that folder easily; write the path down because you will need this in JUnit.</li><li>Click on Finish.</li><li>You will be brought back to the profile chooser dialog. Click on the Don't ask at start-up checkbox.</li></ol><div>Note: To make Firefox use your original configurations when you are browsing, bring up the profile chooser dialog, choose the profile named default, and start Firefox.</div><div>
</div><div>Configuring Firefox</div><div>Now we will configure Firefox to behave like how we want it to.
<ol><li>From the profile chooser dialog, highlight your test profile and click the Start Firefox button.</li><li>(Optional if Firefox is not your default browser) Uncheck "Always perform this check when starting Firefox".</li><li>Click on Tools > Options. We will go through the steps for each tab in the Options dialog box.</li><li>General tab</li><ul><li>Under Startup, choose Show a blank page from the When Firefox starts dropdown.</li><li>Under Downloads, uncheck the Show the Downloads window when downloading a file checkbox.</li><li>Still under Downloads, click on Browse for the Save files to option. Navigate to the folder where you want Firefox to put downloaded files. Take note of this folder as well because we will use this in JUnit.</li></ul><li>Tabs tab</li><ul><li>Uncheck Open new windows in a new tab instead and uncheck all warnings.</li></ul><li>Content tab</li><ul><li>Uncheck Block pop-up windows.</li></ul><li>(Optional) Privacy tab</li><ul><li>Under History, choose Never remember history from the Firefox will: dropdown.</li></ul><li>Advanced tab</li><ul><li>Under the General sub-tab, uncheck Use autoscrolling and uncheck Always check to see if Firefox is the default browser on startup.</li><li>If you will be using a proxy server, choose the Network sub-tab and input your proxy settings there.</li></ul></ol><div>Adding MIME Types</div></div><div>Now we need to tell Firefox how to handle downloading each specific type of file.</div><div><ol><li>Navigate to the folder where you saved your custom profile and open the mimeTypes.rdf file in a text editor.</li><li>Add the following lines towards the end of the file, right above the closing </RDF:RDF> tag.</li><pre class="brush:xml"><RDF:Seq RDF:about=”urn:mimetypes:root”>
<RDF:li RDF:resource=”urn:mimetype:text/plain”/>
</RDF:Seq>

<RDF:Description RDF:about=”urn:mimetype:handler:text/plain” NC:alwaysAsk=”false” NC:saveToDisk=”true”>
<NC:externalApplication RDF:resource=”urn:mimetype:externalApplication:text/plain”/>
</RDF:Description>

<RDF:Description RDF:about=”urn:mimetype:text/plain” NC:value=”text/plain” NC:editable=”true” NC:fileExtensions=”txt” NC:description=”Text Document”>
<NC:handlerProp RDF:resource=”urn:mimetype:handler:text/plain”/>
</RDF:Description></pre>
What we did there is we told Firefox to directly download files with MIME type text/plain. If you need to test downloading other file types like .doc or .pdf, you would need to add their MIME types to this file too.
<li>There are two ways to add MIME types to the mimeTypes.rdf file.</li><ul><li>Via the Firefox Applications GUI</li><ul><li>From Firefox, choose Tools > Options > Applications</li><li>If you have previously downloaded a file of the required MIME type, look for it in the list. In the dropdown menu on the right, under Action choose Save File.</li><li>If the MIME type you want is not in the list, you would need to go to a website that allows you to download a sample file. If the file downloads automatically without showing the download pop-up, you would not have to do anything. If the pop-up shows up, activate the Save File radio button and check the Do this automatically for files like this from now on checkbox and click Okay.</li></ul><li>Manually editing the file</li> Note: This is generally not the advised way to edit the file due to its complexity. Care is required! <ul><li>Open the mimeTypes.rdf file.</li><li>Look for the RDF:Seq node and add your desired MIME type.</li><pre class="brush:xml"><RDF:Seq RDF:about=”urn:mimetypes:root”>
<RDF:li RDF:resource=”urn:mimetype:text/plain”/>
<RDF:li RDF:resource=”urn:mimetype:application/pdf”/>
</RDF:Seq></pre><li>Add the RDF: Description nodes for that MIME type.</li><pre class="brush:xml"><RDF:Description RDF:about=”urn:mimetype:application/pdf” NC:fileExtensions=”pdf” NC:description=”Adobe Acrobat Document” NC:value=”application/pdf” NC:editable=”true”>
<NC:handlerProp RDF:resource=”urn:mimetype:handler:application/pdf”/>
</RDF:Description>

<RDF:Description RDF:about=”urn:mimetype:handler:application/pdf” NC:saveToDisk=”true” NC:alwaysAsk=”false” /></pre></ul></ul></ol>To use this profile in our Selenium test:
<pre class="brush:java">FirefoxProfile profile = new FirefoxProfile(new File(“path/to/your/profile”));

// We can also set the download folder via code
File testFile = new File(“path/to/download/folder”);
String downloadFolder = testFile.getAbsolutePath();
profile.setPreference(“browser.download.dir”, downloadFolder);

WebDriver driver = new FirefoxDriver(profile);</pre> And you’re done. :) </div>

3 min read
Back to Top ↑

file download

Selenium and File Downloads

Lately, one of my tasks has been to automate regression tests on one of our apps. Since this is a web app, we are using Selenium. Here, I enumerate the steps to configure Firefox for file downloading using Selenium and JUnit by foregoing the downloads dialog box.

Setting up the profile
We will create a new profile to be used for testing. A profile is simply a set of configuration that Firefox will use when you start it. You can use your existing profile as well, but I opted to create a new one so that the Firefox instance for testing will be as pristine as possible (i.e. no unnecessary plugins, no bookmarks, etc). A note: I am working on a Windows machine.
<ol><li>Bring up the command prompt and start the profile chooser by typing in firefox.exe -ProfileManager -no-remote</li><li>Click on Create Profile.</li><li>Enter the profile name you wish to use. I suggest you include the name of your project instead of just naming it “Test”.</li><li>Click on Choose Folder and navigate to the folder where you wish to store the profile files. Make sure you can access that folder easily; write the path down because you will need this in JUnit.</li><li>Click on Finish.</li><li>You will be brought back to the profile chooser dialog. Click on the Don't ask at start-up checkbox.</li></ol><div>Note: To make Firefox use your original configurations when you are browsing, bring up the profile chooser dialog, choose the profile named default, and start Firefox.</div><div>
</div><div>Configuring Firefox</div><div>Now we will configure Firefox to behave like how we want it to.
<ol><li>From the profile chooser dialog, highlight your test profile and click the Start Firefox button.</li><li>(Optional if Firefox is not your default browser) Uncheck "Always perform this check when starting Firefox".</li><li>Click on Tools > Options. We will go through the steps for each tab in the Options dialog box.</li><li>General tab</li><ul><li>Under Startup, choose Show a blank page from the When Firefox starts dropdown.</li><li>Under Downloads, uncheck the Show the Downloads window when downloading a file checkbox.</li><li>Still under Downloads, click on Browse for the Save files to option. Navigate to the folder where you want Firefox to put downloaded files. Take note of this folder as well because we will use this in JUnit.</li></ul><li>Tabs tab</li><ul><li>Uncheck Open new windows in a new tab instead and uncheck all warnings.</li></ul><li>Content tab</li><ul><li>Uncheck Block pop-up windows.</li></ul><li>(Optional) Privacy tab</li><ul><li>Under History, choose Never remember history from the Firefox will: dropdown.</li></ul><li>Advanced tab</li><ul><li>Under the General sub-tab, uncheck Use autoscrolling and uncheck Always check to see if Firefox is the default browser on startup.</li><li>If you will be using a proxy server, choose the Network sub-tab and input your proxy settings there.</li></ul></ol><div>Adding MIME Types</div></div><div>Now we need to tell Firefox how to handle downloading each specific type of file.</div><div><ol><li>Navigate to the folder where you saved your custom profile and open the mimeTypes.rdf file in a text editor.</li><li>Add the following lines towards the end of the file, right above the closing </RDF:RDF> tag.</li><pre class="brush:xml"><RDF:Seq RDF:about=”urn:mimetypes:root”>
<RDF:li RDF:resource=”urn:mimetype:text/plain”/>
</RDF:Seq>

<RDF:Description RDF:about=”urn:mimetype:handler:text/plain” NC:alwaysAsk=”false” NC:saveToDisk=”true”>
<NC:externalApplication RDF:resource=”urn:mimetype:externalApplication:text/plain”/>
</RDF:Description>

<RDF:Description RDF:about=”urn:mimetype:text/plain” NC:value=”text/plain” NC:editable=”true” NC:fileExtensions=”txt” NC:description=”Text Document”>
<NC:handlerProp RDF:resource=”urn:mimetype:handler:text/plain”/>
</RDF:Description></pre>
What we did there is we told Firefox to directly download files with MIME type text/plain. If you need to test downloading other file types like .doc or .pdf, you would need to add their MIME types to this file too.
<li>There are two ways to add MIME types to the mimeTypes.rdf file.</li><ul><li>Via the Firefox Applications GUI</li><ul><li>From Firefox, choose Tools > Options > Applications</li><li>If you have previously downloaded a file of the required MIME type, look for it in the list. In the dropdown menu on the right, under Action choose Save File.</li><li>If the MIME type you want is not in the list, you would need to go to a website that allows you to download a sample file. If the file downloads automatically without showing the download pop-up, you would not have to do anything. If the pop-up shows up, activate the Save File radio button and check the Do this automatically for files like this from now on checkbox and click Okay.</li></ul><li>Manually editing the file</li> Note: This is generally not the advised way to edit the file due to its complexity. Care is required! <ul><li>Open the mimeTypes.rdf file.</li><li>Look for the RDF:Seq node and add your desired MIME type.</li><pre class="brush:xml"><RDF:Seq RDF:about=”urn:mimetypes:root”>
<RDF:li RDF:resource=”urn:mimetype:text/plain”/>
<RDF:li RDF:resource=”urn:mimetype:application/pdf”/>
</RDF:Seq></pre><li>Add the RDF: Description nodes for that MIME type.</li><pre class="brush:xml"><RDF:Description RDF:about=”urn:mimetype:application/pdf” NC:fileExtensions=”pdf” NC:description=”Adobe Acrobat Document” NC:value=”application/pdf” NC:editable=”true”>
<NC:handlerProp RDF:resource=”urn:mimetype:handler:application/pdf”/>
</RDF:Description>

<RDF:Description RDF:about=”urn:mimetype:handler:application/pdf” NC:saveToDisk=”true” NC:alwaysAsk=”false” /></pre></ul></ul></ol>To use this profile in our Selenium test:
<pre class="brush:java">FirefoxProfile profile = new FirefoxProfile(new File(“path/to/your/profile”));

// We can also set the download folder via code
File testFile = new File(“path/to/download/folder”);
String downloadFolder = testFile.getAbsolutePath();
profile.setPreference(“browser.download.dir”, downloadFolder);

WebDriver driver = new FirefoxDriver(profile);</pre> And you’re done. :) </div>

3 min read
Back to Top ↑

clone

Quick Tip: git cloning

A user-friendly way of cloning a git repo is through the eGit plug-in in Eclipse. But sometimes, especially on Windows machines, Eclipse has trouble cleaning up after itself after completing a clone operation. The best workaround for this is to clone the repo from git bash and then import the repo in Eclipse.
<pre class="brush:bash">default@ZDOMINGUEZ-T420 ~
$ git clone git@github.com:<your git repo> <local folder to check out to></pre>When git finishes cloning your repo, import it to Eclipse.
<div class="separator" style="clear: both; text-align: center;"></div>Browse to the folder you checked out to, click OK, and the newly-cloned repo should now appear on the Git Repositories view.

~1 min read
Back to Top ↑

float

Adding a float value to your resources

Earlier today, I was trying to figure out how to add a float value to constants file. What I used to do was add a string value in my strings.xml, retrieve the string value, and convert it to float. <pre class="brush:java">float floatFromFile = Float.valueOf(getResources().getString(R.string.my_float));</pre> I was trying out something new but it wasn’t working, so I decided to look for a more accepted solution. Google led me to this StackOverflow question. I was on the right track after all! I think the accepted answer is incomplete, or not clear enough for my purposes. I ended up having this entry in my dimensions.xml file: <pre class="brush:xml"><item name="face_feature_marker_size" type="vals" format="float">2.0</item></pre> And then in my code, I retrieve the value as: <pre class="brush:java">TypedValue tempVal = new TypedValue();
getResources().getValue(R.vals.face_feature_marker_size, tempVal, true);
float markerSize = testVal.getFloat();</pre> I ended up having more lines of code with no idea if this is more optimized. Let me know what you think!

~1 min read
Back to Top ↑

submodule

Cloning a remote branch in git

My current project at work uses git, and I have always been a CVS/SVN baby so I’m still trying to find my way around it. Today I wanted to clone a remote branch to my local computer. This remote branch also has submodules, so I want to get those too.

This assumes that you use Git Bash. First, navigate to the folder in you local computer where you want git to clone the remote branch. Once there, we can start cloning the repo. The following steps do the dirty work:
<pre class="brush:bash">$ git init
$ git fetch <git url> <branch name>:refs/remotes/origin/<branch name>
$ git checkout -b <branch name> origin/<branch name></pre>
This retrieves the contents of the remote branch and copies it to our local computer in a local branch (confused yet?). To update our copy of the submodules, the following commands should work:
<pre class="brush:bash">$ git submodule init
$ git submodule update</pre>

~1 min read
Back to Top ↑

remote branch

Cloning a remote branch in git

My current project at work uses git, and I have always been a CVS/SVN baby so I’m still trying to find my way around it. Today I wanted to clone a remote branch to my local computer. This remote branch also has submodules, so I want to get those too.

This assumes that you use Git Bash. First, navigate to the folder in you local computer where you want git to clone the remote branch. Once there, we can start cloning the repo. The following steps do the dirty work:
<pre class="brush:bash">$ git init
$ git fetch <git url> <branch name>:refs/remotes/origin/<branch name>
$ git checkout -b <branch name> origin/<branch name></pre>
This retrieves the contents of the remote branch and copies it to our local computer in a local branch (confused yet?). To update our copy of the submodules, the following commands should work:
<pre class="brush:bash">$ git submodule init
$ git submodule update</pre>

~1 min read
Back to Top ↑

logcat

Save Logcat contents to file

Note to self: to save the contents of Logcat to a text file:
<ol><li>Navigate to the SDK installation directory.</li><li>Go to the /platform-tools folder.</li><li>adb logcat -d > my_logcat_dump.txt</li></ol><div>If there is more than one device connected to adb, specify which device’s log to dump:</div><div><blockquote class="tr_bq">adb -s emulator-5558 logcat -d > my_logcat_dump.txt</blockquote></div>

~1 min read
Back to Top ↑

connectivity

I Can Haz Internetz!

Last week, I was exploring connectivity monitoring and came up with a small app for demo. The app listens for connectivity changes and sends a notification to the user informing them of the change.

First off, create a class (I named mine ConnectivityUpdate.java) and make it extend BroadcastReceiver. This class should do what you want when notified of connectivity changes. You will be asked to implement the onReceive() method. Now here’s what I want to happen when the system notifies me of changes:
1. Check what kind of change I am being notified of: did I get Internet? Or did I lose Internet?
2. Compare this to what connectivity I had before the notification so I can inform the user (and app-wise do whatever it is I’m supposed to do like start syncing or stop syncing).

In my implementation, this is done as:
<pre class="brush:java">@Override
public void onReceive(Context context, Intent intent) {

boolean hasInternet = false;
Log.d(LOG_TAG, “Received broadcast!”);

// Do I have Internet?
if(intent.getAction().equals(ConnectivityManager.CONNECTIVITY_ACTION)) {
hasInternet = (new NDUtils()).hasInternet(context);
}

// Did I use to have Internet?
SharedPrefsManager prefs = new SharedPrefsManager();
boolean prevValue = prefs.hasNetwork(context);

if(prevValue != hasInternet){
// Remember what we have now
(new SharedPrefsManager()).saveNetworkState(context, hasInternet);
sendNotification(hasInternet, context);
}
}
</pre>
The actual checking if we have Internet or not is done by a utility class: <pre class="brush:java">public boolean hasInternet(Context context){
NetworkInfo networkInfo = (NetworkInfo) ((ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE)).getActiveNetworkInfo();

// Check if we are connected to Wifi or mobile internet
// AND if we can actually send data
if(networkInfo!=null &&
(networkInfo.getType() == ConnectivityManager.TYPE_WIFI
  networkInfo.getType() == ConnectivityManager.TYPE_MOBILE)
&& networkInfo.isConnected()) {
return true;
}

return false;
}
</pre>
The Android javadoc on getActiveNetworkInfo() says it may return null, so we check first to avoid NullPointerExceptions, then we check if we have WiFi or mobile internet, THEN (and this is important) we check if we can send data through this network.

You can also refine this filter more by checking the type of mobile network the user has (we want 3G or faster) or by checking if the user is roaming (user should not be roaming). Here is a more complete method describing what I just said:<pre class="brush:java">public boolean hasInternet(Context context){
NetworkInfo networkInfo = (NetworkInfo) ((ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE)).getActiveNetworkInfo();
TelephonyManager telephony = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
if(networkInfo!=null && networkInfo.isConnected() &&
(networkInfo.getType() == ConnectivityManager.TYPE_WIFI
 
(networkInfo.getType() == ConnectivityManager.TYPE_MOBILE && networkInfo.getSubtype() > TelephonyManager.NETWORK_TYPE_UMTS &&
!telephony.isNetworkRoaming()))) {

return true;
}

return false;
}</pre>
I then compare the returned value of the utility method to the last value saved in my preferences file. That part of the code is straight up saving/getting a boolean value from a SharedPreferences file.

I then inform the user of the network change through a notification. When the user clicks on the expanded notification, I want to open the app. The app can then display details about the network, but right now what my sample app does is simply show the boolean value returned by the utility method. Anyway, here’s how I send the notification:
<pre class="brush:java">private void sendNotification(boolean hasInternet, Context context) {
NotificationManager notificationManager = (NotificationManager)context.getSystemService(Context.NOTIFICATION_SERVICE);

// The notification details seen by the user when the drawer is pulled down
String notificationTitle = “Change in data connection!”;
String notificationText = “We have internet?: “ + (hasInternet ? “YES!” : “NO :(“);

// The icon and the text to be displayed in the notification area
Notification myNotification = new Notification(R.drawable.ic_launcher, “Broadcast received!”, System.currentTimeMillis());

// Create a new intent to launch my app
Intent myIntent = new Intent(context.getApplicationContext(), NetworkDetector.class);
PendingIntent pendingIntent = PendingIntent.getActivity(context.getApplicationContext(), 0, myIntent, Intent.FLAG_ACTIVITY_NEW_TASK);

// Send that notification! MY_NOTIFICATION_ID is a value greater than 0.
myNotification.setLatestEventInfo(context,
notificationTitle,
notificationText,
pendingIntent);
notificationManager.notify(MY_NOTIFICATION_ID, myNotification);
}</pre>
So how do we tell the OS that we have made this receiver and please notify us when the connectivity changes, Mister Android please? We create a broadcast receiver in the app’s manifest! We listen to both CONNECTIVITY_CHANGE and WiFi STATE_CHANGE. The value for android:name is the name of the class containing the receiver implementation.
<pre class="brush:xml"><receiver
android:name=”.util.ConnectivityUpdate”
android:enabled=”true”
android:exported=”true”
android:label=”ConnectivityActionReceiver” >
<intent-filter>
<action android:name=”android.net.conn.CONNECTIVITY_CHANGE” />
<action android:name=”android.net.wifi.STATE_CHANGE” />
</intent-filter>
</receiver></pre>
And don’t forget to add the permissions to read the network state:
<pre class="brush:xml"><uses-permission android:name=”android.permission.ACCESS_WIFI_STATE” />
<uses-permission android:name=”android.permission.ACCESS_NETWORK_STATE” /></pre>
<div>The complete source code for this sample app is in github.</div>
3 min read
Back to Top ↑

notification

I Can Haz Internetz!

Last week, I was exploring connectivity monitoring and came up with a small app for demo. The app listens for connectivity changes and sends a notification to the user informing them of the change.

First off, create a class (I named mine ConnectivityUpdate.java) and make it extend BroadcastReceiver. This class should do what you want when notified of connectivity changes. You will be asked to implement the onReceive() method. Now here’s what I want to happen when the system notifies me of changes:
1. Check what kind of change I am being notified of: did I get Internet? Or did I lose Internet?
2. Compare this to what connectivity I had before the notification so I can inform the user (and app-wise do whatever it is I’m supposed to do like start syncing or stop syncing).

In my implementation, this is done as:
<pre class="brush:java">@Override
public void onReceive(Context context, Intent intent) {

boolean hasInternet = false;
Log.d(LOG_TAG, “Received broadcast!”);

// Do I have Internet?
if(intent.getAction().equals(ConnectivityManager.CONNECTIVITY_ACTION)) {
hasInternet = (new NDUtils()).hasInternet(context);
}

// Did I use to have Internet?
SharedPrefsManager prefs = new SharedPrefsManager();
boolean prevValue = prefs.hasNetwork(context);

if(prevValue != hasInternet){
// Remember what we have now
(new SharedPrefsManager()).saveNetworkState(context, hasInternet);
sendNotification(hasInternet, context);
}
}
</pre>
The actual checking if we have Internet or not is done by a utility class: <pre class="brush:java">public boolean hasInternet(Context context){
NetworkInfo networkInfo = (NetworkInfo) ((ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE)).getActiveNetworkInfo();

// Check if we are connected to Wifi or mobile internet
// AND if we can actually send data
if(networkInfo!=null &&
(networkInfo.getType() == ConnectivityManager.TYPE_WIFI
  networkInfo.getType() == ConnectivityManager.TYPE_MOBILE)
&& networkInfo.isConnected()) {
return true;
}

return false;
}
</pre>
The Android javadoc on getActiveNetworkInfo() says it may return null, so we check first to avoid NullPointerExceptions, then we check if we have WiFi or mobile internet, THEN (and this is important) we check if we can send data through this network.

You can also refine this filter more by checking the type of mobile network the user has (we want 3G or faster) or by checking if the user is roaming (user should not be roaming). Here is a more complete method describing what I just said:<pre class="brush:java">public boolean hasInternet(Context context){
NetworkInfo networkInfo = (NetworkInfo) ((ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE)).getActiveNetworkInfo();
TelephonyManager telephony = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
if(networkInfo!=null && networkInfo.isConnected() &&
(networkInfo.getType() == ConnectivityManager.TYPE_WIFI
 
(networkInfo.getType() == ConnectivityManager.TYPE_MOBILE && networkInfo.getSubtype() > TelephonyManager.NETWORK_TYPE_UMTS &&
!telephony.isNetworkRoaming()))) {

return true;
}

return false;
}</pre>
I then compare the returned value of the utility method to the last value saved in my preferences file. That part of the code is straight up saving/getting a boolean value from a SharedPreferences file.

I then inform the user of the network change through a notification. When the user clicks on the expanded notification, I want to open the app. The app can then display details about the network, but right now what my sample app does is simply show the boolean value returned by the utility method. Anyway, here’s how I send the notification:
<pre class="brush:java">private void sendNotification(boolean hasInternet, Context context) {
NotificationManager notificationManager = (NotificationManager)context.getSystemService(Context.NOTIFICATION_SERVICE);

// The notification details seen by the user when the drawer is pulled down
String notificationTitle = “Change in data connection!”;
String notificationText = “We have internet?: “ + (hasInternet ? “YES!” : “NO :(“);

// The icon and the text to be displayed in the notification area
Notification myNotification = new Notification(R.drawable.ic_launcher, “Broadcast received!”, System.currentTimeMillis());

// Create a new intent to launch my app
Intent myIntent = new Intent(context.getApplicationContext(), NetworkDetector.class);
PendingIntent pendingIntent = PendingIntent.getActivity(context.getApplicationContext(), 0, myIntent, Intent.FLAG_ACTIVITY_NEW_TASK);

// Send that notification! MY_NOTIFICATION_ID is a value greater than 0.
myNotification.setLatestEventInfo(context,
notificationTitle,
notificationText,
pendingIntent);
notificationManager.notify(MY_NOTIFICATION_ID, myNotification);
}</pre>
So how do we tell the OS that we have made this receiver and please notify us when the connectivity changes, Mister Android please? We create a broadcast receiver in the app’s manifest! We listen to both CONNECTIVITY_CHANGE and WiFi STATE_CHANGE. The value for android:name is the name of the class containing the receiver implementation.
<pre class="brush:xml"><receiver
android:name=”.util.ConnectivityUpdate”
android:enabled=”true”
android:exported=”true”
android:label=”ConnectivityActionReceiver” >
<intent-filter>
<action android:name=”android.net.conn.CONNECTIVITY_CHANGE” />
<action android:name=”android.net.wifi.STATE_CHANGE” />
</intent-filter>
</receiver></pre>
And don’t forget to add the permissions to read the network state:
<pre class="brush:xml"><uses-permission android:name=”android.permission.ACCESS_WIFI_STATE” />
<uses-permission android:name=”android.permission.ACCESS_NETWORK_STATE” /></pre>
<div>The complete source code for this sample app is in github.</div>
3 min read
Back to Top ↑

utils

Back to Top ↑

gps

Quick Tip: Updating the location update frequency

When using Google Play’s Location Services and you want to change the frequency of the updates, make sure to do these in order:

<pre class="brush:java">stopLocationUpdates();
// This method should implement mLocationClient.removeLocationUpdates()

// Set the new frequency in your location client
updateLocationClient(frequency);

startLocationUpdates();
// This method should implement mLocationClient.requestLocationUpdates()
// which means it should check for isConnected() as well!</pre>
If you do not remove the updates before updating the frequency, it looks like the old frequency update is still active BUT a new one is started.

~1 min read
Back to Top ↑

location updates

Quick Tip: Updating the location update frequency

When using Google Play’s Location Services and you want to change the frequency of the updates, make sure to do these in order:

<pre class="brush:java">stopLocationUpdates();
// This method should implement mLocationClient.removeLocationUpdates()

// Set the new frequency in your location client
updateLocationClient(frequency);

startLocationUpdates();
// This method should implement mLocationClient.requestLocationUpdates()
// which means it should check for isConnected() as well!</pre>
If you do not remove the updates before updating the frequency, it looks like the old frequency update is still active BUT a new one is started.

~1 min read
Back to Top ↑

swipe to refresh

Swipe, not Pull, to Refresh

I have recently came across this new View in the support library package that allows your app to have built-in support for pull swipe to refresh. This is pretty cool, since we don’t have to use any of the libraries out there. Admittedly, very little customization can be done, but then what else can we customize, right?

Anyway, here’s a short demo of using this nifty little view.
<div class="separator" style="clear: both; text-align: center;"></div><table><tbody><tr><td><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody><tr><td style="text-align: center;"></td></tr><tr><td class="tr-caption" style="text-align: center;">Initial list</td></tr></tbody></table></td><td><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody><tr><td style="text-align: center;"></td></tr><tr><td class="tr-caption" style="text-align: center;">While refreshing</td></tr></tbody></table></td><td><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody><tr><td style="text-align: center;"></td></tr><tr><td class="tr-caption" style="text-align: center;">After refreshing</td></tr></tbody></table></td></tr></tbody></table>
The app is a simple ListView that shows a list of countries. Swiping down on the list will simulate a long-running activity (like connecting to a server, for example) and afterwards updating the list with new data.

Adding support for swipe to refresh is pretty straightforward. You would have to wrap the swipe-able layout in a SwipeRefreshLayout. Here is my XML file:

<pre class="brush:xml"><android.support.v4.widget.SwipeRefreshLayout xmlns:android=”http://schemas.android.com/apk/res/android”
xmlns:tools=”http://schemas.android.com/tools”
android:id=”@+id/container”
android:layout_width=”match_parent”
android:layout_height=”match_parent”
tools:ignore=”MergeRootFrame” >

<ListView
android:id=”@android:id/list”
android:layout_width=”match_parent”
android:layout_height=”match_parent” />

</android.support.v4.widget.SwipeRefreshLayout>
</pre>
In your Fragment, you would then have to put an onRefreshListener on this SwipeRefreshLayout. In my Fragment’s onCreateView, I have this:

<pre class="brush:java">// Configure the swipe refresh layout
mSwipeRefreshLayout = (SwipeRefreshLayout) rootView.findViewById(R.id.container);
mSwipeRefreshLayout.setOnRefreshListener(this);
mSwipeRefreshLayout.setColorScheme(
R.color.swipe_color_1, R.color.swipe_color_2,
R.color.swipe_color_3, R.color.swipe_color_4);
</pre>
The colors are defined in a colors.xml file in my res/values folder. To show or hide the refresh animation, you would have to call setRefreshing(boolean). This means that if you have to kick off an AsyncTask when the user swipes down, call setRefreshing(true) in onPreExecute, and call setRefreshing(false) in onPostExecute.

The implementation of onRefresh in the demo app is pretty simple, it simply grabs the next bunch of countries from a pre-defined list.

<pre class="brush:java">@Override
public void onRefresh() {
// Start showing the refresh animation
mSwipeRefreshLayout.setRefreshing(true);

// Simulate a long running activity
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
updateCountries();
}
}, 5000);
}
</pre>
That’s it really.  Nice and short. The code for this demo is in Github.

1 min read
Back to Top ↑

database

SQLiteAssetHelper + ORMLite

I recently had cause to use Jeff Gilfelt’s SQLite Asset Helper library. For those unfamiliar, it is a library that can help with including a pre-populated SQLite database with your Android application. It is extremely convenient with unbundling a potentially huge database you would want to ship.

For the app I was working on, I also wanted to use ORMLite. This is another library that helps with persisting POJOs to SQLite databases. If you deal with a lot of persisted objects in your code, then this is probably something worth looking into.

I won’t deal here with how ORMLite does its stuff, I’ll leave it to you to go through the documentation. What I’ll write about today is how to make these two libraries work together.

Right. Moving on. If you look at ORMLite’s sample code, it mentions that your database helper class must extend OrmLiteSqliteOpenHelper. If you look at SQLite Asset Helper’s sample code, it mentions that your database helper class must extend SQLiteAssetHelper. What this means for us is that somehow, we need our database helper class to be able to talk to both of these libraries.

Since Android Studio is now the official IDE of choice, the sample code for this post is now AS-compatible. Yay!

First, gradle:
<pre class="brush:xml">compile ‘com.readystatesoftware.sqliteasset:sqliteassethelper:2.0.1’
compile ‘com.j256.ormlite:ormlite-android:4.48’</pre>
When dealing with anything database, I tend to create my POJOs first. For this sample, I will be using the infamous Northwind database. For simplicity, this app will simply get the first entry from the Employees table and dump the contents into a TextView.

Since SQLite Asset Helper is the one who is in charge of our database creation and upgrade operations, we have to let it do the setup. Follow Jeff’s example for that, BUT follow ORMLite’s example for setting up ORMLite with no helper. At the end of it, you should have something similar to this.

To actually use ORMLite, just do as you usually would:
<pre class="brush:java">mOrmDbHelper = getHelper();

try {

    Dao<Employee, Integer> employeeDao = mOrmDbHelper.getEmployeeDao();

    // Try to get the first entry in the table
    Employee employee = employeeDao.queryBuilder().queryForFirst();
    if(employee == null) {
        textView.setText(“No employees found!”);
    } else {
        textView.setText(employee.toString());
    }
} catch (SQLException e) {
    e.printStackTrace();
}</pre>
Here we just get the first entry we can from the table and dump. If all goes well when we run the app, we should see this in the logs:

<pre class="brush:xml">01-20 23:02:39.203  12555-12555/droidista.blogspot.com.ormsqliteassethelper W/SQLiteAssetHelper﹕ copying database from assets…
01-20 23:02:39.226  12555-12555/droidista.blogspot.com.ormsqliteassethelper W/SQLiteAssetHelper﹕ database copy complete
01-20 23:02:39.289  12555-12555/droidista.blogspot.com.ormsqliteassethelper I/SQLiteAssetHelper﹕ successfully opened database northwind.db</pre>
And we should see Nancy’s details displayed on screen in all it’s raw .toString() glory.

2 min read
Back to Top ↑

sqlite

SQLiteAssetHelper + ORMLite

I recently had cause to use Jeff Gilfelt’s SQLite Asset Helper library. For those unfamiliar, it is a library that can help with including a pre-populated SQLite database with your Android application. It is extremely convenient with unbundling a potentially huge database you would want to ship.

For the app I was working on, I also wanted to use ORMLite. This is another library that helps with persisting POJOs to SQLite databases. If you deal with a lot of persisted objects in your code, then this is probably something worth looking into.

I won’t deal here with how ORMLite does its stuff, I’ll leave it to you to go through the documentation. What I’ll write about today is how to make these two libraries work together.

Right. Moving on. If you look at ORMLite’s sample code, it mentions that your database helper class must extend OrmLiteSqliteOpenHelper. If you look at SQLite Asset Helper’s sample code, it mentions that your database helper class must extend SQLiteAssetHelper. What this means for us is that somehow, we need our database helper class to be able to talk to both of these libraries.

Since Android Studio is now the official IDE of choice, the sample code for this post is now AS-compatible. Yay!

First, gradle:
<pre class="brush:xml">compile ‘com.readystatesoftware.sqliteasset:sqliteassethelper:2.0.1’
compile ‘com.j256.ormlite:ormlite-android:4.48’</pre>
When dealing with anything database, I tend to create my POJOs first. For this sample, I will be using the infamous Northwind database. For simplicity, this app will simply get the first entry from the Employees table and dump the contents into a TextView.

Since SQLite Asset Helper is the one who is in charge of our database creation and upgrade operations, we have to let it do the setup. Follow Jeff’s example for that, BUT follow ORMLite’s example for setting up ORMLite with no helper. At the end of it, you should have something similar to this.

To actually use ORMLite, just do as you usually would:
<pre class="brush:java">mOrmDbHelper = getHelper();

try {

    Dao<Employee, Integer> employeeDao = mOrmDbHelper.getEmployeeDao();

    // Try to get the first entry in the table
    Employee employee = employeeDao.queryBuilder().queryForFirst();
    if(employee == null) {
        textView.setText(“No employees found!”);
    } else {
        textView.setText(employee.toString());
    }
} catch (SQLException e) {
    e.printStackTrace();
}</pre>
Here we just get the first entry we can from the table and dump. If all goes well when we run the app, we should see this in the logs:

<pre class="brush:xml">01-20 23:02:39.203  12555-12555/droidista.blogspot.com.ormsqliteassethelper W/SQLiteAssetHelper﹕ copying database from assets…
01-20 23:02:39.226  12555-12555/droidista.blogspot.com.ormsqliteassethelper W/SQLiteAssetHelper﹕ database copy complete
01-20 23:02:39.289  12555-12555/droidista.blogspot.com.ormsqliteassethelper I/SQLiteAssetHelper﹕ successfully opened database northwind.db</pre>
And we should see Nancy’s details displayed on screen in all it’s raw .toString() glory.

2 min read
Back to Top ↑

material design

On being material

In case you missed it, I made a blog post about updating our app to material design. In it I talk about what material design is and what we did to adopt it. I hope you enjoy reading it as much as I did writing it. :) Head on over to Domain’s tech blog for the details.

~1 min read
Back to Top ↑

podcast

In which I was in a podcast

It has been a month since IO and in case you missed it, I got to chat with Kaushik of Fragmented. And by golly, I made it into an episode! At that point I was about to lose my voice, so I sound really husky. :p

~1 min read
Back to Top ↑

open source

A big step

Today was the day.

~1 min read
Back to Top ↑

talks

Tools of the Trade

Here are the slides to my talk at the Android Meetup tonight.

~1 min read
Back to Top ↑

tech talk

Tools of the Trade: Unabridged

I gave an unabridged version of my last Android Meetup talk at this year’s YOW Conference. It has been an honour being part of this awesome conference!

~1 min read
Back to Top ↑

gde

Tools of the Trade: Unabridged

I gave an unabridged version of my last Android Meetup talk at this year’s YOW Conference. It has been an honour being part of this awesome conference!

~1 min read
Back to Top ↑

nougat

The Quirks of Supporting SDK 25

The last developer preview of Android 7.1 has started shipping, which means APIs are (based on past experience) more or less stable. There is a very good write up on developer.android.com on how to get started with supporting these new features. I set about trying it out, and here’s what happened.

4 min read
Back to Top ↑

share

Back to Top ↑

wtm

Back to Top ↑

plaid

@{app.plaid}

I gave a talk this morning in the first ever Droidcon Vietnam! It is about two of the things I love in Android – Plaid and data binding.

~1 min read
Back to Top ↑

io17

There is Always Room for Improvement

During the beginning of my Android career, one of the things I had to do was to save some data to somewhere. I found out that for my purposes, I had to use an SQLite database. Reading through the docs, I was afraid. Petrified, even.

5 min read
Back to Top ↑

arch

There is Always Room for Improvement

During the beginning of my Android career, one of the things I had to do was to save some data to somewhere. I found out that for my purposes, I had to use an SQLite database. Reading through the docs, I was afraid. Petrified, even.

5 min read
Back to Top ↑

quick tip

Children, Respect Your Parent(s)

I was updating a bit of code the other day that involved dynamically inflating views into a LinearLayout using DataBindingUtil.inflate(LayoutInflater.from(context), R.layout.row_related_property, container, false).

1 min read
Back to Top ↑

bye

Next Move

Today is my last day at Domain. After three years, seven months, and three days, it is time to move out.

~1 min read
Back to Top ↑

constraint layout

Effectively Wrangling Together a Bunch of Views

One bit of task that I find myself doing over and over again is managing a bunch of Views and their visibility. In the olden days <insert old person handwave>, before there was ConstraintLayout, I have written my fair share of container_s to make this task manageable. Say we have to do something like this:

2 min read
Back to Top ↑

musings

Your Privilege is Showing

When I left the Philippines five years ago, I had a high-paying job at the heart of the country’s financial district. I was living a very comfortable life: I can afford an annual membership to a yoga studio, I bought an off-the-plan apartment with views of Manila Bay, I get to treat my parents to a holiday once in a while, I get to travel with my friends – we were even able to go abroad a couple of times!

4 min read
Back to Top ↑

a11y

Back to Top ↑

accessibility

Back to Top ↑