I'm new to Java/android so a lot of these terms are foreign but am willing to learn. I'm not gonna go into detail on the app as I dont think it's relevant. My issue as it stands, I've used tutorials and pieces of code from a blog and have gotten my code to work. Trying to clean up and organize my code I get a nullpoiner exception when I move one line (creating my autocompletetextview). Below is the code I've used. My 1 line of code that's giving me an issue is
AutoCompleteTextView companyAutoComplete = (AutoCompleteTextView) addAddressDialog.findViewById(R.id.add_record_dialog_autocomplete);
When I move it to right under the start of my function it errors out but when left in place it works like a charm. I'd like to understand why this is.
public void addAddress() {
final Dialog addAddressDialog = new Dialog(this);
final int[] to = new int[] { android.R.id.text1 };
final String[] from = new String[] { "CompanyName" };
// Create a SimpleCursorAdapter for the CompanyName field.
SimpleCursorAdapter adapter = new SimpleCursorAdapter(this, android.R.layout. select_dialog_item, null, from, to);
addAddressDialog.setContentView(R.layout.add_record_dialog);
addAddressDialog.setTitle(getString(R.string.add_record_dialog_address_title));
addAddressDialog.setCancelable(true);
final EditText text1 = (EditText) addAddressDialog.findViewById(R.id.add_record_dialog_edittext);
text1.setHint(getString(R.string.add_record_dialog_company_hint));
Button buttonOK1 = (Button) addAddressDialog.findViewById(R.id.add_record_dialog_ok);
buttonOK1.setText(getString(R.string.add_record_dialog_ok_button));
Button buttonCancel1 = (Button) addAddressDialog.findViewById(R.id.add_record_dialog_cancel);
buttonCancel1.setText(getString(R.string.add_record_dialog_cancel_button));
buttonOK1.setOnClickListener(new OnClickListener(){
public void onClick(View v) {
Bundle addressBundle = new Bundle();
addressBundle.putString("CompanyName", text1.getText().toString());
Intent intent = new Intent(MenuActivity.this, AddAddressActivity.class);
intent.putExtras(addressBundle);
startActivity(intent);
addAddressDialog.dismiss();
}
});
buttonCancel1.setOnClickListener(new OnClickListener(){
public void onClick(View v) {
Toast.makeText(getBaseContext(), "Cancel button clicked", Toast.LENGTH_SHORT).show();
addAddressDialog.dismiss();
}
});
AutoCompleteTextView companyAutoComplete = (AutoCompleteTextView) addAddressDialog.findViewById(R.id.add_record_dialog_autocomplete);
companyAutoComplete.setAdapter(adapter);
// Set an OnItemClickListener, to update dependent fields when
// a choice is made in the AutoCompleteTextView.
companyAutoComplete.setOnItemClickListener(new OnItemClickListener() {
public void onItemClick(AdapterView<?> listView, View view,
int position, long id) {
// Get the cursor, positioned to the corresponding row in the
// result set
Cursor cursor = (Cursor) listView.getItemAtPosition(position);
// Get the CompanyID from this row in the database.
String companyID = cursor.getString(cursor.getColumnIndexOrThrow("_id"));
// test to make sure CompanyID returned
Toast.makeText(getBaseContext(), companyID, Toast.LENGTH_SHORT).show();
}
});
// Set the CursorToStringConverter, to provide the labels for the
// choices to be displayed in the AutoCompleteTextView.
adapter.setCursorToStringConverter(new CursorToStringConverter() {
public String convertToString(android.database.Cursor cursor) {
// Get the label for this row out of the "CompanyName" column
final int columnIndex = cursor.getColumnIndexOrThrow("CompanyName");
final String str = cursor.getString(columnIndex);
return str;
}
});
// Set the FilterQueryProvider, to run queries for choices
// that match the specified input.
adapter.setFilterQueryProvider(new FilterQueryProvider() {
public Cursor runQuery(CharSequence constraint) {
Cursor cursorReturn = dbAdapter.getCompanies(constraint != null ? constraint.toString() : null);
startManagingCursor(cursorReturn);
return cursorReturn;
}
});
addAddressDialog.show();
}
This happens because you call setContentView later.
setContentView sets up the layout for the addAddressDialog dialog. If you don't call setContentView, it has no layout items, therefore addAddressDialog.findViewById(...); will be null, and, obviously you cannot cast that to anything, nor can you call setHint on it.
It shouldn't matter where this line of code is in your method, as long as your line with setContentView is called before it.
The only thing that matters is that your findViewById() call is called after the call to setContentView(), i.e. this line:
addAddressDialog.setContentView(R.layout.add_record_dialog);
The XML file add_record_dialog.xml is the View hierarchy that you are traversing to find the view with the ID of add_record_dialog_autocomplete. Until you've given the dialog that view hierarchy, it cannot traverse it, hence you'll be getting a NullPointerException when you try to use your AutoCompleteTextView since it cannot find your view.
EDIT: Also, if you mean you placed it at the VERY start of the method, that will also fail due to the fact that addAddressDialog will be null until your call to
final Dialog addAddressDialog = new Dialog(this);
Related
In my app, I have a few AutoCompleteTextView widgets that use an ArrayAdapter.
private List<String> adapterList = new ArrayList<String>();
ArrayAdapter<String> dropdownAdapter;
dropdownAdapter = new ArrayAdapter<>(getContext(), R.layout.simple_dropdown_item, adapterList);
autoCompleteTextView.setAdapter(dropdownAdapter);
It works beautifully. As I type into the View, I get words-starting-with results in the dropdown.
I want to do this with another AutoCompleteTextView, but this time using a SimpleCursorAdapter.
nameSearchCursor = dbHelper.getChecklistTabDataByChecklistId(outingId, checklistId, nameColumn);
NameSearch = root.findViewById(R.id.SearchNames);
String[] nsColumns = new String[]{nameColumn};
int[] nsTo = new int[]{R.id.simpleDropdownItem};
nameSearchCursorAdapter = new SimpleCursorAdapter(getContext(), R.layout.simple_dropdown_item,
nameSearchCursor, nsColumns, nsTo, 0);
NameSearch.setAdapter(nameSearchCursorAdapter);
If I start typing in this new View, the dropdown appears and shows the entire list, and nothing changes as I type. No filtering occurs. What do I need to do differently (and perhaps why) to get a CursorAdapter to work with this View that I didn't need to do when using an ArrayAdapter. I have searched this site and read the Developer Docs and there must be something I just don't get. Please enlighten me.
This site allowed me to answer this question: http://www.outofwhatbox.com/blog/2010/11/android-simpler-autocompletetextview-with-simplecursoradapter/
Here is my completed code:
private void setUpNameSearch() {
// Get AutoCompleteTextView
nameSearchView = root.findViewById(R.id.SearchNames);
// Define from/to info
final String[] nsColumns = new String[]{nameColumn};
final int[] nsTo = new int[]{R.id.simpleDropdownItem};
// Create adapter. Cursor set in setFilterQueryProvider() below.
nameSearchCursorAdapter = new SimpleCursorAdapter(getContext(), R.layout.simple_dropdown_item,
null, nsColumns, nsTo, 0);
// Set adapter on view.
nameSearchView.setAdapter(nameSearchCursorAdapter);
// OnItemClickListener - User selected value from DropDown
nameSearchView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> listView, View view, int position, long id) {
// Get the cursor. Positioned to the corresponding row in the result set.
Cursor cursor = (Cursor) listView.getItemAtPosition(position);
// Get the name selected
String selectedName = cursor.getString(cursor.getColumnIndexOrThrow(nameColumn));
// Do something with this value...
}
});
// Set the CursorToStringconverter, to provide the values for the choices to be displayed
// in the AutoCompleteTextview.
nameSearchCursorAdapter.setCursorToStringConverter(new SimpleCursorAdapter.CursorToStringConverter() {
#Override
public CharSequence convertToString(Cursor cursor) {
final String name = cursor.getString(cursor.getColumnIndexOrThrow(nameColumn));
return name;
}
});
// Set the FilterQueryProvider, to run queries for choices
nameSearchCursorAdapter.setFilterQueryProvider(new FilterQueryProvider() {
#Override
public Cursor runQuery(CharSequence constraint) {
Cursor cursor = dbHelper.getMatchingNames(outingId, checklistId, nameColumn,
(constraint != null ? constraint.toString() : null));
return cursor;
}
});
}
I wanted to duplicate the word-starting-with default functionality of the AutoCompeteTextView using the SQLite Cursor, only to find that REGEXP are not fully supported. So this StackOverflow topic gave me the LIKE workaround. SQLite LIKE alternative for REGEXP, Match Start of Any Word
I hope this helps others.
I have two methods that I want to run inside my onlick. The first method is to display a ListView. The second method is to get data from a previous ListViewand put it in the new ListView. The aim is to have all these data combined and displayed in the new ListView at the same time.
Summary
Display ListView B
Get data from ListView A
Display all Data at the same time
Code
btnSave2.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
PlayerStatsDatabase db = new PlayerStatsDatabase(getApplicationContext());
db.open();
db.createStats(txtGoalsScored.getText().toString(), txtMinutesPlayed.getText().toString(),txtSubstituteIn.getText().toString(),txtSubstituteOut.getText().toString(), checkText.toString());
db.close();
displayListView();
dipsplayPlayerName();
}
});
}
private void displayListView() {
// TODO Auto-generated method stub
//playerTitle.setText (PlayerNameText);
Cursor cursor = dbHelper.fetchAllStats();
setContentView(R.layout.playerstats);
// The desired columns to be bound
String[] columns = new String[] {
PlayerStatsDatabase.KEY_SCORE,
PlayerStatsDatabase.KEY_MINUTES,
PlayerStatsDatabase.KEY_SUBIN,
PlayerStatsDatabase.KEY_SUBOUT,
PlayerStatsDatabase.KEY_BOOKING,
};
// the XML defined views which the data will be bound to
int[] to = new int[] {
R.id.pGoals,
R.id.pMinutes,
R.id.pSubIn,
R.id.pSubOut,
R.id.pBook,
};
// create the adapter using the cursor pointing to the desired data
//as well as the layout information
statsAdapter = new SimpleCursorAdapter(
this, R.layout.statslist,
cursor,
columns,
to
);
ListView list= (ListView) findViewById(R.id.listView1);
// Assign adapter to ListView
list.setAdapter(statsAdapter);
statsAdapter.notifyDataSetChanged();
}
private void dipsplayPlayerName() {
setContentView (R.layout.statslist);
playerTitle = (TextView) findViewById (R.id.textTitle);
playerTitle.setText (PlayerData);
playerNumber = (TextView) findViewById (R.id.pNumber);
playerNumber.setText (playerNumberStr);
playerPosition = (TextView) findViewById (R.id.pPosition);
playerPosition.setText (playerPositionStr);
playerTeam = (TextView) findViewById (R.id.pTeam);
playerTeam.setText (playerTeamStr);
}
}
The problem is they both wont work at the same time. The one that gets called first is the only one that works.
How would I fix this?
I have two methods that I want to run inside my onlick. The first method is to display a ListView. The second method is to get data from a previous ListViewand put it in the new ListView. The aim is to have all these data combined and displayed in the new ListView.
Summary
Display ListView B
Get data from ListView A
Display all Data
Code
btnSave2.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
PlayerStatsDatabase db = new PlayerStatsDatabase(getApplicationContext());
db.open();
db.createStats(txtGoalsScored.getText().toString(), txtMinutesPlayed.getText().toString(),txtSubstituteIn.getText().toString(),txtSubstituteOut.getText().toString(), checkText.toString());
db.close();
displayListView();
dipsplayPlayerName();
}
});
}
private void displayListView() {
// TODO Auto-generated method stub
//playerTitle.setText (PlayerNameText);
Cursor cursor = dbHelper.fetchAllStats();
setContentView(R.layout.playerstats);
// The desired columns to be bound
String[] columns = new String[] {
PlayerStatsDatabase.KEY_SCORE,
PlayerStatsDatabase.KEY_MINUTES,
PlayerStatsDatabase.KEY_SUBIN,
PlayerStatsDatabase.KEY_SUBOUT,
PlayerStatsDatabase.KEY_BOOKING,
};
// the XML defined views which the data will be bound to
int[] to = new int[] {
R.id.pGoals,
R.id.pMinutes,
R.id.pSubIn,
R.id.pSubOut,
R.id.pBook,
};
// create the adapter using the cursor pointing to the desired data
//as well as the layout information
statsAdapter = new SimpleCursorAdapter(
this, R.layout.statslist,
cursor,
columns,
to
);
ListView list= (ListView) findViewById(R.id.listView1);
// Assign adapter to ListView
list.setAdapter(statsAdapter);
statsAdapter.notifyDataSetChanged();
}
private void dipsplayPlayerName() {
setContentView (R.layout.statslist);
playerTitle = (TextView) findViewById (R.id.textTitle);
playerTitle.setText (PlayerData);
playerNumber = (TextView) findViewById (R.id.pNumber);
playerNumber.setText (playerNumberStr);
playerPosition = (TextView) findViewById (R.id.pPosition);
playerPosition.setText (playerPositionStr);
playerTeam = (TextView) findViewById (R.id.pTeam);
playerTeam.setText (playerTeamStr);
}
}
The problem is they both wont work at the same time. The one that gets called first is the only one that works.
How would I work my way around this? Could putting them all in the same method work?
I am developing an app in which I need a ListView whose rows have a TextView, 2 CheckBox and a Spinner.
However, I am experiencing issues with onItemSelected() of the Spinner, as it gets called each time it is displayed for each row. In this method I am updating database records with the selected option, but as Android calls it automatically, every time the items get reset because Android calls it with position 0 and this is the value updated in the database.
I have read a lot of links about the issue with onItemSelected() and some hacks, but all of them are to use without a ListView. Any points here?
I have tried to track in a List which positions are actually displayed to make it work but it does not. I think it is because of the recycling in Android that causes the troubleshooting method get called for Spinners already shown!
So the point is: How can I differenciate a real call to onItemSelected() because of a user selection from the Android call when displaying the Spinner?
Here is the code of my adapter that extends SimpleCursorAdapter.
Thank you so much in advance.
public ParticipationAdapter(Context context, int layout, Cursor c, String[] from, int[] to) {
super(context, layout, c, from, to);
mActivity = (Activity)context;
ParticipationComment.ParticipationCommentManager commentManager = new ParticipationComment.ParticipationCommentManager(mActivity);
mParticipationCommentsCursor = commentManager.get();
mActivity.startManagingCursor(mParticipationCommentsCursor);
commentManager.detach();
mPositionsOfCursorIds = getPositionsOfCursorIds(mParticipationCommentsCursor);
mSpinnerPositionsDisplayed = new ArrayList<Integer>();
}
#Override
public View getView(final int participationPosition, View convertView, ViewGroup parent) {
final Cursor participationsCursor = getCursor();
mActivity.startManagingCursor(participationsCursor);
participationsCursor.moveToPosition(participationPosition);
View participationRow;
if (convertView == null) {
participationRow = LayoutInflater.from(mActivity).inflate(R.layout.participation_row_student, null);
} else {
mSpinnerPositionsDisplayed.remove((Integer)convertView.getTag());
participationRow = convertView;
}
participationRow.setTag(participationPosition);
Spinner commentSpinner = (Spinner)participationRow.findViewById(R.id.participation_comment_id_spinner);
SimpleCursorAdapter commentSpinnerAdapter = new SimpleCursorAdapter(
mActivity,
android.R.layout.simple_spinner_item,
mParticipationCommentsCursor,
new String[] {DatabaseManager.NAME},
new int[] {android.R.id.text1}
);
commentSpinnerAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
commentSpinner.setAdapter(commentSpinnerAdapter);
long participationCommentId = participationsCursor.getLong(participationsCursor.getColumnIndex(DatabaseManager.PARTICIPATION_COMMENT_ID));
if (participationCommentId != 0) {
commentSpinner.setSelection(mPositionsOfCursorIds.get(participationCommentId));
}
commentSpinner.setOnItemSelectedListener(new OnItemSelectedListener() {
#Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
participationsCursor.moveToPosition(participationPosition);
if (!mSpinnerPositionsDisplayed.contains(participationPosition)) {
// Android calls this method the first time a Spinner is displayed,
// to differentiate from a real user click we check if the current Spinner's position
// in the ListView is being shown
mSpinnerPositionsDisplayed.add(participationPosition);
} else {
ParticipationComment participationComment = new ParticipationComment((Cursor)parent.getItemAtPosition(position));
Participation.ParticipationManager participationManager = new Participation.ParticipationManager(mActivity);
Participation participation = new Participation(participationsCursor);
participation.setConnectionProfileParticipationCommentId(participationComment.getConnectionProfileId());
participation.setParticipationCommentId(participationComment.getIdOpenErp());
participation.setChanged(true);
participationManager.update(participation);
participationManager.detach();
}
}
#Override
public void onNothingSelected(AdapterView<?> parent) {
// Not used
}
});
TextView studentName = (TextView)participationRow.findViewById(R.id.participation_student_name);
studentName.setText(participationsCursor.getString(participationsCursor.getColumnIndex(DatabaseManager.NAME)));
CheckBox expectedPresent = (CheckBox)participationRow.findViewById(R.id.participation_expected_present_value);
expectedPresent.setChecked(participationsCursor.getInt(participationsCursor.getColumnIndex(DatabaseManager.EXPECTED_PRESENT)) == 1);
CheckBox present = (CheckBox)participationRow.findViewById(R.id.participation_present_value);
present.setChecked(participationsCursor.getInt(participationsCursor.getColumnIndex(DatabaseManager.PRESENT)) == 1);
return participationRow;
}
A better way is to use a AlertDialog Variant.. like this.. and create a button which initially has the first selection as its Text and its changed based on the AlertDialog choice..
What about using a small flag to discard first call of ItemSelected ?
I have an Android activity which displays a spinner populated with data from a database. The onCreate() is listed here:
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.fuel_entry);
vehicleDataCursor = VehicleDataProvider.getVehicles();
startManagingCursor(vehicleDataCursor);
String[] from = new String[]{REGISTRATION_NO_COLUMN, DESCRIPTION_COLUMN};
int[] to = new int[]{R.id.vehicle_db_row_registration_number, R.id.vehicle_db_row_description};
vehicleAdapter =
new SimpleCursorAdapter(this, R.layout.vehicle_spinner_row, vehicleDataCursor, from, to);
vehicleSpinner = (Spinner) findViewById(R.id.spinner);
vehicleSpinner.setAdapter(vehicleAdapter);
mileageEntry = (EditText) findViewById(R.id.fuel_entry_mileage_edit_text);
fuelAmountEntry = (EditText) findViewById(R.id.fuel_entry_fuel_edit_text);
fuelEntryOkButton = (Button) findViewById(R.id.fuel_entry_ok_button);
fuelEntryOkButton.setOnClickListener(new OnClickListener()
{
#Override
public void onClick(View v)
{
String registrationNumber = "";
Cursor cc = (Cursor)(vehicleSpinner.getSelectedItem());
if (cc != null)
{
registrationNumber = cc.getString(cc.getColumnIndexOrThrow(REGISTRATION_NO_COLUMN));
if(FuelUseDataProvider.addFuelUp(registrationNumber, Integer.parseInt(mileageEntry.getText().toString()), Integer.parseInt(fuelAmountEntry.getText().toString()), System.currentTimeMillis()) != DATABASE_INSERT_ERROR_CODE)
{
showMPGDialog(registrationNumber);
}
else
{
//do error handling
}
cc.close();
}
}
});}
It works fine but has a minor problem - when the user fills in the form and clicks the fuelEntryOkButton, a dialog is display as intended but the spinner is empited of its data. If I removed the cc.close(); line, the problem goes away. Obviously I'd like to close the cursor when I've finished with it. I can't understand this - it is vehicleDataCursor which is providing data for the cursor, not cc.
Any ideas why my Spinner loses its data?
Cursor cc = (Cursor)(vehicleSpinner.getSelectedItem());
As far as I understand it, when you do this you are simply getting a reference to the Cursor associated with the Spinner. In other words, a reference to vehicleDataCursor.
When you close cc, you're effectively closing vehicleDataCursor.
Does that make sense?