How to efficiently loading native ads on demand with the recyclerview adapter? - android

What i am doing is, that i have a recyclerView which has it's adapter and from within adapter i am loading the nativeAds. But due to loading the ads within the recyclerView instead of preloading the ads my recyclerView is not scrolling smoothly.
And also i tried to load the native ad on different thread but that also was't helpful.
Any ideas how to load the native ad without sacrificing the performance??
public class GetInspiredAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
public static int VIEW_TYPE_ADS = 0;
public static int VIEW_TYPE_NOTADS = 1;
// this shows that the ad is to be added after this many items.
public static int ADS_AFTER_HOW_MANY_ITEMS = 3;
private boolean isNetworkAvailable = false;
private Context context;
private ArrayList<Object> list;
private GetInspiredListener listener;
public GetInspiredAdapter(Context context, ArrayList<Object> list, GetInspiredListener listener) {
this.context = context;
this.list = list;
this.listener = listener;
}
private void addNativeToList() {
int i = ADS_AFTER_HOW_MANY_ITEMS;
while (i < list.size()) {
list.add(i, new UnifiedNativeAdView(context));
i += ADS_AFTER_HOW_MANY_ITEMS + 1;
}
}
#NonNull
#Override
public RecyclerView.ViewHolder onCreateViewHolder(#NonNull ViewGroup viewGroup, int viewType) {
if (viewType == VIEW_TYPE_ADS) {
View unifiedNativeLayoutView = LayoutInflater.from(context).inflate(R.layout.ad_unified, viewGroup, false);
unifiedNativeLayoutView.setTag(new Integer(GetInspiredAdapter.VIEW_TYPE_ADS));
return new UnifiedNativeAdViewHolder(unifiedNativeLayoutView);
} else {
View itemView = LayoutInflater.from(context).inflate(R.layout.image_item, viewGroup, false);
itemView.setTag(new Integer(GetInspiredAdapter.VIEW_TYPE_NOTADS));
return new GetInspiredViewHolder(itemView);
}
}
#Override
public void onBindViewHolder(#NonNull final RecyclerView.ViewHolder holder, int position) {
int viewType = getItemViewType(position);
if (viewType == VIEW_TYPE_ADS) {
if (!isNetworkAvailable) {
list.remove(position);
notifyDataSetChanged();
return;
}
AdLoader.Builder builder = new AdLoader.Builder(context, Constants.INSPIRED_MOB)
.forUnifiedNativeAd(new UnifiedNativeAd.OnUnifiedNativeAdLoadedListener() {
#Override
public void onUnifiedNativeAdLoaded(UnifiedNativeAd unifiedNativeAd) {
populateNativeAdView(unifiedNativeAd, (UnifiedNativeAdViewHolder) holder);
}
}).withAdListener(new AdListener() {
#Override
public void onAdFailedToLoad(int i) {
super.onAdFailedToLoad(i);
}
});
builder.build().loadAd(new AdRequest.Builder().build());
} else if (viewType == VIEW_TYPE_NOTADS) {
LoadImage((InspiredObject) list.get(getItemIndex(position)), (GetInspiredViewHolder) holder);
}
}
private void LoadImage(InspiredObject obj, GetInspiredViewHolder viewHolder) {
//Url link to images
String url = "http://aim-itech.com/mandala/image/";
String string = url + obj.low;
Glide.with(context).load(string).override(Constants.SAMPLE_SIZE_MEDIUM).into(viewHolder.imageView);
Log.e("TAG", string);
}
private void populateNativeAdView(UnifiedNativeAd nativeAd, UnifiedNativeAdViewHolder holder) {
if (nativeAd == null) {
holder.getAdView().setVisibility(View.INVISIBLE);
holder.textLoading.setVisibility(View.VISIBLE);
return;
}
holder.textLoading.setVisibility(View.GONE);
UnifiedNativeAdView adView = holder.getAdView();
adView.setVisibility(View.VISIBLE);
((TextView) adView.getHeadlineView()).setText(nativeAd.getHeadline());
((TextView) adView.getBodyView()).setText(nativeAd.getBody());
((Button) adView.getCallToActionView()).setText(nativeAd.getCallToAction());
NativeAd.Image icon = nativeAd.getIcon();
if (icon == null) {
adView.getIconView().setVisibility(View.INVISIBLE);
} else {
((ImageView) adView.getIconView()).setImageDrawable(icon.getDrawable());
adView.getIconView().setVisibility(View.VISIBLE);
}
if (nativeAd.getPrice() == null) {
adView.getPriceView().setVisibility(View.INVISIBLE);
} else {
adView.getPriceView().setVisibility(View.VISIBLE);
((TextView) adView.getPriceView()).setText(nativeAd.getPrice());
}
if (nativeAd.getStore() == null) {
adView.getStoreView().setVisibility(View.INVISIBLE);
} else {
adView.getStoreView().setVisibility(View.VISIBLE);
((TextView) adView.getStoreView()).setText(nativeAd.getStore());
}
if (nativeAd.getStarRating() == null) {
adView.getStarRatingView().setVisibility(View.INVISIBLE);
} else {
((RatingBar) adView.getStarRatingView())
.setRating(nativeAd.getStarRating().floatValue());
adView.getStarRatingView().setVisibility(View.VISIBLE);
}
if (nativeAd.getAdvertiser() == null) {
adView.getAdvertiserView().setVisibility(View.INVISIBLE);
} else {
((TextView) adView.getAdvertiserView()).setText(nativeAd.getAdvertiser());
adView.getAdvertiserView().setVisibility(View.VISIBLE);
}
// Assign native ad object to the native view.
adView.setNativeAd(nativeAd);
}
public int getItemIndex(int position) {
return position;
}
#Override
public int getItemViewType(int position) {
Object recyclerViewItem = list.get(getItemIndex(position));
if (recyclerViewItem instanceof UnifiedNativeAd) {
return VIEW_TYPE_ADS;
} else if (recyclerViewItem instanceof UnifiedNativeAdView) {
return VIEW_TYPE_ADS;
}
return VIEW_TYPE_NOTADS;
}
public boolean isNetworkAvailable() {
return isNetworkAvailable;
}
public void setNetworkAvailable(boolean networkAvailable) {
isNetworkAvailable = networkAvailable;
if (isNetworkAvailable) {
addNativeToList();
}
}
#Override
public int getItemCount() {
return list.size();
}
public class GetInspiredViewHolder extends RecyclerView.ViewHolder {
ImageView imageView;
public GetInspiredViewHolder(#NonNull View itemView) {
super(itemView);
imageView = itemView.findViewById(R.id.imageProf);
imageView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
InspiredObject inspiredObject = (InspiredObject) list.get(getAdapterPosition());
Intent i = new Intent(context, InspiredActivity.class);
i.putExtra("image", inspiredObject.high);
listener.onClick(i);
}
});
}
}
public class UnifiedNativeAdViewHolder extends RecyclerView.ViewHolder {
private UnifiedNativeAdView adView;
private TextView textLoading;
private CardView adContainer;
public UnifiedNativeAdView getAdView() {
return adView;
}
UnifiedNativeAdViewHolder(View view) {
super(view);
textLoading = view.findViewById(R.id.native_loading_text);
adView = view.findViewById(R.id.native_ad_view);
adContainer = view.findViewById(R.id.ad_unified_conatiner);
// The MediaView will display a video asset if one is present in the ad, and the
// first image asset otherwise.
adView.setMediaView((MediaView) adView.findViewById(R.id.ad_media));
// Register the view used for each individual asset.
adView.setHeadlineView(adView.findViewById(R.id.ad_headline));
adView.setBodyView(adView.findViewById(R.id.ad_body));
adView.setCallToActionView(adView.findViewById(R.id.ad_call_to_action));
adView.setIconView(adView.findViewById(R.id.ad_icon));
adView.setPriceView(adView.findViewById(R.id.ad_price));
adView.setStarRatingView(adView.findViewById(R.id.ad_stars));
adView.setStoreView(adView.findViewById(R.id.ad_store));
adView.setAdvertiserView(adView.findViewById(R.id.ad_advertiser));
}
}
}

surprised there is no answer here.
The approach I would use outside of the recyclerview adapter:
adLoader.loadAds(new AdRequest.Builder().build(), NUMBER_OF_ADS_TO_LOAD(Max 5 according to docs);
instead usual adLoader.loadAd
and then
builder.forUnifiedNativeAd(new UnifiedNativeAd.OnUnifiedNativeAdLoadedListener() {
// OnUnifiedNativeAdLoadedListener implementation.
#Override
public void onUnifiedNativeAdLoaded(UnifiedNativeAd unifiedNativeAd) {
nativeAds.add(unifiedNativeAd);
}
});
where
private List<UnifiedNativeAd> nativeAds = new ArrayList<>();
which you pass to your recyclerview adapter and mix in your other items.
This will need some memory handling with destroy called before you request another list etc. but the idea is to preload a list of ads instead of loading them while scrolling

Related

Problem of automatic change of data value when scrolling in RecyclerView

I have attached a picture to help you understand my problem.
I'm making an Workout app.
When the button is pressed, the routine is added
In the added routine, it can use the button again to add detailed data (set, lbs, reps).
So, I am using a two type RecyclerView (except footer).
I used DiffUtil to update the items being added.
I found a strange phenomenon while experimenting for testing. (See photo)
It wasn't an error, so I can't figure out what's wrong with it.
After entering the data, when i added a number of detailed items, the value of the data entered first appeared in the items added later.
And if i scrolled after many items were added, the data moved randomly.
However, what is expected is this phenomenon when you add a lot of items or scroll.
What's wrong?
RoutineAdapter.java
public class RoutineAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
final static int TYPE_ROUTINE = 1;
final static int TYPE_ROUTINE_DETAIL = 2;
final static int TYPE_ROUTINE_FOOTER = 3;
private Context context;
private List<Object> mItems = new ArrayList<>();
OnRoutineItemClickListener routinelistener;
OnRoutineAddClickListener routineAddListener;
public void updateRoutineList(List<Object> newRoutineList) {
final RoutineDiffUtil diffCallback = new RoutineDiffUtil(this.mItems, newRoutineList);
final DiffUtil.DiffResult diffResult = DiffUtil.calculateDiff(diffCallback);
this.mItems.clear();
this.mItems.addAll(newRoutineList);
diffResult.dispatchUpdatesTo(this);
}
#NonNull
#Override
public RecyclerView.ViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
context = parent.getContext();
View itemView;
if(viewType == TYPE_ROUTINE){
itemView = LayoutInflater.from(parent.getContext()).inflate(R.layout.routine_item, parent, false);
return new RoutineViewHolder(itemView);
}
else if(viewType == TYPE_ROUTINE_DETAIL){
itemView = LayoutInflater.from(context).inflate(R.layout.routine_detail_item, parent, false);
return new RoutineDetailViewHolder(itemView);
}
else {
itemView = LayoutInflater.from(context).inflate(R.layout.add_routine_item, parent, false);
return new RoutineAddFooterViewHolder(itemView);
}
}
#Override
public void onBindViewHolder(#NonNull RecyclerView.ViewHolder holder, int position) {
Object obj;
switch (getItemViewType(position)) {
case TYPE_ROUTINE:
obj = mItems.get(position);
setRoutineData((RoutineViewHolder) holder, (RoutineModel) obj);
break;
case TYPE_ROUTINE_DETAIL:
obj = mItems.get(position);
RoutineDetailModel item = (RoutineDetailModel) obj;
((RoutineDetailViewHolder) holder).setDetailItem(item);
break;
case TYPE_ROUTINE_FOOTER:
break;
}
}
#Override
public int getItemCount() {
if(mItems == null)
return -1;
return mItems.size() + 1; // for footer
}
#Override
public int getItemViewType(int position) {
if(position == mItems.size()) {
return TYPE_ROUTINE_FOOTER;
}
else {
Object obj = mItems.get(position);
if(obj instanceof RoutineModel) {
return TYPE_ROUTINE;
}
else {
// obj instanceof RoutineDetailModel
return TYPE_ROUTINE_DETAIL;
}
}
}
// add routine interface
public interface OnRoutineAddClickListener {
public void onAddRoutineClick();
}
public void setOnAddRoutineClickListener(OnRoutineAddClickListener listener) {
this.routineAddListener = listener;
}
// details add / remove interface
public interface OnRoutineItemClickListener {
public void onAddBtnClicked(int curRoutinePos);
public void onDeleteBtnClicked(int curRoutinePos);
public void onWritingCommentBtnClicked(int curRoutinePos);
}
public void setOnRoutineClickListener(OnRoutineItemClickListener listener) {
this.routinelistener = listener;
}
private class RoutineViewHolder extends RecyclerView.ViewHolder {
public TextView routine;
public Button addSet;
public Button deleteSet;
public Button comment;
public RoutineViewHolder(#NonNull View itemView) {
super(itemView);
initViews();
addSet.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if(routinelistener != null && getAdapterPosition() != RecyclerView.NO_POSITION)
routinelistener.onAddBtnClicked(getAdapterPosition());
}
});
deleteSet.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if(routinelistener != null && getAdapterPosition() != RecyclerView.NO_POSITION)
routinelistener.onDeleteBtnClicked(getAdapterPosition());
}
});
comment.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if(routinelistener != null && getAdapterPosition() != RecyclerView.NO_POSITION)
routinelistener.onWritingCommentBtnClicked(getAdapterPosition());
}
});
}
}
private class RoutineDetailViewHolder extends RecyclerView.ViewHolder {
public TextView set;
public TextView weight;
public RoutineDetailViewHolder(#NonNull View itemView) {
super(itemView);
initViews();
}
private void initViews() {
set = itemView.findViewById(R.id.set);
weight = itemView.findViewById(R.id.weight);
}
private void setDetailItem(RoutineDetailModel item) {
set.setText(item.getSet().toString() + "set");
}
}
}
RoutineDiffUtil.java
public class RoutineDiffUtil extends DiffUtil.Callback {
private List<Object> oldRoutineList;
private List<Object> newRoutineList;
public RoutineDiffUtil(List<Object> oldRoutineList, List<Object> newRoutineList) {
this.oldRoutineList = oldRoutineList;
this.newRoutineList = newRoutineList;
}
#Override
public int getOldListSize() {
return oldRoutineList.size();
}
#Override
public int getNewListSize() {
return newRoutineList.size();
}
#Override
public boolean areItemsTheSame(int oldItemPosition, int newItemPosition) {
Object oldObj = oldRoutineList.get(oldItemPosition);
Object newObj = newRoutineList.get(newItemPosition);
if (oldObj instanceof RoutineModel && newObj instanceof RoutineModel) {
return ((RoutineModel) oldObj).id == ((RoutineModel) newObj).id;
}
else if (oldObj instanceof RoutineDetailModel && newObj instanceof RoutineDetailModel) {
return ((RoutineDetailModel) oldObj).id == ((RoutineDetailModel) newObj).id;
}
else if(oldObj instanceof RoutineModel && newObj instanceof RoutineDetailModel) {
return false;
}
else {
return false;
}
}
#Override
public boolean areContentsTheSame(int oldItemPosition, int newItemPosition) {
return (oldRoutineList.get(oldItemPosition)).equals(newRoutineList.get(newItemPosition));
}
}
RoutineDetailModel.java
public class RoutineDetailModel {
public int id;
private int set = 1;
private int weight;
public RoutineDetailModel() {
Random random = new Random();
this.id = random.nextInt();
}
public RoutineDetailModel(int set) {
Random random = new Random();
this.id = random.nextInt();
this.set = set+1;
}
public Integer getSet() {
return set;
}
public int getId() {
return id;
}
#Override
public int hashCode() {
return Objects.hash(set, weight);
}
#Override
public boolean equals(#Nullable Object obj) {
if(obj != null && obj instanceof RoutineDetailModel) {
RoutineDetailModel model = (RoutineDetailModel) obj;
if(this.id == model.getId()) {
return true;
}
}
return false;
}
}
First of all, you should use ListAdapter class with diff util. The problem with your adapter is that, Recycler view recycles views again and again. That is to say that when you entered a text for your first item, this item is used for other views. To solve it after any text change you should keep this text in your model class then you should set this text to the field in onBind() method. To sum up, recycler view uses same view for different items so any data related to any item should be kept in a model and the model should be set to the view in onBind().

Shouldn't DiffUtil compare with hashCode?

I am developing the Workout log app now.
Two items (routine and routine detail) are expressed using one recycler view and adapter.
If i click the Add Routine button, a routine item is added, and the routine basically has one routine detail item.
Routine items have buttons to add or delete routine detail items.
I used DiffUtil to update the item.
In areItemsTheSame(), I used hashCode to compare oldList and newList.
However, there is a problem of unknown cause when adding or deleting items. (Not an error).
If i click the delete button after adding the routine item and the detail item, it works well at first.
The routine detail buttons of the next routine item cannot be added or deleted unless the delete button of the previous routine item is pressed.
If the delete button of the previous routine item is pressed and then the button of the next item is pressed, the addition or deletion is performed.
Why is this?
This happens when you use hashCode comparison.
However, with equals() this does not happen and works fine.
Instead, every time an item is added or deleted, the entire item is updated with blinking.
How did I have to define the DiffUtil class?
CODE
RoutineModel.java
public class RoutineModel {
private ArrayList<RoutineDetailModel> routineDetailList;
private String routine;
public RoutineModel(String routine) {
this.routine = routine;
}
public void addDetail(RoutineDetailModel item) {
if(routineDetailList == null) {
routineDetailList = new ArrayList<>();
}
this.routineDetailList.add(item);
}
public ArrayList<RoutineDetailModel> getDetailItemList() {
return routineDetailList;
}
public int getDetailItemSize() {
return routineDetailList.size();
}
public String getRoutine() {
return routine;
}
public void removeDetails(int index) throws Exception {
this.routineDetailList.remove(index);
}
#Override
public int hashCode() {
return Objects.hash(routineDetailList, routine);
}
#Override
public boolean equals(#Nullable Object obj) {
if (this == obj) {
return true;
}
if (obj == null || getClass() != obj.getClass()) {
return false;
}
RoutineModel that = (RoutineModel) obj;
return Objects.equals(routine, that.routine) && Objects.equals(routineDetailList, that.routineDetailList);
}
}
RoutineAdapter.java
public class RoutineAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>{
final static int TYPE_ROUTINE = 1;
final static int TYPE_ROUTINE_DETAIL = 2;
private Context context;
private List<Object> mItems = new ArrayList<>();
OnRoutineItemClickListener listener;
public void updateRoutineList(List<Object> newRoutineList) {
final RoutineDiffUtil diffCallback = new RoutineDiffUtil(this.mItems, newRoutineList);
final DiffUtil.DiffResult diffResult = DiffUtil.calculateDiff(diffCallback);
this.mItems.clear();
this.mItems.addAll(newRoutineList);
diffResult.dispatchUpdatesTo(this);
}
#NonNull
#Override
public RecyclerView.ViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
context = parent.getContext();
if (viewType == TYPE_ROUTINE) {
View itemView = LayoutInflater.from(context).inflate(R.layout.routine_item, parent, false);
return new RoutineViewHolder(itemView);
}
View itemView = LayoutInflater.from(context).inflate(R.layout.routine_detail_item, parent, false);
return new RoutineDetailViewHolder(itemView);
}
#Override
public void onBindViewHolder(#NonNull RecyclerView.ViewHolder holder, int position) {
Object object = mItems.get(position);
if(object instanceof RoutineModel) {
setRoutineData((RoutineViewHolder) holder, (RoutineModel) object, position);
}
else if(object instanceof RoutineDetailModel) {
}
}
private void setRoutineData(RoutineViewHolder holder, RoutineModel routineItem, int position){
holder.routine.setText(routineItem.getRoutine());
holder.addSet.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if(listener != null) listener.OnAddBtnClick(position);
}
});
holder.deleteSet.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if(listener != null) listener.OnDeleteBtnClick(position);
}
});
}
public Object getRoutineItem(int position) {
if(mItems == null || position < 0 || position >= mItems.size())
return null;
return mItems.get(position);
}
#Override
public int getItemCount() {
if(mItems == null)
return -1;
return mItems.size();
}
#Override
public int getItemViewType(int position) {
Object obj = mItems.get(position);
if(obj instanceof RoutineModel) {
return TYPE_ROUTINE;
}
return TYPE_ROUTINE_DETAIL;
}
// detail add,delete click interface
public interface OnRoutineItemClickListener {
public void OnAddBtnClick(int curRoutinePos);
public void OnDeleteBtnClick(int curRoutinePos);
}
public void setOnRoutineClickListener(OnRoutineItemClickListener listener) {
this.listener = listener;
}
public class RoutineViewHolder extends RecyclerView.ViewHolder {
public TextView routine;
public Button addSet;
public Button deleteSet;
public RoutineViewHolder(#NonNull View itemView) {
super(itemView);
routine = itemView.findViewById(R.id.routine);
addSet = itemView.findViewById(R.id.add_set);
deleteSet = itemView.findViewById(R.id.delete_set);
}
}
public class RoutineDetailViewHolder extends RecyclerView.ViewHolder {
public TextView set;
public TextView weight;
public RoutineDetailViewHolder(#NonNull View itemView) {
super(itemView);
set = itemView.findViewById(R.id.set);
weight = itemView.findViewById(R.id.weight);
}
}
}
RoutineDiffUtil.java
public class RoutineDiffUtil extends DiffUtil.Callback {
private List<Object> oldRoutineList;
private List<Object> newRoutineList;
public RoutineDiffUtil(List<Object> oldRoutineList) {
this.oldRoutineList = oldRoutineList;
newRoutineList = new ArrayList<>();
}
public RoutineDiffUtil(List<Object> oldRoutineList, List<Object> newRoutineList) {
this.oldRoutineList = oldRoutineList;
this.newRoutineList = newRoutineList;
}
#Override
public int getOldListSize() {
return oldRoutineList.size();
}
#Override
public int getNewListSize() {
return newRoutineList.size();
}
#Override
public boolean areItemsTheSame(int oldItemPosition, int newItemPosition) {
// boolean result = oldRoutineList.equals(newRoutineList); // work well
boolean result = oldRoutineList.get(oldItemPosition).hashCode() == newRoutineList.get(newItemPosition).hashCode();
return result;
}
#Override
public boolean areContentsTheSame(int oldItemPosition, int newItemPosition) {
return oldRoutineList.get(oldItemPosition).equals(newRoutineList.get(newItemPosition));
}
}
MainActivity.java
public class WriteRoutineActivity extends AppCompatActivity {
Button add_routine_btn;
TextView title;
RecyclerView routine_rv;
LinearLayoutManager routineLayoutManger;
RoutineAdapter routineAdapter;
List<RoutineModel> items;
List<String> titleData;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_write_routine);
initViews();
setPageTitle(getIntent());
setRoutineRecyclerview();
items = new ArrayList<>();
routineAdapter = new RoutineAdapter();
routine_rv.setAdapter(routineAdapter);
add_routine_btn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
WorkoutListDialogFragment routineDialog = new WorkoutListDialogFragment();
routineDialog.show(getSupportFragmentManager(), "RoutineListDialog");
}
});
routineAdapter.setOnRoutineClickListener(new RoutineAdapter.OnRoutineItemClickListener() {
#Override
public void OnAddBtnClick(int routinePos) {
Object obj = routineAdapter.getRoutineItem(routinePos);
if(obj instanceof RoutineModel) {
RoutineModel item = (RoutineModel) obj;
item.addDetail(new RoutineDetailModel());
routineAdapter.updateRoutineList(getDataToBeDisplayed());
}
}
#Override
public void OnDeleteBtnClick(int routinePos) {
Object item = routineAdapter.getRoutineItem(routinePos);
if(item instanceof RoutineModel) {
RoutineModel routineModel = (RoutineModel) item;
if(routineModel.getDetailItemSize() > 1) {
try {
routineModel.removeDetails(routineModel.getDetailItemSize() - 1);
} catch (Exception e) {
e.printStackTrace();
}
}
else { // if delete item exists only one
items.remove(routineModel);
}
routineAdapter.updateRoutineList(getDataToBeDisplayed());
}
}
});
}
public void addRoutine(String routine) {
RoutineModel routineModel = new RoutineModel(routine);
RoutineDetailModel routineDetailModel = new RoutineDetailModel();
routineModel.addDetail(routineDetailModel);
items.add(routineModel);
routineAdapter.updateRoutineList(getDataToBeDisplayed());
}
private List<Object> getDataToBeDisplayed() {
List<Object> mixedList = new ArrayList<>();
for(RoutineModel rm: items){
mixedList.add(rm);
if(rm.getDetailItemList() != null && rm.getDetailItemSize() > 0){
for(RoutineDetailModel rmdetilas: rm.getDetailItemList()){
mixedList.add(rmdetilas);
}
}
}
return mixedList;
}
}

Insert a native ad in a recyclerview of viewpager fragment

I am trying to build my 1st app, and want to insert an admob native ad in a recyclerview.
I have created the viewpager from android studio's default tabbed activity, and have inserted a recyclerview, which is working fine.
Now, from AdMob Native Advanced Ads in an Android Feed I am trying to insert a native ad.
But, the codelab example uses Fragment Transaction. Do I must need to implement that?
It will be helpful for me, if I can implement the complete ad related part in the fragment only (except the initialisation).
Here is my current status of the fragment:
public class SunFragment extends Fragment {
public static final int NUMBER_OF_ADS = 1;
private AdLoader adLoader;
private List<Object> mRecyclerViewItems = new ArrayList<>();
private List<UnifiedNativeAd> mNativeAds = new ArrayList<>();
ArrayList<Object> sunsList;
Typeface sunfont;
Double Dlat;
Double Dlang;
//to be called by the MainActivity
public SunFragment() {
// Required empty public constructor
}
private static final String KEY_LOCATION_NAME = "location_name";
public String TAG = "SunFragment";
public String location;//="No location name found";
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (savedInstanceState != null) {
location = savedInstanceState.getCharSequence(KEY_LOCATION_NAME).toString();
}
setRetainInstance(true);
}
public List<Object> getRecyclerViewItems() {
return mRecyclerViewItems;
}
private void loadNativeAds() {
AdLoader.Builder builder = new AdLoader.Builder(getContext(), getString(R.string.ad_unit_id));
adLoader = builder.forUnifiedNativeAd(
new UnifiedNativeAd.OnUnifiedNativeAdLoadedListener() {
#Override
public void onUnifiedNativeAdLoaded(UnifiedNativeAd unifiedNativeAd) {
// A native ad loaded successfully, check if the ad loader has finished loading
// and if so, insert the ads into the list.
mNativeAds.add(unifiedNativeAd);
if (!adLoader.isLoading()) {
//insertAdsInMenuItems();
mRecyclerViewItems.add(3, mNativeAds);
}
}
}).withAdListener(
new AdListener() {
#Override
public void onAdFailedToLoad(int errorCode) {
// A native ad failed to load, check if the ad loader has finished loading
// and if so, insert the ads into the list.
Log.e("MainActivity", "The previous native ad failed to load. Attempting to"
+ " load another.");
if (!adLoader.isLoading()) {
//insertAdsInMenuItems();
}
}
}).build();
// Load the Native ads.
adLoader.loadAds(new AdRequest.Builder().build(), NUMBER_OF_ADS);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
//onSaveInstanceState(new Bundle());
if (getArguments() != null) {
Dlat = getArguments().getDouble("loclat");
Dlang = getArguments().getDouble("loclang");
} else {
Dlat = 0.0;
Dlang = 0.0;
}
View rootView = inflater.inflate(R.layout.fragment_sun, container, false);
RecyclerView rv = rootView.findViewById(R.id.rv_recycler_view);
rv.setNestedScrollingEnabled(false);
rv.setHasFixedSize(true);
RecyclerView.LayoutManager llm = new LinearLayoutManager(getActivity());
rv.setLayoutManager(llm);
// System.out.println("location " + location);
setRetainInstance(true);
RecyclerView.Adapter adapter = new SunAdapter(getContext(), sunsList);
rv.setAdapter(adapter);
return rootView;
}
#Override
public void onSaveInstanceState(Bundle locState) {
super.onSaveInstanceState(locState);
if (location != null) {
locState.putCharSequence(KEY_LOCATION_NAME, location);
}
}
}
and the adapter is:
public class SunAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private final Context mContext;
private final ArrayList<Object> mSunsList;
private static final int MENU_ITEM_VIEW_TYPE = 0;
private static final int UNIFIED_NATIVE_AD_VIEW_TYPE = 1;
public SunAdapter(Context context, ArrayList<Object> sunsList) {
this.mContext = context;
this.mSunsList = sunsList;
}
public class MyViewHolder extends RecyclerView.ViewHolder {
private TextView textViewId;
private TextView textViewSicon;
private TextView textViewStime;
private TextView textViewEicon;
private TextView textViewEtime;
private TextView ntextViewSicon;
private TextView ntextViewStime;
private TextView ntextViewEicon;
private TextView ntextViewEtime;
MyViewHolder(View itemView) {
super(itemView);
textViewId = itemView.findViewById(R.id.tv_city);
textViewSicon = itemView.findViewById(R.id.tv_MSicon);
textViewStime = itemView.findViewById(R.id.tv_MStime);
textViewEicon = itemView.findViewById(R.id.tv_MEicon);
textViewEtime = itemView.findViewById(R.id.tv_MEtime);
ntextViewSicon = itemView.findViewById(R.id.tv_NSicon);
ntextViewStime = itemView.findViewById(R.id.tv_NStime);
ntextViewEicon = itemView.findViewById(R.id.tv_NEicon);
ntextViewEtime = itemView.findViewById(R.id.tv_NEtime);
// mSportsImage = itemView.findViewById(R.id.sportsImage);
}
}
#Override
public int getItemCount() {
return mSunsList.size();
}
#Override
public int getItemViewType(int position) {
Object sunList = mSunsList.get(position);
if (sunList instanceof UnifiedNativeAd) {
return UNIFIED_NATIVE_AD_VIEW_TYPE;
}
return MENU_ITEM_VIEW_TYPE;
}
#Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) {
switch (viewType) {
case UNIFIED_NATIVE_AD_VIEW_TYPE:
View unifiedNativeLayoutView = LayoutInflater.from(
viewGroup.getContext()).inflate(R.layout.ad_unified,
viewGroup, false);
return new UnifiedNativeAdViewHolder(unifiedNativeLayoutView);
case MENU_ITEM_VIEW_TYPE:
// Fall through.
default:
View menuItemLayoutView = LayoutInflater.from(viewGroup.getContext()).inflate(
R.layout.card_item, viewGroup, false);
return new MyViewHolder(menuItemLayoutView);
}
}
// #RequiresApi(api = Build.VERSION_CODES.N)
#Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
int viewType = getItemViewType(position);
switch (viewType) {
case UNIFIED_NATIVE_AD_VIEW_TYPE:
UnifiedNativeAd nativeAd = (UnifiedNativeAd) mSunsList.get(position);
populateNativeAdView(nativeAd, ((UnifiedNativeAdViewHolder) holder).getAdView());
break;
case MENU_ITEM_VIEW_TYPE:
// fall through
default:
MyViewHolder myViewHolder = (MyViewHolder) holder;
SunSession sunSession = (SunSession) mSunsList.get(position);
myViewHolder.textViewId.setText(sunSession.getId());
myViewHolder.textViewSicon.setText(HtmlCompat.fromHtml(sunSession.getSicon(), HtmlCompat.FROM_HTML_MODE_LEGACY));
myViewHolder.textViewStime.setText(sunSession.getStime());
myViewHolder.textViewEicon.setText(HtmlCompat.fromHtml(sunSession.getEicon(), HtmlCompat.FROM_HTML_MODE_LEGACY));
myViewHolder.textViewEtime.setText(sunSession.getEtime());
myViewHolder.ntextViewSicon.setText(HtmlCompat.fromHtml(sunSession.getNSicon(), HtmlCompat.FROM_HTML_MODE_LEGACY));
myViewHolder.ntextViewStime.setText(sunSession.getNStime());
myViewHolder.ntextViewEicon.setText(HtmlCompat.fromHtml(sunSession.getNEicon(), HtmlCompat.FROM_HTML_MODE_LEGACY));
myViewHolder.ntextViewEtime.setText(sunSession.getNEtime());
}
}
private void populateNativeAdView(UnifiedNativeAd nativeAd,
UnifiedNativeAdView adView) {
// Some assets are guaranteed to be in every UnifiedNativeAd.
((TextView) adView.getHeadlineView()).setText(nativeAd.getHeadline());
((TextView) adView.getBodyView()).setText(nativeAd.getBody());
((Button) adView.getCallToActionView()).setText(nativeAd.getCallToAction());
// These assets aren't guaranteed to be in every UnifiedNativeAd, so it's important to
// check before trying to display them.
NativeAd.Image icon = nativeAd.getIcon();
if (icon == null) {
adView.getIconView().setVisibility(View.INVISIBLE);
} else {
((ImageView) adView.getIconView()).setImageDrawable(icon.getDrawable());
adView.getIconView().setVisibility(View.VISIBLE);
}
if (nativeAd.getPrice() == null) {
adView.getPriceView().setVisibility(View.INVISIBLE);
} else {
adView.getPriceView().setVisibility(View.VISIBLE);
((TextView) adView.getPriceView()).setText(nativeAd.getPrice());
}
if (nativeAd.getStore() == null) {
adView.getStoreView().setVisibility(View.INVISIBLE);
} else {
adView.getStoreView().setVisibility(View.VISIBLE);
((TextView) adView.getStoreView()).setText(nativeAd.getStore());
}
if (nativeAd.getStarRating() == null) {
adView.getStarRatingView().setVisibility(View.INVISIBLE);
} else {
((RatingBar) adView.getStarRatingView())
.setRating(nativeAd.getStarRating().floatValue());
adView.getStarRatingView().setVisibility(View.VISIBLE);
}
if (nativeAd.getAdvertiser() == null) {
adView.getAdvertiserView().setVisibility(View.INVISIBLE);
} else {
((TextView) adView.getAdvertiserView()).setText(nativeAd.getAdvertiser());
adView.getAdvertiserView().setVisibility(View.VISIBLE);
}
// Assign native ad object to the native view.
adView.setNativeAd(nativeAd);
}
}
with this situation, the normal recyclerview is working, but no ad is inserted.
It will be really helpful if somebody shows me how to insert the ad, following the codelab, which probably means, how to implemeant this section in my fragment.

Ads in recyclerview

I have an app that stores some data in room database. At first, my adapter was like that:
public class ViewCourseAdapter extends ListAdapter<Course, ViewCourseAdapter.ViewCourseHolder> {
private int previousPosition = 0;
public ViewCourseAdapter() {
super(DIFF_CALLBACK);
}
private static final DiffUtil.ItemCallback<Course> DIFF_CALLBACK = new DiffUtil.ItemCallback<Course>() {
#Override
public boolean areItemsTheSame(#NonNull Course oldItem, #NonNull Course newItem) {
return oldItem.getId() == newItem.getId();
}
#Override
public boolean areContentsTheSame(#NonNull Course oldItem, #NonNull Course newItem) {
return oldItem.getfName().equals(newItem.getfName());
}
};
#NonNull
#Override
public ViewCourseHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View itemView = LayoutInflater.from(parent.getContext())
.inflate(R.layout.view_courses_item, parent, false);
return new ViewCourseHolder(itemView);
}
#Override
public void onBindViewHolder(#NonNull ViewCourseHolder holder, int position) {
Course currentCourse = getItem(position);
String fullName = currentCourse.getfName() + " " + currentCourse.getlName();
SpannableString SfullName = new SpannableString(fullName);
SfullName.setSpan(new UnderlineSpan(), 0, fullName.length(), 0);
holder.text_view_firstName_1.setText(SfullName);
if (position > previousPosition) {
AnimationUtil.animate(holder, true);
} else {
AnimationUtil.animate(holder, false);
}
previousPosition = position;
}
class ViewCourseHolder extends RecyclerView.ViewHolder {
private TextView text_view_firstName_1;
ViewCourseHolder(#NonNull View itemView) {
super(itemView);
text_view_firstName_1 = itemView.findViewById(R.id.text_view_firstName_1);
}
}
#Override
public int getItemCount() {
return super.getItemCount();
}
And everything was working perfect. Now I want to show ads inside recyclerview, so I changed my adapter:
public class ViewCourseAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private static final int COURSE_VIEW_TYPE = 0;
private static final int AD_VIEW_TYPE = 1;
private List<Course> data;
private List<Object> ad;
private Context context;
private LayoutInflater layoutInflater;
private int previousPosition = 0;
public ViewCourseAdapter(Context context, List<Object> ad) {
this.data = new ArrayList<>();
this.context = context;
this.layoutInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
this.ad = ad;
}
#NonNull
#Override
public RecyclerView.ViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
switch (viewType ) {
case COURSE_VIEW_TYPE:
View courseView = LayoutInflater.from(parent.getContext()).inflate(R.layout.view_courses_item, parent, false);
return new ViewCourseViewHolder(courseView);
case AD_VIEW_TYPE:
default:
View adView = LayoutInflater.from(parent.getContext()).inflate(R.layout.native_ads, parent, false);
return new AdViewHolder(adView);
}
}
#Override
public void onBindViewHolder(#NonNull RecyclerView.ViewHolder holder, int position) {
int viewType = getItemViewType(position);
switch (viewType) {
case COURSE_VIEW_TYPE:
ViewCourseViewHolder holder1 = (ViewCourseViewHolder) holder;
Course currentCourse = (Course) data.get(position);
String fullName = currentCourse.getfName() + " " + currentCourse.getlName();
SpannableString SfullName = new SpannableString(fullName);
SfullName.setSpan(new UnderlineSpan(), 0, fullName.length(), 0);
holder1.text_view_firstName_1.setText(SfullName);
break;
case AD_VIEW_TYPE:
default:
AdViewHolder bannerHolder = (AdViewHolder) holder;
AdView adView = (AdView) ad.get(position);
ViewGroup adCardView = (ViewGroup) bannerHolder.itemView;
if (adCardView.getChildCount() > 0) {
adCardView.removeAllViews();
}
if (adView.getParent() != null) {
((ViewGroup) adView.getParent()).removeView(adView);
}
adCardView.addView(adView);
}
if (position > previousPosition) {
AnimationUtil.animate(holder, true);
} else {
AnimationUtil.animate(holder, false);
}
previousPosition = position;
}
class AdViewHolder extends RecyclerView.ViewHolder {
AdViewHolder(View view) {
super(view);
}
}
#Override
public int getItemViewType(int position) {
return (position % ViewCoursesActivity.ITEMS_PER_AD == 0) ? AD_VIEW_TYPE
: COURSE_VIEW_TYPE;
}
#Override
public int getItemCount() {
return data.size();
}
public void setData(List<Course> newData) {
if (data != null) {
CourseDiffCallback courseDiffCallback = new CourseDiffCallback(data, newData);
DiffUtil.DiffResult diffResult = DiffUtil.calculateDiff(courseDiffCallback);
data.clear();
data.addAll(newData);
diffResult.dispatchUpdatesTo(this);
} else {
data = newData;
}
}
public class ViewCourseViewHolder extends RecyclerView.ViewHolder {
private TextView text_view_firstName_1;
ViewCourseViewHolder(#NonNull View itemView) {
super(itemView);
text_view_firstName_1 = itemView.findViewById(R.id.text_view_firstName_1);
}
}
private class CourseDiffCallback extends DiffUtil.Callback {
private final List<Course> oldItem, newItem;
private CourseDiffCallback(List<Course> oldItem, List<Course> newItem) {
this.oldItem = oldItem;
this.newItem = newItem;
}
#Override
public int getOldListSize() {
return oldItem.size();
}
#Override
public int getNewListSize() {
return newItem.size();
}
#Override
public boolean areItemsTheSame(int oldItemPosition, int newItemPosition) {
return oldItem.get(oldItemPosition).getId() == newItem.get(newItemPosition).getId();
}
#Override
public boolean areContentsTheSame(int oldItemPosition, int newItemPosition) {
return oldItem.get(oldItemPosition).getfName().equals(newItem.get(newItemPosition).getfName());
}
}
And my activity is:
public class ViewCoursesActivity extends AppCompatActivity {
private CourseViewModel courseViewModel;
// A banner ad is placed in every 8th position in the RecyclerView.
public static final int ITEMS_PER_AD = 8;
private static final String AD_UNIT_ID = "ca-app-pub-3940256099942544/6300978111";
// The RecyclerView that holds and displays banner ads and menu items.
private RecyclerView recyclerView;
// List of banner ads and MenuItems that populate the RecyclerView.
private List<Object> data = new ArrayList<>();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_view_courses);
recyclerView = findViewById(R.id.recycler_view_3);
recyclerView.setHasFixedSize(true);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
addBannerAds();
loadBannerAds();
final ViewCourseAdapter adapter = new ViewCourseAdapter(this, data);
recyclerView.setAdapter(adapter);
courseViewModel = ViewModelProviders.of(this).get(CourseViewModel.class);
courseViewModel.setIdForCourse(0);
//courseViewModel.getCourseByStudentId().observe(this, adapter::submitList);
courseViewModel.getCourseByStudentId().observe(this, adapter::setData);
}
#Override
protected void onResume() {
for (Object item : data) {
if (item instanceof AdView) {
AdView adView = (AdView) item;
adView.resume();
}
}
super.onResume();
}
#Override
protected void onPause() {
for (Object item : data) {
if (item instanceof AdView) {
AdView adView = (AdView) item;
adView.pause();
}
}
super.onPause();
}
#Override
protected void onDestroy() {
for (Object item : data) {
if (item instanceof AdView) {
AdView adView = (AdView) item;
adView.destroy();
}
}
super.onDestroy();
}
/**
* Adds banner ads to the items list.
*/
private void addBannerAds() {
// Loop through the items array and place a new banner ad in every ith position in
// the items List.
for (int i = 0; i <= data.size(); i += ITEMS_PER_AD) {
final AdView adView = new AdView(ViewCoursesActivity.this);
adView.setAdSize(AdSize.SMART_BANNER);
adView.setAdUnitId(AD_UNIT_ID);
data.add(i, adView);
}
}
/**
* Sets up and loads the banner ads.
*/
private void loadBannerAds() {
// Load the first banner ad in the items list (subsequent ads will be loaded automatically
// in sequence).
loadBannerAd(0);
}
/**
* Loads the banner ads in the items list.
*/
private void loadBannerAd(final int index) {
if (index >= data.size()) {
return;
}
Object item = data.get(index);
if (!(item instanceof AdView)) {
throw new ClassCastException("Expected item at index " + index + " to be a banner ad"
+ " ad.");
}
final AdView adView = (AdView) item;
// Set an AdListener on the AdView to wait for the previous banner ad
// to finish loading before loading the next ad in the items list.
adView.setAdListener(new AdListener() {
#Override
public void onAdLoaded() {
super.onAdLoaded();
// The previous banner ad loaded successfully, call this method again to
// load the next ad in the items list.
loadBannerAd(index + ITEMS_PER_AD);
}
#Override
public void onAdFailedToLoad(int errorCode) {
// The previous banner ad failed to load. Call this method again to load
// the next ad in the items list.
Log.e("ViewCoursesActivity", "The previous banner ad failed to load. Attempting to"
+ " load the next banner ad in the items list.");
loadBannerAd(index + ITEMS_PER_AD);
}
});
// Load the banner ad.
adView.loadAd(new AdRequest.Builder().build());
}
After that I have two problems:
1. At frist position it display an ad instead of first item from my database, and first item is nowhere. If I check my database first item is there, just not apear in recyclerview.
2. If I want to scroll items, the app crash, and the error is "java.lang.IndexOutOfBoundsException: Index: 8, Size: 1".
What am I doing wrong?
Please help me. Thank you!
Fundamentally, a RecyclerView is used to display a List to the user. Use this to guide your implementation.
Currently, you have two lists:
private List<Course> data;
private List<Object> ad;
You need to find a way to "collate" these down to a single list. Maybe something like this:
private static List<Object> collate(List<Course> data, List<Object> ads) {
List<Object> collated = new ArrayList<>();
while (data.size() > 0 || ads.size() > 0) {
for (int i = 0; i < ITEMS_PER_AD && data.size() > 0; ++i) {
collated.add(data.remove(0));
}
if (ads.size() > 0) {
collated.add(ads.remove(0));
}
}
return collated;
}
With that method defined, you can replace your existing constructor:
private List<Course> data;
private List<Object> ad;
// ...
public ViewCourseAdapter(Context context, List<Object> ad) {
this.data = new ArrayList<>();
this.ad = ad;
// ...
}
with this:
private List<Object> ad;
private List<Object> collated;
// ...
public ViewCourseAdapter(Context context, List<Object> ad) {
this.ad = ad;
this.collated = new ArrayList<>(ad);
// ...
}
And you can replace your existing setData() method:
public void setData(List<Course> newData) {
if (data != null) {
CourseDiffCallback courseDiffCallback = new CourseDiffCallback(data, newData);
DiffUtil.DiffResult diffResult = DiffUtil.calculateDiff(courseDiffCallback);
data.clear();
data.addAll(newData);
diffResult.dispatchUpdatesTo(this);
} else {
data = newData;
}
}
with this:
public void setData(List<Course> newData) {
if (data != null) {
List<Object> newCollated = collate(ad, newData);
// setup DiffUtil callback here...
this.collated = newCollated;
// dispatch DiffUtil result here...
}
}
Now you will have a single list that you can use in your adapter. Then you can change your adapter's methods to use that one list:
#Override
public int getItemCount() {
return collated.size();
}
#Override
public int getItemViewType(int position) {
return (collated.get(position) instanceof Course)
? COURSE_VIEW_TYPE
: AD_VIEW_TYPE;
}
#Override
public void onBindViewHolder(#NonNull RecyclerView.ViewHolder holder, int position) {
if (holder.getItemViewType() == COURSE_VIEW_TYPE) {
bindCourseHolder((ViewCourseViewHolder) holder, position);
} else if (holder.getItemViewType() == AD_VIEW_TYPE) {
bindAdHolder((AdViewHolder) holder, position);
}
}
private void bindCourseHolder(ViewCourseViewHolder holder, int position) {
// ...
}
private void bindAdHolder(AdViewHolder holder, int position) {
// ...
}
All of these changes are based on the fundamental concept that you just have a single list, and that list holds (potentially) many different types of things.
Thank you #Ben P. for advice...I can't believe I didn't see this...so I modify collate() method like this:
while (data.size() > 0) {
collated.addAll(ad);
for (int i = 0; i < ITEMS_PER_AD && data.size() > 0; ++i) {
collated.add(data.remove(0));
}
}
ad.remove(0);
return collated;
It is there a better way to do this?

Animation on notifyDataSetChanged() in FragmentStatePagerAdapter

By overwriting getItemPosition() method I can refresh my FragmentStatePagerAdapter, which works fine. But the change of the contents is not nice to see.
Is there possibility to apply any kind of animation as I refresh the FragmentStatePagerAdapter?
I was also facing same issue.So, what should you do. Make global variables in your adapter for what you want continuous animate.
Now when you start animation on button click. Pass value to global variables.
When you notifydatasetchanged it doesn't effect your animation.
I haven't found any correct way. So, did this thing.It's working perfect.
public class HomeAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private Context mContext;
private ArrayList<Response.DataBean> feedArrayList = new ArrayList<>();
FeedClickListener mListener;
#Inject
ImageUtility mImageUtility;
#Inject
AppUtils mAppUtils;
#Inject
PreferenceManager mPref;
private float prevPosition = -1;
private YoYo.YoYoString ropeText,ropeImage;
private int tempHandlePlayPause = 0;
private TextView tempTextView;
private ImageView tempImageView;
/**
* click listeners
*/
interface FeedClickListener {
void onPlayAudioClicked( FeedResponse.DataBean feedItem, SeekBar audioProgress, int position);
void onPauseAudioClicked(FeedResponse.DataBean feedItem);
}
public HomeAdapter(Context context, ArrayList<Response.DataBean> mDataArrayList, HomeClickListener mFeedListener) {
((BaseApplication) context.getApplicationContext()).getAppComponent().inject(this);
this.mContext = context;
this.feedArrayList = mDataArrayList;
mListener = mFeedListener;
}
#Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
return new ItemViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.item_layout, parent, false));
}
#Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
switch (holder.getItemViewType()) {
ItemViewHolder holderItem = (ItemViewHolder) holder;
int adapterPosition = holder.getAdapterPosition() - 1;
holderItem.normalContainer.setVisibility(View.VISIBLE);
holderItem.bannerContainer.setVisibility(View.GONE);
setUpNormalItem(adapterPosition, holderItem);
}
}
private void setUpNormalItem(int adapterPosition, ItemViewHolder holder) {
FeedResponse.DataBean feedItem = feedArrayList.get(adapterPosition);
// set up data to current view holder items
setUpItems(holder, feedItem, adapterPosition);
}
private void setUpItems(ItemViewHolder holder, FeedResponse.DataBean feedItem, int position) {
if (feedItem.isstop()) {
holder.playImageView.setVisibility(View.GONE);
holder.pauseImageView.setVisibility(View.VISIBLE);
} else {
holder.playImageView.setVisibility(View.VISIBLE);
holder.pauseImageView.setVisibility(View.GONE);
holder.audioProgress.setProgress(0);
}
holder.playImageView.setOnClickListener(v -> {
feedItem.setIscomplete(false);
if (prevPosition >= 0) {
feedArrayList.get((int)prevPosition).setIsstop(false);
feedArrayList.get((int)prevPosition).setIsPrepare(false);
}
feedArrayList.get(position).setIsstop(true);
feedArrayList.get(position).setIsPrepare(true);
mListener.onPlayAudioClicked(feedItem, holder.audioProgress, position);
prevPosition = position;
tempHandlePlayPause = 1;
tempTextView = holder.tvPlayingBlink;
tempImageView = holder.pauseImageView;
notifyDataSetChanged();
});
holder.pauseImageView.setOnClickListener(v -> {
feedArrayList.get(position).setIsstop(false);
tempTextView = holder.tvPlayingBlink;
tempImageView = holder.pauseImageView;
tempHandlePlayPause = 0;
mListener.onPauseAudioClicked(feedItem);
notifyDataSetChanged();
});
if (feedItem.isPrepare()) {
holder.tvPlayingBlink.setVisibility(View.VISIBLE);
if (tempHandlePlayPause == 1){
startAnimation();
}else {
stopAnimation();
}
} else {
holder.tvPlayingBlink.setVisibility(View.INVISIBLE);
if (tempHandlePlayPause == 1){
startAnimation();
}else {
stopAnimation();
}
}
// play on complete audio
if (feedItem.iscomplete()) {
holder.playImageView.setVisibility(View.VISIBLE);
holder.pauseImageView.setVisibility(View.GONE);
}
if ((!feedItem.iscomplete()) && feedItem.getTotalLength() > 0) {
holder.audioProgress.setMax(feedItem.getTotalLength());
holder.audioProgress.setProgress(0);
}
}
private void startAnimation(){
if (ropeText != null || ropeImage != null) {
ropeText.stop(true);
ropeImage.stop(true);
}
ropeText = YoYo.with(Techniques.Pulse)
.duration(800)
.repeat(YoYo.INFINITE)
.pivot(YoYo.CENTER_PIVOT, YoYo.CENTER_PIVOT)
.interpolate(new AccelerateDecelerateInterpolator())
.playOn(tempTextView);
ropeImage = YoYo.with(Techniques.Pulse)
.duration(800)
.repeat(YoYo.INFINITE)
.pivot(YoYo.CENTER_PIVOT, YoYo.CENTER_PIVOT)
.interpolate(new AccelerateDecelerateInterpolator())
.playOn(tempImageView);
}
private void stopAnimation(){
if (ropeText != null || ropeImage != null) {
ropeText.stop(true);
ropeImage.stop(true);
}
}
public void updateData(List<FeedResponse.DataBean> items) {
feedArrayList.clear();
feedArrayList.addAll(items);
notifyDataSetChanged();
}
public void deleteItem(int position) {
feedArrayList.remove(position);
notifyDataSetChanged();
}
#Override
public int getItemCount() {
return (feedArrayList.size());
}
public static class ItemViewHolder extends RecyclerView.ViewHolder {
#BindView(R.id.image_view_3)
ImageView imageView3;
#BindView(R.id.tvplayingblink)
TextView tvPlayingBlink;
public ItemViewHolder(View itemView) {
super(itemView);
ButterKnife.bind(this, itemView);
}
}
}

Categories

Resources