2

I am now implementing a drag and drop operation . In this operation drag from a relative layout to anther one is allowed . If there's a child in a layout and another image is drag to it the images must exchange position . Here's my problem when i cast a view to view group , Class cast exception occurs . I really don't know how to solve it as I'm a new to android . The error line at log cat points at this ((ViewGroup)parent).addView(nextChild). Please give me advice . Sorry if my question bother you .

This is my Log cat output :

01-09 01:57:27.829: E/AndroidRuntime(2021): FATAL EXCEPTION: main
01-09 01:57:27.829: E/AndroidRuntime(2021): Process: com.example.barnyar, PID: 2021
01-09 01:57:27.829: E/AndroidRuntime(2021): java.lang.ClassCastException: android.view.View cannot be cast to android.view.ViewGroup
01-09 01:57:27.829: E/AndroidRuntime(2021):     at com.example.barnyar.MainActivity$MyDragListener.onDrag(MainActivity.java:751)
01-09 01:57:27.829: E/AndroidRuntime(2021):     at android.view.View.dispatchDragEvent(View.java:17371)
01-09 01:57:27.829: E/AndroidRuntime(2021):     at android.view.ViewGroup.dispatchDragEvent(ViewGroup.java:1300)
01-09 01:57:27.829: E/AndroidRuntime(2021):     at android.view.ViewGroup.dispatchDragEvent(ViewGroup.java:1286)
01-09 01:57:27.829: E/AndroidRuntime(2021):     at android.view.ViewGroup.dispatchDragEvent(ViewGroup.java:1286)
01-09 01:57:27.829: E/AndroidRuntime(2021):     at android.view.ViewGroup.dispatchDragEvent(ViewGroup.java:1286)
01-09 01:57:27.829: E/AndroidRuntime(2021):     at android.view.ViewGroup.dispatchDragEvent(ViewGroup.java:1286)
01-09 01:57:27.829: E/AndroidRuntime(2021):     at android.view.ViewGroup.dispatchDragEvent(ViewGroup.java:1286)
01-09 01:57:27.829: E/AndroidRuntime(2021):     at android.view.ViewRootImpl.handleDragEvent(ViewRootImpl.java:5026)
01-09 01:57:27.829: E/AndroidRuntime(2021):     at android.view.ViewRootImpl.access$800(ViewRootImpl.java:96)
01-09 01:57:27.829: E/AndroidRuntime(2021):     at android.view.ViewRootImpl$ViewRootHandler.handleMessage(ViewRootImpl.java:3213)
01-09 01:57:27.829: E/AndroidRuntime(2021):     at android.os.Handler.dispatchMessage(Handler.java:102)
01-09 01:57:27.829: E/AndroidRuntime(2021):     at android.os.Looper.loop(Looper.java:136)
01-09 01:57:27.829: E/AndroidRuntime(2021):     at android.app.ActivityThread.main(ActivityThread.java:5017)
01-09 01:57:27.829: E/AndroidRuntime(2021):     at java.lang.reflect.Method.invokeNative(Native Method)
01-09 01:57:27.829: E/AndroidRuntime(2021):     at java.lang.reflect.Method.invoke(Method.java:515)
01-09 01:57:27.829: E/AndroidRuntime(2021):     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:779)
01-09 01:57:27.829: E/AndroidRuntime(2021):     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:595)
01-09 01:57:27.829: E/AndroidRuntime(2021):     at dalvik.system.NativeStart.main(Native Method)

This is my code :

@Override 
public boolean onDrag(View v, DragEvent event) {

    View parent = new View(MainActivity.this);
        switch (event.getAction()) {

        case DragEvent.ACTION_DRAG_STARTED:
                Toast.makeText(getApplicationContext(), "Start Drag ", Toast.LENGTH_LONG).show();
                parent = v;
                Log.i("class",parent+"");
            break;

        case DragEvent.ACTION_DRAG_ENTERED:
            v.setBackground(normalShape);   //change the shape of the view
            break;


        case DragEvent.ACTION_DRAG_EXITED:
            v.setBackground(normalShape);   //change the shape of the view back to normal
            break;

        case DragEvent.ACTION_DROP:

            if(v.getClass().toString().equals("class android.widget.RelativeLayout")){
                Log.i("class","Relative");



                if(((ViewGroup)v).getChildCount()!=0){

                View nextChild = ((ViewGroup)v).getChildAt(0);
                Log.i("child",((ViewGroup)v).getChildCount()+"");   
                      ((ViewGroup)parent).addView(nextChild);//the error line
                 View view = (View) event.getLocalState();
                  ViewGroup viewgroup = (ViewGroup) view.getParent();
                  viewgroup.removeView(view);
                  RelativeLayout containView = (RelativeLayout) v;
                  containView.addView(view);
                  view.setVisibility(View.VISIBLE);

                }


                else {
                  View view = (View) event.getLocalState();
                  ViewGroup viewgroup = (ViewGroup) view.getParent();
                  viewgroup.removeView(view);
                  RelativeLayout containView = (RelativeLayout) v;
                  containView.addView(view);
                  view.setVisibility(View.VISIBLE);
                }
                }

            else {

                  Log.i("CLass", v.getClass()+"Cant drop");
                  View view = (View) event.getLocalState();
                  view.setVisibility(View.VISIBLE);

                  break;
               }
              break;

        case DragEvent.ACTION_DRAG_ENDED:
            v.setBackground(normalShape);   //go back to normal shape

        default:
            break;
        }
        return true;
    }
}
Dalorzo
  • 19,312
  • 7
  • 50
  • 97
Chann Lynn
  • 201
  • 3
  • 14

4 Answers4

3

ViewGroup vs View casting

ViewGroup is also a View (extends View) so instead of casting to ViewGroup keep them as View objects and only cast when really needed to (that is when accessing methods that aren't available in View, only in ViewGroup).

// childCount is for ViewGroup only, if problem still occurs you can
// check first if v object really is a ViewGroup instance with the
// below instanceof check
if( v instanceof ViewGroup && parent instanceof ViewGroup && ((ViewGroup)v).getChildCount()!=0 ){

     // perform the cast only once, also now we know it's safe thanks to the instanceof
     ViewGroup vg = (ViewGroup)v

     View nextChild = vg.getChildAt(0);
     Log.i("child", vg.getChildCount()+"");   

     // no guarantee here whatever that parent is a more specific ViewGroup
     // so if we need this to be a ViewGroup we'll have to cast but check
    // with instanceof first
    ((ViewGroup)parent).addView(nextChild); //this was the error line

     View view = (View) event.getLocalState();
     ViewGroup viewgroup = (ViewGroup) view.getParent();
     viewgroup.removeView(view);
     RelativeLayout containView = (RelativeLayout) v;
     containView.addView(view);
     view.setVisibility(View.VISIBLE);

} else {
     // PERFORM SOME LOGGING HERE
     // so you know what views got dropped in here that didn't match your requirements in the first place
     // TODO

}

instanceof

Also avoid checking the name of a Class with a String.equals(String):boolean like you did in the snippet below.

In your case this would even fail since the "class " in front will not be part of the result.

if(v.getClass().toString().equals("class android.widget.RelativeLayout")){

The proper way to check the type of an Object in Java is to use isntanceof like I did in the code below.

if( v instanceof android.widget.RelativeLayout ){

More information about instanceof can be found on this StackOverflow question.

Community
  • 1
  • 1
hcpl
  • 16,793
  • 7
  • 66
  • 71
1

Do less casting and use instanceof to check the type.

if(v instanceof ViewGroup){
    ViewGroup vg = (ViewGroup)v;

    // TODO your code that needs a ViewGroup.
}
alex
  • 6,099
  • 1
  • 21
  • 21
0

problem is here if(((ViewGroup)v).getChildCount()!=0) and View nextChild = ((ViewGroup)v).getChildAt(0);

remove casting and try this way if(v.getChildCount()!=0)

Ketan Ahir
  • 6,458
  • 1
  • 20
  • 43
0

View is the parent of ViewGroup and so you cannot type cast ViewGroup, a child to its parent which is View. Thats the reason why it is throwing ClassCastException.

San
  • 2,143
  • 20
  • 38