CODE
public class QuestInspectingFragment extends Fragment{
// public static ArrayList<String> mParentStepsList;
public ArrayList<QuestObject> mRealQuests;
public ArrayList<QuestObject> mQuestObjectList;
ExpandableListView ExpListView;
LinearLayout toolBarLayout;
ChildEventListener mStepsListener;
DatabaseReference mStepsReference ;
String referencePath;
QuestExpListAdapter questAdapter;
#Nullable
#Override
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.quest_inspect_fragment,container,false);
referencePath = "versions/"+getArguments().getString("questPath")+"/Steps";
mStepsReference = FirebaseHelper.mDatabase.getReference().child(referencePath);
ExpListView = v.findViewById(R.id.ExpandableList);
mQuestObjectList = new ArrayList<>();
questAdapter = new QuestExpListAdapter(this.getContext(),mQuestObjectList);
createStepsListener();
ExpListView.setAdapter(questAdapter);
return v;
}
#Override
public void onResume() {
super.onResume();
mStepsReference.addChildEventListener(mStepsListener);
}
#Override
public void onPause() {
super.onPause();
mStepsReference.removeEventListener(mStepsListener);
}
public static Fragment createInspectFragment(String pathToQuest){
QuestInspectingFragment questInspectingFragment = new QuestInspectingFragment();
Bundle myBundle = new Bundle();
myBundle.putString("questPath",pathToQuest);
questInspectingFragment.setArguments(myBundle);
return questInspectingFragment;
}
public void createStepsListener(){
mStepsListener = new ChildEventListener() {
#Override
public void onChildAdded(#NonNull DataSnapshot dataSnapshot, #Nullable String s) {
//System.out.println((String)dataSnapshot.getKey()+"\n \n \n \n \n \n");
QuestObject mQuest = new QuestObject();
//Populate Step Items
if(dataSnapshot.hasChild("title")){
mQuest.setmStepTitleList((String)dataSnapshot.child("title").getValue());
}else {
mQuest.setmStepTitleList((dataSnapshot.getKey().toUpperCase()));
}
//Populate Substeps Items
if (dataSnapshot.hasChild("Substeps")){
for(DataSnapshot childSnapshot : dataSnapshot.child("Substeps").getChildren()){
System.out.println((String)childSnapshot.getKey()+"\n \n \n \n \n \n");
if(childSnapshot.hasChild("title")){
mQuest.mSubstepTitle.add ((String)childSnapshot.child("title").getValue());
;
}
//populate subsubsteps
if(childSnapshot.hasChild("subsubstep")){
QuestObject.SubsubstepList mList = new QuestObject.SubsubstepList();
for(DataSnapshot subsubstep : childSnapshot.child("subsubstep").getChildren()){
mList.mclassSubstepList.add((String) subsubstep.child("title").getValue());
}
mQuest.mSubSubstep.add(mList);
}
}}
mQuestObjectList.add(mQuest);
}
#Override
public void onChildChanged(#NonNull DataSnapshot dataSnapshot, #Nullable String s) {
}
#Override
public void onChildRemoved(#NonNull DataSnapshot dataSnapshot) {
}
#Override
public void onChildMoved(#NonNull DataSnapshot dataSnapshot, #Nullable String s) {
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
};
}
}
CustomExpandableListAdapter
public class QuestExpListAdapter extends BaseExpandableListAdapter {
private Context mContext;
ArrayList<QuestObject> mQuestsList;
public QuestExpListAdapter(Context context,ArrayList<QuestObject> newQuestList){
mContext = context;
this.mQuestsList = newQuestList;
}
#Override
public int getGroupCount() {
return mQuestsList.size();
}
#Override
public int getChildrenCount(int groupPosition) {
return 1;
}
#Override
public Object getGroup(int groupPosition) {
return groupPosition;
}
#Override
public Object getChild(int groupPosition, int childPosition) {
return childPosition;
}
#Override
public long getGroupId(int groupPosition) {
return groupPosition;
}
#Override
public long getChildId(int groupPosition, int childPosition) {
return 0;
}
#Override
public boolean hasStableIds() {
return true;
}
#Override
public View getGroupView(int groupPosition, boolean isExpanded, View convertView, ViewGroup parent) {
View row = convertView;
MyViewHolder mvh = null;
if(row == null){
LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
row = inflater.inflate(R.layout.quest_exp_row1,null);
mvh = new MyViewHolder(row);
row.setTag(mvh);
}else {
mvh = (MyViewHolder) row.getTag();
}
mvh.step.setText("Step "+(groupPosition+1)+":"+mQuestsList.get(groupPosition).mStepTitleList);
return row;
}
#Override
public View getChildView(int groupPosition, int childPosition, boolean isLastChild, View convertView, ViewGroup parent) {
SubstepExpandableList substepExpList = new SubstepExpandableList(mContext);
substepExpList.setAdapter(new SubstepListAdapter(mContext, mQuestsList.get(groupPosition).mSubstepTitle, mQuestsList.get(groupPosition).mSubSubstep));
substepExpList.setGroupIndicator(null);
return substepExpList;
}
#Override
public boolean isChildSelectable(int groupPosition, int childPosition) {
return true;
}
public class SubstepExpandableList extends ExpandableListView {
public SubstepExpandableList(Context context) {
super(context);
}
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
//999999 is a size in pixels. ExpandableListView requires a maximum height in order to do measurement calculations.
heightMeasureSpec = MeasureSpec.makeMeasureSpec(999999, MeasureSpec.AT_MOST);
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
}
public class SubstepListAdapter extends BaseExpandableListAdapter{
ArrayList<String> myPassedList;
ArrayList<QuestObject.SubsubstepList> mySecondList;
private Context mmContext;
public SubstepListAdapter(Context context, ArrayList<String> myPassedList,ArrayList<QuestObject.SubsubstepList> myList ){
mmContext = context;
this.myPassedList = myPassedList;
this.mySecondList = myList;
}
#Override
public int getGroupCount() {
return myPassedList.size();
}
#Override
public int getChildrenCount(int groupPosition) {
try {
return mySecondList.get(groupPosition).mclassSubstepList.size();
}catch (IndexOutOfBoundsException e){
Toast.makeText(mmContext,"No Further Steps",Toast.LENGTH_SHORT).show();
return 0;
}
//else {
// Toast.makeText(mmContext,"No Further Steps",Toast.LENGTH_SHORT).show();
// return 1;
// }
}
#Override
public Object getGroup(int groupPosition) {
return groupPosition;
}
#Override
public Object getChild(int groupPosition, int childPosition) {
return childPosition;
}
#Override
public long getGroupId(int groupPosition) {
return 0;
}
#Override
public long getChildId(int groupPosition, int childPosition) {
return childPosition;
}
#Override
public boolean hasStableIds() {
return true;
}
#Override
public View getGroupView(int groupPosition, boolean isExpanded, View convertView, ViewGroup parent) {
View row = convertView;
MyViewHolder mvh = null;
if(row == null){
LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
row = inflater.inflate(R.layout.quest_exp_row2,null);
mvh = new MyViewHolder(row);
row.setTag(mvh);
}else {
mvh = (MyViewHolder) row.getTag();
}
mvh.substep.setText(myPassedList.get(groupPosition));
return row;
}
#Override
public View getChildView(int groupPosition, int childPosition, boolean isLastChild, View convertView, ViewGroup parent) {
View row = convertView;
MyViewHolder mvh = null;
if(row == null){
LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
row = inflater.inflate(R.layout.quest_exp_row3,null);
mvh = new MyViewHolder(row);
row.setTag(mvh);
}else {
mvh = (MyViewHolder) row.getTag();
}
if(mySecondList.get(groupPosition)!= null ) {
if (mySecondList.get(groupPosition).mclassSubstepList.size() !=0){
mvh.subsub.setText(mySecondList.get(groupPosition).mclassSubstepList.get(childPosition));
}}
return row;
}
#Override
public boolean isChildSelectable(int groupPosition, int childPosition) {
return false;
}
}
private class MyViewHolder{
TextView step;
TextView substep;
TextView subsub;
MyViewHolder(View v){
step = v.findViewById(R.id.questRow1Text);
substep = v.findViewById(R.id.questRow2Text);
subsub =v.findViewById(R.id.questRow3Text);
}
}
}
public class QuestObject {
public void setmStepTitleList(String mStepTitleList) {
this.mStepTitleList = mStepTitleList;
}
public String mStepTitleList ;
public ArrayList<String> mSubstepTitle = new ArrayList<>();
public ArrayList<SubsubstepList> mSubSubstep = new ArrayList<>();
public static class SubsubstepList{
ArrayList<String> mclassSubstepList = new ArrayList<>();
}
}
DESCRIPTION OF PROBLEM
I have my custom adapter which has a second ExpandableList as children to each parent. I know that it works as i had it successfully populating but ONLY every so often when i clicked (from a listView to create the fragment). To clarify, it wouldnt populate EVERY time the fragment was created, usually i had to create the fragment(empty) , hit the back button, and then re-click on the ListViewItem to re-create it, and most of the time that would populate it.
I used those successful tries to make sure that the actual logic of making the children contain the correct data, but after i got that working, i decided to try to tackle whatever was preventing my ExpList from populating 100% consistently, so i stopped using my static ArrayList mParentStepsList, and instead added the list my QuestObject class but now it isnt populating at all.
Im getting an error about notifyDataSetChanged, saying "
Blockquote
Make sure the content of your adapter is not modified from a background thread, but only from the UI thread. Make sure your adapter calls notifyDataSetChanged() when its content changes. [in ListView(2131296258, class android.widget.ExpandableListView) with Adapter(class android.widget.ExpandableListConnector"
Blockquote
Below is a list of things i've tried.
Things I've tried
I did some reading and seen things about needing to call notifyDataSetChanged and so ive spent 8 hours placing that method and calling it on my adapter from every which way. I've tried runOnUIThread() 6 ways from sunday and every combination i can think of and quite honestly im just stumped. I hope someone can help me. Thanks so much for your time
I was able to get it working. Im calling notifyDataSetChanged in both onResume() AND in onChildAdded() in the childEventListener.
Im thinking the reason i didn't try this particular way earlier is because i assumed you call notifyDataSetChange after you get done adding a bunch of data, but it appears i was supposed to do it after EVERY individual data change. onChildAdded gets called every time for every child of a DatabaseReference - therefore i should call it everytime in that method
EDIT 1- I didnt need to call it in onResume, and i ALSO made my adapter static. hope this helps someone
mStepsListener = new ChildEventListener() {
#Override
public void onChildAdded(#NonNull DataSnapshot dataSnapshot, #Nullable String s) {
//System.out.println((String)dataSnapshot.getKey()+"\n \n \n \n \n \n");
QuestObject mQuest = new QuestObject();
//Populate Step Items
if(dataSnapshot.hasChild("title")){
mQuest.setmStepTitleList((String)dataSnapshot.child("title").getValue());
}else {
mQuest.setmStepTitleList((dataSnapshot.getKey().toUpperCase()));
}
//Populate Substeps Items
if (dataSnapshot.hasChild("Substeps")){
for(DataSnapshot childSnapshot : dataSnapshot.child("Substeps").getChildren()){
System.out.println((String)childSnapshot.getKey()+"\n \n \n \n \n \n");
if(childSnapshot.hasChild("title")){
mQuest.mSubstepTitle.add ((String)childSnapshot.child("title").getValue());
//mSubstepList.add((String)childSnapshot.child("title").getValue());
}
//populate subsubsteps
if(childSnapshot.hasChild("subsubstep")){
QuestObject.SubsubstepList mList = new QuestObject.SubsubstepList();
for(DataSnapshot subsubstep : childSnapshot.child("subsubstep").getChildren()){
mList.mclassSubstepList.add((String) subsubstep.child("title").getValue());
// mSubSubStepList.add((String) subsubstep.child("title").getValue());
}
mQuest.mSubSubstep.add(mList);
}
}}
mQuestObjectList.add(mQuest);
**questAdapter.notifyDataSetChanged();**
}
public void onResume() {
//mQuestObjectList = new ArrayList<>();
super.onResume();
mStepsReference.addChildEventListener(mStepsListener);
getActivity().runOnUiThread(new Runnable() {
#Override
public void run() {
questAdapter.notifyDataSetChanged();
}
});
}
#Override
public void onPause() {
questAdapter.mQuestsList.clear();
super.onPause();
mStepsReference.removeEventListener(mStepsListener);
}
Related
I have Expandable List View in my app with is hardcoded. After getting to know Firebase database i want to add inside child item information from my database. I copyed code and node from here android expandable listview retrieve data from firebase and it worked perfectly fine. Here is the result:
My main Firebase node look like this:
How can i display data from my node? All information stored inside "campus", building and faculties are should be parent item. Building1 and Building2, same goes to faculty item, should be child items. How can i achieve my goal? Here is my Java code:
public class campus extends AppCompatActivity {
CampusAdapter campusAdapter;
List<String> listDataHeader;
HashMap<String, List<String>> listDataChild;
FirebaseDatabase database;
DatabaseReference myRef;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_campus);
database = FirebaseDatabase.getInstance();
myRef = database.getReference("campus");
expandableListView = findViewById(R.id.campusExpandableListView);
SetStandardGroups();
campusAdapter = new CampusAdapter(this, listDataHeader, listDataChild);
expandableListView.setAdapter(campusAdapter);
}
public void SetStandardGroups() {
listDataHeader = new ArrayList<>();
listDataChild = new HashMap<>();
myRef.addChildEventListener(new ChildEventListener() {
int counter = 0;
List<String> childItem;
#Override
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
listDataHeader.add(dataSnapshot.getKey());
Log.e("TAG", listDataHeader.get(counter));
childItem = new ArrayList<>();
for (DataSnapshot ds : dataSnapshot.getChildren()) {
String childNames = (String) ds.getValue();
Log.e("TAG", "childNames :" + childNames);
childItem.add(childNames);
}
listDataChild.put(listDataHeader.get(counter), childItem);
counter++;
Log.e("TAG", "counter :" + counter);
campusAdapter.notifyDataSetChanged();
}
});
}
Here is my Adapter java file:
public class CampusAdapter extends BaseExpandableListAdapter {
private Context context;
private List<String> headerItem;
private HashMap<String, List<String>> childItem;
public CampusAdapter(Context context, List<String> headerItem, HashMap<String, List<String>> childItem) {
this.context = context;
this.headerItem = headerItem;
this.childItem = childItem;
}
#Override
public Object getChild(int groupPosition, int childPosition) {
return childItem.get(headerItem.get(groupPosition)).get(childPosition);
}
#Override
public long getChildId(int groupPosition, int childPosition) {
return childPosition;
}
#Override
public View getChildView(int groupPosition, int childPosition, boolean isLastChild, View convertView, ViewGroup parent) {
String childText = (String) getChild(groupPosition, childPosition);
if (convertView == null) {
LayoutInflater inflater = (LayoutInflater) this.context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = inflater.inflate(R.layout.child_item, null);
}
TextView tv = convertView.findViewById(R.id.campusName);
tv.setText(childText);
return convertView;
}
#Override
public int getChildrenCount(int groupPosition) {
return childItem.get(headerItem.get(groupPosition)).size();
}
#Override
public Object getGroup(int groupPosition) {
return headerItem.get(groupPosition);
}
#Override
public int getGroupCount() {
return headerItem.size();
}
#Override
public long getGroupId(int groupPosition) {
return groupPosition;
}
#Override
public View getGroupView(int groupPosition, boolean isExpanded, View convertView, ViewGroup parent) {
String headerTitle = (String) getGroup(groupPosition);
if (convertView == null) {
LayoutInflater inflater = (LayoutInflater) this.context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = inflater.inflate(R.layout.group_item, null);
}
TextView tv = convertView.findViewById(R.id.groupName);
tv.setText(headerTitle);
return convertView;
}
#Override
public boolean hasStableIds() {
return false;
}
#Override
public boolean isChildSelectable(int groupPosition, int childPosition) {
return true;
}
}
p.s i use Glide to display images
This goes in your onCreate() of the main class (the one with the listView)
DatabaseReference reference = FirebaseDatabase.getInstance().getReference("(campus/building");
reference.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot snapshot) {
for(DataSnapshot ds:snapshot.getChildren()){
String title = ds.child("title").getValue(String.class);
String image = ds.child("image").getValue(String.class);
//TODO: add it to the expandable view with the link above who explains it
ExpandableListView myExpList= (ExpandableListView) this.view.findViewById(R.id.yourExpListView);
ExpandableListAdapter adapter =
(ExpandableListAdapter) myExpList.getExpandableListAdapter();
( (ExpandableListParentClass)adapter.getMParent().get(0) ).getParentChildren().add(title);
( (ExpandableListParentClass)adapter.getMParent().get(0) ).getParentChildren().add(image);
//(change to get(0) which you parent want to get )
adapter.notifyDataSetChanged();
adapter.notifyDataSetInvalidated();
}
}
#Override
public void onCancelled(#NonNull DatabaseError error) {
}
})
Then create a new java class called "ExpandableListAdapter" with following code:
public class ExpandableListAdapter extends BaseExpandableListAdapter implements Filterable{
private LayoutInflater inflater;
private ArrayList<ExpandableListParentClass<Object>> mParent;
private View view;
public ArrayList<Object> getMParent() {
return mParent;
}
public ExpandableListAdapter(Context context,
ArrayList<ExpandableListParentClass<Object>> parentList ) {
this.mParent = parentList;
this.inflater = LayoutInflater.from(context);
}
// counts the number of group/parent items so the list knows how many
// times calls getGroupView() method
public int getGroupCount() {
return mParent.size();
}
// counts the number of children items so the list knows how many times
// calls getChildView() method
public int getChildrenCount(int parentPosition) {
int size =0;
if(mParent.get(parentPosition).getParentChildren() != null){
size = mParent.get(parentPosition).getParentChildren().size();
}
return size;
}
// gets the title of each parent/group
public Object getGroup(int i) {
return mParent.get(i).getParent();
}
// gets the name of each item
public Object getChild(int parentPosition, int childPosition) {
return mParent.get(parentPosition).getParentChildren().get(childPosition);
}
public long getGroupId(int parentPosition) {
return parentPosition;
}
public long getChildId(int i, int childPosition) {
return childPosition;
}
public boolean hasStableIds() {
return true;
}
// in this method you must set the text to see the parent/group on the list
public View getGroupView(int parentPosition, boolean b, View view, ViewGroup viewGroup) {
if (view == null) {
view = inflater.inflate(R.layout.layout_listview, viewGroup, false);
}
return view;
}
// in this method you must set the text to see the children on the list
public View getChildView(int parentPosition, int childPosition, boolean b, View view, ViewGroup viewGroup) {
if (view == null) {
view = inflater.inflate(R.layout.layout_listview, viewGroup, false);
}
// return the entire view
return view;
}
public boolean isChildSelectable(int i, int i1) {
return true;
}
}
List<ExpandableListParentClass> arrayParents = new ArrayList<ExpandableListParentClass>();
ExpandableListParentClass item = new ExpandableListParentClass();
item.setParent(yourParentItem);
item.setParentChildren( yourChildList);
Then create a new java class called "ExpandableListParentClass" with the following code:
public class ExpandableListParentClass{
private Object parent;
private ArrayList<Object> parentChildren;
public ExpandableListParentClass() {
}
public ExpandableListParentClass(Object parent, ArrayList<Object> parentChildren) {
this.parent = parent;
this.parentChildren = parentChildren;
}
public Object getParent() {
return parent;
}
public void setParent(Object parent) {
this.parent = parent;
}
public ArrayList<Object> getParentChildren() {
return parentChildren;
}
public void setParentChildren(ArrayList<Object> parentChildren) {
this.parentChildren = parentChildren;
}
}
On each row i have two EditTexts.when i change the first one , i want the other to be changed as well(if needed ,for now just setting there '25' for testing).I am using a viewholder pattern,and setting on each of the first edittexts a TextChangedListener,expecting the second to be changed as well .problem is , whenever i change ANY of the first edittexts on ANY of the rows ,only the edittext on the last row is changed. here is the code of the adapter(listener is in getgroupview):
public class CustomExpandableListAdapterNewWorkout extends BaseExpandableListAdapter {
private Context context;
private List<String> expandableListTitle;
private HashMap<String, List<String>> expandableListDetail;
private ChildViewHolder childViewHolder;
private GroupViewHolder groupViewHolder;
public CustomExpandableListAdapterNewWorkout(Context context, List<String> expandableListTitle,
HashMap<String, List<String>> expandableListDetail) {
this.context = context;
this.expandableListTitle = expandableListTitle;
this.expandableListDetail = expandableListDetail;
}
#Override
public Object getChild(int listPosition, int expandedListPosition) {
return this.expandableListDetail.get(this.expandableListTitle.get(listPosition))
.get(expandedListPosition);
}
#Override
public long getChildId(int listPosition, int expandedListPosition) {
return expandedListPosition;
}
#Override
public View getChildView(int listPosition, final int expandedListPosition,
boolean isLastChild, View convertView, ViewGroup parent) {
final String expandedListText = (String) getChild(listPosition, expandedListPosition);
String categoryName= (String)getGroup(listPosition);
if (convertView == null)
{
LayoutInflater layoutInflater = (LayoutInflater) this.context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = layoutInflater.inflate(R.layout.list_item_exercises_exercise, null);
childViewHolder = new ChildViewHolder();
childViewHolder.mChildTitle = (TextView) convertView.findViewById(R.id.expandedListItem);
childViewHolder.mChildImage = (ImageView) convertView.findViewById(R.id.ImgExercisePic);
convertView.setTag(childViewHolder);
}
else
{
childViewHolder = (ChildViewHolder) convertView.getTag();
}
childViewHolder.mChildTitle.setText(expandedListText);
childViewHolder.mChildTitle.setTextAppearance(context,R.style.TitleStyle);
return convertView;
}
#Override
public int getChildrenCount(int listPosition) {
return this.expandableListDetail.get(this.expandableListTitle.get(listPosition))
.size();
}
#Override
public Object getGroup(int listPosition) {
return this.expandableListTitle.get(listPosition);
}
#Override
public int getGroupCount() {
return this.expandableListTitle.size();
}
#Override
public long getGroupId(int listPosition) {
return listPosition;
}
#Override
public View getGroupView(int listPosition, boolean isExpanded,
View convertView, ViewGroup parent) {
String listTitle = (String) getGroup(listPosition);
if (convertView == null)
{
LayoutInflater layoutInflater = (LayoutInflater) this.context.
getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = layoutInflater.inflate(R.layout.list_group_new_workout_exercise, null);
groupViewHolder = new GroupViewHolder();
groupViewHolder.mGroupTitle = (TextView) convertView.findViewById(R.id.exerciseName);
groupViewHolder.mMinSets = (EditText) convertView.findViewById(R.id.edtMinimumSets);
groupViewHolder.mMaxSets = (EditText) convertView.findViewById(R.id.edtMaxSets);
groupViewHolder.mMinSets.addTextChangedListener(new TextWatcher() {
#Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
#Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
#Override
public void afterTextChanged(Editable s) {
groupViewHolder.mMaxSets.setText("25");
}
});
convertView.setTag(groupViewHolder);
}
else
{
groupViewHolder = (GroupViewHolder) convertView.getTag();
}
groupViewHolder.mGroupTitle.setText(listTitle);
return convertView;
}
#Override
public boolean hasStableIds() {
return false;
}
#Override
public boolean isChildSelectable(int listPosition, int expandedListPosition) {
return true;
}
public final class GroupViewHolder {
TextView mGroupTitle;
EditText mMinSets;
EditText mMaxSets;
}
public final class ChildViewHolder {
TextView mChildTitle;
ImageView mChildImage;
}
}
probably there is something basic i don't understand about adapters and viewholders, and i would like to know the correct method to address it.
ok my bad.
should have declared "GroupViewHolder groupViewHolder" inside the getGroupView method,this way a new one with a new listener is created each time and affects his corresponding row
how can i use firebase to retrieve data for my Expandable listview. my firebase node is like this..
Adapter class:
public class CustomExpandableListViewAdapter extends BaseExpandableListAdapter {
private Context context;
private List<String> headerItem;
private HashMap<String, List<String>> childItem;
public CustomExpandableListViewAdapter(Context context, List<String> headerItem, HashMap<String, List<String>> childItem) {
this.context = context;
this.headerItem = headerItem;
this.childItem = childItem;
}
#Override
public Object getChild(int groupPosition, int childPosition) {
return childItem.get(headerItem.get(groupPosition)).get(childPosition);
}
#Override
public long getChildId(int groupPosition, int childPosition) {
return childPosition;
}
#Override
public View getChildView(int groupPosition, int childPosition, boolean isLastChild, View convertView, ViewGroup parent) {
String childText = (String) getChild(groupPosition, childPosition);
if (convertView == null) {
LayoutInflater inflater = (LayoutInflater) this.context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = inflater.inflate(R.layout.child_items, null);
}
TextView tv = convertView.findViewById(R.id.tvChildItem);
tv.setText(childText);
return convertView;
}
#Override
public int getChildrenCount(int groupPosition) {
return childItem.get(headerItem.get(groupPosition)).size();
}
#Override
public Object getGroup(int groupPosition) {
return headerItem.get(groupPosition);
}
#Override
public int getGroupCount() {
return headerItem.size();
}
#Override
public long getGroupId(int groupPosition) {
return groupPosition;
}
#Override
public View getGroupView(int groupPosition, boolean isExpanded, View convertView, ViewGroup parent) {
String headerTitle = (String) getGroup(groupPosition);
if (convertView == null) {
LayoutInflater inflater = (LayoutInflater) this.context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = inflater.inflate(R.layout.group_items, null);
}
TextView tv = convertView.findViewById(R.id.tvItemHeader);
tv.setText(headerTitle);
return convertView;
}
#Override
public boolean hasStableIds() {
return false;
}
#Override
public boolean isChildSelectable(int groupPosition, int childPosition) {
return true;
}
MainActivity :
public class MainActivity extends AppCompatActivity {
ExpandableListView expandableListView;
CustomExpandableListViewAdapter customExpandableListViewAdapter;
List<String> listDataHeader;
HashMap<String, List<String>> listDataChild;
FirebaseDatabase database;
DatabaseReference myRef;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
database = FirebaseDatabase.getInstance();
myRef = database.getReference("Expandable ListView Data");
expandableListView = findViewById(R.id.expLv);
SetStandardGroups();
customExpandableListViewAdapter = new CustomExpandableListViewAdapter(this, listDataHeader, listDataChild);
expandableListView.setAdapter(customExpandableListViewAdapter);
}
public void SetStandardGroups() {
listDataHeader = new ArrayList<>();
listDataChild = new HashMap<>();
myRef.addChildEventListener(new ChildEventListener() {
int counter = 0;
List<String> childItem = new ArrayList<>();
#Override
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
final String headerTitle = dataSnapshot.getKey();
listDataHeader.add(headerTitle);
Log.e("TAG", headerTitle);
for (DataSnapshot ds : dataSnapshot.getChildren()){
String child = (String) ds.getValue();
childItem.add(child);
}
listDataChild.put(listDataHeader.get(counter), childItem);
counter++;
Log.e("TAG", "counter :" + counter);
customExpandableListViewAdapter.notifyDataSetChanged();
}
#Override
public void onChildChanged(DataSnapshot dataSnapshot, String s) {
}
#Override
public void onChildRemoved(DataSnapshot dataSnapshot) {
}
#Override
public void onChildMoved(DataSnapshot dataSnapshot, String s) {
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
}
}
The out put is this:
Out put
and i need Task1 the header tittle of first item and its contains 8 child's and like 2nd Task2 the header tittle of 2nd item and it will contains 5 child's
and 3rd Task3 the header tittle of 3rd item and will contain's 10 child how can i achieved please help me i new to firebase Thanks...
At last i found the problem. the problem is that i create a single Object of ArrayList for child which runs 3 times and save all data in one Object, so i found out that i need to create ArrayList Object Accordingly to loop Turn's which is 3.
this is the code which is working now.
myRef.addChildEventListener(new ChildEventListener() {
int counter = 0;
List<String> childItem;
#Override
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
listDataHeader.add(dataSnapshot.getKey());
Log.e("TAG", listDataHeader.get(counter));
childItem = new ArrayList<>();
for (DataSnapshot ds : dataSnapshot.getChildren()) {
String childNames = (String) ds.getValue();
Log.e("TAG", "childNames :" + childNames);
childItem.add(childNames);
}
listDataChild.put(listDataHeader.get(counter), childItem);
counter++;
Log.e("TAG", "counter :" + counter);
customExpandableListViewAdapter.notifyDataSetChanged();
}
I have created an expandable listview, but the onclick listener to the child list items could not be attached.
The activity code:
public class MyActivity extends Activity {
private ExpandableListView mExpandableList;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
mExpandableList = (ExpandableListView)findViewById(R.id.expandable_list);
ArrayList<Parent> arrayParents = new ArrayList<Parent>();
ArrayList<String> arrayChildren = new ArrayList<String>();
//here we set the parents and the children
for (int i = 0; i < 2; i++){
//for each "i" create a new Parent object to set the title and the children
Parent parent = new Parent();
parent.setTitle("Parent " + i);
arrayChildren = new ArrayList<String>();
for (int j = 0; j < 3; j++) {
arrayChildren.add("Child " + j);
}
parent.setArrayChildren(arrayChildren);
//in this array we add the Parent object. We will use the arrayParents at the setAdapter
arrayParents.add(parent);
}
//sets the adapter that provides data to the list.
mExpandableList.setAdapter(new MyCustomAdapter(MyActivity.this,arrayParents));
}
}
The custom adapter for the lists:
public class MyCustomAdapter extends BaseExpandableListAdapter {
private LayoutInflater inflater;
private ArrayList<Parent> mParent;
public MyCustomAdapter(Context context, ArrayList<Parent> parent){
mParent = parent;
inflater = LayoutInflater.from(context);
}
#Override
//counts the number of group/parent items so the list knows how many times calls getGroupView() method
public int getGroupCount() {
return mParent.size();
}
#Override
//counts the number of children items so the list knows how many times calls getChildView() method
public int getChildrenCount(int i) {
return mParent.get(i).getArrayChildren().size();
}
#Override
//gets the title of each parent/group
public Object getGroup(int i) {
return mParent.get(i).getTitle();
}
#Override
//gets the name of each item
public Object getChild(int i, int i1) {
return mParent.get(i).getArrayChildren().get(i1);
}
#Override
public long getGroupId(int i) {
return i;
}
#Override
public long getChildId(int i, int i1) {
return i1;
}
#Override
public boolean hasStableIds() {
return true;
}
#Override
//in this method you must set the text to see the parent/group on the list
public View getGroupView(int i, boolean b, View view, ViewGroup viewGroup) {
if (view == null) {
view = inflater.inflate(R.layout.list_item_parent, viewGroup,false);
}
TextView textView = (TextView) view.findViewById(R.id.list_item_text_view);
//"i" is the position of the parent/group in the list
textView.setText(getGroup(i).toString());
//return the entire view
return view;
}
#Override
//in this method you must set the text to see the children on the list
public View getChildView(int i, int i1, boolean b, View view, ViewGroup viewGroup) {
if (view == null) {
view = inflater.inflate(R.layout.list_item_child, viewGroup,false);
}
TextView textView = (TextView) view.findViewById(R.id.list_item_text_child);
//"i" is the position of the parent/group in the list and
//"i1" is the position of the child
textView.setText(mParent.get(i).getArrayChildren().get(i1));
//return the entire view
return view;
}
#Override
public boolean isChildSelectable(int i, int i1) {
return true;
}
#Override
public void registerDataSetObserver(DataSetObserver observer) {
/* used to make the notifyDataSetChanged() method work */
super.registerDataSetObserver(observer);
}
}
The parent class:
public class Parent {
private String mTitle;
private ArrayList<String> mArrayChildren;
public String getTitle() {
return mTitle;
}
public void setTitle(String mTitle) {
this.mTitle = mTitle;
}
public ArrayList<String> getArrayChildren() {
return mArrayChildren;
}
public void setArrayChildren(ArrayList<String> mArrayChildren) {
this.mArrayChildren = mArrayChildren;
}
}
What should I do to add onclick listener to the child list items?
Add this after you setAdapter of the Expandable list
mExpandableList.setOnChildClickListener(new OnChildClickListener() {
#Override
public boolean onChildClick(ExpandableListView parent, View v,int groupPosition, int childPosition, long id) {
/* You must make use of the View v, find the view by id and extract the text as below*/
TextView tv= (TextView) v.findViewById(R.id.childTextView);
String data= tv.getText().toString();
return true; // i missed this
}
});
You need to add
ChildClickListener
like this : mExpandableList.setOnChildClickListener
add this line to onCreate method
read here
also this is a good example
Declare your listView with an overridden onChildClick
ExpandableListView listView = getExpandableListView();
listView.setChoiceMode(ExpandableListView.CHOICE_MODE_SINGLE);
listView.setOnChildClickListener(new ExpandableListView.OnChildClickListener() {
#Override
public boolean onChildClick(ExpandableListView parent, View v,int groupPosition, int childPosition,long id) {
Log.d(TAG,"I got clicked childPosition:["+childPosition+"] groupPosition:["+groupPosition+"] id:["+id+"]");
return true;
}
});
So i am having an expandable listview. What i want is to make clickable each children. if I press the first one I want to open the class1, if I press the second one I want to open the class2, if I press the third one I want to open the class3 and so on... I am new in programming so please explain me like you would do it for a dummie.
This is my Activity
public class Mecanica extends ExpandableListActivity implements OnChildClickListener {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ExpandableListView expandbleLis = getExpandableListView();
expandbleLis.setDividerHeight(2);
expandbleLis.setGroupIndicator(null);
expandbleLis.setClickable(true);
setGroupData();
setChildGroupData();
NewAdapter mNewAdapter = new NewAdapter(groupItem, childItem);
mNewAdapter.setInflater((LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE), this);
getExpandableListView().setAdapter(mNewAdapter);
expandbleLis.setOnChildClickListener(this);
}
public void setGroupData() {
groupItem.add("Directia");
groupItem.add("Franarea");
groupItem.add("Motorul");
groupItem.add("Rotile");
groupItem.add("Siguranta si control");
groupItem.add("Suspensia");
groupItem.add("Transmisia");
}
ArrayList<String> groupItem = new ArrayList<String>();
ArrayList<Object> childItem = new ArrayList<Object>();
public void setChildGroupData() {
/**
* Add Data For TecthNology
*/
ArrayList<String> child = new ArrayList<String>();
child.add("Java");
child.add("Drupal");
child.add(".Net Framework");
child.add("PHP");
childItem.add(child);
/**
* Add Data For Mobile
*/
child = new ArrayList<String>();
child.add("Android");
child.add("Window Mobile");
child.add("iPHone");
child.add("Blackberry");
childItem.add(child);
/**
* Add Data For Manufacture
*/
child = new ArrayList<String>();
child.add("HTC");
child.add("Apple");
child.add("Samsung");
child.add("Nokia");
childItem.add(child);
/**
* Add Data For Extras
*/
child = new ArrayList<String>();
child.add("Contact Us");
child.add("About Us");
child.add("Location");
child.add("Root Cause");
childItem.add(child);
}
}
And the adapter class
#SuppressWarnings("unchecked")
public class NewAdapter extends BaseExpandableListAdapter {
public ArrayList<String> groupItem, tempChild;
public ArrayList<Object> Childtem = new ArrayList<Object>();
public LayoutInflater minflater;
public Activity activity;
public NewAdapter(ArrayList<String> grList, ArrayList<Object> childItem) {
groupItem = grList;
this.Childtem = childItem;
}
public void setInflater(LayoutInflater mInflater, Activity act) {
this.minflater = mInflater;
activity = act;
}
#Override
public Object getChild(int groupPosition, int childPosition) {
return null;
}
#Override
public long getChildId(int groupPosition, int childPosition) {
return 0;
}
#Override
public View getChildView(int groupPosition, final int childPosition,
boolean isLastChild, View convertView, ViewGroup parent) {
tempChild = (ArrayList<String>) Childtem.get(groupPosition);
TextView text = null;
if (convertView == null) {
convertView = minflater.inflate(R.layout.childrow, null);
}
text = (TextView) convertView.findViewById(R.id.textView1);
text.setText(tempChild.get(childPosition));
/*convertView.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
Toast.makeText(activity, tempChild.get(childPosition),
Toast.LENGTH_SHORT).show();
}
});*/
return convertView;
}
#Override
public int getChildrenCount(int groupPosition) {
return ((ArrayList<String>) Childtem.get(groupPosition)).size();
}
#Override
public Object getGroup(int groupPosition) {
return null;
}
#Override
public int getGroupCount() {
return groupItem.size();
}
#Override
public void onGroupCollapsed(int groupPosition) {
super.onGroupCollapsed(groupPosition);
}
#Override
public void onGroupExpanded(int groupPosition) {
super.onGroupExpanded(groupPosition);
}
#Override
public long getGroupId(int groupPosition) {
return 0;
}
#Override
public View getGroupView(int groupPosition, boolean isExpanded,
View convertView, ViewGroup parent) {
if (convertView == null) {
convertView = minflater.inflate(R.layout.grouprow, null);
}
((CheckedTextView) convertView).setText(groupItem.get(groupPosition));
//((CheckedTextView) convertView).setChecked(isExpanded);
return convertView;
}
#Override
public boolean hasStableIds() {
return false;
}
#Override
public boolean isChildSelectable(int groupPosition, int childPosition) {
return true;
}
}
I can't find your OnChildClickListener, which you should implement.
This will give you access to the specific child clicked and hence the position in your List of items.
The implementation could look something like this example:
#Override
public boolean onChildClick(ExpandableListView parent, View v, int groupPosition, int childPosition, long id) {
// Create a switch that switches on the specific child position.
switch(childPosition) {
case 0:
// Go to child #0 specific class.
Intent child0Intent = new Intent(this, Child0Activity.class);
startActivity(child0Intent);
break;
case 1:
// Go to child #1 specific class.
Intent child1Intent = new Intent(this, Child1Activity.class);
startActivity(child1Intent);
break;
}
return false;
}
A full example of how to implement it can be found here:
http://www.mysamplecode.com/2012/10/android-expandablelistview-example.html