0

I'm trying to use JSON to insert images into a recycler view. It seems like the information is being read, but it never stops and eventually gives me an out of memory exception. The trace says Background sticky concurrent mark sweep GC freed over and over for about 2 minutes then throws the error. The real error here isn't clear to me or I would give more information, please ask questions for clarification if you need it.

Retrofit retrofit = new Retrofit.Builder()
                .baseUrl("https://dog.ceo/api/breeds/image/random/")
                .addConverterFactory(GsonConverterFactory.create())
                .build();
        JsonAnimalApi jsonAnimalApi = retrofit.create(JsonAnimalApi.class);
        Call<Animal> call = jsonAnimalApi.getAnimals();
        System.out.println("Here");
        call.enqueue(new Callback<Animal>() {
            @Override
            public void onResponse(Call<Animal> call, Response<Animal> response) {
                System.out.println("HERE");
                if (response.isSuccessful()) {
                    while (names.size() < 50) names.add(response.body().getPicture());
                    tvResponse.setText("Code: " + response.code());
                    return;
                }
RecyclerView recyclerView = rootView.findViewById(R.id.recycler_view);
        RecyclerViewAdapter rAdapter = new RecyclerViewAdapter(names, this);
        recyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
        recyclerView.setAdapter(rAdapter);
public interface JsonAnimalApi {
    @GET("animals")
    Call<Animal> getAnimals();
}
public class Animal {
    private ImageView  picture;
    private String status;
    private String message;

    public ImageView getPicture() {
        return picture;
    }

    public String getStatus() {
        return status;
    }

    public String getMessage() {
        return message;
    }
}
public class RecyclerViewAdapter extends RecyclerView.Adapter<RecyclerViewAdapter.ViewHolder> {
    private ArrayList<ImageView> mAnimalNames;
    private OnNoteListener mOnNote;
    public RecyclerViewAdapter(ArrayList<ImageView> mAnimalNames, OnNoteListener mOnNote) {
        this.mAnimalNames = mAnimalNames;
        this.mOnNote = mOnNote;
    }
    @NonNull
    @Override
    public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.layout_listitem, parent, false);
        ViewHolder holder = new ViewHolder(view, mOnNote);
        return holder;
    }
    @Override
    public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
        Log.d(TAG, "onBindViewHolder: ");
    }
    @Override
    public int getItemCount() {
        return mAnimalNames.size();
    }

    public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
        ImageView animalName;
        OnNoteListener onNote;
        public ViewHolder(@NonNull View itemView, OnNoteListener onNote) {
            super(itemView);
            animalName = itemView.findViewById(R.id.animal_name);
            this.onNote = onNote;

            itemView.setOnClickListener(this);
        }

        @Override
        public void onClick(View view) {
            mOnNote.onNoteClick(getAdapterPosition(), mAnimalNames);
        }
    }

    public interface OnNoteListener {
        void onNoteClick(int pos, ArrayList<ImageView> names);
    }
}
5
  • share some code where how you attach adapter into recyclerview Commented Apr 24, 2020 at 17:25
  • I have done as you asked, under the JSON call. Commented Apr 24, 2020 at 17:37
  • oh my god I thought that was a fake API URL, that is the best API I've ever seen Commented Apr 24, 2020 at 17:38
  • add your json data. Commented Apr 24, 2020 at 17:41
  • The JSON data looks something like this (according to the API site) : { "message": "images.dog.ceo/breeds/hound-english/n02089973_255.jpg", "status": "success" } Commented Apr 24, 2020 at 17:45

2 Answers 2

1

A couple problems I see: it looks like you're trying to use Gson to fill in an ImageView directly:

public class Animal {
    private ImageView  picture;

This isn't going to work, because whatever format the picture attribute is in is not compatible with ImageView's internal implementation (and that internal implementation could change without warning).

But you've got a more fundamental issue in your onResponse - your conditional is reversed:

if (!response.isSuccessful()) {

You're only adding the items if the response is not successful, rather than if it is.

Beyond that, depending on the rest of your code, you may need to use one of the notify... methods on your adapter to inform the RecyclerView about the new items.

Sign up to request clarification or add additional context in comments.

6 Comments

Wow thank you, can't believe I didn't notice that. I fixed the conditional, but now I've figured out by adding tags that the code doesn't execute that far even. It only gets to Call<Animal> call = jsonAnimalApi.getAnimals().
Hmmmm....like the "Here" doesn't print? The code looks correct to me...you're able to see similar log statements print before it?
Exactly. I put the "Here" in several locations above and it prints out, but after that statement it doesn't.
and it's not crashing or anything? There aren't any exceptions in the logcat?
It will throw an OutOfMemory exception after a few minutes of being suspended and crash, but no others.
|
0

For some reason you include an imageView in your Animal class, so remove it:

public class Animal {

private String status;
private String message;



public String getStatus() {
    return status;
}

public String getMessage() {
    return message;
}
 }

The while loop

 //names must be of type string

while (names.size() < 50) names.add(response.body().getMessage());

And mAnimalNames in the adapter must of type String

private ArrayList<String> mAnimalNames;

//constructor
public RecyclerViewAdapter(ArrayList<String> mAnimalNames,.......... 

Also not sure why use a while loop, maybe trying to fill the list:

Do this:

 @Override
public void onResponse(Call<Animal> call, Response<Animal> response) {

if(response.isSuccessful()){
for(int i=0 ; i<50 ; i++){
//names has to be of type String
names.add(response.body().getMessage())
}
RecyclerView recyclerView = rootView.findViewById(R.id.recycler_view);
RecyclerViewAdapter rAdapter = new RecyclerViewAdapter(names, this);
recyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
recyclerView.setAdapter(rAdapter);
}

3 Comments

I want it to put pictures into the recycler view though, can I still do this?
imageView is not a data you add from JSON, what I did for you above helps you pass the urls to the adapter as a string, then in the adapter you use the strings to display images in an imageview that is part of the recyclerview item.
the urls in the json are what you want to use to display images in the adpater.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.