Я знаю, что этот вопрос задают много раз, и я знаю ответ для обычного случая: arraylist.clear()
очистите arraylist
перед вытягиванием SwipeRefreshLayout
. Но в моем случае это выглядит немного по-другому, и я понятия не имею об этом, поэтому позвольте мне рассказать об этом шаг за шагом.
Что я хочу сделать:
У меня есть RecyclerView
, который обычно представляет только 1 тип данных, который List<Post> posts
. Отсюда это работает отлично. Теперь я хочу добавить NatvieAds
из Google 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()
(для которого я прикреплю код ниже). Так что, если я не ошибаюсь, arraylist должен быть ясен.
Вот код в 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
в моем случае) или 2-х массивов в 1 RecyclerView?