问题描述
我正在制作新闻应用程序,并且正在使用页面库进行新闻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);