Search code examples
androidretrofitrx-javaandroid-roomandroid-mvvm

Fetching data with retrofit2 and saving in room


I am using retrofit2 for fetching data from the server and after fetching saving data in room database and then showing in recycler view. But it is no displayed (my data what I get using retrofit). I try display it in my fragment. In file ...data/data/databese/source.db these data are saved. I see it. So, that means that my code works. But I can't understand why it is not displayed. my database class:

@Database(entities = {Source.class}, exportSchema = false, version = 1)
public abstract class SourceDatabase extends RoomDatabase {

    private static final String DB_NAME = "source.db";
    public abstract SourceDao sourceDao();
    private static SourceDatabase instance;

    public static SourceDatabase getInstance(Context context) {
        if (instance == null) {
            instance =buildDatabaseInstance(context);
        }
        return instance;
    }
    private static SourceDatabase buildDatabaseInstance(Context context) {
        return Room.databaseBuilder(context,
                SourceDatabase.class,
                DB_NAME).build();
    }
}

repository:

public class DataBaseRepository {
    private static DataBaseRepository  dataBaseRepository;
    private SourceDao sourceDao;
    private LiveData<List<Source>> allSourcestoDb;
    private Context context;

    public static DataBaseRepository getInstance(Context context) {
        if (dataBaseRepository == null) {
            dataBaseRepository = new DataBaseRepository(context);
        }
        return dataBaseRepository;
    }

    public DataBaseRepository(Context context) {
        this.context = context;
        SourceDatabase db = SourceDatabase.getInstance(context);
        sourceDao = db.sourceDao();
        allSourcestoDb = sourceDao.getSources();
    }

    public void getSourceListTodb(String key) {//отправка данных в LiveData
        RestClient restClient = RestClient.getInstance();
        restClient.startRetrofit();

        restClient.getServerApi().getNews(key).enqueue(new Callback<News>() {
            @Override
            public void onResponse(Call<News> call, Response<News> response) {

                Completable.fromAction(new Action (){
                    @Override
                    public void run() throws Exception {
                        if (response.body() != null) {

                            List<Source> list = response.body().getSources();
                            sourceDao.insert(list);
                        }
                    }
                }).subscribeOn(Schedulers.io())
                        .observeOn(AndroidSchedulers.mainThread())
                        .subscribe(new CompletableObserver() {
                            @Override
                            public void onSubscribe(Disposable d) {

                            }

                            @Override
                            public void onComplete() {
                            }

                            @Override
                            public void onError(Throwable e) {

                            }
                        });
            }

            @Override
            public void onFailure(Call<News> call, Throwable t) {
                Log.d("error", "Can't parse data " + t);
            }
        });
    }

    public LiveData<List<Source>> getAllSourcestoDb() {
        return allSourcestoDb;
    }
}

dao:

@Dao
public interface SourceDao {
    @Insert(onConflict = OnConflictStrategy.REPLACE)
    void insert(List<Source> sources);

    @Query("SELECT * FROM source")
    LiveData<List<Source>> getSources();
}

viewModel:

public class SourceViewModel extends AndroidViewModel {
    private DataBaseRepository dataBaseRepository;
    private LiveData<List<Source>> allSources; //for db

    public SourceViewModel(@NonNull Application application) {
        super(application);
        dataBaseRepository =DataBaseRepository.getInstance(application); //for db
        allSources = dataBaseRepository.getAllSourcestoDb();
    }

    public LiveData<List<Source>> getAllSources() {
        return allSources;
    }
}

and fragment:

public class SavedDataFragment extends Fragment {
    private SourceViewModel sourceViewModel;
    private DataBaseRepository dataBaseRepository;
    private RecyclerView recyclerView;
    private List<Source> sourceList;
    private SavedDataAdapter adapter;

    public SavedDataFragment() {
    }

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

        DataSharedPreference sharedPreference = DataSharedPreference.getSPInstance();
        String api_key = sharedPreference.loadText(getActivity());

        dataBaseRepository = new DataBaseRepository(getActivity());
        sourceViewModel = ViewModelProviders.of(this).get(SourceViewModel.class);

        recyclerView = view.findViewById(R.id.recyclerViewSavedFragment);
        recyclerView.setHasFixedSize(true);
        recyclerView.setLayoutManager(new LinearLayoutManager(view.getContext()));

        sourceList = new ArrayList<>();

        adapter = new SavedDataAdapter(getActivity(), sourceList);
        recyclerView.setAdapter(adapter);

        sourceViewModel.getAllSources().observe(this, new Observer<List<Source>>() {
            @Override
            public void onChanged(List<Source> sources) {
              adapter.setSourceList(sourceList);
            }
        });
        dataBaseRepository.getSourceListTodb(api_key);
        return view;
    }

}

adapter:

public class SavedDataAdapter extends RecyclerView.Adapter<SavedDataAdapter.SourceSavedViewHolder> {
    private LayoutInflater inflater;
    private List<Source> sources;

    public SavedDataAdapter(Context context, List<Source> sources) {
        this.sources = sources;
        this.inflater = LayoutInflater.from(context);
    }

    @NonNull
    @Override
    public SavedDataAdapter.SourceSavedViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        View view = inflater.inflate(R.layout.saved_item, parent, false);
        return new SourceSavedViewHolder(view);
    }

    @Override
    public void onBindViewHolder(@NonNull final SavedDataAdapter.SourceSavedViewHolder holder, int position) {
        final Source source = sources.get(position);
        holder.sourceId.setText(source.getId());
        holder.sourceName.setText(source.getName());
        holder.sourceDescription.setText(source.getDescription());
        holder.sourceURL.setText(source.getUrl());
        holder.sourceCategory.setText(source.getCategory());
        holder.sourceLanguage.setText(source.getLanguage());
        holder.sourceCountry.setText(source.getCountry());
    }

    @Override
    public int getItemCount() {
        return sources.size();
    }
    public void setSourceList(List<Source> sources) {
        this.sources = sources;
        notifyDataSetChanged();
    }

    public static class SourceSavedViewHolder extends RecyclerView.ViewHolder {
        TextView sourceName, sourceId, sourceDescription, sourceURL, sourceCategory, sourceLanguage, sourceCountry;

        public SourceSavedViewHolder(View view) {
            super(view);

            sourceName = view.findViewById(R.id.sourceName);
            sourceId = view.findViewById(R.id.sourceIdItem);
            sourceDescription = view.findViewById(R.id.sourceDescription);
            sourceURL = view.findViewById(R.id.sourceURL);
            sourceCategory = view.findViewById(R.id.sourceCategory);
            sourceLanguage = view.findViewById(R.id.sourceLanguage);
            sourceCountry = view.findViewById(R.id.sourceCountry);
        }
    }
}

Solution

  • In your Fragment inside onChanged, you're setting adapter.setSourceList(sourceList) where sourceList is an empty arrayList. You should instead setSourceList to sources which is the updated list passed as an argument to onChanged method

    That is :-

    sourceViewModel.getAllSources().observe(this, new Observer<List<Source>>() {
                @Override
                public void onChanged(List<Source> sources) {
                  adapter.setSourceList(sources); // sources and not sourceList
                }
            });
    

    Also there are few more things that should be taken care of. For ex- in your observe method, you have passed this as first argument which is wrong when using Fragments as it may causes memory leaks. Instead you should pass viewLifeOwner.. More can found on this link Use viewLifecycleOwner as the LifecycleOwner