Removing items from array list without using position - android

Morning everyone
Currently I have an ArrayList which allows me to remove by a set of item position which is perfect in most situations. But I was wondering if it was possible to remove my something e.g. a long variable.
My current ArrayList which is currently set on my recyclerView adapter.
private ArrayList<NoteInfoModal> mAdapter = new ArrayList (List)
Under the NoteInfoModal we also have the getters and setters for multiple rows that I use for my recyclerView e.g. Name, Description, Col ID etc...
Removing an item at the moment I simply use the following code below
mAdapter.remove(position)
Is there a way of altering this ArrayList so I can for example delete a result from this arraylist without using the position but instead an item inside the arraylist e.g. col id?
Thank you

Yes, but you will have to run a for-each loop for that.
//suppose you have col_Id;
for(NoteInfoModel noteInfoModel : mAdapter) {
if(noteInfoModel.getColId == col_Id) {
mAdapter.remove(noteInfoModel);
break;
}
}

Sure, instead of using the position to remove, you simply put in the Object you want to remove from the ArrayList:
mAdapter.remove(yourObject)
take a look at the official documentation.
Ganesh Gudghe also mentioned, that its neccessary to implement hashCode() and equals() for your class NoteInfoModal.

Related

How to show items in a list view only when the sequence is the same

I want to display "best" below only those comments that match the sequence of the top three best comments.
CommentAdapter
for (GoodsComment num : list) {
if (item.getSeq() == num.getSeq()) {
holder.txtBest.setVisibility(View.VISIBLE);
} else {
holder.txtBest.setVisibility(View.GONE);
}
}
This code works but only one
Assuming you are doing this inside the adapter, you should not use the for loop. Create an array containing sequence numbers of best comments and put it as a variable in the adapter.
Then in the adapter, getView() (for Listview) or bindView() (for RecyclerView) check if the sequence number is in the array you created earlier.
This should show the "best" flag in all the matching rows.
try to use integer flag and each time increment flag then check if flag = 3 or not
Are you updating the list item item every time after the for loop?

How to prevent double items but also prevent entire list from refreshing?

I am getting a JSON Array of user ids strings from a database:
["uid1", "uid103", "uid322"]
I am fetching this array on a time triggered loop, and I use notifyDataSetChanged with myDataSet.clear() to display the list, and to prevent duplicates. The problem with this method is that the list is constantly "refreshing", and I just want to either add or remove the items that's needed to be removed or added.
If I remove the clear() part, then the list won't refresh, but I will get duplicate items.
This is how the code (+pseudo) looks like:
trigger(just a time based loop) {
myDataset.clear();
jsonArray = //the id array from the database;
for (int i=0;i<jsonArray.length;i++){
myDataset.add(new User(jsonArray.get(i), imageUrl));
mAdapter.notifyDataSetChanged();
}
}
You can use for this purpose DiffUtil class (Medium example).
It calculates differences between new and old datasets and updates it.
But if you don't want to deep dive into DiffUtil you can try to use combination of notifyItemInserted() and notifyItemChanged()
You need to compare the 2 lists before refreshing. So,
If an item is removed, Your list's size will be smaller.
If an item is added, the list's size will be bigger and the new item will be the last item in the retrieved array.
But if an item is removed and at the same time an item is added, your list's size will be the same but the last item will change.
So, you need to check both array size and the last item before refreshing like this:
trigger(just a time based loop) {
if((myDataset.size() != jsonArray.size()) || myDataset[last] != jsonArray[last]) {
myDataset.clear();
jsonArray = //the id array from the database;
for (int i=0;i<jsonArray.length;i++){
myDataset.add(new User(jsonArray.get(i)));
mAdapter.notifyDataSetChanged();
}
}
}
Change your code as below, Your loop will do all the changes in your data and once the loop is over you notify those changes to your list in one go, instead of refreshing it each time.
for (int i=0;i<jsonArray.length;i++){
myDataset.add(new User(jsonArray.get(i)));
}
mAdapter.notifyDataSetChanged();
If you want to avoid duplicates use Set, add items to set from your json array and use it as datasource for your list.
You have a basic misunderstanding of the timer trigger. The loop will not pause there waiting for your next User entry from JSON. So adding notify in the loop is very bad practice. One notify outside the loop is enough. If a new User is added, it should appear in another timer trigger, i.e., another loop.
If you are seeing duplicate, that must be in the code handling the JSON to insert your database. However this code is not listed here so you need to look at that code.
Adding a unique index in the database table is a good solution.
for avoiding duplicate use contains
myDataset.clear();
for (int i=0;i<jsonArray.length;i++){
User user=new User(jsonArray.get(i), imageUrl);
//now check if its already in list or not by using contains.
if(!myDataset.contains(user)){
myDataset.add(user)
}
}//end of loop
and then pass list to your adapter and then call notifyDataSetChanged()
mAdapter.notifyDataSetChanged();

Getting all Listview checked Indexes

This is a follow up question to this question:
Retrieving the selected items from a multi-select ListView
I'm using a ListView with mode CHOICE_MODE_MULTIPLE_MODAL.
Is there a way to get the indexes of all checked Items ? In the question I posted above, there's a suggestion to use the method getCheckedItemPositions(), but I don't want to iterate over the entire list and check if it returns true so this is not what I need. I want to do something like this (pseudo code):
int[] checkedPositions = list.getCheckedIndexes();
for(int index : checkedPositions)
{
list.remove(index);
}
Is there a way to do something like that?
It may use less code if such a method exists to return an array of checked items, but that method would likely use the same time complexity as just iterating yourself.
Try getCheckedItemIds as mentioned in the documentation :
Returns the set of checked items ids.
To make it works correctly , in the adapter getItemId make it returns the position of the item

Android How to change image inside a listview for a particular condition

I have a listview. I have infalted that list view with a layout file which contain a textView and an imageview.
Textview for that is populated from a arraylist. I have used an array-adapter,because it directly gives me the getFilter() which in turn i use to filter the list.
I am running a database query , which returns a list of items.I am storing all the items in a Cursor. Now i am iterating through the cursor and checking whether the items from the database are contained in the arraylist.
I want to toggle the image if there is a match.how do i do that.
Cursor crs = actSl.execSQL(sqlQuery);
if (crs != null && crs.getCount() > 0) {
crs.moveToFirst();
if (crs.getCount() > 0) {
do {
for(String favItem:favouritesList){
if (favItem.contains(crs.getString(0))) {
}
}
} while (crs.moveToNext());
}
}
If you don't want to change your datastructure one way would be to create a new array(or arraylist) of boleans the size of your favouritesList that will hold status of your images.
You then modify these values and call yourListAdapter.notifyItemsChanged()
Oh yeah, and inside getView in your adapter you have to (of course) read the booleans.
Note you cannot access the separate views of a list outside adapter and holding a reference to them is highly discouraged.
Follow the following steps :
Initially set the imageViews from an arrayList ( Pass the arrayList to the customAdapter)
When an imageView has to be changed, just change the arrayList() ie update it.
Now notify the adapter using
customListAdapter.notifyItemsChanged();
This will solve the problem. Please feel free to ask any further doubts

How to remove the filter on an ArrayAdapter used in an AutoCompleteTextView?

As the title, how can I remove the filtering on an ArrayAdapter used by an AutoCompleteTextView to get the original list back?
A little more background:
It all started from the sad fact that the "position" value passed in to onItemClick() is useless. The "position" refers to the position AFTER the array has been filtered, but I need to know its REAL position. So, what I'm trying to do is when I've got the text of the selected item (by using getItemAtPosition(position)), I compare it one-by-one with the original string array that backs the ArrayAdapter. However, I found that when onItemClick() is called, the adapter is already filtered, I no longer have access to the original array. So I thought if I can remove the filter, maybe I can get back the original array and look for the selected item in it.
ArrayAdapter<String> mAdapter;
public void onCreate() {
// Create an adapter and remembere it as a class member.
mAdapter = new ArrayAdapter<String>(this, layoutId);
// Add 100 strings to it and attach it to an AutoCompleteTextView
for (int i = 0; i < 100; i++)
mAdapter.add("random text");
((AutoCompleteTextView)findViewById(id)).setAdapter(mAdapter);
}
#Override
public void onItemClick(AdapterView<?> actv, View view, int position, long id) {
if (actv.getAdapter().equals(mAdapter))
Log.d("The adapter contained in actv is the same one I created earlier.");
// And, I can get the text of the item the user selected
String selected = (String)actv.getItemAtPosition(position);
// However, although the adapter passed in is still the same one, but the
// number of items in it is only 1! Because the array has been filtered.
int numItems = actv.getAdapter.getCount();
// So, I'm thinking if I can somehow remove the filtering here, then I can
// get back those 100 items, and do a search like following:
for (int i = 0; i < actv.getAdapter.getCount(); i++)
if (selected == actv.getAdapter.getItem(i))
break; // Eureka!!!
}
To tackle the problem of obtaining the REAL position of the selected item:
Is there a way to utilize the "id" value? Like, assign each item an id, then hopefully onItemClick() would pass back the correct id.
Like I said above, remove the filter (is it possible), get back the original 100 items, and perform a one-by-one search.
This is the last resort, I know it'll work, but I don't want to do it: Once I get the text of the selected text, I go back to the source of the data (from a database), query those 100 items out, and perform the search.
Another lame last resort: To avoid the overhead on accessing the database again as in #3, when in onCreate(), while creating the ArrayAdapter, I use an ArrayList of my own to remember all those 100 strings.
Am I doing it all wrong? What's the "right" way of obtaining the real position of the selected item from an AutoCompleteTextView?
Thank you very much!
(I read somewhere, some buy that seemed to be from Google Android team, said that one should use getFirstVisiblePosition() to resolve the position. But I can't figure out how.)
I don't know if you're still interested, but I found this answering a similar question: Problem with AutoCompleteTextView and Spinner using the same Adapter
Copying the method in the AutoCompleteTextView source code:
Filter filter = mAdapter.getFilter();
filter = null;
See my response in the above question for the grepcode link.
This is actually pretty simple to solve.. Instead of adding each element to the adapter as you get it (I'm assuming your random text part is just for example purposes), instead use the following:
First build your array into a variable, call it myArray..
then initialize your adapter like this:
mAdapter = new ArrayAdapter<String>(this, layoutId, myArray);
Now make sure that myArray is a class variable so you can reference it from anywhere else in the class.. Of course if you need access to this from another class you'd want to make a getter for it... Then you can easily iterate over the array to see if the value selected is in the array.. You'll have the whole set of data there instead of trying to get it from the adapter.
Here is a good example on using a validator for a similar looking use case:
Android, Autocomplettextview, force text to be from the entry list
In my case, I have address that can be set either by autocomplete or clicking on the map. If user click on the map, editText text should be set to address selected from the map, and in that case filtering should be disable temporarily.
I code like this:
public void OnAddressFound(String address) {
// Temporary disable autocomplete
editTextSearch.setAdapter(null);
editTextSearch.setText(address);
// Enable autocomplete again
setAutoCompleteAdapter();
}
where setAutoCompleteAdapter() is called during onCreate, and again in temporary disable/enable filter:
void setAutoCompleteAdapter() {
PlacesAutoCompleteAdapter adapter = new PlacesAutoCompleteAdapter(this, R.layout.item_autocomplete_map_search, autoCompleteList);
editTextSearch.setAdapter(adapter);
adapter.notifyDataSetChanged();
}
Hope its help you also.
I found the solution, kinnda tricky but its works
after i looking inside of the source, i found that th treshold variable used as filtering validation, here we just need to set the treshold to maximum int so filtering never perform.
threshold = Integer.MAX_VALUE
or
setThreshold(Integer.MAX_VALUE)

Categories

Resources