'How do I add API data to a fragment's recycler view using query text listener to call the GET query

I created a requestManager class

    package com.example.pantry;

import android.content.Context;

import com.example.pantry.models.apiResponse;

import java.util.List;

import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;
import retrofit2.http.GET;
import retrofit2.http.Query;

public class requestManager {

    Context context;
    Retrofit retrofit = new Retrofit.Builder()
            .baseUrl("https://api.spoonacular.com/")
            .addConverterFactory(GsonConverterFactory.create())
            .build();

    public requestManager(Context context){this.context = context;}

    public void getFoodNames(OnFetchDataListener listener, String query){

        callFoodApi CallFoods = retrofit.create(callFoodApi.class);
        Call<apiResponse> call = CallFoods.callFoods(context.getString(R.string.api_key), query, "5");
        call.enqueue(new Callback<apiResponse>() {
            @Override
            public void onResponse(Call<apiResponse> call, Response<apiResponse> response) {
                if(!response.isSuccessful()){
                    listener.didNotFetch(response.message());
                }
                listener.didFetch(response.body(), response.message());
            }

            @Override
            public void onFailure(Call<apiResponse> call, Throwable t) {
                listener.didNotFetch(t.getMessage());
            }
        });

    }

    private interface callFoodApi{
        @GET("food/ingredients/search")
        Call<apiResponse> callFoods(
                @Query("apiKey") String apiKey,
                @Query("query") String query,
                @Query("number") String number

        );
    }

}

and a FetchDataListener interface

package com.example.pantry;

public interface OnFetchDataListener<apiResponse> {
    void didFetch(apiResponse response, String message);
    void didNotFetch(String message);
}

and here is my fragment code

 RecyclerView recyclerView;
    addFoodAdapter adapter;
    requestManager manager;
    SearchView searchView;
    String foodNames;

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {

        View view = inflater.inflate(R.layout.fragment_add_food, container, false);

        searchView = view.findViewById(R.id.addFoodSearch);




        searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
            @Override
            public boolean onQueryTextSubmit(String query) {
                foodNames = query;
                manager.getFoodNames(listener, foodNames);
                Log.d("executed", "submitted");
                return true;
            }

            @Override
            public boolean onQueryTextChange(String newText) {
                return false;
            }
        });

        return view;
    }

    private final OnFetchDataListener<apiResponse> listener = new OnFetchDataListener<apiResponse>() {
        @Override
        public void didFetch(apiResponse apiResponse, String message) {
            recyclerView = recyclerView.findViewById(R.id.addFoodRecycler);
            recyclerView.setHasFixedSize(true);
            recyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
            adapter = new addFoodAdapter(apiResponse.results);
            recyclerView.setAdapter(adapter);
        }

        @Override
        public void didNotFetch(String message) {
            Toast.makeText(getContext(), message, Toast.LENGTH_SHORT).show();
        }
    };

The adapter

package com.example.pantry;

import android.content.Context;
import android.view.LayoutInflater;
import android.view.ViewGroup;

import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;

import com.example.pantry.models.Result;

import java.util.List;

public class addFoodAdapter extends RecyclerView.Adapter<addFoodViewHolder> {


    private List<Result> foodNames;

    public addFoodAdapter(List<Result> foodNames){
        this.foodNames = foodNames;
    }


    @NonNull
    @Override
    public addFoodViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        return new addFoodViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.add_food_row, parent, false));
    }

    @Override
    public void onBindViewHolder(@NonNull addFoodViewHolder holder, int position) {
            holder.foodName.setText(foodNames.get(position).getName());
    }

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

and the viewholder

package com.example.pantry;

import android.view.View;
import android.widget.TextView;

import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;

public class addFoodViewHolder extends RecyclerView.ViewHolder {

    TextView foodName;

    public addFoodViewHolder(@NonNull View itemView) {
        super(itemView);

        foodName = itemView.findViewById(R.id.addFoodItem);
    }
}

but when I try and run it, and I submit the search query the app crashes and I get an error response in the log

java.lang.NullPointerException: Attempt to invoke virtual method 'void com.example.pantry.requestManager.getFoodNames(com.example.pantry.OnFetchDataListener, java.lang.String)' on a null object reference

I've tried to solve it and figured out the crash and error only come when the search is submitted. I've only been doing this for a couple of months so still learning but I'm very lost, is it a fragments problem or am I just misunderstanding how fragments work? Any help would be greatly appreciated.



Solution 1:[1]

I didn't initalizee the manager

solved

@Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {

        v = inflater.inflate(R.layout.fragment_add_food, container, false);

        searchView = v.findViewById(R.id.addFoodSearch);

        *manager = new requestManager(getContext());*

        searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
            @Override
            public boolean onQueryTextSubmit(String query) {
                foodNames = query;
                manager.getFoodNames(listener, foodNames);
                return true;
            }

            @Override
            public boolean onQueryTextChange(String newText) {
                return false;
            }
        });

        return v;
    }

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Phil Morrison