Tuesday, November 29, 2011

Convert UNIX timestamp to human date using command-line

I'm working on a project where date/time are sent in UNIX timestamp. Sometimes when I'm debugging, I want to check whether the usually 10-digit number is correct.

The easiest way I found is using the command-line terminal:


~$ date -r 1322532029 
Tue Nov 29 10:00:29 SGT 2011

Friday, November 4, 2011

List of Inlined/intrinsic methods in Android's Dalvik VM

Android's Designing for Performance document, states:
In addition to all the usual reasons to prefer library code over rolling your own, bear in mind that the system is at liberty to replace calls to library methods with hand-coded assembler, which may be better than the best code the JIT can produce for the equivalent Java. The typical example here is String.indexOf and friends, which Dalvik replaces with an inlined intrinsic. Similarly, the System.arraycopy method is about 9x faster than a hand-coded loop on a Nexus One with the JIT.
Unfortunately, as are other Android SDK documentation, this doesn't tell you much which methods gets inlined with machine code.

Examining the Dalvik VM source code, I found dalvik/vm/InlineNative.c that starts with an introduction:


/*
 * Inlined native functions.  These definitions replace interpreted or
 * native implementations at runtime; "intrinsic" might be a better word.
 */


So the inlined methods are:
  • class String:
    • charAt(int)
    • compareTo(String)
    • equals(Object)
    • fastIndexOf(int, int)
    • isEmpty()
    • length()
  • class Math:
    • abs(int)
    • abs(long)
    • abs(float)
    • abs(double)
    • min(int, int)
    • max(int, int)
    • sqrt(double)
    • cos(double)
    • sin(double)
  • class Float:
    • floatToIntBits(float)
    • floatToRawIntBits(float)
    • intBitsToFloat(int)
  • class Double:
    • doubleToLongBits(double)
    • doubleToRawLongBits(double)
    • longBitsToDouble(long)
That's it! Now don't be so scared to use those methods in your code.

Bonus: fastIndexOf ? What is that? Java's String has indexOf, but never an fastIndexOf.

Answer: The implementation of String's indexOf(int) or indexOf(int, int) that Android uses, calls fastIndexOf if the char to be searched is <= 0xffff (which most probably is). So, if your code has a call of indexOf('x'), the native implementation will still be used.

Saturday, October 22, 2011

AnimationDrawable doesn't start after calling start()

Frame animations (sometimes declared in xml as <animation>) produces an AnimationDrawable. However, in some situations, such as using it as one of the ListView items, the animation doesn't start. Even if you call start().

The solution is simple. Just call stop() and then start().

In the source code of AnimationDrawable, the method start() can sometimes do nothing.

public void start() {
        if (!isRunning()) {
            run();
        }
    }

I have encountered this twice. I hope this helps you.

Thursday, August 11, 2011

Don't use Adapter#isEnabled(int) to disable individual list items (Android)

When we have items in a ListView, we may want to disable some of the items.

Disabling some of the items can be done by overriding isEnabled(int position) on the adapter, but unfortunately the list item dividers are not drawn anymore! Overriding isEnabled(int position) was meant to be used to create some kind of "separator" or "list header".

The correct way to disable an item in a ListView is to call setEnabled(false) on the view of the item itself. In other words, call setEnabled(false) on the view that is returned from getView(int position, View convertView, ViewGroup parent).

Reference: Romain Guy's post on android-developers.

Monday, May 9, 2011

Using convertView and returning the correct view in Adapter's getView in one line!

Are you tired seeing or typing these lines over and over again?

public View getView(int position, View convertView, ViewGroup parent) {
    View v;
    if (convertView == null) {
        v = LayoutInflater.from(getApplicationContext()).inflate(R.layout.row, null);
    } else {
        v = convertView;
    }
    // later:
    return v;
}

Do that in one line!

View v = convertView != null? convertView: LayoutInflater.from(getApplicationContext()).inflate(R.layout.row, null);

This seems easy but at first I didn't think of that!

Monday, April 25, 2011

Better findViewById that doesn't require you to type-cast the result

If you started developing Android apps, you must have known the findViewById method. That is the method that glues UI and code.

However, findViewById returns the generic View, so you need to type-cast it to the specific view if you want to do widget-specific operations on it (e.g. setText).

TextView lAddress = (TextView) findViewById(R.id.lAddress);

or,

ImageButton bSubmit = (ImageButton) findViewById(R.id.bSubmit);

That's so annoying, even more if you change the type of the widget with similar but unrelated ones, like swapping a Button with an ImageButton.

Solution: use a generic method that returns you an object of the type that you request.

Paste the 2 methods below anywhere you like.

/**
 * Convenience method of findViewById
 */
@SuppressWarnings("unchecked")
public static <T extends View> T getView(View parent, int id) {
 return (T) parent.findViewById(id);
}

/**
 * Convenience method of findViewById
 */
@SuppressWarnings("unchecked")
public static <T extends View> T getView(Activity activity, int id) {
 return (T) activity.findViewById(id);
}

Now, you can just call them like:

TextView lAddress = getView(this, R.id.lAddress);

// or, if not inside an activity, let's say in an Adapter's getView:
View res = convertView != null? convertView: getLayoutInflater().inflate(R.layout.item_person, null);
TextView lAddress = getView(res, R.id.lAddress);

Friday, April 15, 2011

Call getItem instead of parent.getItemAtPosition

On your list item click listener, usually you will need to get the item clicked. You can do it with:

News news = (News) parent.getItemAtPosition(position);


However, I don't recommend that, mainly because of the cast. If you change the adapter to operate on items of different type, the compiler will not catch the error.

Instead, access the adapter directly.


News news = adapter.getItem(position);


This is possible only if you make the adapter return the correct item type instead of Object:

public News getItem(int position) {
return list == null || position >= list.items.size()? null: list.items.get(position);
}


(for long-time Java user, you may not have noticed that that was possible starting Java 5.)