I am facing a problem that when I try to dynamically add items to my spinner the app crashes. So first I add an array from Strings.xml my R.array.restrictions contains 16 items therefore I am inserting each key into 16 and then adding it onto the next position. and after that I load each item from firebase and add it to the adapter, then I set the adapter, so in my mind it should work. Any ideas why it causes a crash? Says:
UnsupportedOperationException at
java.util.AbstractList.add(AbstractList.java:148)
Thanks.
public void startSpinner(){
//built in Profiles
spinner = (Spinner) findViewById(R.id.spinnerProfiles);
adapter = ArrayAdapter.createFromResource(this, R.array.restrictions, android.R.layout.simple_spinner_item);
myRef.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
// This method is called once with the initial value and again
// whenever data at this location is updated.
map = (Map<String, Object>) dataSnapshot.child("users").child(userID).getValue();
ArrayList<String> array = new ArrayList<>();
int x = 16;
for (Map.Entry<String,Object> entry : map.entrySet()) {
// key contains Profile Name
String key = entry.getKey();
adapter.insert(key, x);
x++;
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
//Auto Generated Method
}
});
adapter.setDropDownViewResource(android.R.layout.simple_list_item_1);
spinner.setAdapter(adapter);
spinner.setOnItemSelectedListener(this);
}
Perhaps the problem is that you are changing an array that is coming from resources. This can happen as the list you are using is not created by you.
You can try the following:
ArrayList<CharSequence> array = new ArrayList<CharSequence>(Arrays.asList(context.getResources().getTextArray(R.array.restrictions)));
adapter = new ArrayAdapter<>(context, android.R.layout.simple_spinner_item, array);
Related
I doing a ArrayList with a Class "Company", this list a companys what get for firestore.
The code for class is:
public ArrayList<String> companyList (View view) {
CompanyList.add(0, "Seleccione un proveedor");
FirebaseUser currentFirebaseUser = FirebaseAuth.getInstance().getCurrentUser() ;
FirebaseFirestore db = FirebaseFirestore.getInstance();
db.collection("users").document(currentFirebaseUser.getUid()).get().addOnSuccessListener(new OnSuccessListener<DocumentSnapshot>() {
#Override
public void onSuccess(DocumentSnapshot documentSnapshot) {
User = (HashMap<String, Object>) documentSnapshot.getData();
if(User.get("List") != "") {
List = (HashMap<String, Object>) User.get("List");
CompanyList.addAll(List.keySet());
Log.i("Current User: ", CompanyList.toString());
}
}
});
return CompanyList;
}`
This class work fine, i used on spinners but when i use for charge a ArrayList on fragment don't work. The code for fragment is:
Company company = new Company();
ArrayList<String> arrayList = new ArrayList<>(company.companyList(root));
Log.i("Current User: ", arrayList.toString());
When executed code the log show this:
2022-04-02 13:34:12.370 17434-17434/com.martin.preventapp I/Current User:: [Seleccione un proveedor] 2022-04-02 13:34:12.615 17434-17434/com.martin.preventapp I/Current User:: [Seleccione un proveedor, Nutrifresca, Ideas Gastronomicas, Pollo]
The first log show a arrayList from fragment and second log show the class arrayList.
I can't charge the arrayList at fragment as a class show, what's wrong??
I try this methods for charge a ArrayList:
ArrayList<String> arrayList = new ArrayList<>(company.companyList(root)
ArrayList<String> arrayList = new ArrayList<>();
arrayList.addAll(company.companyList(root));
ArrayList<String> arrayList;
arrayList = (ArrayList<String>) company.companyList();
I could suggest that you start by declaring a variable as an ArrayList such as :
ArrayList<String> resultArraylist = new ArrayList<>();
And then you add your first item :`
resultArrayList.add("Seleccionne un providor");
With ArrayList except if you always want to add in first position, the method add will put your item at the end of the list.
Louis Wasserman, Cheshiremoe, Thomas Koenig, thanks for reply.
Thomas, i tried with this method but no result.
Louis and Cheshiremoe, i try implemented a AsyncTask. On doInBackground put the code what get arraylist from firestore, in onPostExecute i try compare a arrayList. The code is this:
private class Task extends AsyncTask<String, String, ArrayList<String>> {
// Runs in UI before background thread is called
#Override
protected void onPreExecute() {
super.onPreExecute();
// Do something like display a progress bar
}
// This is run in a background thread
#Override
protected ArrayList<String> doInBackground(String... params) {
Company company = new Company();
// Call this to update your progress
//publishProgress(companyList);
return company.companyList(getView());
}
// This is called from background thread but runs in UI
protected void onProgressUpdate(ArrayList<String> arr1) {
}
// This runs in UI when background thread finishes
#Override
protected void onPostExecute(ArrayList<String> result) {
super.onPostExecute(result);
ArrayList<String> companyList = new ArrayList<String>(result);
TextView tvt = getView().findViewById(R.id.textView7);
if(companyList.size() > 1){
addFragmentListAdd();
tvt.setText(companyList.toString());
}
Log.i("Current User TASK: ", companyList.toString());
}
}
and the call is:
new Task().execute();
but this don't work as expected, the log is:
I/Current User TASK:: [Seleccione un proveedor]
Is the first time i implement AsyncTask, is this way correct??
I want to add the content from an EditText to a ListView here is my code that dosen't work:
mass = userInput.getText().toString();
//fruits is a String[]
final List<String> fruits_list = new ArrayList<String(Arrays.asList(fruits));
final ArrayAdapter<String> arrayAdapter = new ArrayAdapter<String>(context.getApplicationContext(), android.R.layout.simple_list_item_1, fruits_list);
fruits_list.add(mass);
lv.setAdapter(arrayAdapter);
The code adds the item to the listview but when the process is repeated it replaces the previously added string from the EditText.
Your code appears to create a new fruits_list array every time you read the user's entry from the EditText. This will result in only the latest entry being added to your list, replacing any previously added entries.
You need to create the array once (probably as a class member) and then update it each time you read the user input, e.g. something like:
private ArrayList<String> fruits_list;
private ArrayAdapter<String> arrayAdapter;
...
public void initialise(Context context) {
fruits_list = new ArrayList<>(Arrays.asList(fruits));
arrayAdapter = new ArrayAdapter<>(context, android.R.layout.simple_list_item_1, fruits_list);
lv.setAdapter(arrayAdapter);
}
....
public void getInput(
mass = userInput.getText().toString();
fruits_list.add(mass);
arrayAdapter.notifyDataSetChanged();
}
Note the use of arrayAdapter.notifyDataSetChanged() to signal that new data has been added to the underlying data set.
As #Aaron says, you should also look at RecyclerView as a possible replacement, although that's a little bit more complicated to set up.
I'm trying to perform a search on my recycler adapter when onQueryTextChange
as shown below.
newText = newText.toLowerCase();
List<HymnDataModel> search_list = new ArrayList<>();
for(HymnDataModel hymnDataModel : hymnDataList){
String hymn_title = hymnDataModel.getHymnTitle().toLowerCase();
String hymn_subTitle = hymnDataModel.getHymnSubTitle().toLowerCase();
if (hymn_title.contains(newText) || hymn_subTitle.contains(newText)){
search_list.add(hymnDataModel);
}
}
And i filter the Adapter using the setFilter.
adapterRV.setFilter(search_list);
This is the setFilter function in my Adapter
public void setFilter(List<HymnDataModel> search_list) {
mHymnsList = new ArrayList<>();
mHymnsList.addAll(search_list);
//notify to reload
notifyDataSetChanged();
}
The search works just fine, onQueryTextChange
, but after filtering the Adapter and displaying on the RecyclerView, when i click on the filtered/searched item on my recyclerview, it doesn't open that particular item, instead, it opens another item that's not on the filtered list.
Try this instead.Assign search_list to the existing array List.
public void setFilter(List<HymnDataModel> search_list) {
mHymnsList = search_list;
//notify to reload
notifyDataSetChanged();
}
You are appending Filtered data item's in your Arraylist that's why your adapter display item that's not on the filtered list. try this clear your Arraylist before adding Filtered item in your Arraylist
Try this
public void setFilter(List<HymnDataModel> search_list) {
mHymnsList.clear();
mHymnsList.addAll(search_list);
or
mHymnsList = search_list;
//notify to reload
notifyDataSetChanged();
}
Can someone please advice me on this issue:
I am trying to load some filtered data from Firebase DB onCreate and populate a custom array with data.
After doing some debugging I can tell that the data is loaded from DB but my custom array is not getting populated.
Please have a look at my code below.
Even though my loadAllBooks() method is populating the array, it gets completed too late and the line:
//3) Create the adapter
BooksAdapter adapter = new BooksAdapter (this, booksList);
is executed before loadAllBooks() is completed which results in an empty list...
It's as if i need some sort of onComple for the addChildEventListener...
Please Help, if more information is needed let me know, thank you:
ArrayList<BookItem> booksList;
ListView listView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//1) empty books list
booksList = new ArrayList<BookItem>();
//2) load all books from firebase DB - into booksList array
loadAllBooks();
//3) Create the adapter
BooksAdapter adapter = new BooksAdapter (this, booksList);
//4) Attach the adapter to a ListView
listView = (ListView) findViewById(R.id.lvBooks);
listView.setAdapter(adapter);
}
public void loadAllBooks() {
Firebase ref = new Firebase(".......firebaseio.com/books");
Query queryRef = ref.orderByChild("bookType").equalTo("drama");
queryRef.addChildEventListener(childEventListener);
}
ChildEventListener childEventListener = new ChildEventListener() {
#Override
public void onChildAdded (DataSnapshot bookNode, String previousChild){
BookItem bookItemModel = bookNode.getValue(BookItem.class);
booksList.add(bookItemModel);
}
public void onChildRemoved(DataSnapshot snapshot) {}
public void onChildChanged(DataSnapshot snapshot, String previousChild){}
public void onChildMoved(DataSnapshot snapshot, String previousChild) {}
#Override
public void onCancelled(FirebaseError firebaseError) {}
};
Thank you!
When you call addChildEventListener() Firebase starts loading the data from the remote location asynchronously. This means that the code after it executes straight away and you pass an empty list to the adapter. Later, when the initial data has synchronized from Firebase, it is added to the list. But by that time you've already created the adapter.
You can most easily see the flow, by adding a few log statements:
System.out.println("Start loading/synchronizing books");
loadAllBooks();
System.out.println("Creating adapter");
BooksAdapter adapter = new BooksAdapter (this, booksList);
public void onChildAdded (DataSnapshot bookNode, String previousChild){
System.out.println("Adding book to list");
BookItem bookItemModel = bookNode.getValue(BookItem.class);
booksList.add(bookItemModel);
}
These will print in this order:
Start loading/synchronizing books
Creating adapter
Adding book to list
Adding book to list
Adding book to list
...
Likely this is not the order that you expected. Welcome to asynchronous loading 101, it makes the modern web tic and makes developers lose their mind when they first encounter it. :-)
Most likely all that is required is that you call adapter.notifyDataSetChanged() from onChildAdded(). This informs Android that the data in the adapter has changed and that it should repaint the associated view(s).
public void onChildAdded (DataSnapshot bookNode, String previousChild){
BookItem bookItemModel = bookNode.getValue(BookItem.class);
booksList.add(bookItemModel);
adapter.notifyDataSetChanged();
}
Note that I can't be sure if this will work, because you didn't include the code for BooksAdapter in your question.
Here is the code:
ibtSearchStart.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View arg0) {
try{
searchQuery = etSearchThis.getText().toString();
searchQuery = searchQuery.toUpperCase();
cursor = searchActivity.getData(product, "product", tableColumns);
//Clean ArrayList
resultRow.clear();
resultTable.clear();
//Get Search Result
resultTable = searchActivity.searchByProductName(cursor, searchQuery);
//Display Search Result
for(int ctr = 0; ctr < resultTable.size(); ctr++){
HashMap<String, String> map = new HashMap<String, String>();
resultRow = resultTable.get(ctr);
String result = resultRow.get(2);
map.put("ProductName",result);
list.add(map);
}
Log.e("resultProduct", "" + list);
adapter = new SimpleAdapter(
SearchMain.this,
list,
R.layout.search_result,
new String[]{"ProductName"},
new int[]{R.id.tvProductName}
);
lvSearchResult.setAdapter(adapter);
}
finally{
product.close();
}
}
});
The function of this is that it will search for a match in the database then it will insert the result of the search in a HashMap then on a adapter.
But every click i am not able to remove the previous result.
What is the proper implementation to this?
When you are working with adapters and the information changes, be sure that you are calling adapter.notifyDataSetChanged();
You set a new adapter each time the OnClick event is triggered. As Jay Snayder wrote you should use adapter.notifyDataSetChanged(); instead. But be sure to set the adapter only once and move the following part of your code (e.g. to your onCreate() method of the activity):
adapter = new SimpleAdapter(
SearchMain.this,
list,
R.layout.search_result,
new String[]{"ProductName"},
new int[]{R.id.tvProductName}
);
lvSearchResult.setAdapter(adapter);
Just update the DataSet of your adapter (here: 'list').