Search code examples
androidandroid-recyclerviewcrashfloating-action-buttonmaterial-components-android

Adding Floating Action Button to Recycler View Crash: The style on this component requires your app theme to be Theme.AppCompat


I'm trying to add a unique floating action button to every item in a recycler grid view. I tried changing the theme to MaterialComponent but that didn't work. The error tells me the crash is occurring during inflation and that my theme is not AppCompat even though it is in styles. I think I might just have to add something into the XML but I am unsure. Does anyone know how to fix this?

Error:

E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.example.imagegridactivity, PID: 17829
    android.view.InflateException: Binary XML file line #36 in com.example.imagegridactivity:layout/custom_view: Binary XML file line #36 in com.example.imagegridactivity:layout/custom_view: Error inflating class com.google.android.material.floatingactionbutton.FloatingActionButton
    Caused by: android.view.InflateException: Binary XML file line #36 in com.example.imagegridactivity:layout/custom_view: Error inflating class com.google.android.material.floatingactionbutton.FloatingActionButton
    Caused by: java.lang.reflect.InvocationTargetException
        at java.lang.reflect.Constructor.newInstance0(Native Method)
        at java.lang.reflect.Constructor.newInstance(Constructor.java:343)
        at android.view.LayoutInflater.createView(LayoutInflater.java:854)
        at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:1006)
        at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:961)
        at android.view.LayoutInflater.rInflate(LayoutInflater.java:1123)
        at android.view.LayoutInflater.rInflateChildren(LayoutInflater.java:1084)
        at android.view.LayoutInflater.rInflate(LayoutInflater.java:1126)
        at android.view.LayoutInflater.rInflateChildren(LayoutInflater.java:1084)
        at android.view.LayoutInflater.inflate(LayoutInflater.java:682)
        at android.view.LayoutInflater.inflate(LayoutInflater.java:534)
        at com.example.imagegridactivity.AnimalsAdapter.onCreateViewHolder(AnimalsAdapter.java:135)
        at com.example.imagegridactivity.AnimalsAdapter.onCreateViewHolder(AnimalsAdapter.java:29)
        at androidx.recyclerview.widget.RecyclerView$Adapter.createViewHolder(RecyclerView.java:7078)
        at androidx.recyclerview.widget.RecyclerView$Recycler.tryGetViewHolderForPositionByDeadline(RecyclerView.java:6235)
        at androidx.recyclerview.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:6118)
        at androidx.recyclerview.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:6114)
        at androidx.recyclerview.widget.LinearLayoutManager$LayoutState.next(LinearLayoutManager.java:2303)
        at androidx.recyclerview.widget.GridLayoutManager.layoutChunk(GridLayoutManager.java:561)
        at androidx.recyclerview.widget.LinearLayoutManager.fill(LinearLayoutManager.java:1587)
        at androidx.recyclerview.widget.LinearLayoutManager.onLayoutChildren(LinearLayoutManager.java:665)
        at androidx.recyclerview.widget.GridLayoutManager.onLayoutChildren(GridLayoutManager.java:170)
        at androidx.recyclerview.widget.RecyclerView.dispatchLayoutStep2(RecyclerView.java:4134)
        at androidx.recyclerview.widget.RecyclerView.onMeasure(RecyclerView.java:3540)
        at android.view.View.measure(View.java:25086)
        at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:6872)
        at android.widget.LinearLayout.measureChildBeforeLayout(LinearLayout.java:1552)
        at android.widget.LinearLayout.measureHorizontal(LinearLayout.java:1204)
        at android.widget.LinearLayout.onMeasure(LinearLayout.java:723)
        at android.view.View.measure(View.java:25086)
        at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:6872)
        at android.widget.LinearLayout.measureChildBeforeLayout(LinearLayout.java:1552)
        at android.widget.LinearLayout.measureHorizontal(LinearLayout.java:1204)
        at android.widget.LinearLayout.onMeasure(LinearLayout.java:723)
        at android.view.View.measure(View.java:25086)
        at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:6872)
        at android.widget.FrameLayout.onMeasure(FrameLayout.java:194)
        at androidx.appcompat.widget.ContentFrameLayout.onMeasure(ContentFrameLayout.java:143)
        at android.view.View.measure(View.java:25086)
        at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:6872)
        at androidx.appcompat.widget.ActionBarOverlayLayout.onMeasure(ActionBarOverlayLayout.java:403)
        at android.view.View.measure(View.java:25086)
        at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:6872)
        at android.widget.FrameLayout.onMeasure(FrameLayout.java:194)
        at android.view.View.measure(View.java:25086)
E/AndroidRuntime:     at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:6872)
        at android.widget.LinearLayout.measureChildBeforeLayout(LinearLayout.java:1552)
        at android.widget.LinearLayout.measureVertical(LinearLayout.java:842)
        at android.widget.LinearLayout.onMeasure(LinearLayout.java:721)
        at android.view.View.measure(View.java:25086)
        at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:6872)
        at android.widget.FrameLayout.onMeasure(FrameLayout.java:194)
        at com.android.internal.policy.DecorView.onMeasure(DecorView.java:742)
        at android.view.View.measure(View.java:25086)
        at android.view.ViewRootImpl.performMeasure(ViewRootImpl.java:3083)
        at android.view.ViewRootImpl.measureHierarchy(ViewRootImpl.java:1857)
        at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:2146)
        at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1745)
        at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:7768)
        at android.view.Choreographer$CallbackRecord.run(Choreographer.java:967)
        at android.view.Choreographer.doCallbacks(Choreographer.java:791)
        at android.view.Choreographer.doFrame(Choreographer.java:726)
        at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:952)
        at android.os.Handler.handleCallback(Handler.java:883)
        at android.os.Handler.dispatchMessage(Handler.java:100)
        at android.os.Looper.loop(Looper.java:214)
        at android.app.ActivityThread.main(ActivityThread.java:7356)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:930)
     Caused by: java.lang.IllegalArgumentException: The style on this component requires your app theme to be Theme.AppCompat (or a descendant).
        at com.google.android.material.internal.ThemeEnforcement.checkTheme(ThemeEnforcement.java:248)
        at com.google.android.material.internal.ThemeEnforcement.checkAppCompatTheme(ThemeEnforcement.java:218)
        at com.google.android.material.internal.ThemeEnforcement.checkCompatibleTheme(ThemeEnforcement.java:153)
        at com.google.android.material.internal.ThemeEnforcement.obtainStyledAttributes(ThemeEnforcement.java:81)
        at com.google.android.material.floatingactionbutton.FloatingActionButton.<init>(FloatingActionButton.java:212)
        at com.google.android.material.floatingactionbutton.FloatingActionButton.<init>(FloatingActionButton.java:201)

Adapter:

public class AnimalsAdapter extends RecyclerView.Adapter<AnimalsAdapter.ViewHolder> {

    ImageView imageView;
    FloatingActionButton floatingActionButton;

    private Uri imageUri;
    private ArrayList<animal_item> mDataSet;
    private Context mContext;
    private OnItemClickListener mListener;

    public ArrayList<animal_item> getDataSet() {
        return mDataSet;
    }

    public void setDataSet(ArrayList<animal_item> mDataSet) {
        this.mDataSet = mDataSet;
    }

    public ImageView getImageView() {
        return imageView;
    }

    public void setImageView(ImageView imageView) {
        this.imageView = imageView;
    }

    public Context getContext() {
        return mContext;
    }

    public void setContext(Context mContext) {
        this.mContext = mContext;
    }

    public Uri getImageUri() {
        return imageUri;
    }

    public void setImageUri(Uri imageUri) {
        this.imageUri = imageUri;
    }

    public interface OnItemClickListener {

        void onItemClick(int position);

    }

    public void setOnItemClickListener(OnItemClickListener listener) {

        mListener = listener;

    }

    public AnimalsAdapter(Context context, ArrayList<animal_item> DataSet) {
        mDataSet = DataSet;
        mContext = context;
    }

    public ArrayList<animal_item> DataSet() {

        return mDataSet;
    }

    public static class ViewHolder extends RecyclerView.ViewHolder {
        public ImageView mImageView;
        public FloatingActionButton mFloatingActionButton;
        public RelativeLayout mLinearLayout;

        public ViewHolder(View v, final OnItemClickListener listener) {
            super(v);

            mImageView = (ImageView) v.findViewById(R.id.tv);
            mFloatingActionButton = (FloatingActionButton) v.findViewById(R.id.floatingActionButton);

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

                    if (listener != null) {

                        int position = getAdapterPosition();
                        if (position != RecyclerView.NO_POSITION) ;
                        listener.onItemClick(position);
                    }
                }
            });
            mLinearLayout = (RelativeLayout) v.findViewById(R.id.ll);
        }



        public ImageView getImageView() {

            return mImageView;
        }

        public void setImageView(ImageView mImageView) {

            this.mImageView = mImageView;
        }
    }

    @Override
    public AnimalsAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {

        View v = LayoutInflater.from(mContext).inflate(R.layout.custom_view, parent, false);
        ViewHolder vh = new ViewHolder(v, (OnItemClickListener) mListener);
        return vh;
    }

    @Override
    public void onBindViewHolder(final ViewHolder holder, final int position) {

        final animal_item animalItem = mDataSet.get(position);

        holder.mImageView.setImageResource(animalItem.getImageResource());

        imageView = holder.mImageView;

    }

    @Override
    public int getItemCount() {

        return mDataSet.size();
    }

}

Custom view:

<?xml version="1.0" encoding="utf-8"?>
<androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:card_view="http://schemas.android.com/apk/res-auto"
    android:id="@+id/card_view"
    android:layout_width="123dp"
    android:layout_height="123dp"
    card_view:cardElevation="0dp"
    card_view:cardMaxElevation="0dp"
    card_view:contentPadding="0dp">

    <RelativeLayout
        android:id="@+id/ll"
        android:layout_width="110dp"
        android:layout_height="110dp"
        android:padding="0dp"
        android:orientation="horizontal">

        <ImageButton
            android:id="@+id/tv"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_gravity="center"
            android:layout_margin="0dp"
            android:gravity="center"
            android:padding="0dp"
            android:textColor="#000"
            android:textSize="25dp"
            android:textStyle="bold"
            />


     <com.google.android.material.floatingactionbutton.FloatingActionButton
            android:id="@+id/floatingActionButton"
            android:layout_width="25dp"
            android:layout_height="25dp"
            android:layout_alignParentStart="true"
            android:layout_alignParentLeft="true"
            android:layout_alignParentTop="true"
            android:layout_marginStart="95dp"
            android:layout_marginLeft="95dp"
            android:layout_marginTop="96dp"
            android:layout_weight="1"
            android:clickable="true"
            android:background="@drawable/image_background_base"/>

    </RelativeLayout>



</androidx.cardview.widget.CardView>

Styles:

<resources>

    <style name="AppTheme" parent="@style/Theme.AppCompat.Light">">

        <item name="colorPrimary">@color/colorPrimary</item>
        <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
        <item name="colorAccent">@color/colorAccent</item>
    </style>

</resources>

Manifest:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.imagegridactivity">

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".PickImageActivity"></activity>
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

Gradle:

apply plugin: 'com.android.application'

android {
    compileSdkVersion 29
    buildToolsVersion "29.0.2"

    defaultConfig {
        applicationId "com.example.imagegridactivity"
        minSdkVersion 16
        targetSdkVersion 29
        versionCode 1
        versionName "1.0"

        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
    }

    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }

}

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])

    implementation 'androidx.appcompat:appcompat:1.1.0'
    implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
    testImplementation 'junit:junit:4.12'
    androidTestImplementation 'androidx.test.ext:junit:1.1.1'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
    implementation 'androidx.recyclerview:recyclerview:1.1.0'
    implementation 'androidx.recyclerview:recyclerview-selection:1.1.0-rc01'
    implementation "androidx.cardview:cardview:1.0.0"
    implementation 'com.github.bumptech.glide:glide:4.11.0'
    annotationProcessor 'com.github.bumptech.glide:compiler:4.11.0'
    implementation 'com.google.android.material:material:1.1.0'

}

Main Activity:

public class MainActivity extends AppCompatActivity {


    private Context mContext;

    //RelativeLayout mRelativeLayout;
    private RecyclerView mRecyclerView;
    private AnimalsAdapter mAdapter;
    private RecyclerView.LayoutManager mLayoutManager;
    private ArrayList<animal_item> arrayList;
    private Uri imageUri;

    private int imagePosition;

    @Override
    protected void onCreate(Bundle savedInstanceState) {

        requestWindowFeature(Window.FEATURE_ACTION_BAR);
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);


        mContext = getApplicationContext();

        //mRelativeLayout = findViewById(R.id.rl);
        mRecyclerView = findViewById(R.id.recycler_view);

        final int[] imageArray = new int[9];

        for (int i = 0; i < imageArray.length; i++) {

            imageArray[i] = R.drawable.image_background_base;

        }

        arrayList = new ArrayList<>();

        for (int i = 0; i < imageArray.length; i++) {

            int image = imageArray[i];
            arrayList.add(new animal_item(image));

        }

        mLayoutManager = new GridLayoutManager(mContext, 3);
        mRecyclerView.setLayoutManager(mLayoutManager);
        mAdapter = new AnimalsAdapter(mContext, arrayList);
        mRecyclerView.setAdapter(mAdapter);

        mAdapter.setOnItemClickListener(new AnimalsAdapter.OnItemClickListener() {
            @Override
            public void onItemClick(int position) {

                Intent intent = new Intent(Intent.ACTION_PICK);
                intent.setType("image/*");
                intent.setAction(Intent.ACTION_GET_CONTENT);
                startActivityForResult(intent, 1);


                imagePosition = position;
            }
        });

        ItemTouchHelper helper = new ItemTouchHelper(new ItemTouchHelper.SimpleCallback(ItemTouchHelper.UP | ItemTouchHelper.DOWN | ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT, 0) {

            final ArrayList aL = new ArrayList<>();

            @Override
            public boolean onMove(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder dragged, @NonNull RecyclerView.ViewHolder target) {

                int position_dragged = dragged.getAdapterPosition();
                int position_target = target.getAdapterPosition();

                Collections.swap(arrayList, position_dragged, position_target);
                mAdapter.notifyItemMoved(position_dragged, position_target);
                //Collections.copy(mQuestion11List, aL);

                return false;
            }

            @Override
            public void onSwiped(@NonNull RecyclerView.ViewHolder viewHolder, int direction) {

            }
        });

        helper.attachToRecyclerView(mRecyclerView);

    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
        super.onActivityResult(requestCode, resultCode, data);

        imageUri = data.getData();

        //mAdapter.getDataSet().get(imagePosition).setImageResource();

        mLayoutManager.findViewByPosition(imagePosition).findViewById(R.id.tv);

        Glide.with(MainActivity.this).load(imageUri).centerCrop().into((ImageView) mLayoutManager.findViewByPosition(imagePosition).findViewById(R.id.tv));

    }
}

Main Activity XML:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/rl"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#c2dbfd"
    tools:context=".MainActivity">


    <androidx.recyclerview.widget.RecyclerView

        android:id="@+id/recycler_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        >

    </androidx.recyclerview.widget.RecyclerView>



</LinearLayout>

Solution

  • Caused by: java.lang.IllegalArgumentException: 
    The style on this component requires your app theme to be Theme.AppCompat (or a descendant).
    

    There is an issue with the context used to instantiate the Adapter. You need to pass in the Activity, not an ApplicationContext.
    The application context doesn't have your app theme.

    In your Activity change

    mContext = getApplicationContext();
    mAdapter = new AnimalsAdapter(mContext, arrayList);
    

    to

    mAdapter = new AnimalsAdapter(this, arrayList);
    

    Also pay attention since with the Material Components 1.1.0 your app theme should inherit from a Material Components theme.