我知道这个问题被问了很多遍,我也知道通常情况下的答案,那就是 arraylist.clear()
扫除 arraylist
在拉动 SwipeRefreshLayout
. 但我的情况似乎有点不一样,我完全没有任何头绪,所以让我一步步讲出来。
我想做什么。
我有一个 RecyclerView
通常只显示1种类型的数据,那就是 List<Post> posts
. 从这里开始,这个工作完全正常。现在,我想添加 NatvieAds
从谷歌Admobs到第一元素的。RecyclerView
.
所以这是我的代码设置。
PostFragment:
public class PostFragment extends Fragment implement .....{
@Override
public void onViewCreated(@NonNull final View view, @Nullable Bundle savedInstanceState) {
initializeRecyclerView();
setUpSwipeRefreshLayout();
mSwipeRefreshLayout.post(new Runnable() {
@Override
public void run() {
mSwipeRefreshLayout.setRefreshing(true);
postAdapter.removeAllStuff(); //Here clear all the item in post
getPostInRoom(roomId);
}
});
}
private void initializeRecyclerView() {
recyclerView = binding.postRecyclerView;
recyclerView.setLayoutManager(new LinearLayoutManager(getActivity(),RecyclerView.VERTICAL,false));
postAdapter = new PostAdapter(this);
recyclerView.setAdapter(postAdapter);
}
private SwipeRefreshLayout mSwipeRefreshLayout;
private void setUpSwipeRefreshLayout() {
mSwipeRefreshLayout = binding.swipeRefreshLayout;
mSwipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
@Override
public void onRefresh() {
mSwipeRefreshLayout.setRefreshing(true);
postAdapter.removeAllStuff(); //Here clear all the item in post
getPostInRoom(roomId);
}
});
}
// I calling my own API in ViewModel and observe the LiveData returned.
private void getPostInRoom(String roomId) {
viewModel.getAllPostInRoom(roomId).observe(getViewLifecycleOwner(), new Observer<List<Post>>() {
@Override
public void onChanged(List<Post> posts) {
mSwipeRefreshLayout.setRefreshing(false);
if(posts != null && posts.size() > 0){
binding.postRecyclerView.setVisibility(View.VISIBLE);
binding.emptyStateContainer.setVisibility(View.GONE);
binding.unblockRoomButton.setVisibility(View.GONE);
postAdapter.addAllPostToList(posts); // Here add all the arraylist item into the list in adapter
getNativeAdsFromAdmobForPostFragment(); // here called for Admobs
}else if(Objects.requireNonNull(posts).size() == 0){
binding.emptyStateContainer.setVisibility(View.VISIBLE);
binding.postRecyclerView.setVisibility(View.GONE);
}
}
});
}
所以你可以看到,在 getPostInRoom()
所谓 SwipeRefreshLayout
我已经打电话给你了 postAdapter.removeAllStuff()
(我将在下面附上代码)。所以如果我没有弄错的话,数组列表应该是很清楚的。
以下是代码 PostFragment
致电给Admob索取广告
//HERE CALLED TO GOOGLE ADMOB FOR THE ADS
private AdLoader adLoader;
public void getNativeAdsFromAdmobForPostFragment(){
NativeAdOptions adOptions = new NativeAdOptions.Builder()
.setAdChoicesPlacement(ADCHOICES_TOP_RIGHT)
.build();
adLoader = new AdLoader.Builder(getActivity(), getResources().getString(R.string.admob_test_ad))
.forUnifiedNativeAd(new UnifiedNativeAd.OnUnifiedNativeAdLoadedListener() {
@Override
public void onUnifiedNativeAdLoaded(UnifiedNativeAd unifiedNativeAd) {
// Show the ad.
if(!adLoader.isLoading()){
postAdapter.addAdsToList(unifiedNativeAd); //here update the ads into the arraylist of the recyclerView
}
}
})
.withAdListener(new AdListener() {
@Override
public void onAdFailedToLoad(int errorCode) {
// Handle the failure by logging, altering the UI, and so on.
Log.e("MainActivity", "The previous native ad failed to load. Attempting to"
+ " load another.");
if (!adLoader.isLoading()) {
}
}
})
.withNativeAdOptions(adOptions)
.build();
adLoader.loadAd(new AdRequest.Builder().build());
}
}
PostAdapater.java
public class PostAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private static final int UNIFIED_ADS_VIEW = 1;
private static final int POST_ITEM_VIEW = 2;
private List<Object> mRecyclerViewItem = new ArrayList<>();
public PostAdapter(PostAdapterListener listener) {
this.listener = listener;
}
public void addAllPostToList(List<Post> posts){
mRecyclerViewItem.addAll(posts); // Here add all the post into the mRecyclerViewItem
notifyDataSetChanged();
}
public void addAdsToList(UnifiedNativeAd unifiedNativeAd){
mRecyclerViewItem.add(0,unifiedNativeAd); // Here add the 1 nativeAds into the arrayList
notifyDataSetChanged();
}
public void removeAllStuff(){
mRecyclerViewItem.clear(); // Here already called before `getPostInRoom()` in SwipeFreshLayout
notifyDataSetChanged();
}
@Override
public int getItemViewType (int position) {
Object recyclerViewItem = mRecyclerViewItem.get(position);
if (recyclerViewItem instanceof UnifiedNativeAd) {
return UNIFIED_ADS_VIEW;
}
return POST_ITEM_VIEW;
}
@Override
public int getItemCount() {
return mRecyclerViewItem.size();
}
... all other code
}
我现在有什么。
经过上面所有的代码,
第一次加载时 PostFragment
:行为是正确的,这意味着广告出现在第一项的 recyclerView
那么,以下是 post
我从服务器获取的。
当我把 SwipeRefreshLayout
同上 post
(这是3个帖子)重复和一个新的广告出现在。RecyclerView
每次我拉动 SwipeRefreshLayout
另外3个相同的帖子和1个新的广告被插入到了这个网站。RecyclerView
再。
这意味着, mRecyclerViewItem
在 PostAdapater
从来没有 clear()
但是,新的项目会不断地加入到 ArrayList
虽然我已经 clear()
在我获取新项目之前。
问题:我在上面的情况中做错了什么?
在上述情况下,我做错了什么?
正确的处理2种类型的 data
(Post
和 UnifiedNativeAd
在我的例子中)还是在1个RecyclerView中使用2个arraylist?
RecyclerView的构建目的是 recycle views
. 其中的所有内容都是一个独立的过程。
即使在 Setting Adapter
部分。Adapter
不在乎 what
数据正在被传递,它只关心的是 data is there
.
在你的情况下,我的建议是不要使用 ArrayList
,使用 Set
. a Set
你不能重复这些元素,因为这是它的基本标准。保留所有的刷新逻辑封装在 ViewController
在你的情况下,它看起来像一个 Fragment
.
我想指出的是这个功能。
public void removeAllStuff(){
mRecyclerViewItem.clear(); // Here already called before `getPostInRoom()` in SwipeFreshLayout
notifyDataSetChanged();
}
这应该被避免,因为增加或删除一个项目在 DataSet
不应要求摧毁一切在 RecyclerView
,然后重建它。你实际上是在阻碍主要目标的实现 RecyclerView
జజజజజజజజజజజజజజజజజజజజజజజజజజజజజజజజజజజజజజజ recycling
部分。而是利用智能方法,如 notifyItemChanged(position: Int)
,它将通知 RecyclerView
只有该位置的元素发生了变化,所以不必担心其他元素。