Вернуть данные из метода обратного вызова в репозиторий - PullRequest
0 голосов
/ 06 августа 2020

Я использую шаблон репозитория в моем Android Архитектура приложения . Мой репозиторий с именем NewsRepository извлекает данные из API используя Retrofit , а затем сохраните данные в Database , используя Room liberary. Вот мой файл NewsRepository .

public class NewsRepository {

private final String TAG = NewsRepository.class.getSimpleName();
//Creating a NewsApiService instance
private NewsApiService newsApiService;
//Creating a NewsViewModel instance
private NewsViewModel newsViewModel;
//Creating an array
private String fragment[];
//Creating an Executor instance
private Executor DBExecutor;
//Creating a Retrofit instance
private Retrofit retrofit = null;
//Creating a NewsDatabase instance
private NewsDatabase mNewsDatabase;
//A reference to the (@link NewsDao} class
private NewsDao mNewsDao;
//Creating a MainActivity instance
private MainActivity mainActivity ;
//Creating an Observable instance
private Observable<News> DBObservable;
//Creating a Subscriber instance
private Subscriber<News> DBOSubscriber;

public NewsRepository(@NonNull Application application){
    //Initializing MainActivity instance
    mainActivity = new MainActivity();
    //Getting the retrofit instance
    retrofit = getRetrofitInstance();
    //Configure the NewsApiService class with retrofit to receive the response
    newsApiService = retrofit.create(NewsApiService.class);
    //Retrieving the Database instance
    mNewsDatabase = NewsDatabase.getDatabase(application);
    //Retrieving the NewDao instance
    mNewsDao = mNewsDatabase.newsDao();
    //Creating a string array of fragment titles
    fragment = new String[] {CATEGORY_LATEST, CATEGORY_BUSINESS, CATEGORY_SCIENCE, 
   CATEGORY_TECHNOLOGY,
            CATEGORY_HEALTH, CATEGORY_SPORTS, CATEGORY_ENTERTAINMENT};
}

/**
 * This method will setup the data for the view model
 */
public void setupData(int category){
    Log.i(TAG, "Setting up the data");

    if (category > 6) {
        MainActivity.loadingState.setValue(MainActivity.LoadingState.LOADING_COMPLETE);;
    }else {
        connectGetAndPersistData(category);
    }
 }

/**
 * Utility to setup Observable and Subscriber
 */
private List<News> getCategoricalNews(String category){
    
mNewsDao.getCategoricalNews(category).subscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe(new Observer<List<News>>(){

                @Override
                public void onSubscribe(Disposable d) {

                }

                @Override
                public void onNext(List<News> news) {

                }

                @Override
                public void onError(Throwable e) {

                }

                @Override
                public void onComplete() {

                }
            }
}

/**
 * This utility will establish the connection with the server and retrieve the data from the specified URL.
 * @param category
 */
private void connectGetAndPersistData(int category){

    Log.i(TAG, "Connecting with the URL......");
    Call<NewsApiResponse> call;
    //Call appropriate methods according to the category
    if (fragment[category].equals(CATEGORY_LATEST))
        call = newsApiService.getTopHeadlines(country, apiKey);
    else
        call = newsApiService.getTopHeadlines(fragment[category], country, apiKey);

    Log.i(TAG, "Connecting with " + category + " headlines URL");

    call.enqueue(new Callback<NewsApiResponse>() {
        @Override
        public void onResponse(Call<NewsApiResponse> call, Response<NewsApiResponse> response) {
            //In-case if response body is null
            if (response.body() == null){
                try {
                    Log.d(TAG, "Error response body" + response.errorBody().string());
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            //Retrieving the articles list from the response body
            List<com.example.megaflip.Model.FetchModel.News> news = response.body().getArticles();
            Log.i(TAG, "Successfully get the response consist of list of size " + news.size());
            //Inserting the news list to the database
            persistData(news, fragment[category]);
            Log.i(TAG, "Data is persisted successfully for the "+ category + " URL");
            MainActivity.loadingState.setValue(MainActivity.LoadingState.LOAD_NEWS);
        }

        @Override
        public void onFailure(Call<NewsApiResponse> call, Throwable t) {
            Log.e(TAG, t.toString());
        }
    });
 }

/**
 * This utility will persist the data into the local database
 * @param news
 * @param category
 */
private void persistData(List<com.example.megaflip.Model.FetchModel.News> news, String category){
    Log.i(TAG, "Preparing to persist the data.....");
    com.example.megaflip.Model.FetchModel.News newsItem;
    for (int count=0;  count<news.size();  count++){
        newsItem = news.get(count);
        mNewsDao.insert(new News(category, newsItem.getSource(), newsItem.getAuthor(), 
  newsItem.getTitle(), newsItem.getDescription(),
                newsItem.getUrl(), newsItem.getUrlToImage(), newsItem.getPublishedAt(), 
 newsItem.getContent()));
    }
    Log.i(TAG, "Successfully inserted the " + category + "URL data of size " + news.size());
}

public void deleteData(){
    mNewsDao.deleteAll();
}




/**
 * This utility will create new retrofit instance
 */
public Retrofit getRetrofitInstance(){
    //Creating a Retrofit instance from the base url
    if (retrofit == null) {
        retrofit = new Retrofit.Builder()
                .baseUrl(BASE_URL)
                .addConverterFactory(GsonConverterFactory.create())
                .build();
     }
      return retrofit;
   }

}

Теперь проблема в том, что функция getCategoricalNews (String category) извлекает новости указанной категории из базы данных, используя Rx Java liberary и в метод обратного вызова onNext Мне нужно установить news в адаптер с именем NewsListAdapter , используя метод в классе NewsListAdapter , помеченный как setNews . Вот класс NewsListAdapter .

public class NewsListAdapter extends RecyclerView.Adapter<NewsListAdapter.NewsViewHolder> {

private List<com.example.megaflip.Model.FetchModel.News> newsList;

private LayoutInflater layoutInflater;

private Context context;

//This constructor initializes the list
public NewsListAdapter( Context context ){
    //Inflate the layout for the specified context
    layoutInflater = LayoutInflater.from( context );
    this.context = context;
}


@NonNull
@Override
public NewsViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
    Log.i(getClass().getName(), "inflated");
    //Inflate the list item view for each recycler view item
    View itemView = layoutInflater.inflate( R.layout.news_list_item, parent , false);
    return new NewsViewHolder(itemView);
}

@Override
public void onBindViewHolder(@NonNull NewsViewHolder holder, int position) {
    //In-case when data is not being ready yet
    if ( newsList!= null ) {
        //Getting the pet data at the specified place in the list
        com.example.megaflip.Model.FetchModel.News news = newsList.get(position);
        //Load the picture by the url and set it to the source picture image view
        Log.v("MainActivity", "Before picasso");
        Picasso.get().load(news.getUrlToImage()) .
                into(holder.sourcePictureImageView);
        Log.v("ImageUrl", news.getUrlToImage());
        Log.v("MainActivity", "Before picasso");
        holder.newsTitleTextView.setText(news.getTitle());
        holder.sourceNameTextView.setText(news.getSource().getName());
    }
}

@Override
public int getItemCount() {
    if(newsList != null){
        Log.v("ViewModel: ", "List size = "+Integer.toString(newsList.size()));
        return newsList.size();
    }
    Log.v("ViewModel: ", "Returning empty list.");
    return 0;
}

public class NewsViewHolder extends RecyclerView.ViewHolder{

    //All the Text views holder
    ImageView sourcePictureImageView;
    AppCompatTextView sourceNameTextView;
    AppCompatTextView newsTitleTextView;


    public NewsViewHolder(@NonNull View itemView) {
        super(itemView);
        //Find the Text views by the corresponding id's
        sourcePictureImageView = (ImageView) itemView.findViewById( R.id.source_picture_image_view );
        sourceNameTextView = (AppCompatTextView) itemView.findViewById( R.id.source_name_text_view);
        newsTitleTextView = (AppCompatTextView) itemView.findViewById( R.id.news_title_TextView_view );
    }
}

//Update the pet list to the changed data
public void setNews( List<News> newsList )
{
    this.newsList = newsList;
    Log.v("NewsListAdapter: ", "Assigning new list of size = "+newsList.size());
    notifyDataSetChanged();
}
}

Фрагмент с именем LatestFragment содержит экземпляр класса NewsListAdapter , и мне нужно настроить newsListAdapter с recyclerView . Вот файл LatestFragament .

public class LatestFragment extends Fragment {

private static final String TAG = LatestFragment.class.getSimpleName();

public enum LoadingState{
    LOAD_NEWS,
    LOAD_CONTINUE,        //Indicates that news should be load
    LOADING_COMPLETE     //Indicates that news is loaded successfully
}
public static MutableLiveData<MainActivity.LoadingState> loadingState = new MutableLiveData<>(MainActivity.LoadingState.LOAD_NEWS);

public static final String NEWS_CATEGORY = "latest";
private NewsViewModel mNewsViewModel;
//Creating a recycler view instance
private RecyclerView recyclerView;
//Creating a NewsListAdapter instance
private NewsListAdapter mNewsListAdapter;

public static LatestFragment newInstance(){ return new LatestFragment(); }

@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    //Retrieve the existing news view model
    mNewsViewModel = new ViewModelProvider(this).get(NewsViewModel.class);
}

@Override
public View onCreateView(final LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) {
    // Inflate the layout for this fragment
    View rootView = inflater.inflate(R.layout.list_view, container, false);

    return rootView;
}

@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
    mNewsViewModel = new ViewModelProvider(requireActivity()).get(NewsViewModel.class);
    RecyclerView recyclerView = view.findViewById(R.id.recycler_view);
    NewsListAdapter newsListAdapter = new NewsListAdapter(getContext());
    recyclerView.setAdapter(newsListAdapter);

}

/**
 * Method to get the news view model instance
 */
public ViewModel getNewViewModel(){ return mNewsViewModel; } ;
}

Как передать список новостей из onNext метода обратного вызова newsListAdapter , потому что onNext находится в репозиторий и newsListAdapter находится в LatestFragment или как передать данные списка news в LatestFragment Вот мой код ViewModel с именем NewsViewModel .

public class NewsViewModel extends AndroidViewModel {

private static final String TAG = NewsViewModel.class.getSimpleName();
//Creating a NewsRepositoryInstance
private NewsRepository newsRepository;

public NewsViewModel(@NonNull Application application) {
    super(application);
    newsRepository = new NewsRepository(application);
}

/**
 * This method will prepare data to be used to display into the views for the user
 */
public void prepareData(int category){
    Log.i(TAG, "Preparing the data");
    newsRepository.setupData(category);
}

public void deleteAllData(){
    Log.i(TAG, "Deleting the data");
    newsRepository.deleteData();
}
Какой должна быть схема для этого? Что нужно сделать и чего мне не хватает? Ваша помощь будет поощряться.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...