Search code examples
androidandroid-fragmentsandroid-recyclerviewdependency-injectiondagger-2

How to call fragment function from RecyclerView.Adapter click for android application build using dagger2


Can someone suggest me the best way to call a fragment function from the RecyclerView without causing any memmory leaks

My fragment code is given below

    <androidx.constraintlayout.widget.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".ui.auth.AuthActivity">


   <com.google.android.exoplayer2.ui.PlayerView
    android:id="@+id/videoID"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@color/black"
    app:resize_mode="fill"
    app:controller_layout_id="@layout/player_control_view"
    app:layout_constraintBottom_toBottomOf="parent"
    app:layout_constraintLeft_toLeftOf="parent"
    app:layout_constraintRight_toRightOf="parent" />

    <androidx.recyclerview.widget.RecyclerView
    android:id="@+id/materialList"
    android:layout_width="0dp"
    android:layout_height="0dp"
    app:layout_constraintBottom_toBottomOf="parent"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintTop_toBottomOf="@id/videoID">

    </androidx.recyclerview.widget.RecyclerView>


</androidx.constraintlayout.widget.ConstraintLayout>

My recycler view layout is

<androidx.constraintlayout.widget.ConstraintLayout 
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical"
    android:padding="@dimen/_10sdp">

    <androidx.cardview.widget.CardView
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:cardBackgroundColor="@color/circle_color_light"
        app:layout_constraintVertical_bias="0.6">

        <TextView
            android:id="@+id/name"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text=""
        />

    </androidx.cardview.widget.CardView>
</androidx.constraintlayout.widget.ConstraintLayout>    

Please ignore any error on the above layouts since my issue lies on java code

My fragment code is given below

public class MaterialFragment extends DaggerFragment implements View.OnClickListener {

    SimpleExoPlayer player;
    PlayerView playerView;

    @Inject
    MaterialAdapter adapter;
    @Inject
    ViewModelProviderFactory providerFactory;

    @Override
    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {


        makeVideo("https://samplevideo.com/test.mp4");

        materialList = view.findViewById(R.id.materialList);
        GridLayoutManager gridLayoutManager = new GridLayoutManager(getActivity(),3,GridLayoutManager.VERTICAL,false);
        materialList.setLayoutManager(gridLayoutManager);
        materialList.setAdapter(adapter);
        // The above code succesfully load the grid view using recycler adapter(Code for adapter is given below)

    }

    public void makeVideo(){

        // Video loading code goes here  : Loads video on findViewById(R.id.videoID)
    }


}

Finally my Recycler Adapter view

public class MaterialAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
    private static final String TAG = "MaterialAdapter";
    private List<Material> materials = new ArrayList<>();
    private Context context;

    public MaterialAdapter(){
    }

    @NonNull
    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.material_grid_layout, parent, false);
        PlayerView playerView = ((Activity)parent.getContext()).getWindow().getDecorView().findViewById(R.id.matVideo);
        SimpleExoPlayer player = new SimpleExoPlayer.Builder(((Activity)parent.getContext()).getApplicationContext()).build();
        context   = parent.getContext();
        return new MaterialAdapter.MaterialViewHolder(view,parent.getContext(),playerView,player);
    }

    @Override
    public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
        ((MaterialAdapter.MaterialViewHolder)holder).bind(materials.get(position),context);
    }

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

    public void setMaterials(List<Material> materials){
        this.materials = materials;
        notifyDataSetChanged();
    }

    public class MaterialViewHolder extends RecyclerView.ViewHolder {
        TextView name,letter;
        public Context cxt;

        private  SimpleExoPlayer player;
        private  PlayerView playerView;

        public MaterialViewHolder(@NonNull View itemView, Context cxt, final PlayerView playerView, SimpleExoPlayer player) {

            super(itemView);
            this.cxt = cxt;
            this.playerView = playerView;
            this.player = player;
            name = itemView.findViewById(R.id.name);
            clayout = (ConstraintLayout) itemView.findViewById(R.id.card_layout);

            itemView.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                     // I need to change the video of the fragment on click of each block.
                     //The below code will work by implementing full makevideo function on this file 
                     //But I need the bes method without repeting this function and call the methods of he fragment by passing video url or setting view contents of the outer fragment
                    //makeVideo("https://samplevideo.com/test.mp4");  // Not think this is he best solution as I need fullscreen function also.

                    // How to trigger button click of fragment, eg full screen

                }
            });
        }

        

        public void bind(Material material, Context context){

            name.setText(material.getName());
        }

    }
}

Adapter is injected using module as given below

@Provides
static MaterialAdapter provideMaterialAdapter(){
    return new MaterialAdapter();
}

After referring, I got some suggestion by using my own interface as a bridge between adapter and fragment , But It didn't work may be my dagger is causing some injection error,

Can someone give me a best solution to get rid of this issue

Screenshot of my screen is given below enter image description here


Solution

  • Use this adapter = new MaterialAdapter(); in your fragment rather than injecting it. Just remove the @Inject annotation and add the above adapter creation statement in onViewCreated of your fragment. By this way your get more control on your adapter creation and you can pass an interface through the constructor.