0

So I am coding a custom listview & adapter to display my own custom item rows in a list view. I have a functional list view with features to toggle between choice modes and have checkable list row items through a custom relative layout in my list view row xml file. Now I am trying to add drag and drop ability to resort the list view items with target code for android v3.0 and up. I came across this post on this sites for a excellent implementation of drag and drop and am now adding it to my project. Github source here

When I compile my project I am getting a cast exception error as stated in my post title and I am having trouble getting past it. I can't work out if its my custom relative layout that implements checkable, or its the custom list view for the drag and drop, etc. Here is my log output

08-02 09:53:37.065: W/dalvikvm(16119): threadid=1: thread exiting with uncaught exception (group=0x40c6f1f8)
08-02 09:53:37.090: E/AndroidRuntime(16119): FATAL EXCEPTION: main
08-02 09:53:37.090: E/AndroidRuntime(16119): java.lang.ClassCastException: android.widget.RelativeLayout cannot be cast to au.drp.mylistview.draganddrop.DragSortListView
08-02 09:53:37.090: E/AndroidRuntime(16119):    at au.drp.mylistview.MyListViewAdapter.getView(MyListViewAdapter.java:62)
08-02 09:53:37.090: E/AndroidRuntime(16119):    at au.drp.mylistview.draganddrop.DragSortListView$AdapterWrapper.getView(DragSortListView.java:270)
08-02 09:53:37.090: E/AndroidRuntime(16119):    at android.widget.AbsListView.obtainView(AbsListView.java:2424)
08-02 09:53:37.090: E/AndroidRuntime(16119):    at android.widget.ListView.makeAndAddView(ListView.java:1781)
08-02 09:53:37.090: E/AndroidRuntime(16119):    at android.widget.ListView.fillDown(ListView.java:679)
08-02 09:53:37.090: E/AndroidRuntime(16119):    at android.widget.ListView.fillFromTop(ListView.java:739)
08-02 09:53:37.090: E/AndroidRuntime(16119):    at android.widget.ListView.layoutChildren(ListView.java:1632)
08-02 09:53:37.090: E/AndroidRuntime(16119):    at au.drp.mylistview.draganddrop.DragSortListView.layoutChildren(DragSortListView.java:961)
08-02 09:53:37.090: E/AndroidRuntime(16119):    at android.widget.AbsListView.onLayout(AbsListView.java:2254)
08-02 09:53:37.090: E/AndroidRuntime(16119):    at android.view.View.layout(View.java:11467)
08-02 09:53:37.090: E/AndroidRuntime(16119):    at android.view.ViewGroup.layout(ViewGroup.java:4237)
08-02 09:53:37.090: E/AndroidRuntime(16119):    at android.widget.FrameLayout.onLayout(FrameLayout.java:431)
08-02 09:53:37.090: E/AndroidRuntime(16119):    at android.view.View.layout(View.java:11467)
08-02 09:53:37.090: E/AndroidRuntime(16119):    at android.view.ViewGroup.layout(ViewGroup.java:4237)
08-02 09:53:37.090: E/AndroidRuntime(16119):    at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1644)
08-02 09:53:37.090: E/AndroidRuntime(16119):    at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1502)
08-02 09:53:37.090: E/AndroidRuntime(16119):    at android.widget.LinearLayout.onLayout(LinearLayout.java:1415)
08-02 09:53:37.090: E/AndroidRuntime(16119):    at android.view.View.layout(View.java:11467)
08-02 09:53:37.090: E/AndroidRuntime(16119):    at android.view.ViewGroup.layout(ViewGroup.java:4237)
08-02 09:53:37.090: E/AndroidRuntime(16119):    at android.widget.FrameLayout.onLayout(FrameLayout.java:431)
08-02 09:53:37.090: E/AndroidRuntime(16119):    at android.view.View.layout(View.java:11467)
08-02 09:53:37.090: E/AndroidRuntime(16119):    at android.view.ViewGroup.layout(ViewGroup.java:4237)
08-02 09:53:37.090: E/AndroidRuntime(16119):    at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:1721)
08-02 09:53:37.090: E/AndroidRuntime(16119):    at android.view.ViewRootImpl.handleMessage(ViewRootImpl.java:2678)
08-02 09:53:37.090: E/AndroidRuntime(16119):    at android.os.Handler.dispatchMessage(Handler.java:99)
08-02 09:53:37.090: E/AndroidRuntime(16119):    at android.os.Looper.loop(Looper.java:137)
08-02 09:53:37.090: E/AndroidRuntime(16119):    at android.app.ActivityThread.main(ActivityThread.java:4514)
08-02 09:53:37.090: E/AndroidRuntime(16119):    at java.lang.reflect.Method.invokeNative(Native Method)
08-02 09:53:37.090: E/AndroidRuntime(16119):    at java.lang.reflect.Method.invoke(Method.java:511)
08-02 09:53:37.090: E/AndroidRuntime(16119):    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:993)
08-02 09:53:37.090: E/AndroidRuntime(16119):    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:760)
08-02 09:53:37.090: E/AndroidRuntime(16119):    at dalvik.system.NativeStart.main(Native Method)

However I found by changing the error'ing section in the DragSortListView class I can change the outcome but still a cast exception error between a relative layout type and a list view. This section I talk of is the following getView code of the DragSortListView class. And what I tried changing is the RelativeLayout variable type and casts to CheckableRelativelayout.

NOTE: My comments in code "//DOES NOT LIKE THIS STATEMENT CODE" is the error lines

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {

  RelativeLayout v;
  View child;

  //Log.d("mobeta", "getView: position="+position+" convertView="+convertView);
  if (convertView != null) {

    v = (RelativeLayout) convertView;
    View oldChild = v.getChildAt(0);

    //child = super.getView(position, oldChild, v);
    child = mAdapter.getView(position, oldChild, v);
    if (child != oldChild) {
      // shouldn't get here if user is reusing convertViews properly
      v.removeViewAt(0);
      v.addView(child);
      // check that tags are equal too?
      v.setTag(child.findViewById(R.id.drag));
    }

  } else {
    AbsListView.LayoutParams params =
      new AbsListView.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
    v = new RelativeLayout(getContext());
    v.setLayoutParams(params);
    child = mAdapter.getView(position, null, v);  //DOES NOT LIKE THIS STATEMENT CODE
    v.addView(child);

    v.setTag(child.findViewById(R.id.drag));
  }

And here is my getView of my adapter class

@Override
public View getView(int position, View convertView, ViewGroup parent) {
    // This is how you would determine if this particular item is checked
    // when the view gets created
    // --       
    final DragSortListView lv = (DragSortListView) parent;  // DOES NOT LIKE THIS STATEMENT CODE
    final boolean isChecked = lv.isItemChecked(position);

    // Get the listview Choice Mode
    //
    final int selectionMode = lv.getChoiceMode();

    // The item we want to get the view for
    // --
    Item currentItem = getItem(position);

    // Re-use the view if possible (recycle)
    // --
    ViewHolder holder = null;
    //final View mView = mInflator.inflate(R.layout.listview_row, null);
    if (convertView == null) {
        convertView = mInflator.inflate(R.layout.listview_row, null);
        holder = new ViewHolder();
        holder.txtTitle = (TextView) convertView.findViewById(R.id.title);
        holder.txtDescription = (TextView) convertView.findViewById(R.id.description);
        holder.txtSessionCount = (TextView) convertView.findViewById(R.id.session_count);
        holder.listThumbnailImage = (ImageView) convertView.findViewById(R.id.list_image);
        holder.listStatusIndicatorImage = (ImageView) convertView.findViewById(R.id.drag);
        holder.Checkbox = (InertCheckBox) convertView.findViewById(R.id.inertCheckBox);
        convertView.setTag(holder);
    } else {
        holder = (ViewHolder)convertView.getTag();
    }
    // End recycler
    //

    holder.txtTitle.setText(currentItem.getTitle());
    holder.txtDescription.setText(currentItem.getDescription());
    holder.txtSessionCount.setText(currentItem.getSessionCount());
    holder.listThumbnailImage.setImageBitmap((Bitmap) currentItem.getThumbnailImage());

    // Now the Status ImageView and/or the InertCheckBox view
    switch (selectionMode) {
    case ListView.CHOICE_MODE_NONE:
        holder.Checkbox.setVisibility(InertCheckBox.INVISIBLE);
        holder.listStatusIndicatorImage.setVisibility(ImageView.VISIBLE);

        holder.listStatusIndicatorImage.setAdjustViewBounds(true);
        holder.listStatusIndicatorImage.setMaxHeight(48);
        holder.listStatusIndicatorImage.setMaxWidth(48);
        if (!dndMode) {
            holder.listStatusIndicatorImage.setImageBitmap((Bitmap) currentItem.getListIndicatorImage());

        } else {
            holder.listStatusIndicatorImage.setImageResource(R.drawable.list_icon_reorder_holo_dark);
        }   
        holder.listStatusIndicatorImage.setScaleType(ScaleType.CENTER_INSIDE);
        break;
    case ListView.CHOICE_MODE_SINGLE: case ListView.CHOICE_MODE_MULTIPLE:
        MyListViewAdapter.dndMode = false;
        holder.listStatusIndicatorImage.setVisibility(ImageView.INVISIBLE);
        holder.Checkbox.setVisibility(InertCheckBox.VISIBLE);
        if (!chkbxDelete) {
            holder.Checkbox.setButtonDrawable(R.drawable.checkbox);
        } else {
            holder.Checkbox.setButtonDrawable(R.drawable.checkboxdelete);
        }
        holder.Checkbox.setChecked(isChecked);
        break;
    }           

    return convertView;
}

my list view row layout

<?xml version="1.0" encoding="utf-8"?>
<au.drp.mylistview.widget.CheckableRelativeLayout 
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:drp="http://schemas.android.com/apk/res/au.drp.mylistview"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/list_selector"
android:orientation="horizontal"
android:padding="2dip" >

<!-- ListRow Left side Thumbnail image -->

<LinearLayout
    android:id="@+id/thumbnail"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_alignParentLeft="true"
    android:layout_alignParentTop="true"
    android:layout_marginRight="5dip"
    android:gravity="center_vertical"
    android:padding="3dip" >

    <ImageView
        android:id="@+id/list_image"
        android:layout_width="50dip"
        android:layout_height="50dip"
        android:src="@drawable/icon" >
    </ImageView>
</LinearLayout>

<!-- Title Of Exercise -->
<TextView
    android:id="@+id/title"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_alignTop="@+id/thumbnail"
    android:layout_toLeftOf="@+id/inertCheckBox"
    android:layout_toRightOf="@+id/thumbnail"
    android:text="This is the Title - Testing 1 2 3 "
    android:textColor="#ffffffff"
    android:textSize="18dip"
    android:textStyle="bold"
    android:typeface="sans" />

<TextView
    android:id="@+id/description"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_below="@+id/title"
    android:layout_toLeftOf="@+id/inertCheckBox"
    android:layout_toRightOf="@id/thumbnail"
    android:text="this is the description - Testing 1 2 3"
    android:textColor="#ffcccccc"
    android:textSize="14dip" />

<TextView
    android:id="@+id/session_count"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_alignParentRight="true"
    android:layout_alignParentTop="true"
    android:gravity="right"
    android:text="100"
    android:textColor="#ffcccccc"
    android:textSize="10dip"
    android:textStyle="bold" />
<ImageView
    android:id="@+id/drag"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_alignBottom="@id/inertCheckBox"
    android:layout_alignLeft="@id/inertCheckBox"
    android:layout_alignParentRight="true"
    android:layout_alignTop="@id/inertCheckBox"
    android:layout_below="@id/session_count"
    android:layout_centerVertical="false"
    android:adjustViewBounds="true"
    android:maxHeight="32dip"
    android:maxWidth="32dip"
    android:scaleType="center"
    android:src="@drawable/arrow_32_holo_dark"
    android:visibility="visible" />
<au.drp.mylistview.widget.InertCheckBox
    android:id="@+id/inertCheckBox"
    style="@drawable/checkbox"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_alignParentRight="true"
    android:layout_below="@id/session_count"
    android:button="@drawable/checkbox"
    android:checked="true"
    android:clickable="false"
    android:focusable="false"
    android:focusableInTouchMode="false" />

</au.drp.mylistview.widget.CheckableRelativeLayout>

My CheckableRelativeLayout class

public class CheckableRelativeLayout extends RelativeLayout implements Checkable {

private boolean isChecked;
private List<Checkable> checkableViews;

public CheckableRelativeLayout(Context context, AttributeSet attrs, int defStyle) {
    super(context, attrs, defStyle);
    initialise(attrs);
}

public CheckableRelativeLayout(Context context, AttributeSet attrs) {
    super(context, attrs);
    initialise(attrs);
}

public CheckableRelativeLayout(Context context, int checkableId) {
    super(context);
    initialise(null);
}

/*
 * @see android.widget.Checkable#isChecked()
 */
public boolean isChecked() {
    return isChecked;
}

/*
 * @see android.widget.Checkable#setChecked(boolean)
 */
public void setChecked(boolean isChecked) {
    this.isChecked = isChecked;
    for (Checkable c : checkableViews) {
        c.setChecked(isChecked);
    }
}

/*
 * @see android.widget.Checkable#toggle()
 */
public void toggle() {
    this.isChecked = !this.isChecked;
    for (Checkable c : checkableViews) {
        c.toggle();
    }
}

@Override
protected void onFinishInflate() {
    super.onFinishInflate();

    final int childCount = this.getChildCount();
    for (int i = 0; i < childCount; ++i) {
        findCheckableChildren(this.getChildAt(i));
    }
}

/**
 * Read the custom XML attributes
 */
private void initialise(AttributeSet attrs) {
    this.isChecked = false;
    this.checkableViews = new ArrayList<Checkable>(5);
}

/**
 * Add to our checkable list all the children of the view that implement the
 * interface Checkable
 */
private void findCheckableChildren(View v) {
    if (v instanceof Checkable) {
        this.checkableViews.add((Checkable) v);
    }

    if (v instanceof ViewGroup) {
        final ViewGroup vg = (ViewGroup) v;
        final int childCount = vg.getChildCount();
        for (int i = 0; i < childCount; ++i) {
            findCheckableChildren(vg.getChildAt(i));
        }
    }
}

}

And the custom listview layout for DragsortListView

<?xml version="1.0" encoding="utf-8"?>
<au.drp.mylistview.draganddrop.DragSortListView
  xmlns:android="http://schemas.android.com/apk/res/android"
  xmlns:dslv="http://schemas.android.com/apk/res/au.drp.mylistview"
  android:id="@android:id/list"
  android:layout_width="fill_parent"
  android:layout_height="fill_parent"
  android:paddingTop="20dp"
  android:paddingBottom="20dp"
  dslv:collapsed_height="5dp"
  dslv:drag_scroll_start="0.33"
  dslv:max_drag_scroll_speed="0.5"
  dslv:float_background_color="#000000"
  dslv:remove_mode="none"
  dslv:track_drag_scroll="false" />

Is anyone able to point out my error to me? I am stuck.

thanks,

Paul.

Community
  • 1
  • 1
luthepa1
  • 99
  • 2
  • 6

3 Answers3

0

Ok I found the problem! But raises another issue. The problem is this line in my MyListViewAdapter class

 final ListView lv = (ListView) parent;  // DOES NOT LIKE THIS STATEMENT CODE

If I comment this out and everything that uses lv the app runs and drag and drop works! But the problem now is how to determine if items in list view are checked? So this is how I am obtaining if a view is checked

    // This is how you would determine if this particular item is checked
    // when the view gets created
    // --       
    final ListView lv = (ListView) parent;  // DOES NOT LIKE THIS STATEMENT CODE
    final boolean isChecked = lv.isItemChecked(position);

    // Get the listview Choice Mode
    //
    final int selectionMode = lv.getChoiceMode();

I guess I could add a if statement around the code for when drag and drop support mode is engaged but that seems like a work around. Any ideas?

luthepa1
  • 99
  • 2
  • 6
0

View parent parameter passed into getView is not the ListView containing the list, it is just the parent of convertView (ie, for inflating into). It is fundamentally, not a ListView object which is why you are getting a ClassCastException when trying to cast it, because it can't be cast to a ListView. You should pass the ListView object into the Adapter sublcass's constructor then use it in getView..

user965369
  • 4,613
  • 10
  • 29
  • 43
0

In my case ClassCastException was because in my_custom_view.xml (which I use to inflate MyCustomView) I've defined its id:

android:id="@+id/myCustomView"

And then in my_activity.xml I've defined its id again:

<com.example.app.views.custom.MyCustomView
        android:id="@+id/myCustomView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

Removing id parameter from my_custom_view.xml resolved the issue.

Yamashiro Rion
  • 980
  • 1
  • 12
  • 22