问题
I need an Activity with an expandable RecyclerView like the one in this picture:
So I am using this third party library project . That part works.
The problem arose when I did what I am describing in the next two paragraphs:
My next requirement is that I want different child-rows for different parent-rows. I am reproducing (if that's the right word) this example to create multiple child-viewholders.
Description of Example: The idea is basically to have the different Child-viewholders (corresponding to each child-row style) extending one common childview-holder, and then inside our ExpandableRecyclerAdapter where we are passed the ArrayList of the data displayed in parent-rows in the constructor (parentItemList
in the SSCCE), we declare constants representing all the child-row-types (TYPE_EDITTEXT and TYPE_SPINNER in the SSCCE below); and then inside getItemViewType(int position)
we compare the data item from parentItemList
using the passed int position
as the index, with each text string on parent-rows and in each case, assign the viewType
int variable a TYPE constant, and the viewType
.Then this int viewType
is passed to the onCreateChildViewHolder
and onBindChildViewHolder
, so we execute another switch-block in the definitions of each of these methods and then in onCreateChildViewHolder we return a corresponding ChildViewHolder (inflated from a corresponding layout resource) (either R.layout.custom_row_child_with_edittext
or R.layout.custom_row_child_with_spinner
in the SSCCE) ; and in onBindChildViewHolder
, update the data according to the case in the switch-block.
The problem is the dollowing ClassCastException:
07-26 18:21:54.380: E/AndroidRuntime(276): FATAL EXCEPTION: main
07-26 18:21:54.380: E/AndroidRuntime(276): java.lang.ClassCastException: tests.test.epmc_mobile.search_module.no_ui.expandable_recycler_view.EPMCChildViewHolder
07-26 18:21:54.380: E/AndroidRuntime(276): at com.bignerdranch.expandablerecyclerview.Adapter.ExpandableRecyclerAdapter.onBindViewHolder(ExpandableRecyclerAdapter.java:144)
The thing is that ExpandableRecyclerAdapter.java is a part of the third party library project, and Line#144 (and 142 and 143 which I added) are:
Log.i(TAG, "+++++++++++++++++++++++++THE TYPE OF THE RecyclerView.ViewHolder WHICH HAS BEEN PASSED AS AN ARGUMENT IS "
+ holder.getClass().getSimpleName() + "++++++++++++++++++++++++++++");
PVH parentViewHolder = (PVH) holder;
Before I tried to do what I am doing above, it was working fine.
MainActivity.java
public class MainActivity extends FragmentActivity {
private static final String TAG = MainActivity.class.getSimpleName();
private RecyclerView recyclerView;
private static int [] imageIds = {R.drawable.ic_action_call, R.drawable.ic_action_copy, R.drawable.ic_action_discard};
private static String [] titles = {"Dummy Text One", "Dummy Text Two", "Dummy Text Three"};
@Override
protected void onCreate(Bundle savedInstanceState) {
Log.i(TAG, "onCreate of MainActivity called.");//check
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
recyclerView = (RecyclerView) findViewById(R.id.mainActivity_recyclerView);
MyExpandableRecyclerAdapter myExpandableRecyclerAdapter = new MyExpandableRecyclerAdapter(this, populateDataList(this));
recyclerView.setAdapter(myExpandableRecyclerAdapter);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
}
private ArrayList<ParentObject> populateDataList(Context context) {
Log.i(TAG, "populateDataList of MainActivity called.");//check
ArrayList<ParentObject> parentObjectList = new ArrayList<>();
for (int i=0; i<imageIds.length && i<titles.length; i++) {
MyCustomParentObject myCustomParentObject = new MyCustomParentObject(context);
myCustomParentObject.setImageId(imageIds[i]);
myCustomParentObject.setTitle(titles[i]);
parentObjectList.add(myCustomParentObject);
}
return parentObjectList;
}
}
MyExpandableRecyclerAdapter.java
public class MyExpandableRecyclerAdapter extends ExpandableRecyclerAdapter<ParentViewHolder, ChildViewHolder> {
private static final String TAG = MyExpandableRecyclerAdapter.class.getSimpleName();
LayoutInflater layoutInflater;
Context context;
private List<ParentObject> parentItemList = new ArrayList<>();
private static final int TYPE_EDITTEXT = 0;
private static final int TYPE_SPINNER = 1;
public MyExpandableRecyclerAdapter(Context context, List<ParentObject> parentObjectItemsList) {
super(context, parentObjectItemsList);
Log.i(TAG, "Constructor of MyExpandableRecyclerAdapter called.");//check
layoutInflater = LayoutInflater.from(context);
this.context = context;
parentItemList = parentObjectItemsList;
}
@Override
public int getItemViewType(int position) {
int viewType;
if (parentItemList.get(position).equals("EditText Entry")) {
viewType = TYPE_EDITTEXT;
} else {
viewType = TYPE_SPINNER;
}
return viewType;
}
@Override
public MyParentViewHolder onCreateParentViewHolder(ViewGroup container, int viewType) {
Log.i(TAG, "onCreateParentViewHolder of MyExpandableRecyclerAdapter called.");//check
Log.i(TAG, "IN onCreateParentViewHolder, THE TYPE OF AN ITEM IN THE parentItemList IS " + parentItemList.get(1));
return new MyParentViewHolder(layoutInflater.inflate(R.layout.custom_row_parent, container, false));
}
@Override
public MyChildViewHolder onCreateChildViewHolder(ViewGroup container, int viewType) {
Log.i(TAG, "onCreateChildViewHolder of MyExpandableRecyclerAdapter called.");//check
switch(viewType) {
case TYPE_EDITTEXT:
return new MyChildViewHolder(layoutInflater.inflate(R.layout.custom_row_child_with_edittext, container, false), context);
case TYPE_SPINNER:
return new MyChildViewHolder(layoutInflater.inflate(R.layout.custom_row_child_with_spinner, container, false), context);
default:
return new MyChildViewHolder(layoutInflater.inflate(R.layout.custom_row_child_with_edittext, container, false), context);
}
}
@Override
public void onBindParentViewHolder(ParentViewHolder parentViewHolder, int position, Object parentObject) {
Log.i(TAG, "onBindParentViewHolder of MyExpandableRecyclerAdapter called.");//check
MyParentViewHolder myParentViewHolder = (MyParentViewHolder) parentViewHolder;
MyCustomParentObject myCustomParentObject = (MyCustomParentObject) parentObject;
myParentViewHolder.textView.setText(myCustomParentObject.getTitle());
myParentViewHolder.imageView.setImageResource(myCustomParentObject.getImageId());
}
@Override
public void onBindChildViewHolder(ChildViewHolder childViewHolder, int position, Object childObject) {
Log.i(TAG, "onBindChildViewHolder of MyExpandableRecyclerAdapter called.");//check
switch(childViewHolder.getItemViewType()) {
case TYPE_EDITTEXT:
MyChildViewHolderWithEditText myChildViewHolderWithEditText = (MyChildViewHolderWithEditText) childViewHolder;
myChildViewHolderWithEditText.textView.setText("TextView " + (position+1) + " Title");
case TYPE_SPINNER:
MyCustomChildObject myCustomChildObject = (MyCustomChildObject) childObject;
ArrayAdapter arrayAdapter = new ArrayAdapter(context, android.R.layout.simple_list_item_1, myCustomChildObject.getSpinnerItems());
arrayAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
MyChildViewHolderWithSpinner myChildViewHolderWithSpinner = (MyChildViewHolderWithSpinner) childViewHolder;
myChildViewHolderWithSpinner.spinner.setAdapter(arrayAdapter);
}
}
}
MyCustomParentObject.java
public class MyCustomParentObject implements ParentObject {
private static final String TAG = MyCustomParentObject.class.getSimpleName();
//List to store all the children of the parent object in.
private List<Object> childObjectList;
private String [] bib;
MyCustomParentObject (Context context) {
super();
bib = context.getResources().getStringArray(R.array.spinner_options);
}
@Override
public List<Object> getChildObjectList() {
Log.i(TAG, "getChildObjectList of MyCustomParentObject called.");//check
//"You can either return a newly created list of children here or attach them later"
return populateChildObjectList();
}
@Override
public void setChildObjectList(List<Object> childObjectList) {
Log.i(TAG, "setChildObjectList of MyCustomParentObject called.");//check
childObjectList = childObjectList;
}
private List<Object> populateChildObjectList() {
Log.i(TAG, "populateChildObjectList of MyCustomParentObject called.");//check
childObjectList = new ArrayList<>();
MyCustomChildObject myCustomChildObject = new MyCustomChildObject();
myCustomChildObject.setSpinnerItems(bib);
Object myCustomChildObjectCasted = (Object) myCustomChildObject;
childObjectList.add(myCustomChildObjectCasted);
return childObjectList;
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
private int imageId;
private String title;
public int getImageId() {
Log.i(TAG, "getImageId of MyCustomParentObject called.");//check
return imageId;
}
public void setImageId(int imageId) {
Log.i(TAG, "setImageId of MyCustomParentObject called.");//check
this.imageId = imageId;
}
public String getTitle() {
Log.i(TAG, "getTitle of MyCustomParentObject called.");//check
return title;
}
public void setTitle(String title) {
Log.i(TAG, "setTitle of MyCustomParentObject called.");//check
this.title = title;
}
}
MyCustomChildObject.java
public class MyCustomChildObject {
private static final String TAG = MyCustomParentObject.class.getSimpleName();
private String [] spinnerItems;
public String [] getSpinnerItems() {
return spinnerItems;
}
public void setSpinnerItems(String [] spinnerItems) {
this.spinnerItems = spinnerItems;
}
}
MyCustomParentViewHolder.java
public class MyParentViewHolder extends ParentViewHolder {
private static final String TAG = MyParentViewHolder.class.getSimpleName();
TextView textView;
ImageView imageView;
public MyParentViewHolder(View itemView) {
super(itemView);
Log.i(TAG, "Constructor of MyParentViewHolder called.");//check
textView = (TextView) itemView.findViewById(R.id.parentCustomRow_textView);
imageView = (ImageView) itemView.findViewById(R.id.parentCustomRow_imageView);
}
}
MyCustomChildViewHolder.java
public class MyChildViewHolder extends ChildViewHolder {
private static final String TAG = MyChildViewHolder.class.getSimpleName();
public MyChildViewHolder(View itemView, final Context context) {
super(itemView);
Log.i(TAG, "Constructor of MyChildViewHolder called.");// check
}
}
MyCustomChildViewHolderWithEditText.java
public class MyChildViewHolderWithEditText extends MyChildViewHolder {
EditText editText;
TextView textView;
public MyChildViewHolderWithEditText(View itemView, Context context) {
super(itemView, context);
textView = (TextView) itemView.findViewById(R.id.childViewHolderWithEditText_TextView);
editText = (EditText) itemView.findViewById(R.id.childViewHolderWithEditText_editText);
}
}
MyCustomChildViewHolderWithSpinner.java
public class MyChildViewHolderWithSpinner extends MyChildViewHolder {
Spinner spinner;
public MyChildViewHolderWithSpinner(View itemView, Context context) {
super(itemView, context);
spinner = (Spinner) itemView.findViewById(R.id.childViewHolderWithSpinner_spinner);
//ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(context, R.array.childViewSpinnerFields, android.R.layout.simple_spinner_item);
//adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
///spinner.setAdapter(adapter);
spinner.setOnItemSelectedListener(new OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {}
@Override
public void onNothingSelected(AdapterView<?> parent) {}
});
}
}
回答1:
By comparing Line#13 of this stack-trace of the error free program, and this one of the program which results in the exception, and by looking at the onCreateViewHolder(ViewGroup viewGroup, int viewType)
method definition on Line#117 of this ExpandableRecyclerAdapter.java class, from which I infer that onCreateViewHolder
is being passed the wrong viewType
parameter.
But I haven't yet been able to figure out why!
I think I have figured it out.
Actually the trick of TYPE_SOMETHING
constants that I am using in MyExpandableRecyclerAdapter
is the same one they have used in ExpandableRecyclerAdapter
, i.e. in my MyExpandableRecyclerAdapter
, 0
is the value of TYPE_EDITTEXT
and 1
is the value of TYPE_SPINNER
; whereas in their ExpandableRecyclerAdapter
, which is extended by my MyExpandableRecyclerAdapter
, 0
is the value of TYPE_PARENT
and 1
is the value of TYPE_CHILD
.
If the Android framework passes the same viewType
parameter to onCreateViewHolder
which is returned from getItemViewType(int position)
, it will pass 1
if it was TYPE_SPINNER
in my MyExpandableRecyclerAdapter
, but their ExpandableRecyclerAdapter
will understand it as TYPE_CHILD
, and thus call onCreateChildViewHolder
.
So I think the whole thing I am trying to achieve can't be done. =(
来源:https://stackoverflow.com/questions/31648760/how-to-use-expandablerecyclerview-library-with-multiple-child-viewtypes