In my Android application I am having custom ListView that contains EditText and Spinner.
My problem is when I choose a Spinner (spDevice) I need to load corresponding values in another spinner (spModel). The problem I am facing is, when I select the value in spDevice its loading corresponding values in the spModel after some time delay, its not loading immediately (sometime data is not loading properly). I feel we have to use AsyncTask for this. Can anyone help me how to create AsyncTaskfor this or else can anyone tell me whats the best method to solve this issue.
Below is the code I am using now
private void spDevicesetItemSelectedListener(final DeviceHolder holder){
holder.spDevice.setOnItemSelectedListener(new OnItemSelectedListener() {
public void onItemSelected(AdapterView<?> parent, View view, int position,long id) {
String strDevices =(String)parent.getSelectedItem(); //Get selected value from SpDevices
ArrayList<String> lstModels = db.getAllModels(strDevices);
// Creating adapter for spinner
ArrayAdapter<String> dataAdapter = new ArrayAdapter<String>(context,android.R.layout.simple_spinner_item, lstModels);
dataAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
// attaching data adapter to spinner
holder.spModel.setAdapter(dataAdapter);
Its not needed, basically AsyncTask are used for long running tasks like network operations, database operations. One thing remind 'AsyncTask' are not needed for faster operations. The delay its taking is to fetch data from database, so using AsyncTask, it will not fasten up the loading.
I had solved this issue through calling AsyncTask, its working perfectly as intended. I feel in Custom ListView with more than one Spinner and the values are dependent on other Spinner, this is the best way to do. If I am wrong means correct me
if(strDevices != null && ! strDevices.isEmpty()) {
try {
ArrayList<String> lstModels = new LongOperation().execute(strDevices).get(); // Call Async Task
ArrayAdapter<String> dataAdapter = new ArrayAdapter<String>(context, android.R.layout.simple_spinner_item, lstModels);
dataAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
// attaching data adapter to spinner
holder .spModel.setAdapter(dataAdapter);
} catch (Exception e){
e.printStackTrace();;
}
}
Related
I have an AlertDialog with a ListView set to multiple selection on it. It also has a Button on it.
The Button open another AlertDialog that if ok'ed will remove the selected items from the data set of the ListView, and then tell the adapter of the list view that the dataset has changed with the notifyDataSetChanged() method.
This all works fine except for one thing. The ListView does not update it's content until I interact with something. Then it updates to the correct data.
This is not a big problem, but I really would like the ListView to appear correct at once, and not just after the focus has changed.
Code:
Button remove = (Button) view.findViewById(R.id.btn_remove_questions_edit_rack);
final Context con = this;
remove.setOnClickListener(new OnClickListener()
{
#Override
public void onClick(View v)
{
Builder warnBuild = new Builder(con);
warnBuild.setMessage(R.string.question_deletion_warning);
warnBuild.setPositiveButton(R.string.ok, new DialogInterface.OnClickListener()
{
#Override
public void onClick(DialogInterface dialog, int which)
{
SparseBooleanArray checked = list.getCheckedItemPositions();
for (String s : keys)
{
int i = keys.indexOf(s);
if (checked.get(i))
{
toRemove.add(map.get(s));
map.remove(s);
}
}
keys.clear();
keys.addAll(map.keySet());
((ArrayAdapter) list.getAdapter()).notifyDataSetChanged();
list.clearChoices(); //This makes sure the selection is cleared, if it isn't, some of the other items (those that now has the index of the selected items) will be selected when the View refreshes.
dialog.dismiss();
}
});
//Negative button here, not relevant.
}
});
Where map and keys are:
final HashMap<String, QualityQuestion> map = new HashMap<>();
//I add items to the map
final ArrayList<String> keys = new ArrayList<>(map.keySet());
And toRemove is where I store the items to be removed from the actual object they are on when the ok button on the original AlertDialog is pressed.
This is how I populate my ListView in the first place:
final ListView list = (ListView) view.findViewById(R.id.list_questions_edit_rack);
list.setAdapter(
new ArrayAdapter<String>(this,
android.R.layout.simple_list_item_activated_1,
keys));
I have tried things like list.invalidateViews(), list.invalidate and other things I found in questions similar to mine here on SO. But none of that made any difference. I suspect my problem to be different from theirs since my items clearly are updated, it just takes a change of focus on the original AlertDialog for the change to be visible.
How can I make the ListView show the changes in it's data source imidiatly insted of after a focus change?
By calling
((ArrayAdapter) list.getAdapter()).notifyDataSetChanged();
you get a fresh adapter which is almost certainly not identical to the anonymous adapter you used to populate your list in the first instance.
See also the documentation for ListView.getAdapter()
Returns the adapter currently in use in this ListView.
The returned adapter might not be the same adapter passed to setAdapter(ListAdapter) but might be a WrapperListAdapter.
From the point of view of this fresh adapter, the data set hasn't changed because the changes happened way before it was instantiated.
To solve your problem, make your list and your list adapter members of your activity class (or the scope where you want to keep them alive):
private ArrayList<String> keys;
private ArrayAdapter myAdapter;
private ListView list;
Then in your "onCreate()"
keys = ...; // initialization of ArrayList with the needed data
myAdapter = new ArrayAdapter<String>(this,
android.R.layout.simple_list_item_activated_1,
keys);
list = (ListView) view.findViewById(R.id.list_questions_edit_rack);
list.setAdapter(myAdapter);
This way, in your "OnClickListener" you can notify "myAdapter":
keys.addAll(map.keySet());
myAdapter.notifyDataSetChanged();
Hope this helps :)
You can tweak it, by granting focus to another view, and then requesting it back:
view.requestFocus();
You can also use:
view.requestFocusFromTouch();
I have a listview in my android program that gets its information from an ArrayList adapter.
I have three methods that call listview.invalidateViews().
Two of these methods work without fail, and the third seems to freeze the listview. The information is correctly saved when backing out of the activity and on a screen rotate. But without taking these actions, the listview does not update.
Any Ideas?
UPDATE:
These instances work:
public void onItemClick(AdapterView<?> a, View v, int index, long id) {
al.remove(index);
adapter.notifyDataSetChanged();
}
public void addToList(View view) {
EditText et = (EditText) findViewById(R.id.ListText1);
if (et.getText().toString().equals("")) {
//do nothing
}
else {
al.add(et.getText().toString());
adapter.notifyDataSetChanged();
et.setText(null);
}
}
This method does not work:
public void resetList(View view) {
al = new ArrayList<String>();
adapter.notifyDataSetChanged();
}
you are using invalidateViews() differently, if you want to change the view of the listview's child then you can use the invalidateViews() but if you are changing the data/content of the listview's adapter you need to use notifyDataSetChanged() method.
the difference of the two are discussed in this question
ListView.invalidateViews()
is used to tell the ListView to invalidate all its child item views (redraw them). Note that there not need to be an equal number of views than items. That's because a ListView recycles its item views and moves them around the screen in a smart way while you scroll.
Adapter.notifyDataSetChanged()
on the other hand, is to tell the observer of the adapter that the contents of what is being adapted have changed. Notifying the dataset changed will cause the listview to invoke your adapters methods again to adjust scrollbars, regenerate item views, etc...
and with your method
public void resetList(View view) {
al = new ArrayList<String>();
adapter.notifyDataSetChanged();
}
making a new object of ArrayList<String>(); will not reset the data of your list view. just because the al ArrayList that you passed on your adapter is now different to your al = new ArrayList<String>(); what you need to do now is to access your current arraylist then clearing its content with al.clear() method.
I have two elements:
Spinner INSIDE THE ACTIONBAR (HoloEverywhere (support.v7)) of my Activity set with an onItemSelectedListener().
Listview in my Activity which is filled with an ArrayAdapter
When I choose an Item from the Spinner, the ListView should be updated. But somehow there is a problem with my Spinner I guess. The ListView first updates when I clicked in a TextField of my Activity after I choose a SpinnerItem.
My code:
// Get a databaseConnection and fills the history variable with the data of
// the selected spinnerItem "history" is right filled with all Strings for
// the chosen Spinner from the database -> works correct
public void updateHistory() {
sqlLightDatabase database = new sqlLightDatabase(this);
ArrayList<String> history = database.getArrayList(
mySpinner.getSelectedItem().toString());
// set the adapter to the ListView
ArrayAdapter<String> listenAdapter = new ArrayAdapter<String>(this,
R.layout.list_item, history);
myListView.setAdapter(listenAdapter);
// the code works through, but the ListView is not shown the update
// instantly. But now, when I click a TextField in my Activity, myListView
// shows the new data
}
// Is instantly called when an Item is selected in mySpinner (in my ActionBar)
#Override
public void onItemSelected(AdapterView<?> parent, View view, int position,
long id)
{
// the updateHistory function is called but myLitstView doesn't get
// updated with new Data
updateHistory();
//Just for testing. The following is working instantly fine.
drivenDistance_TF.setText("History changed");
}
I tried the last two days to fix this issue, but I have absolute no idea what I could else try to get the ListView instantly updated.
There is no ErrorLog, because there are no errors.
You must call notifyDataSetChanged method to update data in list view
So write this line
listenAdapter.notifyDataSetChanged();
after myListView.setAdapter(listenAdapter);
in updateHistory();
So, I have two spinners, let's call the first spinner Parent (account_type_spinner) and the second spinner Child (account_name_spinner). Please notice in the following code the ArrayAdapter initialization for the Child (account_name_spinner), I am feeding it a string array of account names I previously queried before the following lines of code (account_name_array):
//---define spinner objects as variables, assign adapters and listeners---
account_type_spinner = (Spinner) findViewById(R.id.account_type_spinner);
account_type_adapter = new ArrayAdapter<String>(this, android.R.layout.simple_spinner_item, account_type_array);
account_type_adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
account_type_spinner.setAdapter(account_type_adapter);
account_type_spinner.setOnItemSelectedListener(new SpinnerSelectionListener());
account_name_spinner = (Spinner) findViewById(R.id.account_name_spinner);
account_name_adapter = new ArrayAdapter<String>(this, android.R.layout.simple_spinner_item, account_name_array);
account_name_adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
account_name_spinner.setAdapter(account_name_adapter);
Selection in the Parent spinner triggers my "SpinnerSelectionListener" which is simply my class implementing OnItemSelectedListener. This class fires obviously each time a selection is made in the Parent spinner and the code looks like the following:
public class SpinnerSelectionListener implements OnItemSelectedListener {
public void onItemSelected(AdapterView<?> parent,
View view, int pos, long id) {
String spinner_selection = parent.getItemAtPosition(pos).toString();
if(spinner_selection.contentEquals(INCOME)) {
//---grab Income type accounts from db and build array---
db.open();
account_name_array = db.getAccounts(INCOME);
account_name_adapter.notifyDataSetChanged();
dr_amount_textview.setVisibility(View.GONE);
dr_amount.setVisibility(View.GONE);
cr_amount_textview.setVisibility(View.VISIBLE);
cr_amount.setVisibility(View.VISIBLE);
db.close();
} else {
//---grab Expense type accounts from db and build array---
db.open();
account_name_array = db.getAccounts(EXPENSE);
account_name_adapter.notifyDataSetChanged();
cr_amount_textview.setVisibility(View.GONE);
cr_amount.setVisibility(View.GONE);
dr_amount_textview.setVisibility(View.VISIBLE);
dr_amount.setVisibility(View.VISIBLE);
db.close();
}
}
public void onNothingSelected(AdapterView<?> parent) {
// Do nothing.
}
}
The code above should update the Child (account_name_spinner) with INCOME or EXPENSE accounts whenever the Parent's selection changes from INCOME to EXPENSE or vice versa (this is an accounting app). The updating of the Child's spinner list should be facilitated by the "account_name_adapter.notifyDataSetChanged();" however nothing is happening.
I looked into this issue further on StackOverflow and found that I must .clear() or .remove() items from my Child's ArrayAdapter (account_name_adapter) before the list will update, however, when I try "account_name_adapter.clear();" before notifying the ArrayAdapter I get an error that the operation is illegal. Any ideas what I am doing wrong?
You can just reassign the adapter after you got the updated array (account_name_array)
account_name_adapter = new ArrayAdapter<String>(this, android.R.layout.simple_spinner_item, account_name_array);
account_name_adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
account_name_spinner.setAdapter(account_name_adapter);
EDIT: To the adapter you don't pass a reference, so when you update the array the adapter still have the same data. Calling .notifyDataSetChanged() do not update the adapter with the new array.
I have an application with a Spinner whos data is populated by a cursor from the database. Works great if there is something in the database table on startup. However, if I add something to the database after the app is running my spinner always shows that it has zero choices, even if one was there to begin with.
My code is as follows. The adapter.getCursor().requery(); did no good. I would like the Spinner to update its choices when the user clicks on it and I found a couple posts on StackOverflow that say you have to use the TextView behind the Spinner for the OnClickListener. However, for me that did nothing. Mostly likely because I'm missing one minor
c1 = myDbHelper.readCars();
startManagingCursor(c1);
// create an array to specify which fields we want to display
String[] from = new String[]{"nickname"};
// create an array of the display item we want to bind our data to
int[] to = new int[]{android.R.id.text1};
adapter = new SimpleCursorAdapter(this, android.R.layout.simple_spinner_item, c1, from, to);
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
spinVehicle.setAdapter(adapter);
txtVehiclePrompt.setOnClickListener(new OnClickListener()
{
public void onClick(View v)
{
adapter.getCursor().requery();
}
});
Just change the underlying data and call notifyDataSetChanged()
list.clear();
//list modify
list.add("A");
list.add("B");
dataAdapter.notifyDataSetChanged();
Ok,
I got it figured out. I needed to close the adapter, stop managing the cursor, close the cursor & close the db helper in the onSuspend() method then set everything back up in the onResume method since I was using a seperate activity to add records to the table.