Weird behavior in Android's "if" block
It walks like a bug, it chirps like a bug.... I need someone to confirm that it's a bug.
I was trying to get phone numbers from the address book with this code:
public JSONObject getAllPhones() throws JSONException{
String mPhoneNumberProjection[] = new String[] {
Contacts.Phones.NAME, Contacts.Phones.NUMBER, Contacts.Phones.TYPE
};
Uri phoneNumbersUri = Contacts.Phones.CONTENT_URI;
JSONObject result = new JSONObject();
JSONArray phones = new JSONArray();
Cursor myCursor = mApp.managedQuery(phoneNumbersUri, mPhoneNumberProjection, null, null, null);
mApp.startManagingCursor(myCursor);
if (!myCursor.isAfterLast()){
myCursor.moveToFirst()开发者_如何转开发;
do{
JSONObject aRow = new JSONObject();
for (int i = 0; i < myCursor.getColumnCount(); i++){
Log.d(LOG_TAG, myCursor.getColumnName(i) + " -> " + myCursor.getString(i));
aRow.put(myCursor.getColumnName(i), myCursor.getString(i));
}
phones.put(aRow);
} while (myCursor.moveToNext());
}
result.put("phones", phones);
result.put("phoneTypes", getPhoneTypes());
return result;
}
But when there are no contacts, and !myCursor.isAfterLast() evaluates as "false", program steps into "for" loop. So it enters "if" block, skips several methods and lands in "for" loop...
When I extract this loop into a separate function, everything works ok.
I'm doing this in Eclipse Helios on 32-bit Vista. I tried cleaning the project, erasing Java cache, restarting computer, creating new AVD... I used Android 1.6 and Android 2.2, but the error stays on...
Can someone explain what's going on?
It seems that this behavior cannot be reproduced outside my machine, so, I guess, you are all safe from harm :)
Are you sure isAfterLast evaluates to false if the cursor is before the first of 0 entries? ;) Why don't you just evaluate moveToFirst() instead? It would evaluate to false if there are no entries so the call to isAfterLast() is unnecessary anyway.
rewrite that if
and while
into this
try {
if (c!=null) {
for (c.moveToFirst(); !c.isAfterLast(); c.moveToNext()) {
//stuff here
}
}
} finally {
if (c!=null) {
c.close();
}
}
I agree, this smells like a compiler bug. It's possible that the compiler creates a wrong jump target address in the byte code. Do you have the same problem on the emulator and device? You could add an emulator for a different phone (and different hardware architecture) to check, if this is a general problem or if it is limited to your device.
What one could try - grab a decompiler (I'd recommend JD Java Decompiler, hoping it works for android applications too) and try to decompile the class files to see, id the decompiler result matches your source code - at least logically. If there's a big difference -> potential compiler bug -> issue report to the android development team.
I believe isAfterLast is working as intended. isAfterLast will be false because there are no rows as you stated, so it can never evaluate if it is at the last row.
Plus in your code example above you never moved to the first row to begin with prior to calling isAfterLast(), The if statement never gets evaluated again.
use
if (cursor.moveToFirst()) {
// code
while(cursor.isAfterLast() == false) {
// code
String[] columNames = cursor.getColumnNames();
for (String column : columnNames) {
aRow.put(column, cursor.getString(cursor.getColumnIndex(column)));
}
cursor.moveToNext();
phones.put(aRow);
}
}
Hope that helps.
精彩评论