Problem with threads on Android

Asked

Viewed 82 times

0

I’m trying to get values from a json and play in a recycleview using OkHttp, he is taking the values and playing in the list, no errors, but I am not able to pass these values to the Adapter, the list is reaching null on fragment, I’m pretty sure the problem is with thread, probably the main thread is taking the value of the list before the callback set...

How to solve?

Class where I take the json values: (I think the problem is in the method sendGetRecipes)

public class HttpRequest {

    private List<Recipes> recipesList;

    public void sendGetRecipes(String url) {

        OkHttpClient client = new OkHttpClient();
        Request request = new Request.Builder().url(url).build();

        client.newCall(request).enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                call.cancel();
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                String strResponse = response.body().string();
                setRecipesList(strResponse);
                Log.d("HTTP", "PASSOU!!!!!");
                Log.d("HTTP", strResponse);
            }
        });
    }

    public void setRecipesList(String response) {
        recipesList = new ArrayList<>();

        List<Ingredients> ingredientsList = new ArrayList<>();
        List<Steps> stepsList = new ArrayList<>();

        if (response != null) {
            try {

                JSONArray jsonArray = new JSONArray(response);

                for (int i = 0; i < jsonArray.length(); i++) {
                    JSONObject jsonObject = jsonArray.getJSONObject(i);
                    Recipes recipes = new Recipes();
                    recipes.setId(jsonObject.getInt("id"));
                    recipes.setName(jsonObject.getString("name"));
                    recipes.setImage(jsonObject.getString("image"));
                    recipes.setServings(jsonObject.getInt("servings"));

                    JSONArray ingrJsonArray = jsonObject.getJSONArray("ingredients");
                    for (int j = 0; j < ingrJsonArray.length(); j++) {
                        JSONObject ingrJsonObject = ingrJsonArray.getJSONObject(j);
                        Ingredients ingredients = new Ingredients();
                        ingredients.setIngredient(ingrJsonObject.getString("ingredient"));
                        ingredients.setMeasure(ingrJsonObject.getString("measure"));
                        ingredients.setQuantity(ingrJsonObject.getInt("quantity"));

                        ingredientsList.add(ingredients);
                        //Log.d("ARRAY-JSON-INGR", ingrJsonObject.getString("ingredient"));

                    }

                    JSONArray stepsJsonArray = jsonObject.getJSONArray("steps");
                    for (int j = 0; j < stepsJsonArray.length(); j++) {
                        JSONObject stepsJsonObject = stepsJsonArray.getJSONObject(j);
                        Steps steps = new Steps();
                        steps.setId(stepsJsonObject.getInt("id"));
                        steps.setDescription(stepsJsonObject.getString("description"));
                        steps.setShortDescription(stepsJsonObject.getString("shortDescription"));
                        steps.setVideoUrl(stepsJsonObject.getString("videoUrl"));
                        steps.setThumbnailUrl(stepsJsonObject.getString("thumbnailUrl"));

                        stepsList.add(steps);
                        //Log.d("ARRAY-JSON-INGR", ingrJsonObject.getString("ingredient"));

                    }

                    recipes.setIngredientsList(ingredientsList);
                    recipes.setStepsList(stepsList);

                    recipesList.add(recipes);
                }

            } catch (JSONException e) {
                e.printStackTrace();
            }
        }
    }

    public List<Recipes> getRecipesList() {
        return recipesList;
    }
}

Fragment (commented on where he tries to get the list)

public class MainFragment extends Fragment {

    private static final String TAG = MainFragment.class.getSimpleName();
    private RecyclerView recipesRecycleView;
    private List<Recipes> recipesList;

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.fragment_main, container, false);

        recipesRecycleView = (RecyclerView) view.findViewById(R.id.recipesRecycleView);

        LinearLayoutManager layoutManager = new LinearLayoutManager(getActivity());
        layoutManager.setOrientation(LinearLayoutManager.VERTICAL);
        recipesRecycleView.setLayoutManager(layoutManager);

        HttpRequest httpRequest = new HttpRequest();
        httpRequest.setRecipesList(Recipes.RECIPES_URL);
        recipesList = httpRequest.getRecipesList();  // <------------- AQUI

        RecipesAdapter recipesAdapter = new RecipesAdapter(getActivity(), recipesList);
        recipesRecycleView.setAdapter(recipesAdapter);


        return view;
    }

}

I didn’t post the Adapter code because the problem isn’t there

1 answer

1


You can create an interface in your Httprequest class with a callback method that will work with the list of obtained recipes.

public interface OnRecipesReady {
    public void getRecipes(List<Recipes> recipes);
}

Creates an Handler variable to use the interface in this same class and a constructor to receive a reference from your Fragment:

private OnRecipesReady handler;

public HttpRequest(OnRecipesReady h){
   handler = h;
}

In the setRecipesList() method after for and before catch, add this line:

handler.getRecipes(recipesList);

In your Fragment implement the callback interface and method and pass the creation of the Adapter and association in Recyclerview to the Adapter:

public class MainFragment extends Fragment implements OnRecipesReady {

 ...

   @Overide
   public void getRecipes(List<Recipes> recipes){
        recipesAdapter = new RecipesAdapter(getActivity(), recipes);
        recipesRecycleView.setAdapter(recipesAdapter); 
   }
}

Finally, in Oncreateview change the construction to:

HttpRequest httpRequest = new HttpRequest(this);

fix request startup by calling the method:

httpRequest.sendGetRecipes(Recipes.RECIPES_URL);

and remove all following lines until "Return view"

  • It didn’t work, but maybe it’s because I don’t understand what you mean... I don’t understand why you’re calling getRecipes inside setRecipesList

  • getRecipes() is the callback of the interface I created. I placed inside the setRecipesList, at the end of the method, to pass the list of recipes generated nomesmo to Handler that is implementing the interface, in this case your Fragment. The idea is that your Fragment awaits the completion of sendGetRecipes and only update the list Adapter when the list is ready, the problem, by better analyzing the code now, is that it is not being called anywhere in the code. I confused the name of this method with setRecipesList. I’ll take a closer look at the code later and edit my answer.

  • This error "android.view.Viewrootimpl$Calledfromwrongthreadexception: Only the original thread that created a view Hierarchy can touch its views."

  • Yes, as I confused the name of the methods and answered in a hurry, it won’t even work. Later I see calmly, because I am at work.

  • I actually noticed this and changed the name of the method to getRecipesList, now I solved this problem by setting this Adapter in Uithread (runOnUiThread), I still didn’t understand 100% of what you did, my java is really weak, I didn’t know I could use interface like this, and tb a little confused with threads on Android, but I’m giving a read here... Updates your answer with the name of the true method I accept it here

  • Dude, I edited my answer, but basically all that was missing was correcting the httprequest call by changing the name of the method. All the rest of the suggestions I’ve made I believe are correct.

Show 1 more comment

Browser other questions tagged

You are not signed in. Login or sign up in order to post.