简体   繁体   中英

How to build recyclerview with remote data after the data transfer from server thorugh API is complete

I have built a recyclerview inside a fragment. The data that is to be populated in the recyclerview is stored in remote server and is being parsed thorugh JSON.

I am using Retrofit to transfer data from server to the application. Note: I am beginner in Android development and using Retrofit for the first time by watching tutorials.

Until now I have understood the following, corret me if I am wrong As the Retrofit library uses another thread instead of main thread to get response from server, it take few seconds for the data to transfer completely but till that time the recyclerview is already built with an empty ArrayList.

So, my question here is, How to hold the recyclerView from being built until the data transfer is complete? OR How to update the empty ArrayList after the data transfer is complete and populate the recyclerview from that data? OR You can tell me whatever is the best and most efficient way to achieve the desired result.

I already tried adapter.notifyDataSetChanged() , but either I didn't use it at correct place, or I didn't use it the correct way as it didn't work. You can see it in the code.

Library Fragment:-

package com.diginfoexpert.mybooks.Fragment;

import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Toast;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;

import com.diginfoexpert.mybooks.Activity.CategoryActvity;
import com.diginfoexpert.mybooks.Adapter.LibraryCategoriesCardAdapter;
import com.diginfoexpert.mybooks.Model.Category;
import com.diginfoexpert.mybooks.Model.LibraryAPI;
import com.diginfoexpert.mybooks.Model.LibraryCategories;
import com.diginfoexpert.mybooks.R;

import java.util.ArrayList;

import Controllers.JSONApiHolder;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
import retrofit2.Retrofit;
import retrofit2.Retrofit.Builder;
import retrofit2.converter.gson.GsonConverterFactory;

public class LibraryFragment extends Fragment implements LibraryCategoriesCardAdapter.CategoryClickListener {

    private JSONApiHolder jsonApiHolder;
    ArrayList<Category> categories = new ArrayList<>();
    LibraryCategoriesCardAdapter adapter;
    RecyclerView recyclerView;


    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.fragment_library, container, false);
        Log.d("RETROFIT", "onCreateView: Library Fragment Started");

        recyclerView = view.findViewById(R.id.library_category_recycler_view);

        Retrofit retrofit = new Retrofit.Builder()
                .baseUrl("http://myurl.in/")
                .addConverterFactory(GsonConverterFactory.create())
                .build();

        jsonApiHolder = retrofit.create(JSONApiHolder.class);

        getCategories();

        buildRecyclerView();

        return view;
    }

    private void buildRecyclerView() {
        LinearLayoutManager linearLayoutManager = new LinearLayoutManager(getActivity());
        adapter = new LibraryCategoriesCardAdapter(buildCategoryList(),this);
        recyclerView.setLayoutManager(linearLayoutManager);
        recyclerView.setAdapter(adapter);
    }

    private void getCategories() {
        Call<LibraryAPI> call = jsonApiHolder.getLibrary();

        call.enqueue(new Callback<LibraryAPI>() {
            @Override
            public void onResponse(Call<LibraryAPI> call, Response<LibraryAPI> response) {
                if(!response.isSuccessful()){
                    Log.d("RETROFIT", "onResponse: callback failed");
                    return;
                }

                else{
                    Log.d("RETROFIT", "onResponse: callback successful");
                    LibraryAPI libraryAPI = response.body();
                    categories = libraryAPI.getCategories();
                    adapter.notifyDataSetChanged();

                    for (Category category :categories){
                        Log.d("RETROFIT", "onResponse: "+category.getTitle());
                    }

                }
            }

            @Override
            public void onFailure(Call<LibraryAPI> call, Throwable t) {
                Log.d("RETROFIT", "onFailure: response failed : " +t.getMessage());
            }
        });
    }

    private ArrayList<Category> buildCategoryList() {
        ArrayList<Category> mList = new ArrayList<>();
//        mList.add(new Category("Art"));
//        mList.add(new Category("Action"));
//        mList.add(new Category("Thrill"));
//        mList.add(new Category("Fiction"));
//        mList.add(new Category("Romance"));
//        mList.add(new Category("Crime"));
//        mList.add(new Category("Classical"));
//        mList.add(new Category("Financial"));
//        mList.add(new Category("Business"));
        Log.d("RETROFIT", "Size of categories ArrayList "+categories.size());
        return categories;
    }

    @Override
    public void onCategoryClick() {
        Intent intent = new Intent(getActivity(), CategoryActvity.class);
        startActivity(intent);
    }
}

Debug Log:-

2020-03-25 14:26:37.536 1703-1703/com.myurl.mybooks D/RETROFIT: onCreateView: Library Fragment Started
2020-03-25 14:26:37.630 1703-1703/com.myurl.mybooks D/RETROFIT: Size of categories ArrayList 0
2020-03-25 14:26:42.171 1703-1703/com.myurl.mybooks D/RETROFIT: onResponse: callback successful
2020-03-25 14:26:42.172 1703-1703/com.myurl.mybooks D/RETROFIT: onResponse: MPPSC Mains Syllabus
2020-03-25 14:26:42.172 1703-1703/com.myurl.mybooks D/RETROFIT: onResponse: MPPSC MAINS PAPER 1 PART "A" History
2020-03-25 14:26:42.172 1703-1703/com.myurl.mybooks D/RETROFIT: onResponse: MPPSC MAINS PAPER 1 PART "B" Geography
2020-03-25 14:26:42.172 1703-1703/com.myurl.mybooks D/RETROFIT: onResponse: MPPSC MAINS PAPER-2 (PART "A") Polity
2020-03-25 14:26:42.172 1703-1703/com.myurl.mybooks D/RETROFIT: onResponse: MPPSC MAINS PAPER 2 (PART "B") Economics & Social
2020-03-25 14:26:42.172 1703-1703/com.myurl.mybooks D/RETROFIT: onResponse: MPPSC MAINS PAPER 3 Science
2020-03-25 14:26:42.172 1703-1703/com.myurl.mybooks D/RETROFIT: onResponse: MPPSC MAINS PAPER 4 Ethics
2020-03-25 14:26:42.173 1703-1703/com.myurl.mybooks D/RETROFIT: onResponse: MPPSC HINDI

Here is your modified code portion

public void onResponse(Call<LibraryAPI> call, Response<LibraryAPI> response) {
                if(!response.isSuccessful()){
                    Log.d("RETROFIT", "onResponse: callback failed");
                    return;
                }

                else{
                    Log.d("RETROFIT", "onResponse: callback successful");
                    LibraryAPI libraryAPI = response.body();
                    categories = libraryAPI.getCategories();
                    adapter.notifyDataSetChanged();

                    for (Category category :categories){
                      categories.add(category) // Added by me  
                      Log.d("RETROFIT", "onResponse: "+category.getTitle());
                    }
                    adapter.notifyDataSetChanged() // Added by me
                }
            }

I found the way out after sometime. I was building the recycler view in main method, which is the main thread. When we enque network requests in retrofit, it works on a different thread and hence till the data transfer completes, the recycler view has already been built in the main thread with no data available.

So instead of building the recycler view in main thread, I created a method to build it. And I called the method after the application has got response from the server.

private void buildRecyclerView() {
        LinearLayoutManager linearLayoutManager = new LinearLayoutManager(getActivity());
        adapter = new LibraryCategoriesCardAdapter(buildCategoryList(),this);
        recyclerView.setLayoutManager(linearLayoutManager);
        recyclerView.setAdapter(adapter);
    }



private void getCategories() {
    Call<LibraryAPI> call = jsonApiHolder.getLibrary();

    call.enqueue(new Callback<LibraryAPI>() {
        @Override
        public void onResponse(Call<LibraryAPI> call, Response<LibraryAPI> response) {
            if(!response.isSuccessful()){
                Log.d("RETROFIT", "onResponse: callback failed");
                return;
            }

            else{
                Log.d("RETROFIT", "onResponse: callback successful");
                LibraryAPI libraryAPI = response.body();
                categories = libraryAPI.getCategories();
                buildRecyclerView();

                for (Category category :categories){
                    Log.d("RETROFIT", "onResponse: "+category.getTitle());
                }

            }
        }

        @Override
        public void onFailure(Call<LibraryAPI> call, Throwable t) {
            Log.d("RETROFIT", "onFailure: response failed : " +t.getMessage());
        }
    });
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM