如何使用具有多个(子)viewTypes的ExpandableRecyclerView库?

时间:2015-07-27 08:52:52

标签: android android-recyclerview recycler-adapter

我需要一个带有可扩展RecyclerView的Activity,如下图所示:

enter image description here

所以我使用this third party library project该部分有效。

当我在接下来的两段中完成我所描述的内容时,问题出现了

我的下一个要求是我希望不同的父行有不同的子行。我正在复制(如果那是正确的话)this example to create multiple child-viewholders

示例说明: 这个想法基本上是让不同的子视图符号(对应于每个子行样式)扩展一个共同的子视图持有者,然后在我们的ExpandableRecyclerAdapter中,我们传递构造函数(SSCCE中的parentItemList)中父行中显示的数据的ArrayList,我们声明表示所有子行类型的常量(下面SSCCE中的TYPE_EDITTEXT和TYPE_SPINNER) );然后在getItemViewType(int position)内部,我们使用传递的parentItemList作为索引来比较来自int position的数据项,每个文本字符串都在父行上,并且在每种情况下,分配viewType } int变量一个TYPE常量,viewType。然后这个int viewType被传递给onCreateChildViewHolderonBindChildViewHolder,所以我们在每个的定义中执行另一个switch-block这些方法然后在onCreateChildViewHolder中我们返回一个相应的ChildViewHolder(从相应的布局资源中膨胀)(SSCCE中的R.layout.custom_row_child_with_edittextR.layout.custom_row_child_with_spinner);并在onBindChildViewHolder中,根据switch-block中的大小写更新数据。

问题是多才多艺的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)

问题是ExpandableRecyclerAdapter.java是第三方图书馆项目的一部分,第144行(以及我添加的142和143)是:

Log.i(TAG, "+++++++++++++++++++++++++THE TYPE OF THE RecyclerView.ViewHolder WHICH HAS BEEN PASSED AS AN ARGUMENT IS "
                    + holder.getClass().getSimpleName() + "++++++++++++++++++++++++++++");
            PVH parentViewHolder = (PVH) holder;

在我尝试做上面的工作之前,它工作正常。

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 个答案:

答案 0 :(得分:0)

通过比较Line#13 of this stack-trace of the error free programthis one of the program which results in the exception,并查看Line#117 of this ExpandableRecyclerAdapter.java class上的onCreateViewHolder(ViewGroup viewGroup, int viewType)方法定义,我从中推断onCreateViewHolder正在传递错误的viewType参数。

但我还没弄清楚原因!

我认为我已经弄清楚了。

实际上我在TYPE_SOMETHING中使用的MyExpandableRecyclerAdapter常量技巧与他们在ExpandableRecyclerAdapter中使用的相同,即在MyExpandableRecyclerAdapter,{{1} }是0的值,TYPE_EDITTEXT1的值;而在我TYPE_SPINNER扩展的ExpandableRecyclerAdapter中,MyExpandableRecyclerAdapter的{​​{1}}值是0,而TYPE_PARENT的值是1

如果Android框架将相同的TYPE_CHILD参数传递给viewTypeonCreateViewHolder会从getItemViewType(int position)返回1,如果它是TYPE_SPINNER MyExpandableRecyclerAdapter,但他们的ExpandableRecyclerAdapter会将其理解为TYPE_CHILD,从而致电onCreateChildViewHolder

所以我认为我想要完成的所有事情都无法完成。 =(