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?
Related
ok so I'm making an app where I use an edit text to write anything and when I press a button it adds whatever I wrote in the edit to a listView, and it works, but I want the List to be in a different activity than the button and edit text, so I moved it without changing the code.can anyone figure this out,
BTW all the variables are public.
public class MainActivity extends AppCompatActivity {
public ArrayList<String> arrayList2;
public ArrayAdapter<String> adapter,adapter2;
public EditText editText,editText2;
public ArrayList<String> itemList,itemList2;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
String[] items = {};
itemList = new ArrayList<String>(Arrays.asList(items));
adapter = new ArrayAdapter<String>(this, R.layout.activity_list_layout,R.id.txtItem,itemList);
ListView listV = (ListView)findViewById(R.id.list_layout);
listV.setAdapter(adapter);
editText = (EditText)findViewById(R.id.thingadd);
Button btAdd = (Button)findViewById(R.id.add);
String[] age = {};
arrayList2 = new ArrayList<String>(Arrays.asList(age));
itemList2 = new ArrayList<String>(Arrays.asList(age));
adapter2 = new ArrayAdapter<String>(this, R.layout.activity_list__layout2,R.id.txtage,itemList2);
ListView listV2 = (ListView)findViewById(R.id.Age);
listV2.setAdapter(adapter2);
editText2 = (EditText)findViewById(R.id.agetxt);
btAdd.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
String newItem=editText.getText().toString();
String newItem2=editText2.getText().toString();
itemList.add(newItem);
itemList2.add(newItem2);
adapter.notifyDataSetChanged();
adapter2.notifyDataSetChanged();
}
});
}
}
You can use SQLite Database for that, where you would be saving data in database from one activity and reading it and displaying it in listview from another.
You have 2 options to do so.
You can use any database service. Store the values and display them in the next activity. But this needs Internet service to be enabled in the phone.
You can use intent. Convert those input to string type and pass them to next activity and display them using ids. This type do not require Internet service. To know more about this, Visit this link
I have a
EditText- addArea = (EditText) findViewById(R.id.editTextArea);
and ArrayList - public static ArrayList<String> areaList = new ArrayList<String>();
and a Button- addbtn = (Button) findViewById(R.id.addBTN);
This is my code to Store Strings into array. It displaying the toastMessage but I doesn't know whether its storing Strings or not.
addbtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
String area = addArea.getText().toString();
if (!area.isEmpty()){
areaList.add(area);
toastmessage(area+" added successfully.");
addArea.setText("");
}
}
});
What is need is, The spinner is in the next layout. When I click the spinner it should diplay the items that i have enterd in the edittext.
To check whether the list is added, you can check by this way
for (int i=0; i<areaList.size();i++){
addArea.append(areaList.get(i));
addArea.append("\n");
}
You can know whether the string is stored into the areaList by checking the textView setText value.
To pass the areaList to next Activity, add this
Intent intent = new Intent(MainActivity.this, secondActivity.class);
intent.putExtra("areaList",areaList);
In the second Activity, use this line to get all the areaList data
ArrayList<String> areaList = (ArrayList<String>)getIntent().getSerializableExtra("areaList");
Then set the areaList to spinner
ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, android.R.layout.simple_spinner_dropdown_item, areaList);
spinner.setAdapter(adapter);
In order to see make sure the item is added you can print the array or check its size.
First declare a global variable as int lastSize;
lastSize = 0; //we start from 0
addbtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
String area = addArea.getText().toString();
if (!area.isEmpty()){
areaList.add(area);
//size has changed, means new item added successfully
if (areaList.size() > lastSize) {
toastmessage(area+" added successfully.");
addArea.setText("");
}
//lets update lastSize to record latest size
lastSize = areaList.size();
}
}
});
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?
In my code, right now, in order to properly refresh a listview I have to re-fetch my database information and recreate the SimpleCursorAdapter.
For example, I have a button inside a listview. When this button is clicked, it removes the entry from the database for the listview item. So all I want to happen is have the item removed from the listview, without having to recreate the adapter.
I've tried changing my global from SimpleCursorAdapter to BaseAdapater (because it extends SimpleCursorAdapater and allows for the notifyDataSetChanged() function to be used), but it still doesn't work.
Here is the code I'm using now (which does work):
Code for global declarations and onCreate():
private RoutinesDataSource datasource;
private SimpleCursorAdapter dataAdapter;
private boolean isEditing = false;
private Toast toast_deleted;
private String[] columns = new String[] { MySQLiteHelper.COLUMN_NAME };
private int[] to;
#SuppressLint("ShowToast")
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_routines);
toast_deleted = Toast.makeText(this, "", Toast.LENGTH_SHORT);
datasource = new RoutinesDataSource(this);
datasource.open();
Cursor cursor = datasource.fetchAllRoutines();
to = new int[] { R.id.listitem_routine_name };
dataAdapter = new SimpleCursorAdapter(this, R.layout.listitem_routine, cursor, columns, to, 0);
setListAdapter(dataAdapter);
}
Code for the delete button inside the listview item:
public void onClick(View view) {
ListView l = getListView();
int position = l.getPositionForView(view);
Cursor cursor = ((SimpleCursorAdapter)l.getAdapter()).getCursor();
cursor.moveToPosition(position);
long id = cursor.getLong(cursor.getColumnIndex(MySQLiteHelper.COLUMN_ID));
String name = cursor.getString(cursor.getColumnIndex(MySQLiteHelper.COLUMN_NAME));
switch (view.getId()) {
case R.id.button_routine_delete:
toast_deleted.setText(getString(R.string.toast_routine_deleted));
toast_deleted.show();
datasource.deleteRoutine(id);
onResume();
break;
}
}
Take note of me using onResume().
I know that datasource.deleteRoutine(id) works because when I close the activity and reopen it the list item is gone.
Code for onResume() which shows the list properly with the listview item removed:
#Override
protected void onResume() {
datasource.open();
Cursor cursor = datasource.fetchAllRoutines();
if (isEditing) {
to = new int[] { R.id.listitem_routine_edit_name };
dataAdapter = new SimpleCursorAdapter(this, R.layout.listitem_routine_edit, cursor, columns, to, 0);
setListAdapter(dataAdapter);
}
else {
to = new int[] { R.id.listitem_routine_name };
dataAdapter = new SimpleCursorAdapter(this, R.layout.listitem_routine, cursor, columns, to, 0);
setListAdapter(dataAdapter);
}
super.onResume();
}
I just think its bad practice to recreate the adapter every time I simply want a list item removed that has been removed from the database. Like I said I've tried notifyDataSetChanged with a BaseAdapater and it simply does not work.
Also take note of the isEditing boolean. That is set to true if the edit button is clicked in the action bar, which shows the delete button. This is useful because I also have an edit button which starts an activity when clicked, so when they come back after they are done editing it still shows the buttons for the user.
So anyways, can someone point me out how to refresh the list without having to recreate the adapter - or is what I've done the best method?
The URL in mango's comment to his resolution worked perfectly.
I just changed the code inside onResume() to this:
datasource.open();
Cursor cursor = datasource.fetchAllRoutines();
dataAdapter.changeCursor(cursor);
super.onResume();
Since onResume() is already called after someone adds or edits an item, I figured it wouldn't hurt to call it when the delete button is pressed considering it no longer recreates the adapter, rather simply changes the cursor.
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);