androidgetview

java.lang.ClassCastException, trying to have two activites using the same custom adapter


I have two activities, NewContact.java and ViewContact.java, that I want to have using the same custom adapter as the two activites are very similar.

But I am getting the following error and my app crashes:

AndroidRuntime: FATAL EXCEPTION: main
java.lang.ClassCastException: com.example.chris.tutorialspoint.ViewContact cannot be cast to com.example.chris.tutorialspoint.NewContact

I've read quite a few posts here with subjects AndroidRuntime: FATAL EXCEPTION:, java.lang.ClassCastExceptionbut I don't know how to adjust the answers to suit my needs.

Here's my getView code from my adapter. I know the problem is with the lines:

    viewHolder.check.setOnCheckedChangeListener((NewContact) _c);
    viewHolder.check.setOnCheckedChangeListener((ViewContact) _c);

If I delete one of the lines then the custom adapter works for the remaining activity but I want to have it working for both activities, NewContact and ViewContact.

 @Override
    public View getView(int i, View convertView, ViewGroup viewGroup) {
        System.out.println("getView number is :" + i + "convertView is : " + convertView);
        //we're naming our convertView as view
        //  View view = convertView;
        ViewHolder viewHolder = null;

        if (convertView == null) {

            //if there is nothing there (if it's null) inflate the view with the layout
            LayoutInflater li = (LayoutInflater) _c.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            convertView = li.inflate(R.layout.phone_inflate_listview, null);

            viewHolder = new ViewHolder();
            //      So, for example, title is cast to the name id, in phone_inflate_listview,
            //      phone is cast to the id called no etc
            viewHolder.title = (TextView) convertView.findViewById(R.id.name);
            viewHolder.phone = (TextView) convertView.findViewById(R.id.no);
            viewHolder.invite = (Button)  convertView.findViewById(R.id.btnInvite);
            viewHolder.check = (CheckBox) convertView.findViewById(R.id.checkBoxContact);
            // viewHolder.check.setVisibility(View.GONE);

            //remember the state of the checkbox
            viewHolder.check.setOnCheckedChangeListener((NewContact) _c);
            viewHolder.check.setOnCheckedChangeListener((ViewContact) _c);

            convertView.setTag(viewHolder);

        } else {

            viewHolder = (ViewHolder) convertView.getTag();

        }
//        store the holder with the view
        final SelectPhoneContact data = (SelectPhoneContact) arraylist.get(i);
        //in the listview for contacts, set the name
        viewHolder.title.setText(data.getName());
        //in the listview for contacts, set the number
        viewHolder.phone.setText(data.getPhone());

        ////*********************

        //for every phone number in the MatchingContactsAsArrayList array list...
        for (int number = 0; number < MatchingContactsAsArrayList.size(); number++) {

            //if a phone number is in our array of matching contacts
            if (MatchingContactsAsArrayList.contains(data.getPhone()))

            {
                //if a matching contact, no need to show the Invite button
                viewHolder.invite.setVisibility(View.GONE);
                System.out.println("it's a match: phoneNumberofContact is : " + data.getPhone());
                //once a matching contact is found, no need to keep looping x number of time, move onto next contact
                break;

            }

            else {
                //if not a matching contact, no need to show the check box
                viewHolder.check.setVisibility(View.GONE);

            }

        }


        viewHolder.check.setChecked(data.isSelected());



        viewHolder.check.setTag(data);

        // Return the completed view to render on screen

        return convertView;

    }

Solution

  • You don't need to cast that Context to the specific Activity types. The setOnCheckedChangeListener() method just needs an OnCheckedChangeListener, and if both classes implement that interface, you need only one call that casts the Context to OnCheckedChangeListener.

    viewHolder.check.setOnCheckedChangeListener((OnCheckedChangeListener) _c);
    

    It might be prudent to add an instanceof check in the constructor to make sure the passed Context is indeed an OnCheckedChangeListener, which would have the benefits of failing sooner, and giving you the opportunity to perhaps throw an Exception with a more informative message.