动态查询使用 Android 分页库

huangapple go评论74阅读模式
英文:

dynamic query using android paging library

问题

我正在制作一个新闻应用我正在使用分页库来管理我的新闻 RecyclerView我想要根据新闻类别显示新闻我从对话框中选择类别并将其分配给主活动中的 TextView[这里][1] 是我的应用我想要观察该值并根据该值动态发送请求我正在使用 Retrofit 作为网络库

MainActivity.java

public class MainActivity extends AppCompatActivity {

    private MainActivityViewModel mViewModel;
    private NewsAdapter mAdapter;
    // 小部件
    @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、NewsDataSourceFactory.java、RetroApi.java、RetroService.java、NewsAdapter.java 等。

[1]: https://i.stack.imgur.com/OBzBY.jpg
英文:

I am making a news app and I am using paging library for my news recyclerview.I want to show news based on categories.I am choosing category from dialogbox and assigning it to texview inside main activity.Here is my app.I want to observe that value and sending request based on that value dynamically.I'm using retrofit as network library.

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 -&gt; {
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 -&gt; {
mAdapter.submitList(newsModels);
});
mRecyclerView.setAdapter(mAdapter);
} 
}

MainActivityViewModel.java

public class MainActivityViewModel extends AndroidViewModel {
private LiveData&lt;NewsDataSource&gt; liveDataSource;
public LiveData&lt;PagedList&lt;NewsModel&gt;&gt; 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&lt;&gt;(newsFactory,config).build();
}
}

NewsDataSource.java

public class NewsDataSource extends PageKeyedDataSource&lt;Integer, NewsModel&gt; {
Single&lt;Response&gt; mResponse;
List&lt;NewsModel&gt; newsResponse;
@Override
public void loadInitial(@NonNull LoadInitialParams&lt;Integer&gt; params, @NonNull LoadInitialCallback&lt;Integer, NewsModel&gt; callback) {
RetroService service = RetroService.getInstance();
mResponse = service.getData(FIRST_PAGE, PAGE_SIZE, &quot;us&quot;, API_KEY,&quot;general&quot;);
mResponse.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new SingleObserver&lt;Response&gt;() {
@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&lt;Integer&gt; params, @NonNull LoadCallback&lt;Integer, NewsModel&gt; callback) {
RetroService service = RetroService.getInstance();
mResponse = service.getData(FIRST_PAGE, PAGE_SIZE, &quot;us&quot;, API_KEY,&quot;general&quot;);//Want to change that general data dynamically.
mResponse.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new SingleObserver&lt;Response&gt;() {
@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 &gt; 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&lt;Integer&gt; params, @NonNull LoadCallback&lt;Integer, NewsModel&gt; callback) {
RetroService service = RetroService.getInstance();
mResponse = service.getData(params.key, PAGE_SIZE, &quot;us&quot;,API_KEY,&quot;general&quot;);
mResponse.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new SingleObserver&lt;Response&gt;() {
@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&lt;Integer, NewsModel&gt; {
private MutableLiveData&lt;NewsDataSource&gt; newsDataSourceMutableLiveData;
NewsDataSource newsDataSource;
@NonNull
@Override
public DataSource&lt;Integer, NewsModel&gt; create() {
newsDataSource = new NewsDataSource();
newsDataSourceMutableLiveData=new MutableLiveData&lt;&gt;();
newsDataSourceMutableLiveData.postValue(newsDataSource);
return newsDataSource;
}
public MutableLiveData&lt;NewsDataSource&gt; getNewsDataSourceMutableLiveData() {
return newsDataSourceMutableLiveData;
}
}

RetroApi.java

public interface RetroApi {
@GET(&quot;top-headlines&quot;)
Single&lt;Response&gt; getAllNews(@Query(&quot;page&quot;) int page,
@Query(&quot;pageSize&quot;) int pageSize,
@Query(&quot;country&quot;) String country,
@Query(&quot;apiKey&quot;) String apiKey,
@Query(&quot;category&quot;)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&lt;Response&gt; 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&lt;NewsModel,NewsAdapter.NewsViewHolder&gt;  {
private Context context;
private List&lt;NewsModel&gt; mNews;
private static final DiffUtil.ItemCallback&lt;NewsModel&gt; NEWS_COMPARATOR=new DiffUtil.ItemCallback&lt;NewsModel&gt;() {
@Override
public boolean areItemsTheSame(@NonNull NewsModel oldItem, @NonNull NewsModel newItem) {
return oldItem.getTitle() == newItem.getTitle();
}
@SuppressLint(&quot;DiffUtilEquals&quot;)
@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 -&gt; {
setupBottomSheetDialog(news);
});
}
private void setupBottomSheetDialog(NewsModel mNew) {
LayoutBottomSheetBinding binding = DataBindingUtil.inflate(LayoutInflater.from(context), R.layout.layout_bottom_sheet, null, 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();
}
}
}

答案1

得分: 0

我解决了我的问题,但我不建议那种方式。我认为可能有更好的解决方案。所以,如果你有更好的解决方案,请告诉我。以下是我的解决方案。首先,我在我的 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。

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 中添加了一个带有 category 参数的构造函数。

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

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

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

并将该 category 传递给了我的请求方法。

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

I solved my problem but I don't recommend that way.I think there might be a better solution for this.So if you have a better solution please let me know.Here is my solution. Firstly I added public MutableLiveData&lt;String&gt; categoryLiveData=new MutableLiveData&lt;&gt;(); to my MainActivityViewModel class.Then ı changed my init() method to

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&lt;&gt;(newsFactory,config).build();
}

I added these lines to my MainActivity to observe categoryData and then inside onOptionsItemSelected() assigned the selected value to categoryLiveData.

MainActivity

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

I added a constructor to NewsDataSourceFactory with category parameter.

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

Lastly created a constructor in NewsDataSource and passed category as an argument.

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

and passed that category to my request method.

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

huangapple
  • 本文由 发表于 2020年9月4日 03:14:07
  • 转载请务必保留本文链接:https://go.coder-hub.com/63730261.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定