使用Android分页库进行动态查询

问题描述

我正在制作新闻应用程序,并且正在使用页面库进行新闻recyclerview。我想根据类别显示新闻。我从对话框中选择类别,并将其分配给主要活动中的texview。Here是我的应用程序。我想观察该值并动态地基于该值发送请求。我正在使用翻新作为网络库。

MainActivity.java

public class MainActivity extends AppCompatActivity{

private MainActivityviewmodel mviewmodel;
private NewsAdapter mAdapter;
//widgets
@BindView(R.id.recyclerView)
RecyclerView mRecyclerView;
@BindView(R.id.toolbar)
MaterialToolbar toolbar;
@BindView(R.id.searchView)
SearchView mSearchView;
@BindView(R.id.categoryTv)
TextView categoryTv;
private String [] categoryArray;


@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    ButterKnife.bind(this);
    mAdapter = new NewsAdapter(this);
    categoryArray=getResources().getStringArray(R.array.category_array);
    mviewmodel = new viewmodelProvider(this,viewmodelProvider.AndroidviewmodelFactory.getInstance(this
            .getApplication())).get(MainActivityviewmodel.class);
    setSupportActionBar(toolbar);
    initRecyclerView();
    observeviewmodel();
    mRecyclerView.setAdapter(mAdapter);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
    getMenuInflater().inflate(R.menu.activity_toolbar_menu,menu);
    return true;
}
@Override
public boolean onoptionsItemSelected(@NonNull MenuItem item) {
    int id=item.getItemId();
    if(id==R.id.category){
        Dialog d=new Dialog(this);
        d.setContentView(R.layout.number_picker);
        Button selectBtn=d.findViewById(R.id.select);
        NumberPicker np=d.findViewById(R.id.numberPicker);
        np.setMinValue(0);
        np.setTextColor(getResources().getColor(R.color.colorPrimary));
        np.setMaxValue(categoryArray.length-1);
        np.setdisplayedValues(categoryArray);
        np.setWrapSelectorWheel(false);
        selectBtn.setonClickListener(v -> {
            categoryTv.setText(categoryArray[np.getValue()]);
            d.dismiss();
        });
        d.show();
    }
    return super.onoptionsItemSelected(item);
}
private void initRecyclerView(){
    linearlayoutmanager layoutManager = new linearlayoutmanager(this);
    mRecyclerView.setLayoutManager(layoutManager);
}
private void observeviewmodel() {
    mviewmodel.newsPagedList.observe(this,newsModels -> {
        mAdapter.submitList(newsModels);
    });
  mRecyclerView.setAdapter(mAdapter);
} 
}

MainActivityviewmodel.java

public class MainActivityviewmodel extends Androidviewmodel {

private LiveData<NewsDataSource> liveDataSource;

public LiveData<PagedList<NewsModel>> newsPagedList;

public MainActivityviewmodel(Application application) {
    super(application);
    init();
}
private void init() {
    NewsDataSourceFactory newsFactory=new NewsDataSourceFactory();
    liveDataSource=newsFactory.getNewsDataSourcemutablelivedata();
    PagedList.Config config=new PagedList.Config.Builder()
            .setEnablePlaceholders(false)
            .setPageSize(PAGE_SIZE)
            .build();
    newsPagedList=new LivePagedListBuilder<>(newsFactory,config).build();
}
}

NewsDataSource.java

public class NewsDataSource extends PageKeyedDataSource<Integer,NewsModel> {
Single<Response> mResponse;
List<NewsModel> newsResponse;
@Override
public void loadInitial(@NonNull LoadInitialParams<Integer> params,@NonNull LoadInitialCallback<Integer,NewsModel> callback) {
    RetroService service = RetroService.getInstance();

    mResponse = service.getData(FirsT_PAGE,PAGE_SIZE,"us",API_KEY,"general");
    mResponse.subscribeOn(Schedulers.newThread())
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe(new SingleObserver<Response>() {
                @Override
                public void onSubscribe(@io.reactivex.rxjava3.annotations.NonNull disposable d) {

                }

                @Override
                public void onSuccess(@io.reactivex.rxjava3.annotations.NonNull Response response) {
                    newsResponse = response.getNewsList();
                    callback.onResult(newsResponse,null,FirsT_PAGE + 1);
                }

                @Override
                public void onError(@io.reactivex.rxjava3.annotations.NonNull Throwable e) {

                }
            });
}

@Override
public void loadBefore(@NonNull LoadParams<Integer> params,@NonNull LoadCallback<Integer,NewsModel> callback) {
    RetroService service = RetroService.getInstance();
    mResponse = service.getData(FirsT_PAGE,"general");//Want to change that general data dynamically.
    mResponse.subscribeOn(Schedulers.newThread())
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe(new SingleObserver<Response>() {
                @Override
                public void onSubscribe(@io.reactivex.rxjava3.annotations.NonNull disposable d) {

                }

                @Override
                public void onSuccess(@io.reactivex.rxjava3.annotations.NonNull Response response) {
                    newsResponse = response.getNewsList();
                    if (newsResponse != null) {
                        int key;
                        if (params.key > 1) {
                            key = params.key - 1;
                        } else {
                            key = 0;
                        }
                        callback.onResult(newsResponse,key);
                    }
                }

                @Override
                public void onError(@io.reactivex.rxjava3.annotations.NonNull Throwable e) {

                }
            });
}

@Override
public void loadAfter(@NonNull LoadParams<Integer> params,NewsModel> callback) {
    RetroService service = RetroService.getInstance();
         mResponse = service.getData(params.key,"general");
    mResponse.subscribeOn(Schedulers.newThread())
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe(new SingleObserver<Response>() {
                @Override
                public void onSubscribe(@io.reactivex.rxjava3.annotations.NonNull disposable d) {

                }

                @Override
                public void onSuccess(@io.reactivex.rxjava3.annotations.NonNull Response response) {
                    newsResponse = response.getNewsList();
                    if (newsResponse != null) {
                        callback.onResult(newsResponse,params.key + 1);
                    }
                }
                @Override
                public void onError(@io.reactivex.rxjava3.annotations.NonNull Throwable e) {

                }
            });
}
}

NewsDataSourceFactory.java

public class NewsDataSourceFactory extends DataSource.Factory<Integer,NewsModel> {
private mutablelivedata<NewsDataSource> newsDataSourcemutablelivedata;
NewsDataSource newsDataSource;

@NonNull
@Override
public DataSource<Integer,NewsModel> create() {
    newsDataSource = new NewsDataSource();
    newsDataSourcemutablelivedata=new mutablelivedata<>();
    newsDataSourcemutablelivedata.postValue(newsDataSource);
    return newsDataSource;
}

public mutablelivedata<NewsDataSource> getNewsDataSourcemutablelivedata() {
    return newsDataSourcemutablelivedata;
}
}

RetroApi.java

public interface RetroApi {
    @GET("top-headlines")
    Single<Response> getAllNews(@Query("page") int page,@Query("pageSize") int pageSize,@Query("country") String country,@Query("apiKey") String apiKey,@Query("category")String category);
}

RetroService.java

public class RetroService {

private static OkHttpClient client = new OkHttpClient.Builder()
        .connectTimeout(CONNECTION_TIMEOUT,TimeUnit.SECONDS)
        .readTimeout(READ_TIMEOUT,TimeUnit.SECONDS)
        .writeTimeout(WRITE_TIMEOUT,TimeUnit.SECONDS)
        .retryOnConnectionFailure(false)
        .build();


private static RetroApi api;

private static RetroService instance;

public static RetroService getInstance(){
    if(instance == null){
        instance=new RetroService();
    }
    return instance;
}

private RetroService() {
    api = new Retrofit.Builder()
            .baseUrl(BASE_URL)
            .client(client)
            .addConverterFactory(GsonConverterFactory.create())
            .addCallAdapterFactory(RxJava3CallAdapterFactory.create())
            .build()
            .create(RetroApi.class);
}
public Single<Response> getData(int page,int pageSize,String country,String key,String category){
    return api.getAllNews(page,pageSize,country,key,category);
}
}

NewsAdapter.java

public class NewsAdapter extends Pagedlistadapter<NewsModel,NewsAdapter.NewsViewHolder>  {

private Context context;
private List<NewsModel> mNews;


private static final DiffUtil.ItemCallback<NewsModel> NEWS_COMParaTOR=new DiffUtil.ItemCallback<NewsModel>() {
    @Override
    public boolean areItemsTheSame(@NonNull NewsModel oldItem,@NonNull NewsModel newItem) {
        return oldItem.getTitle() == newItem.getTitle();
    }

    @SuppressLint("DiffUtilEquals")
    @Override
    public boolean areContentsTheSame(@NonNull NewsModel oldItem,@NonNull NewsModel newItem) {
        return oldItem.equals(newItem);
    }
};

public NewsAdapter(Context context) {
    super(NEWS_COMParaTOR);
    this.context=context;
}

@NonNull
@Override
public NewsViewHolder onCreateViewHolder(@NonNull ViewGroup parent,int viewType) {
 LayoutInflater mInflater= LayoutInflater.from(parent.getContext());
    NewsItembinding binding=DataBindingUtil.inflate(mInflater,R.layout.news_item,parent,false);
    return new NewsViewHolder(binding);
}

@Override
public void onBindViewHolder(@NonNull NewsViewHolder holder,int position) {
    holder.bindData(getItem(position));
    holder.binding.setClickListener(news -> {
        setupBottomSheetDialog(news);
    });
}

private void setupBottomSheetDialog(NewsModel mNew) {
    LayoutBottomSheetBinding binding = DataBindingUtil.inflate(LayoutInflater.from(context),R.layout.layout_bottom_sheet,false);
    BottomSheetDialog dialogBox=new BottomSheetDialog(context);
    View v=binding.getRoot();
    dialogBox.setContentView(v);
    binding.setMNew(mNew);
    dialogBox.show();
}

class NewsViewHolder extends RecyclerView.ViewHolder{

    NewsItembinding binding;

    public NewsViewHolder(@NonNull NewsItembinding binding) {
        super(binding.getRoot());
        this.binding=binding;

    }
    public void bindData(NewsModel model){
        binding.setMNew(model);
        binding.executePendingBindings();
    }
}
}

解决方法

我解决了我的问题,但我不建议这样做,我认为可能有更好的解决方案,所以如果您有更好的解决方案,请告诉我,这是我的解决方案。首先,我在MainActivityViewModel类中添加了public MutableLiveData<String> categoryLiveData=new MutableLiveData<>();。然后我将init()方法更改为

public void init(String category) {
    NewsDataSourceFactory newsFactory=new NewsDataSourceFactory(category);
    liveDataSource=newsFactory.getNewsDataSourceMutableLiveData();
    PagedList.Config config=new PagedList.Config.Builder()
            .setEnablePlaceholders(false)
            .setPageSize(PAGE_SIZE)
            .build();
    newsPagedList=new LivePagedListBuilder<>(newsFactory,config).build();
}

我将这些行添加到MainActivity中以观察categoryData,然后在onOptionsItemSelected()内部将所选值分配给categoryLiveData。

MainActivity

 mViewModel.categoryLiveData.postValue(categoryTv.getText().toString().toLowerCase());
    mViewModel.categoryLiveData.observe(mActivity,s -> {
        mViewModel.init(s);           
        observeViewModel();
    });
selectBtn.setOnClickListener(v -> {
            categoryTv.setText(categoryArray[np.getValue()]);
            mViewModel.categoryLiveData.postValue(categoryTv.getText().toString().toLowerCase());
            d.dismiss();
        });

我向带有类别参数的NewsDataSourceFactory添加了一个构造函数。

    public NewsDataSourceFactory(String category) {
    newsDataSource = new NewsDataSource(category);
}    

最后在NewsDataSource中创建了一个构造函数,并通过category作为参数。

private String category;
public NewsDataSource(String category){
    this.category=category;
}

并将该类别传递给我的请求方法。

mResponse = service.getData(FIRST_PAGE,PAGE_SIZE,"us",API_KEY,category);