Search code examples
androidfragmentadapter

ContextThemeWrapper cannot be cast in AppCompatActivity


Cannot solve as:: java.lang.ClassCastException: android.view.ContextThemeWrapper cannot be cast to androidx.appcompat.app.AppCompatActivity.
Went through various sites but cannot solve my problem.

holder.ivPlace.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

                AppCompatActivity activity = (AppCompatActivity) v.getContext();
                Fragment myFragment = new BookingDetailsFragment();
                activity.getSupportFragmentManager().beginTransaction().replace(R.id.bookingFragment, myFragment)
                        .addToBackStack(null).commit();



            }
        });

Layout is inflated in this way::

@NonNull
    @Override
    public BookingActivityAdapter.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.activity_booking_data, parent, false);
        ViewHolder viewHolder = new ViewHolder(view);
        return viewHolder;

    }

Solution

  • I think you can make use of the following snippet for your issue. But I would like to recommend you do not do so as such for two reasons mainly.

    • Since you explicitly need Activity only, why not send that through or even better implement an interface for callback.
    • What if tomorrow this will be changed, and there will be other context for View?
    /**
     * Get activity instance from desired context.
     */
    public static Activity getActivity(Context context) {
        if (context == null) return null;
        if (context instanceof Activity) return (Activity) context;
        if (context instanceof ContextWrapper) return getActivity(((ContextWrapper)context).getBaseContext());
        return null;
    }
    

    EDIT: Snippets for callback to activity

    public interface MyAdapterListener {
            void onPlaceClick();
        }
    

    And then when you are creating an instance of your Adapter you can pass it like this

    public BookingActivityAdapter(MyAdapterListener myAdapterListener){
            this.myAdapterListener = myAdapterListener;
    }
    

    Just be sure to implement this interface in your activity. Then finally inside your onClick you can use this interface as follows

    holder.ivPlace.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
    
                    myAdapterListener.onPlaceClick();
    
                }
            });