Editing duplicated item in RecyclerView with EditText - java

I have a list of elements that is editable: I can add/delete new elements to the list. Furthermore I can duplicate each Element - duplicated elements are appended to the end of the list. Each element is displayed with a corresponding EditText where users can input quantity of the given element. The Problem: After duplicating an Element E1, editing the quantity of E1 also changes quantity of E2.
Every ListItem looks like this:
TextView(ElementTitle) / EditText(ElementQuantity)
Everything works flawlessly on lists of many elements - until I use my "duplicate" function.
I assume that the problem has something to do with the Recyclerview reusing the EditTextListeners. I am assigning these in onCreateViewHolder as described in this answer: https://stackoverflow.com/a/31860393/6551120.
I tried adding notifydatasetchanged() wherever I could imagine any value. In duplicatedSelected() I tried unregistering and clearing adapter and LayoutManager and creating a new Adapter - without any result.
This is the method that duplicates my elements (In ListActivity):
private void duplicateSelected(){
List selectedItemPositions = mAdapter.getSelectedItems();
for (int i = 0; i < selectedItemPositions.size(); i++) {
int j =(int) selectedItemPositions.get(i);
modulElements.add(modulElements.get(j));
}
mAdapter.notifyDataSetChanged();
In MyAdapter:
private class ModulElementEditTextListener implements TextWatcher {
private int position;
public void updatePosition(int position) {
this.position = position;
}
//Other Override Methods cut out for simplicity
#Override
public void afterTextChanged(Editable editable) {
updatePosition(position);
int timesMultiplied;
if(editable.toString().equals("")){
timesMultiplied=Integer.parseInt("0");
}else{
timesMultiplied = Integer.parseInt(editable.toString());
}
modulElements.get(position)
.setMultiplier(newModulElementMultiplier());
modulElements.get(position)
.getMultiplier().setTimesMultiplied(timesMultiplied);
}
}
Expected result when entering quantity for E1: Quantity for E1 changes
Actual result when entering quantity for E1: Quantity for E1 and E2 (And E3, E4,E5... when I duplicate multiple times) changes.
If I save the list of elements to a database and reopen it I can flawlessy edit quantity of E1 and it does NOT change quantity of E2 - as I would expect it to happen in the first case.
Every hint or idea welcome, thank you so much!

You must implement the cloneable interface for your data model and modify this line
modulElements.add(modulElements.get(j).clone());
Now you have different objects in the list

Related

How to go through a listview and get the position of a item in it WITHOUT click on it Android Studio

I want to get the position of a item in the list view and use it in a if.
Now i am going through the listview using a for loop, and i want when i find the specfic Product Id equal to the Same Product (if clause), and when i find it i use that position to update my list
for (int i = 0; i < adapterItensDoCarrinho.getCount(); i++) {
Log.d("ENTROU", "ENTROU");
Log.d("ID", String.valueOf(lsvCarrinhoCompras.getId()));
if (produtoSelecionado.getId() == adapterItensDoCarrinho.getItemId(i)) {
Log.d("ENTROU 2", "ENTROU 2");
int novaQte = itemDoCarrinho.getQtdeSelecionada();
novaQte++;
itemDoCarrinho.setNome(produtoSelecionado.getNome());
itemDoCarrinho.setQtdeSelecionada(novaQte);
itemDoCarrinho.setPrecoItemVenda(produtoSelecionado.getPrecoProduto());
adapterItensDoCarrinho.updateItemCarrinho(lsvCarrinhoCompras.getId(), itemDoCarrinho);
break;
}
else {
itemDoCarrinho.setNome(produtoSelecionado.getNome());
itemDoCarrinho.setQtdeSelecionada(qtdeProduto);
itemDoCarrinho.setPrecoItemVenda(produtoSelecionado.getPrecoProduto());
adapterItensDoCarrinho.addItemCarrinho(itemDoCarrinho);
}
}
Hope you understand it!
Your Adapter should be the one to handle this behavior. Write a public method in the Adapter class which allows you to pass in the selected product ID. Whenever the selected product ID changes in your Activity/Fragment/whatever, call the public method in the Adapter to update the product ID value. Then, in the getView() method of the Adapter, if the ID matches, perform whatever special behavior you want to have happen for the product with that ID.

Easy way to rewrite in a loop

Is there an easier way to write this code to make my image views invisible? I was hoping I could use some type of for loop. I am also new to programming so in your answer, can you please explain how the loop is working so I can use it in future references? Also, how do I assign 15 image views to 1 array?
iv_1.setVisibility(View.INVISIBLE);
iv_2.setVisibility(View.INVISIBLE);
iv_3.setVisibility(View.INVISIBLE);
iv_4.setVisibility(View.INVISIBLE);
iv_5.setVisibility(View.INVISIBLE);
iv_6.setVisibility(View.INVISIBLE);
iv_7.setVisibility(View.INVISIBLE);
iv_8.setVisibility(View.INVISIBLE);
iv_9.setVisibility(View.INVISIBLE);
iv_10.setVisibility(View.INVISIBLE);
iv_11.setVisibility(View.INVISIBLE);
iv_12.setVisibility(View.INVISIBLE);
iv_13.setVisibility(View.INVISIBLE);
iv_14.setVisibility(View.INVISIBLE);
iv_15.setVisibility(View.INVISIBLE);
iv_16.setVisibility(View.INVISIBLE);
iv_17.setVisibility(View.INVISIBLE);
iv_18.setVisibility(View.INVISIBLE);
iv_19.setVisibility(View.INVISIBLE);
iv_20.setVisibility(View.INVISIBLE);
iv_21.setVisibility(View.INVISIBLE);
iv_22.setVisibility(View.INVISIBLE);
iv_23.setVisibility(View.INVISIBLE);
iv_24.setVisibility(View.INVISIBLE);
iv_25.setVisibility(View.INVISIBLE);
iv_26.setVisibility(View.INVISIBLE);
iv_27.setVisibility(View.INVISIBLE);
iv_28.setVisibility(View.INVISIBLE);
iv_29.setVisibility(View.INVISIBLE);
iv_30.setVisibility(View.INVISIBLE);
iv_31.setVisibility(View.INVISIBLE);
iv_32.setVisibility(View.INVISIBLE);
iv_33.setVisibility(View.INVISIBLE);
iv_34.setVisibility(View.INVISIBLE);
iv_35.setVisibility(View.INVISIBLE);
iv_36.setVisibility(View.INVISIBLE);
iv_37.setVisibility(View.INVISIBLE);
iv_38.setVisibility(View.INVISIBLE);
iv_39.setVisibility(View.INVISIBLE);
iv_40.setVisibility(View.INVISIBLE);
iv_41.setVisibility(View.INVISIBLE);
iv_42.setVisibility(View.INVISIBLE);
iv_43.setVisibility(View.INVISIBLE);
iv_44.setVisibility(View.INVISIBLE);
iv_45.setVisibility(View.INVISIBLE);
iv_46.setVisibility(View.INVISIBLE);
iv_47.setVisibility(View.INVISIBLE);
iv_48.setVisibility(View.INVISIBLE);
iv_49.setVisibility(View.INVISIBLE);
iv_50.setVisibility(View.INVISIBLE);
iv_51.setVisibility(View.INVISIBLE);
iv_52.setVisibility(View.INVISIBLE);
iv_53.setVisibility(View.INVISIBLE);
iv_54.setVisibility(View.INVISIBLE);
iv_55.setVisibility(View.INVISIBLE);
iv_56.setVisibility(View.INVISIBLE);
iv_57.setVisibility(View.INVISIBLE);
iv_58.setVisibility(View.INVISIBLE);
iv_59.setVisibility(View.INVISIBLE);
iv_60.setVisibility(View.INVISIBLE);
Put your iv_xx objects in a list or array, then use a loop to iterate through the array:
ArrayList<IVType> ivList = new ArrayList<>();
// use ivList.add() to add each object to the list.
for (IVType iv: ivList)
{
iv.setVisibility(View.INVISIBLE);
}
First create a array of size N of type img(Your object).
N—> will be the number of images.
img[] a=new img[N];
Here, we are creating a array of type img with size N.
Now you need to add all your 50 image object to this array using for loop
Then loop through the array and set the property like below.
for(int i =0; i<N;i++){
a[i].setVisibilty(View.INVISIBLE);
}
Let's assume this is your POJO
public class ImageView {
private View visibility;
public ImageView(View view) {
visibility = view;
}
public View getVisibility() {
return visibility;
}
public void setVisibility(View visibility) {
this.visibility = visibility;
}
enum View {
VISIBLE, INVISIBLE
}
}
Also, consider the scenario that you have already ImageView list that contains 60 image instances.
List<ImageView> imageViews = new ArrayList<>();
//instead of creating 60 beans separately and adding it to list you can just follow the below code
IntStream.range(0, 60).forEach(e -> {
imageViews.add(new ImageView(ImageView.View.INVISIBLE));
});
//you can manipulate the ImageView instances as below
//imageViews.forEach(e -> e.setVisibility(ImageView.View.INVISIBLE));
//As per the requirement you can convert the list into array as below. There is no need to mention the pre-sized array (new ImageView[imageViews.size()]) here
ImageView[] imageViewsArr = imageViews.toArray(new ImageView[0]);
//If you want to make a arrays of first 15 instances then you can limit the size to 15 (your question mentioned just 15 imageViews to 1 array)
//ImageView[] imageViewsArr = imageViews.stream().limit(15).toArray(new ImageView[0]);

RecyclerView list row is repeating JsonArray data at the end

In the data I'm getting from the server, not a single item is repeating. I debugged my code during this loop, which adds in the model class then sets in the adapter. Again, no single item is repeating.
However, in my list items are repeating after performing the click event on a row button. When I use the methods defined below the text never appears in a row but the number of empty rows is increasing.
/*When I use these 2 methods then it never displays text in the list but increases list*/
#Override
public long getItemId(int position) {
return position;
}
#Override
public int getItemViewType(int position) {
return position;
}
/*When I use these 2 methods then it never displays text in the list but increases list*/
Make sure you empty the list before adding data coming from server to your list and setting adapter to your recyclerview

Unable to write an algorithm for filtering out items in a RecyclerView based on a long saved with each item

I have several items in a RecyclerView and each item has a long value saved with it. I'm using FastAdapter as the adapter for my RecyclerView.
Suppose there are 7 items in the RecyclerView with the long values: 11122, 12321, -98811, 8870, -88009, 3398, and -22113.
So, what I want to do is, I want to filter the items based on the above given long values using this logic:
if (l <= 1000) {
// show items with long value <=1000
} else if (l > 1000) {
// show items with long value >1000
}
I tried various things, but nothing worked out.
UPDATE 1: Items here are a sort of different data stored in CardView and then shown in RecyclerView. Each card contains different data, one of which are the above given long values. I want to filter the data based on these long values stored in each card based on the logic given above.
Please help me with this issue and suggest some algorithm or code with which I can achieve this.
With the amount of information given I can only suppose l is a foreign selector value which controls the items to be displayed inside the RecyclerView. Comment below if this is not the case, I will try to correct my answer.
I recommend implementing a custom ViewAdapter, sending in the list of items and the selector variable l using respective methods:
public class ItemsAdapter extends
RecyclerView.Adapter<ItemsAdapter.ItemViewHolder> {
private List<Long> mItemList;
private List<Long> mDisplayItems;
private boolean mAboveThousand = true;
public void setItemList(List<Long> list) {
mItemList = list;
updateDisplayItems();
}
public void setSelectionType(boolean aboveThousand) {
mAboveThousand = aboveThousand;
updateDisplayItems();
}
private updateDisplayItems() {
mDisplayItems.clear();
for(Long item: mItemList) {
if(/*check your contition*/) {
mDisplayItems.add(item);
}
}
notifyDataSetChanged(); //important
}
...
// Rest of implementation
}
Also, I have never used FastAdapter, but I suppose there must be some methods to override if you extend its class.
Update
Since, you are facing problems understanding the basics of using a ViewAdapter, I would recommend learning and implementing a custom ViewAdapter before using any library. Here's a extensive tutorial for how to implement ViewAdapter for RecyclerView.
Now, after you have implemented the ViewAdapter you can use my piece of code to filter out cards. Basically, what the code is doing is saving a list of all the required data inside mItemList, while mDisplayList is a list storing the items to be displayed, which is updated every-time mAboveThousand, which stores the user preference of above or below 1000, is set. Now this mDisplayList must be used to inflate data inside the RecyclerView.
Even your very basic code there would work. You can count the number of items in that range and return the number in that range. I suggest you try to do this without FastAdapter because the core concept of parsing the data based on a filter value is rightly perfectly solid. You can iterate the loop and count them, and you can iterate the loop and return the nth item.
If you do want to keep using FastAdapter, it has a built-in filter functionality (see point number 5 in the README of the project. Note that the filter method should be called after withFilterPredicate and not before as shown there).
EDIT - after you pointed out that I misunderstood you before - here is my updated proposed instructions:
You need to resolve the logics of which set you want to display (using the checkboxes in the dialog you mentioned in the comment) and pass that information onto the filter, for example:
boolean displayUnderThreshold = //put the logic here - true if you want <1000
fastAdapter.filter(Boolean.toString(displayUnderThreshold));
And where you set the adapter (before the above line is called) have:
final long threshold = 1000;
fastAdapter.withFilterPredicate(new IItemAdapter.Predicate<GRModeClass>() {
#Override
public boolean filter(GRModeClass item, CharSequence constraint) {
boolean displayUnderThreshold = new Boolean(constraint.toString());
return (displayUnderThreshold ^ (item.l<threshold)); //false to remove from list
}
});
Old answer From when I thought you wanted to filter the items according to their ms long values, using an external l long indicator:
In your code, assuming your app does get to the if you mentioned in the question when it should - remove the fastItemAdapter.clear(); and instead of the for loop with the if inside it write
fastItemAdapter.filter(Long.toString(l));
and somewhere before that, preferably where you set the adapter (most likely in the onCreate of MainActivity) add the following:
final long threshold = 1000;
fastAdapter.withFilterPredicate(new IItemAdapter.Predicate<GRModeClass>() {
#Override
public boolean filter(GRModeClass item, CharSequence constraint) {
long indicator = new Long(constraint.toString());
return (item.ms<threshold && indicator>=threshold) || (item.ms>=threshold && indicator<threshold) ;
}
});
(Assuming here that GRModeClass is your items' class and that the long ms is the long you referred to that should determine whether the )
I guess your class is like
public Class ListItem {
// .. Some other attributes
public long l;
}
Now I hope you've some function which is called when you're putting a filter in your RecyclerView. Let the function name is toggleFilter.
public void toggleFilter(long l) {
if(l <= 1000) {
fastAdapter.withFilterPredicate(new IItemAdapter.Predicate<Item>() {
#Override
public boolean filter(ListItem item, CharSequence constraint) {
if(item.l <= 1000) return true;
else return false;
}
});
} else if (l > 1000) {
fastAdapter.withFilterPredicate(new IItemAdapter.Predicate<Item>() {
#Override
public boolean filter(ListItem item, CharSequence constraint) {
if(item.l > 1000) return true;
else return false;
}
});
}
// Finally call notifyDataSetChanged
fastAdapter.notifyDataSetChanged();
}
You can filter while fetching from firebase.
l <= 1000
firebaseDatabase.child(key).orderByChild("long_value_key_in_firebase").endAt(1000);
l > 1000
firebaseDatabase.child(key).orderByChild("long_value_key_in_firebase").startAt(1000);

ArrayAdapter : Remove by Index

I have a ListView that is populated by a news server rundown (just a list of story slugs) and an arrayAdapter to modify that ListView.
I can remove items by the 'remove(Object)' function but what if there are multiple instances of 'Object'? remove() only removed the first instance of 'Object'. I cannot remove, for example, the second 'Object' in my array adapter without removing the first one. So my question is how can i work around this?
ex : Rundown A
story 1
story 2
Break
story 3
story 4
Break
story 5
etc...
so in this example i cannot delete the Second 'Break' because remove('Break') will remove the first one. if i could removeByIndex(5), that would be perfect but....
Ive tried writing my own remove function that creates a whole new adapter with all members but the specified index. here is what i was messing around with.
public ArrayAdapter<String> removeIndex(ArrayAdapter<String> arr, int index) {
ArrayAdapter<String> temp = new ArrayAdapter<String>(arr.getContext(),R.layout.list_item);
for(int i =0 ; i<arr.getCount();i++){
if(i != index) temp.add(arr.getItem(i));
}
return temp;
}
Help or suggestions are appriciated.
Handle the collection of strings yourself with a List and pass the object into the constructor of the ArrayAdapter. This leaves you with a reference to the List so you can alter the data while allowing the adapter to manage and display as needed.
Note: When modifying the data object you must call
myAdapter.notifyDataSetChanged()
afterwards - which must also be on the UI thread. Obviously the changes to the list don't have to take place on the UI thread and should most likely not happen on the UI thread.
private ArrayList<String> mData = new ArrayList<String>();
private ArrayAdapter<String> mAdapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
// ...
// Code that adds the strings
// Create the list adapter
mAdapter = new ArrayAdapter<String>(myActivity.this, android.R.layout.simple_list_item_1, mData);
}
private void removeItem(int index) {
mData.removeAt(index);
myActivity.this.runOnUiThread(new Runnable() {
public void run() {
mAdapter.notifyDataSetChanged();
}
}
}

Categories

Resources