Why is this variable set to an empty string when it is already initialized to an empty string?
I took the following snippet from snippet 5 in this content provider developer guide.
The confusion is that in the first statement String[] mSelectionArgs = {""};
, mSelectionArgs[0]
the value is set ""
.
Then, if mSearchString
empty ( TextUtils.isEmpty(mSearchString)
) is then mSelectionArgs[0]
assigned again ""
.
So the question is, why do they set it to an empty string when it's already initialized to an empty string?
/*
* This defines a one-element String array to contain the selection argument.
*/
String[] mSelectionArgs = {""};
// Gets a word from the UI
mSearchString = mSearchWord.getText().toString();
// Remember to insert code here to check for invalid or malicious input.
// If the word is the empty string, gets everything
if (TextUtils.isEmpty(mSearchString)) {
// Setting the selection clause to null will return all words
mSelectionClause = null;
mSelectionArgs[0] = "";
} else {
// Constructs a selection clause that matches the word that the user entered.
mSelectionClause = UserDictionary.Words.WORD + " = ?";
// Moves the user input string to the selection arguments.
mSelectionArgs[0] = mSearchString;
}
...
source to share
Aside from the added clarity and readability of the code as noted in another answer, this coding style makes the code less error prone and easier to maintain.
Thus, if the initial value is mSelectionArgs
changed or new code is added that overrides this value before the block is executed if-else
, the code in that block will execute correctly. Without this "rudimentary" assignment, a change as described above could result in an error that would be very difficult to track down.
As a side note:
This special piece of code is not that good (yes I know it is from the Android developer site ...) - if you pass null
as an selection
argument query()
then it is better to pass null
as an argument as well selectionArgs
. I would change this example to something like this (by setting selection
and selectionArgs
the value null):
// Gets a word from the UI
mSearchString = mSearchWord.getText().toString();
// Remember to insert code here to check for invalid or malicious input.
String[] mSelectionArgs = null;
// If the word is the empty string, gets everything
if (TextUtils.isEmpty(mSearchString)) {
// Setting the selection clause to null will return all words
mSelectionClause = null;
mSelectionArgs = null;
} else {
// Constructs a selection clause that matches the word that the user entered.
mSelectionClause = UserDictionary.Words.WORD + " = ?";
// Moves the user input string to the selection arguments.
mSelectionArgs = new String[] {mSearchString};
}
Edit: Why is the above code snippet better than the original one?
Error passing null in quality selection
and not null in quality selectionArgs
. This array will be passed to the specific address ContentProvider
you are addressing and should not be used at all as it selection
does not contain any placeholders ?
. Anyone ContentProvider
violating this assumption is a mistake. While not a bug, it looks odd - why are you passing in an object that should be ignored anyway? It also has an execution cost (which is higher if ContentProvider
running in a different process) that is proportional to the size of the transferred object.
Edit 2: Why is the above code snippet much better than the original one? It turns out that what I said above can be misleading. I found this the hard way:
Caused by: java.lang.IllegalArgumentException: Cannot bind argument at index 3 because the index is out of range. The statement has 1 parameters.
at android.database.sqlite.SQLiteProgram.bind(SQLiteProgram.java:212)
at android.database.sqlite.SQLiteProgram.bindString(SQLiteProgram.java:166)
at android.database.sqlite.SQLiteProgram.bindAllArgsAsStrings(SQLiteProgram.java:200)
at android.database.sqlite.SQLiteDirectCursorDriver.query(SQLiteDirectCursorDriver.java:47)
at android.database.sqlite.SQLiteDatabase.rawQueryWithFactory(SQLiteDatabase.java:1314)
at android.database.sqlite.SQLiteDatabase.queryWithFactory(SQLiteDatabase.java:1161)
at android.database.sqlite.SQLiteDatabase.query(SQLiteDatabase.java:1032)
at android.database.sqlite.SQLiteDatabase.query(SQLiteDatabase.java:1200)
The above exception was thrown because I tried to pass selectionArgs
one that contained more items than the number of ?
placeholders in selection
.
These two methods SQLiteProgram.java
should "blame" for this exception:
public void bindAllArgsAsStrings(String[] bindArgs) {
if (bindArgs != null) {
for (int i = bindArgs.length; i != 0; i--) {
bindString(i, bindArgs[i - 1]);
}
}
}
private void bind(int index, Object value) {
if (index < 1 || index > mNumParameters) {
throw new IllegalArgumentException("Cannot bind argument at index "
+ index + " because the index is out of range. "
+ "The statement has " + mNumParameters + " parameters.");
}
mBindArgs[index - 1] = value;
}
Now that I've learned about this behavior, I think that the sample code from the Android Developers site is not just ineffective, but also complete crap!
Bottom line: if you pass null
as selection
, pass null
as selectionArgs
. If selection
it is not null and contains ?
placeholders, make sure the length of the array selectionArgs
is equal to the number of placeholders ?
in selection
.
source to share