Search code examples
androidandroid-dialogfragmentclasscastexception

DialogFragment is throwing ClassCastException onAttach


I want to update the existing data from SQLite database and for this purpose I made a class UpdateData but when the data is getting attached it is throwing ClassCastException. I almost got there where everything is going wrong. But don't know what to fix

Here is the Log

E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.example.recyclerviewwithsqlite, PID: 2257
    java.lang.ClassCastException: com.example.recyclerviewwithsqlite.MainActivity@2d3a0725
        at com.example.recyclerviewwithsqlite.UpdateData.onAttach(UpdateData.java:52)
        at androidx.fragment.app.Fragment.performAttach(Fragment.java:2922)
        at androidx.fragment.app.FragmentStateManager.attach(FragmentStateManager.java:464)
        at androidx.fragment.app.FragmentStateManager.moveToExpectedState(FragmentStateManager.java:275)
        at androidx.fragment.app.FragmentManager.executeOpsTogether(FragmentManager.java:2189)
        at androidx.fragment.app.FragmentManager.removeRedundantOperationsAndExecute(FragmentManager.java:2100)
        at androidx.fragment.app.FragmentManager.execPendingActions(FragmentManager.java:2002)
        at androidx.fragment.app.FragmentManager$5.run(FragmentManager.java:524)
        at android.os.Handler.handleCallback(Handler.java:739)
        at android.os.Handler.dispatchMessage(Handler.java:95)
        at android.os.Looper.loop(Looper.java:135)
        at android.app.ActivityThread.main(ActivityThread.java:5221)
        at java.lang.reflect.Method.invoke(Native Method)
        at java.lang.reflect.Method.invoke(Method.java:372)
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:899)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:694)

Here is my code of UpdateData.java



import android.app.Dialog;
import android.content.Context;
import android.content.DialogInterface;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.EditText;;

import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatDialogFragment;

public class UpdateData extends AppCompatDialogFragment {
    private Data listener;
    @Override
    public Dialog onCreateDialog(Bundle savedInstances) {
        AlertDialog.Builder builder= new AlertDialog.Builder(getActivity());
        LayoutInflater inflater = getActivity().getLayoutInflater();
        View view = inflater.inflate(R.layout.update_data,null);
        EditText name = view.findViewById(R.id.update_name);
        EditText salary = view.findViewById(R.id.update_salary);
        Bundle bundle = listener.ReceiveData();
        String n = bundle.getString("name");
        double s = bundle.getDouble("salary");

        name.setText(n);
        salary.setText(Double.toString(s));
        builder.setView(view)
                .setTitle("Update Data")
                .setNegativeButton("Cancel",new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {

                    }
                })
                .setPositiveButton("Add", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {

                    }
                });
        return builder.create();
    }

    public void onAttach(Context context) {
        super.onAttach(context);
        try {
            listener = (Data) context;
        } catch (ClassCastException e) {
            throw new ClassCastException(context.toString());
        }
    }

    public interface Data {
        Bundle ReceiveData();
    }
}

Here is EmployeeAdapter.java

package com.example.recyclerviewwithsqlite;

import android.content.Context;
import android.os.Bundle;
import android.view.ContextMenu;
import android.view.LayoutInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

import androidx.fragment.app.FragmentManager;
import androidx.recyclerview.widget.RecyclerView;

import java.util.List;

public class EmployeeAdapter extends RecyclerView.Adapter<EmployeeAdapter.ViewHolder> {
    private List<Employee> employeeList;
    private int position;
    FragmentManager fragmentManager;
    public EmployeeAdapter(List<Employee> employeeList, FragmentManager fragmentManager) {
        this.employeeList = employeeList;
        this.fragmentManager = fragmentManager;
    }

    @Override
    public EmployeeAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        Context context = parent.getContext();
        LayoutInflater inflater = LayoutInflater.from(context);

        View employeeView = inflater.inflate(R.layout.list_item_view,parent,false);

        ViewHolder viewHolder = new ViewHolder(employeeView);
        return viewHolder;
    }


    void setPosition(int position) {
        this.position = position;
    }
    @Override
    public void onBindViewHolder(EmployeeAdapter.ViewHolder holder, int position) {
        Employee employee = employeeList.get(position);
        TextView name = holder.name;
        TextView salary = holder.salary;
        name.setText(employee.getName());
        salary.setText(Double.toString(employee.getSalary()));
        holder.itemView.setOnLongClickListener(new View.OnLongClickListener() {
            @Override
            public boolean onLongClick(View v) {
                setPosition(holder.getPosition());
                return false;
            }
        });
    }

    @Override
    public int getItemCount() {
        return employeeList.size();
    }

    public class ViewHolder extends RecyclerView.ViewHolder implements View.OnCreateContextMenuListener,UpdateData.Data {
        public TextView name;
        public TextView salary;

        public ViewHolder(View itemView) {
            super(itemView);

            name = itemView.findViewById(R.id.name_text_view);
            salary = itemView.findViewById(R.id.salary_text_view);
            itemView.setOnCreateContextMenuListener(this);
            itemView.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    UpdateData updateData = new UpdateData();
                    updateData.show(fragmentManager,"Update Data");
                }
            });
        }

        @Override
        public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
            MenuItem edit = menu.add(0, R.id.edit, 0, "Edit");
            MenuItem delete = menu.add(0, R.id.delete, 1, "Delete");
            edit.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
                @Override
                public boolean onMenuItemClick(MenuItem item) {

                    return true;
                }
            });
            delete.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
                @Override
                public boolean onMenuItemClick(MenuItem item) {
                    Data listener;
                    try {
                        listener = (Data) v.getContext();
                        listener.deleteData(position);
                    } catch (ClassCastException ex) {
                        throw new ClassCastException(v.getContext().toString());
                    }

                    return true;
                }
            });

        }

        @Override
        public Bundle ReceiveData() {
            Bundle bundle = new Bundle();
            bundle.putString("name",employeeList.get(position).getName());
            bundle.putDouble("salary",employeeList.get(position).getSalary());
            return bundle;
        }
    }

    public interface Data {
        public void deleteData(int position);
    }
}

The FragmentManager in EmployeeAdapter.java is from MainActivity.java using the function getSupportFragmentManager(). I guess that is the part where I'm doing things wrong. Then what changes should I made to make it work.


Solution

  • I finally did it by replacing onAttach method with setListener's method. Following is the code

    package com.example.recyclerviewwithsqlite;
    
    
    import android.app.Activity;
    import android.app.Dialog;
    import android.content.Context;
    import android.content.DialogInterface;
    import android.os.Bundle;
    import android.view.LayoutInflater;
    import android.view.View;
    import android.widget.EditText;;
    
    import androidx.appcompat.app.AlertDialog;
    import androidx.appcompat.app.AppCompatDialogFragment;
    
    public class UpdateData extends AppCompatDialogFragment {
        DataListener dataListener;
    
        public Dialog onCreateDialog(Bundle savedInstances) {
            AlertDialog.Builder builder= new AlertDialog.Builder(getActivity());
            LayoutInflater inflater = getActivity().getLayoutInflater();
            View view = inflater.inflate(R.layout.update_data,null);
            EditText name = view.findViewById(R.id.update_name);
            EditText salary = view.findViewById(R.id.update_salary);
            Bundle bundle = dataListener.ReceiveData();
            String n = bundle.getString("name");
            double s = bundle.getDouble("salary");
    
            name.setText(n);
            salary.setText(Double.toString(s));
            builder.setView(view)
                    .setTitle("Update Data")
                    .setNegativeButton("Cancel",new DialogInterface.OnClickListener() {
                        @Override
                        public void onClick(DialogInterface dialog, int which) {
    
                        }
                    })
                    .setPositiveButton("Add", new DialogInterface.OnClickListener() {
                        @Override
                        public void onClick(DialogInterface dialog, int which) {
    
                        }
                    });
            return builder.create();
        }
    
        public void setDataListener(DataListener dataListener) {
            this.dataListener = dataListener;
        }
    
        public interface DataListener {
            Bundle ReceiveData();
        }
    }
    
    

    In this code, the method setDataListener(DataListener dataListener) is allowed me to create an instance of dataListener and then pass it to DialogFragment

    Then in the adapter it is implemented as

    UpdateData updateData = new UpdateData();
        UpdateData.DataListener dataListener = new UpdateData.DataListener() {
            @Override
            public Bundle ReceiveData() {
                Bundle bundle = new Bundle();
                bundle.putString("name",employeeList.get(position).getName());
                bundle.putDouble("salary",employeeList.get(position).getSalary());
                return bundle;
            }
    
        };
        updateData.setDataListener(dataListener);
        updateData.show(fragmentManager,"Update Data");
    
    }
    

    In this way it worked successfully.