ArrayList values changed without modification in android - android

I'm developing one Android Application.
I have one screen-A with show button. When user clicks on this show button, then I'm showing one dialog which contains Listview with checkboxes and two buttons submit , cancel.
editGroupUsersDialog = new Dialog(mcontext);
editGroupUsersDialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
editGroupUsersDialog.setContentView(R.layout.edit_group_users_layout);
editGroupUsersDialog.setCanceledOnTouchOutside(true);
editGroupUsersDialog.getWindow().setBackgroundDrawable(new ColorDrawable(0));
editGroupUsersDialog.show();
ArrayList<User> users = //got from the server;
Now I have taken one more static variable in the screnn-A and initialized with above users.
public static ArrayList<User> editUsers = users;
Now I have created adapter object and send the static users to the adapter.
ListView users_listview = (ListView)editGroupUsersDialog.findViewById(R.id.user_listView);
EditGroupUsersAdapter edit_group_users_adapter = new EditGroupUsersAdapter(
mcontext, edit_group_users);
users_listview.setAdapter(edit_group_users_adapter);
Now when the user check or uncheck any item in the dialog, then i'm setting the state of that item in the bean class User.
checkbox.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
// add this line too for getting position of clicked
int pos = (Integer) v.getTag();
Log.v("Position is:", ""+pos);
Log.v("Befoer checkbox status is:", ""+GroupsAdapter.edit_group_users.get(position).isSelected());
if(!GroupsAdapter.edit_group_users.get(pos).isSelected()) {
//set the value to true in the user bean
GroupsAdapter.edit_group_users.get(pos).setSelected(true);
//checkbox.setChecked(true);
} else {
//set the value to false in the user bean
GroupsAdapter.edit_group_users.get(pos).setSelected(false);
//checkbox.setChecked(false);
}
}
});
Here i'm changing the state in static user variable only. i.e. GroupsAdapter.edit_group_users which is of type ArrayList
But the objects int non static variable users of type ArrayList is also changing.
I don't know what was the wrong I'm doing here.
The main purpose i'm taking another static variable of type **ArrayList is to store the modified User objects. But I don't want to change the original users which are available in users variable.
Please tell me how to solve my problem.
Thanks.

Both your static and non-static Arraylist are referencing to list of user.
Now say for some user A, you changes its state from X to Y. Then, this change will be reflected to both Arraylist because both Arraylist are pointing to same object, and you are changing the state of object.

Related

Select multiple items from recycler view list delete not working Properly

if (RFidList.size() >0){
for (String s: RFidList){
RFidTagValueList.remove(s);
}
}
mTimeAdapter.notifyDataSetChanged();
dialog.dismiss();
when choose multiple items in recyclerview checkbox not working / and am use private ArrayList<String> data = new ArrayList<>();
You can't move and delete from the list. The best option to do this is to have an array that will remember the state of the checkbox. Scrolling through your recycler view will always change the state of the checkbox and maybe won't remember it. The way to do this is to add an array of boolean
private boolean[] checkStates;
then inside your constructor of the adapter do this.
checkStates = new boolean[data.size()];
This way you'll create an array of boolean filled with FALSE value the same size your data array is. Now, inside your adapter when you are binding your view do this for the checkbox.
holder.checkbox.setChecked(checkStates[position]);
Also, don't use onCheckedChangeListener on checkbox inside adapter. This will be called even when you scroll and it will change whatever you are doing inside the function. What you can do is override onClick for the checkbox, but there is something tricky here. When you click the checkbox to check it, inside the onClick method the view will have the state as it is already checked so to follow this do it like this:
holder.checkbox.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Checkbox c = (CheckBox) v;
checkStates[position] = c.isChecked();
}
});
I wrote this from my head and maybe there are some mistakes but you'll get the point. The animation of the check state will be handled you just need to handle changes inside the checkStates array.
Now your checkbox will always have the state it had before. After this, you can create a function to delete items from your data.
public void removeItems() {
ArrayList<YOUR-MODEL> items_to_delete = new ArrayList<>();
for (int i = 0; i < checkStates.length(); ++i) {
if (checkStates[i]) items_to_delete.add(data.get(i]);
}
data.removeAll(items_to_delete);
notifyDataSetChanged();
checkStates = new boolean[data.size()];
}
This works if your data is a type of ArrayList. I think this is the best way to go.

Why in RecyclerView findViewByPosition() returns null on EditText

I have an Activity, which has a RecyclerView and save Button. Each item (football match) of the RecyclerView contains some text (name of teams) and EditText, where user enters data (actually bet the match). My goal is to save those scores to the list in the Activity, when user clicked on save Button.
I implemented this method in Activity, which actually get particular item from LinearLayoutManager and then get data from EditText, but the findViewByPosition() method (or getChildAt() there are different way to do this) sometimes returns null.
I saw another answers on similar question, but they didn't help me. Maybe my strategy is wrong, because I made whole my logic in Activity (better to do this in Adapter?) and I get though all of my items in RecyclerView even if only in one user entered the score.
private List<Bet> getUserBets() {
View betView;
Bet betItem;
EditText userBet1;
EditText userBet2;
int numberOfMatches = rvBetsAdapter.getItemCount();
List<Bet> bets = new ArrayList<>();
for (int i = 0; i < numberOfMatches; i++)
{
betItem = rvBetsAdapter.getItem(i);
betView = linearLayoutManager.findViewByPosition(i);
userScore1 = (EditText) betView.findViewById(R.id.result1); // <- NPE appears
userScore2 = (EditText) betView.findViewById(R.id.result2);
//here i checked whether the editText is empty and other stuff
bets.add(betItem);
}
return bets;
}
How do I fix it? I suppose I should do something in onBindViewHolder method in my adapter, but what exactly?
I would really appreciate any help.
You should add to your Bet model variable which holds EditText value for example editTextValue.
And access it using list in adapter list like this end use EditText value from there. rvBetsAdapter.getItem(i).editTextValue
editTextValue can be set using TextWatcher.afterTextChanged() callback
You can only find or get views that are visible on the screen.
before using findViewByPosition(2)
go to position 2 by recyclerView.scrollToPosition(2);
if you want to change value of this views, The best way is get your item in list
yourModel item = (yourModel) itemList.Get(2)
item.Name = "Edited";
yourAdapter.notifyItemChanged(2);

Get all items from adapter (recyclerview) in Fragment

Hello I'm having an issue getting all of the items from my adapter in my fragment. To be more specific I am using a ScaleInAnimatorAdapter along with my Customer Adapter and when I attempt to get my checkbox items from the below posted code, within my Fragment, I only seem to get the visible items on screen.
private View.OnClickListener onAllClick = new View.OnClickListener() {
#Override public void onClick(View v) {
int count = listAdapter.getItemCount();
for (int i = 0; i < count; i++) {
View mChild = listTopics.getChildAt(i);
if( mChild != null ) {
Log.d(TAG,"getItemCount(): " + i );
CheckBox cBox = (CheckBox)mChild.findViewById(R.id.topic_chk);
cBox.setChecked(((CheckBox) v).isChecked());
Log.d(TAG,"isChecked" + cBox.getTag());
cBox.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if(((CheckBox) v).isChecked()) {
checkboxAll.setChecked(false);
}
}
});
}
}
}
};
Essentially I am attempting to create a check all feature from the fragment, so that when this is clicked all of the checkbox items from the adapter are checked. I got that to work with the code I presented however the main issue is that I only get the items visible on the screen, so when I scroll to my other items they are not checked. Thus I am wondering if there is a better way or another way for me to get all of the items
Adapters are meant to bind underlying data stores to views; they generally shouldn't be used to store data themselves (except for having a copy of the data for view binding purposes) nor should they perform actions on data.
Instead, you should be modifying the underlying data, then updating the adapter through whatever mechanism you are already using. (Loaders, custom setters with notifyDataItemChanged, etc.).
Basically you can't. It'll be reusing the UI views.
You need to set a flag in all your data list objects, call notifyDataSetChanged() and onBindViewHolder check that flag and use it to check uncheck
if(listAdapter.getItem(position).getIsChecked())
viewHolder.checkBox.setChecked(true);
else
viewHolder.checkBox.setChecked(false);
Ok. Thank you all for those who have replied you helped me grasp something really basic and important that had alluded me.
I got it to work, so for anyone who might read this post, here is my solution:
Create necessary methods and field to update your data in a model (ie, private is_checked, set_checked(), is_checked(), etc)
In your adapter onBindViewHolder, you will set your holder checkbox to be associated to the data so something like:
holder.checkBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
#Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
obj.setSelected(buttonView.isChecked());
}
});
holder.checkBox.setChecked(obj.isSelected());
Then in your fragment or activity I just have a click listener on my main checkbox, and then when checked I loop through my data list, and using the model method I update my data and just simply use listAdapter.notifyDataSetChanged()
You are doing it wrongly.
You should update the adapter instead of updating the check box view.
What you can do , you can create a field in adapter data holder .
And whenever you change the selection,just update the field or multiple field and finally refresh the view.

Keep a view state/aspect after rotation

In my application I populate a GridView's adapter with random data from a file. The data is shown to the user as a TextView per item. If the user touch an item, the item changes the background colour.
The problem is that if the user touches an item and then rotates the device, the item returns to its original aspect (with the normal background colour)
I've tried different approaches:
Implementing my own adapter
Extending BaseAdapter
Using ArrayAdapter
Using selectors for the TextView
Extending the TextView item with custom styles (from here and here)
Disabling the View within the GridView's onItemClick(AdapterView<?> parent, View view, int position, long id)
What I want to do is keep the Views' colour/style/aspect when I rotate the device
Note:
Why I load data radomly from a file?
The file contains different words. Every time the player start the activity (it is a game) different words in random order are shown inside the GridView. The user hast to point to the right word. If the user make a mistake, the word changes the colour (indeed, I prefer to disable the View). The process is repeated till the user makes the right choice.
You can save the selected states of your list using onSaveInstanceState.
As you click on an item in your list you can assign a state to a boolean array.
Implement the onSaveInstanceState method in your Fragment/Activity.
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putBooleanArray(BundleArgs.STATES, mAdapter.getStates());
}
And then in onCreateView you pass those values to your adapter.
if (savedInstanceState != null) {
states = savedInstanceState.getBooleanArray(BundleArgs.STATES);
//Declare adapter and pass states to it
myAdapter = new Adapter(context, values, states);
}
That's a mistake I've seen several times repeated on SO.
The data and the view that represents the data are totally different entities and they should be treated separately.
You need to keep the state of your data in another data element and preserve that data element during rotation. For example (it's just an example, there' several ways of doing it):
// possible states
private static final int NORMAL = 0;
private static final int RIGHT = 1;
private static final int WRONG = 2;
Map<String, Integer> states; // here you keep the states
then on every click, on the code that checks the answer and change color:
// process the click/state change
states.put(word, newState);
then on rotation:
public void onSaveInstanceState(Bundle outState) {
outState.putSerializable("states", states);
}
and on create
// onCreate
if (savedInstanceState != null) {
states = (Map<String, Integer>) savedInstanceState.getSerializable("states");
} else {
states = new HashMap<String, Integer>();
}
and then back on your custom adapter you have to check the state and modify the view accordingly.
// inside getView
int state = 0
if(states.containsKey(word)){
state = states.get(word).intValue();
}
switch(state){
// deal with the cases and set the color
}

Android - How to read checked items when DialogFragment is called after create

I am using DialogFragment with multichoice checkboxes to allow the user to pick a number of options. I have a Hashmap to which selections are added or removed depending on whether on item is selected when it is clicked - see below. This works fine.
When the user re-opens the Fragment the state of the Dialog is preserved and the items that were previously checked are shown as expected - good so far. However I'd like to know how to read the state of these and add them to my HashMap so that they are returned along with any that are picked up by Listener class. I'm sure this is simple, but I can't find an example.
I've had a look through the API Reference but I can't find an obvious method that provides this.
Thanks in advance.
public class DialogSelectionClickHandler implements
DialogInterface.OnMultiChoiceClickListener {
public void onClick(DialogInterface dialog, int clicked,
boolean selected) {
if (selected) {
// write to a hashmap
groupSelectHash.put(groups[clicked].toString(), "");
}
else
{
// remove from hashmap
groupSelectHash.remove(groups[clicked].toString());
}
Log.i( "DialogTest", "groupSelectHash" + groupSelectHash.toString());
}
}

Categories

Resources