Retain radiobutton check in ListView after configuration change - android

In my fragment, I have 4 ListViews (all 4 containing custom rows with a radio button) where a user needs to select a row for each ListView. Initially I was having trouble with getting the radio button to be checked whenever the user selects a particular row, however I came across this solution which worked well for me https://stackoverflow.com/a/12823457/3739918
Now everything is good, except I'm unable to retain the checked radio buttons after a configuration change (eg. phone changes from portrait to landscape or vice versa). I have tried to using setRetainInstance(true) which works to retain the selections prior to the configuration change (I just use an integer array to keep track of the user selections in the different list views), however I have been unsuccessful in using this information to recheck the corresponding radio button after the configuration change.
Here is the code of my fragment containing the ListViews (minus irrelevant lines):
public class FourBandFrag extends Fragment implements
AdapterView.OnItemClickListener {
private ArrayList<ListView> lists = new ArrayList<ListView>();
private ArrayList<CustomAdapter> adapters = new ArrayList<CustomAdapter>();
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setRetainInstance(true);
View result = inflater.inflate(R.layout.fourbandlayoutfrag, container,
false);
return result;
}
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
lists.add((ListView) getActivity().findViewById(R.id.FourListView1));
lists.add((ListView) getActivity().findViewById(R.id.FourListView2));
lists.add((ListView) getActivity().findViewById(R.id.FourListView3));
lists.add((ListView) getActivity().findViewById(R.id.FourListView4));
adapters.add(new CustomAdapter(getActivity(), generateData(1)));
adapters.add(new CustomAdapter(getActivity(), generateData(1)));
adapters.add(new CustomAdapter(getActivity(), generateData(2)));
adapters.add(new CustomAdapter(getActivity(), generateData(3)));
for (int i = 0; i < lists.size(); i++) {
lists.get(i).setAdapter(adapters.get(i));
}
for (int q = 0; q < lists.size(); q++) {
lists.get(q).setOnItemClickListener(this);
}
for (int i = 0; i < lists.size(); i++) {
lists.get(i).setAdapter(adapters.get(i));
}
}
#Override
public void onItemClick(AdapterView<?> parent, View view, int position,
long id) {
//This checks the corresponding radio button for the corresponding listview
((CustomAdapter) parent.getAdapter()).setSelectedIndex(position);
((CustomAdapter) parent.getAdapter()).notifyDataSetChanged();
}
}
The CustomAdapter.java looks like (minus irrelevant lines):
public class CustomAdapter extends ArrayAdapter<Model> {
private final Context context;
private final ArrayList<Model> modelsArrayList;
private int selectedIndex = -1;
public CustomAdapter(Context context, ArrayList<Model> modelsArrayList) {
super(context, R.layout.listitem, modelsArrayList);
this.context = context;
this.modelsArrayList = modelsArrayList;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
LayoutInflater inflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View rowView = inflater.inflate(R.layout.listitem, parent, false);
RadioButton radiobutton = (RadioButton) rowView
.findViewById(R.id.radioButton);
// Check the correct radio button when person selects a listview item
if (selectedIndex == position) {
radiobutton.setChecked(true);
} else {
radiobutton.setChecked(false);
}
return rowView;
}
public void setSelectedIndex(int index) {
selectedIndex = index;
}
}
Anyone have ideas?
Thank you
Update 1
Because a radio button is only checked when the user clicks on a row, I decided to simulate a click using the information retained regarding the user selections prior to the configuration change. So now my fragment looks like this:
public class FourBandFrag extends Fragment implements
AdapterView.OnItemClickListener {
private ArrayList<ListView> lists = new ArrayList<ListView>();
private ArrayList<CustomAdapter> adapters = new ArrayList<CustomAdapter>();
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setRetainInstance(true);
View result = inflater.inflate(R.layout.fourbandlayoutfrag, container,
false);
return result;
}
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
lists.add((ListView) getActivity().findViewById(R.id.FourListView1));
lists.add((ListView) getActivity().findViewById(R.id.FourListView2));
lists.add((ListView) getActivity().findViewById(R.id.FourListView3));
lists.add((ListView) getActivity().findViewById(R.id.FourListView4));
adapters.add(new CustomAdapter(getActivity(), generateData(1)));
adapters.add(new CustomAdapter(getActivity(), generateData(1)));
adapters.add(new CustomAdapter(getActivity(), generateData(2)));
adapters.add(new CustomAdapter(getActivity(), generateData(3)));
for (int i = 0; i < lists.size(); i++) {
lists.get(i).setAdapter(adapters.get(i));
}
for (int q = 0; q < lists.size(); q++) {
lists.get(q).setOnItemClickListener(this);
}
for (int i = 0; i < lists.size(); i++) {
lists.get(i).setAdapter(adapters.get(i));
}
// Retain radio button selections after configuration change
for (int w = 0; w < bandRowNumber.length; w++) {
if (bandRowNumber[w] != unselected) {
lists.get(w).performItemClick(
lists.get(w).getAdapter()
.getView(bandRowNumber[w], null, null),
bandRowNumber[w],
lists.get(w).getAdapter().getItemId(bandRowNumber[w]));
Log.d(TAG, "Rechecking radio button " + bandRowNumber[w] + " from ListView " + w);
}
}
}
#Override
public void onItemClick(AdapterView<?> parent, View view, int position,
long id) {
//This checks the corresponding radio button for the corresponding listview
((CustomAdapter) parent.getAdapter()).setSelectedIndex(position);
((CustomAdapter) parent.getAdapter()).notifyDataSetChanged();
}
}
This certainly does attempt to recheck the correct radiobuttons judging from the logcat I'm getting, however the radiobuttons remain unchecked after the config change. Here is what it looks like:
In portrait mode I make a selection in each of the listviews.
http://s17.postimg.org/nm4wyve4v/portrait.png
I change the phone to landscape mode and the radio button selections dissapear.
http://s10.postimg.org/459rrgc9l/landscape.png
The logcat after changing from portrait to landscape is:
07-02 12:56:14.407: D/FourBandFrag(30090): Rechecking radio button 0 from ListView 0
07-02 12:56:14.417: D/FourBandFrag(30090): Rechecking radio button 1 from ListView 1
07-02 12:56:14.427: D/FourBandFrag(30090): Rechecking radio button 2 from ListView 2
07-02 12:56:14.427: D/FourBandFrag(30090): Rechecking radio button 3 from ListView 3
Any suggestions for a fix?

This used as per your condition
View rowView = null;
if (convertView == null) {
View rowView = inflater.inflate(R.layout.listitem, parent, false);;
} else {
rowView = convertView;
}

Related

Dialog with Gridview sometimes doesn't load

I'm making an app that makes use of a GridView to display subcategories.
I have the categories displayed on screen and when clicked a dialog appears with a GridView displaying subcategories and a button to view everything in that category.
Here's the problem:
Sometimes the GridView doesn't load on the first click, I have to close it and then click on the category again for it to open. Categories are basically images with a textview on top. Pictures are loaded from the Internet.
Code for Dialog:
public class dialogFragment extends android.support.v4.app.DialogFragment {
private Button mViewAll;
private GridView mSubCatsView;
public ArrayList<category> mCats = new ArrayList<>();
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.dialog_fragment, container);
mCats.addAll(((shopActivity)getActivity()).mDialogCats);
mViewAll = v.findViewById(R.id.viewAllBTN);
mSubCatsView = v.findViewById(R.id.subCatsView);
final gridAdapter adapada = new gridAdapter(getActivity(), mCats);
mSubCatsView.setAdapter(adapada);
mSubCatsView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
ArrayList<category> subSubCats = new ArrayList<>();
for (int y = 0; y < ((shopActivity)getActivity()).mCategoriesAll.size(); y++){
if(mCats.get(i).getId() == ((shopActivity)getActivity()).mCategoriesAll.get(y).getParent()){
subSubCats.add(((shopActivity)getActivity()).mCategoriesAll.get(y));
}
}
if(subSubCats.size() > 0){
mCats.clear();
mCats.addAll(subSubCats);
adapada.notifyDataSetChanged();
}
}
});
mViewAll.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
}
});
return v;
}
}
If anyone else has this problem, I fixed it by using a RecyclerView + GridLayoutManager to mimic a GridView.

Previous items piling up in the Listview

I've created a listview which takes the input from the alertDialog editText and populate it. Everything is working fine but after deleting the item from the row and adding something again it adds up the previous deleted item also which is not a good thing. I know the clear picture of my problem but it is difficult to find out whether how to do that.
This is my code where I'm adding the list inside the listView :
Adding Items
{ items[items.length - 1] = value;
List<String> newList = new LinkedList<String>(Arrays.asList(items));
//Log.e("STRIING", newArray.toString());
adapter = new MyListAdapter(RecyclerActivity.this, newList);
mListView.setAdapter(adapter);
String[] temp = new String[items.length + 1];
for (int i = 0; i < items.length; i++)
temp[i] = items[i];
items = temp;
alertDialog.dismiss();
adapter.notifyDataSetChanged();
input.getText().clear();
}
In here I have to notify the changes of the deleted item in order to get the desired result but i don't know how.
Here is the place where I'm deleting the item from the listview:
mListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(final AdapterView<?> adapterView, View view, int i, long l) {
final String pos = mListView.getItemAtPosition(i).toString();
Log.e("POS", pos);
deleteDialog.setButton(DialogInterface.BUTTON_POSITIVE, "OK", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialogInterface, int i) {
adapter.remove(pos);
adapter.notifyDataSetChanged();
}
});
deleteDialog.show();
}
});
and here is the MyAdapter class which binds the data :
public class MyListAdapter extends ArrayAdapter<String>{
private final Context context;
private final List<String> values;
class ViewHolder {
public TextView text;
}
public MyListAdapter(Context context, List<String> newList) {
super(context, R.layout.row_item, newList);
this.context = context;
this.values = newList;
}
#Override
public View getView(final int position, View convertView, ViewGroup parent) {
LayoutInflater inflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
final View rowView = inflater.inflate(R.layout.row_item, parent, false);
TextView textView = (TextView) rowView.findViewById(R.id.tvItem);
textView.setText(values.get(position));
return rowView;
}
}
My adapter is the Global Variable
I've tried using this in order to see whether the problem is getting fixed or not by following this link :
Deleting the items for the listview
The code looked like this now . :
newList.remove(pos);
adapter.notifyDataSetChanged();
newList is nothing but a List<> of type String
Please help me with this because I have wasted a long hour in this only. Thanks in advance.
EDITS
I've tried adding this in my Adapter Class, but this is giving me the same result :
public void removeItem(String position) {
values.remove(position);
notifyDataSetChanged();
}
Calling this method like this
adapter.removeItem(pos);
But same result
SOLVED
I've solved this problem by defining the single ArrayList in Global and using it. Made my work easy.
In my add section I've changed it like this
{
newArrayList.add(value);
adapter = new MyListAdapter(RecyclerActivity.this, newList);
mListView.setAdapter(adapter);
String[] temp = new String[items.length + 1];
for (int i = 0; i < items.length; i++)
temp[i] = items[i];
items = temp;
alertDialog.dismiss();
adapter.notifyDataSetChanged();
input.getText().clear();
}
Just creation of single variable as the array works smoothly.

ListView creates one more item than needed

I have a ListView which is populated in my MainActivity, but when i want to find the selected item, all of the items appear to have the same position.
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_select_teams);
ListView mainListView;
// Find the ListView in the UI.
mainListView = (ListView) findViewById( R.id.listView );
String values = "Team A vs Team B=Team C vs Team D";
//Matches are send in one long string, and are separated by the = sign.
//This splits the string up and puts it into an array.
String[] array = values.split("=", -1);
ArrayList<String> arraylist = new ArrayList<String>();
arraylist.addAll( Arrays.asList(array) );
ArrayAdapter listAdapter;
// Create ArrayAdapter using the planet list.
listAdapter = new ArrayAdapter<String>(this, R.layout.list_view_style, arraylist);
// Set the ArrayAdapter as the ListView's adapter.
mainListView.setAdapter(listAdapter);
}
This makes a list like this:
Team A vs Team B [checkbox]
Team C vs Team D [checkbox]
I have a button and when it is clicked it runs this method:
public void matchStart(View view){
String selectedMatch = String.valueOf(((ListView) findViewById( R.id.listView )).getSelectedItemPosition());
Toast.makeText(SelectTeams.this, selectedMatch, Toast.LENGTH_SHORT).show();
}
However whenever i click the button, the toast displays the same value no matter which item in the listview is selected. Why is this?
You should use the adapters getView method, something like this:
#Override
public View getView(final int position, View convertView, ViewGroup parent) {
LayoutInflater inflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
if (convertView == null) {
convertView = inflater.inflate(R.layout.some_layout, parent,
false);
convertView.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
//here get what you need by the position
}
});
}
}

custom adapter isn't showing any items

This is a follow on from an earlier question: ImageButton within row of ListView android not working
But after suggestions from SO gurus it has been suggested I post a new question.
The issue is that I have a custom adapter that is not showing any data. I have looked into other questions, but it didn't provide a solution.
In my Main Activity I have a couple of buttons, one of them: ToDo, should create a row that displays data from a SQLite database, and depending on some factors (dates mainly), it shows a type of traffic light that is stored as a drawable.
Part of the Items in this Row is an Image Button that I want the user to be able to click and the image should change. The user should be able also to click on the actual row and a new activity starts.
The issue I have is that NO DATA is being displayed.
So, here is my code:
public class MainActivity extends Activity {
// definitions etc ...
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// definitions etc ...
}
public void ToDo(View v){ // the user has clicked in the ToDo button
IgroDatabaseHelper helper = new IgroDatabaseHelper(getBaseContext()); // create instance of SQLIte database
numRows = helper.NumEntries("ToDo"); // Get the number of rows in table
int i = 1;
ArrayList<RowItem> rowItems = new ArrayList<>();
RowItem myItem1;
while (i <= numRows){
// get items from database
// depending on value select different drawable
// put data into List Array of RowItem
myItem1 = new RowItem(TheWhat, R.drawable.teamworka, R.drawable.redtrafficlight, R.drawable.checkbox, TheWhenBy);
rowItems.add(myItem1);
//
i = i+ 1;
}
ListView yourListView = (ListView) findViewById(R.id.list);
CustomListViewAdapter customAdapter = new CustomListViewAdapter(this, R.layout.todo_row, rowItems);
yourListView.setAdapter(customAdapter);
}
The CustomListViewAdapter looks like this:
public class CustomListViewAdapter extends ArrayAdapter<RowItem> {
Context context;
ArrayList<RowItem> _rowItems;
public CustomListViewAdapter(Context context, int resourceId,
ArrayList<RowItem> rowItems) {
super(context, resourceId);
this.context = context;
_rowItems = rowItems;
System.out.println("I am in the custom Adapter class "+ _rowItems);
}
#Override
public View getView(int position, View convertView, ViewGroup parent){
System.out.println("This is the get view");
View row = convertView;
RowItem item = _rowItems.get(position);
// you can now get your string and drawable from the item
// which you can use however you want in your list
String columnName = item.getColumnName();
int drawable = item.getDrawable();
if (row == null) {
LayoutInflater mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
row = mInflater.inflate(R.layout.todo_row, parent, false);
}
ImageButton chkDone = (ImageButton) row.findViewById(R.id.chkDone);
chkDone.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
View parentRow = (View) v.getParent();
ListView listView = (ListView) parentRow.getParent();
final int position = listView.getPositionForView(parentRow);
System.out.println("I am in position "+ position);
}
});
return row;
}
}
The RowItem Class looks like:
public class RowItem {
private String _heading;
private int _icon;
private int _lights;
private int _chkdone;
private String _date;
public RowItem(String heading, int icon, int lights, int chkDone, String date) {
_heading = heading;
_icon = icon;
_lights = lights;
_chkdone = chkDone;
_date = date;
System.out.println("adding stuff to my rows");
System.out.println("my column Name is " + heading);
System.out.println("My drawable int is "+ icon);
}
public String getColumnName() {
System.out.println("column Names is "+ _heading);
return _heading;
}
public int getDrawable() {
return _icon;
}
public int getLights(){
return _lights;
}
public int getchkDone(){
return _chkdone;
}
public String getDate(){
return _date;
}
}
I am obviously missing something, as I mentioned earlier, no data gets shown. I know that there are 2 row items that get passed to the CustomListViewAdapter. But I also know that the View getView inside the CustomListViewAdapter does not actually get called.
I hope I have put enough information/code, but if you feel I need to explain something further, please say.
Thanking all very much in advance!
I don't see a getCount() method. You should be overriding it like this:
#Override
public int getCount() {
return _rowItems.getCount();
}
Alternatively, calling super(context, resourceId, rowItems); should also fix it.
Your ListView thinks there are no items to display. If you are using your own array, you must override the getCount() method to indicate the number of items you want to display.

CheckBox event listener from setChoiceMode(ListView.CHOICE_MODE_MULTIPLE)

So I have a listview that I want to add checkboxes to.
lv = (ListView)findViewById(R.id.list);
adapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_multiple_choice, listItems);
lv.setAdapter(adapter);
lv.setItemsCanFocus(true);
lv.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
This works and the checkboxes show up. Then I have my setOnItemClickListener() for my listview because the user needs to select an item, then the next acitivty will be launched
lv.setOnItemClickListener(new AdapterView.OnItemClickListener()
{
#Override
public void onItemClick(AdapterView<?> parent, View view,int position, long id)
{
Intent components = new Intent();
components.setClass(context, ComponentsActivity.class);
components.putExtra("studyID", studyID);
components.putExtra("studyName", studyName);
startActivity(components);
}
});
However, I want to add a checkbox so that the user can tick that item in the listview to perform other actions. The problem is I can't differentiate the events. When I click on the checkbox, it gets checked but then the list item also gets selected and the new activity starts. I only want the checkbox to be affected when they click on it, not have it launch the new acitivty. I know you can also just create your own adapter but why bother if I can make a checkbox in 2 lines of code. Any suggestions? I just want to be able to check the textbox and get the id of the checked items.
I never managed to find anything for what I was looking for so I bit the bullet and decided to learn how to make my own custom adapter class. Here is my code if anybody ever runs into this problem. This adapter class is for a listview with text(TextView) and a checkbox.
public class CustomAdapter extends BaseAdapter
{
ArrayList<String> studies;
Context context;
LayoutInflater myInflater;
ArrayList<Boolean> positionArray;
public CustomAdapter(ArrayList<String> arr, Context c)
{
studies = arr;
context = c;
myInflater = (LayoutInflater)c.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
positionArray = new ArrayList<Boolean>();
for(int i = 0; i < studies.size(); ++i)
{
positionArray.add(false);
}
}
#Override
public int getCount() {
return studies.size();
}
#Override
public Object getItem(int i) {
return studies.get(i);
}
#Override
public long getItemId(int i) {
return 0;
}
public void remove(int i)
{
this.studies.remove(i);
this.positionArray.remove(i);
}
#Override
public View getView(int position, View view, ViewGroup viewGroup)
{
final int pos = position;
Holder holder = null;
//Create the views and populate it with an element from teh array
if(view == null)
view = myInflater.inflate(R.layout.custom_list_layout, viewGroup, false);//made my own layout for each listview 'cell'
holder = new Holder();
TextView study = (TextView)view.findViewById(R.id.adapterTextView);
holder.ckbox = (CheckBox)view.findViewById(R.id.adapterCheckBox);
holder.ckbox.setOnCheckedChangeListener(null);
study.setText(studies.get(position));
holder.ckbox.setFocusable(false);
//Since this method gets called whenever we scroll(view recycling), we have to re-check the checkboxes
holder.ckbox.setChecked(positionArray.get(position));
holder.ckbox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener(){
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked)
{
//checkBoxArray[pos].setChecked(isChecked);
positionArray.set(pos, isChecked);
}
});
return view;
}
static class Holder
{
CheckBox ckbox;
}
}

Categories

Resources