Friends, help me please. I'm making a RecyclerView with ads. The list is not displayed correctly. When embedded advertising, break sequence list. In the screenshot I give an example.
The list is not currently displayed correctly. Item 10 is not displayed:
I need Item 10 to be visible as in this screenshot:
My adapter code:
public class ScheduleAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private List<Card> scheduleList;
private static final int CONTENT = 0;
private static final int AD = 1;
public class MyViewHolder extends RecyclerView.ViewHolder {
public TextView textDate;
public TextView textSubject;
public Button share;
public MyViewHolder(View view) {
super(view);
textDate = view.findViewById(R.id.textDate);
textSubject = view.findViewById(R.id.textSubject);
share = view.findViewById(R.id.shareBtn);
Typeface custom_font = Typeface.createFromAsset(view.getContext().getAssets(), "Exo2Light.ttf");
textDate.setTypeface(custom_font);
textSubject.setTypeface(custom_font);
}
}
public static class ViewHolderAdMob extends RecyclerView.ViewHolder {
public AdView mAdView;
public ViewHolderAdMob(View view) {
super(view);
mAdView = view.findViewById(R.id.adView);
}
}
public ScheduleAdapter(List<Card> scheduleList) {
this.scheduleList = scheduleList;
}
#Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
RecyclerView.ViewHolder viewHolder = null;
LayoutInflater inflater = LayoutInflater.from(parent.getContext());
if (viewType == CONTENT) {
View v = inflater.inflate(R.layout.recycler_item, parent, false);
viewHolder = new MyViewHolder(v);
} else {
View v = inflater.inflate(R.layout.recycler_item_admob, parent, false);
viewHolder = new ViewHolderAdMob(v);
}
return viewHolder;
}
#Override
public void onBindViewHolder(final RecyclerView.ViewHolder holder, int position) {
if (getItemViewType(position) == CONTENT) {
MyViewHolder viewHolder = (MyViewHolder) holder;
Card card = scheduleList.get(position);
viewHolder.textDate.setText(card.getDateline());
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N)
viewHolder.textSubject.setText(Html.fromHtml(card.getContentline(), Html.FROM_HTML_MODE_COMPACT));
else
viewHolder.textSubject.setText(Html.fromHtml(card.getContentline()));
((MyViewHolder) holder).share.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// handle your click here.
Intent sharingIntent = new Intent(Intent.ACTION_SEND);
sharingIntent.setType("text/plain");
sharingIntent.putExtra(Intent.EXTRA_TEXT, "\uD83D\uDCC5 " + ((MyViewHolder) holder).textDate.getText().toString()+"\r\n"+((MyViewHolder) holder).textSubject.getText().toString());
v.getContext().startActivity(Intent.createChooser(sharingIntent,"Поділитися..."));
} });
} else {
AdRequest adRequest = new AdRequest.Builder()
//.addTestDevice("B86C95B89D21A5F8E2C22F0D94470A13")
.build();
((ViewHolderAdMob) holder).mAdView.setAdListener(new AdListener() {
#Override
public void onAdLoaded() {
super.onAdLoaded();
((ViewHolderAdMob) holder).mAdView.setVisibility(View.VISIBLE);
}
#Override
public void onAdFailedToLoad(int errorCode) {
super.onAdFailedToLoad(errorCode);
((ViewHolderAdMob) holder).mAdView.setVisibility(View.GONE);
}
});
((ViewHolderAdMob) holder).mAdView.loadAd(adRequest);
}
}
#Override
public int getItemViewType(int position) {
if (position == 10) {
return AD;
}
return CONTENT;
}
#Override
public int getItemCount() {
return scheduleList.size();
}
}
Replace your code with
#Override
public int getItemCount() {
return scheduleList.size() + 1;
}
and use this function get Card object in onBindViewHolder
public Card getItem(int position) {
if(position > 10){
return scheduleList.get(position - 1)
}else{
return scheduleList.get(position)
}
}
By adding 1 to getItemCount() function, we are making adapter to draw one more line which represents ad.
And being sure we dont have IndexOutOfBoundsException for 13th row by decreasing position by minus one for the values which bigger than 10 in getItem(int position) function.
Related
I'm trying to show a list of data with RecyclerView and add an AdMob after 3 data showed. I have followed this stackoverflow Q&A because it's almost the same as my code but I'm using Retrofit.
But my result is just showing test AdMob rows only... It's not show my data's name String.
This is my MainActivity:
public class Nilai extends AppCompatActivity implements NilaiView {
RecyclerView recyclerView;
SwipeRefreshLayout swipeRefresh;
NilaiPresenter presenter;
RecyclerViewAdopter adapter;
List<modelNilai> score;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_nilai);
MobileAds.initialize(this, "ID_APP");
recyclerView = findViewById(R.id.recyclerView);
swipeRefresh = findViewById(R.id.swipe_refresh);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
presenter = new NilaiPresenter(this);
presenter.getNilai();
swipeRefresh.setOnRefreshListener(
() -> presenter.getNilai()
);
}
#Override
public void showLoading() {
swipeRefresh.setRefreshing(true);
}
#Override
public void hideLoading() {
swipeRefresh.setRefreshing(false);
}
#Override
public void onGetNilai(List<modelNilai> scores) {
adapter = new RecyclerViewAdopter(Nilai.this, scores);
adapter.notifyDataSetChanged();
recyclerView.setItemAnimator(new DefaultItemAnimator());
recyclerView.setAdapter(adapter);
score = scores;
for (int i = 0; i <= scores.size(); i += 3)
{
modelNilai myString2 = new modelNilai();
myString.setId(i);
scores.add(i,myString);
}
}
}
My Adapter:
public class RecyclerViewAdopter extends RecyclerView.Adapter<RecyclerView.ViewHolder>{
private Context mContext;
private List<modelNilai> mList;
public RecyclerViewAdopter(Context mContext, List<modelNilai> mList) {
this.mList = mList;
this.mContext = mContext;
}
public static class MyViewHolder extends RecyclerView.ViewHolder {
public TextView name;
public MyViewHolder(View view) {
super(view);
name = view.findViewById(R.id.namaSoal);
}
}
public static class ViewHolderAdMob extends RecyclerView.ViewHolder {
public AdView mAdView;
public ViewHolderAdMob(View view) {
super(view);
mAdView = view.findViewById(R.id.adView);
AdRequest adRequest = new AdRequest.Builder()
.addTestDevice("CEE26DC1A5BBF0E603B08A5460483046")
.build();
mAdView.loadAd(adRequest);
}
}
#Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
RecyclerView.ViewHolder viewHolder = null;
LayoutInflater inflater = LayoutInflater.from(parent.getContext());
switch(viewType){
case 1:
{
View v = inflater.inflate(R.layout.list_nilai_ad, parent, false);
viewHolder = new MyViewHolder(v);
break;
}
case 2:
default:
{
View v = inflater.inflate(R.layout.banner_ad_row, parent, false);
viewHolder = new ViewHolderAdMob(v);
break;
}
}
return viewHolder;
}
#Override
public void onBindViewHolder(final RecyclerView.ViewHolder holder, final int position) {
modelNilai model = mList.get(holder.getAdapterPosition());
switch(holder.getItemViewType()){
case 1:{
MyViewHolder viewHolder = (MyViewHolder) holder;
viewHolder.name.setText(model.getName());
break;
}
case 2:{
break;
}
}
}
#Override
public int getItemViewType(int position)
{
return mList.get(position).getId();
}
#Override
public int getItemCount() {
return mList.size();
}
}
My presenter:
public class NilaiPresenter {
private NilaiView view;
public NilaiPresenter(NilaiView view) {
this.view = view;
}
void getNilai() {
view.showLoading();
ApiInterface apiInterface = ApiClient.getApiClient().create(ApiInterface.class);
Call<List<modelNilai>> call = apiInterface.getNilai();
call.enqueue(new Callback<List<modelNilai>>() {
#Override
public void onResponse(#NonNull Call<List<modelNilai>> call, #NonNull Response<List<modelNilai>> response) {
view.hideLoading();
if (response.isSuccessful() && response.body() != null) {
view.onGetNilai(response.body());
}
}
#Override
public void onFailure(#NonNull Call<List<modelNilai>> call, #NonNull Throwable t) {
view.hideLoading();
view.onRequestError(t.getLocalizedMessage());
}
});
}
}
My model class:
public class modelNilai {
#Expose
#SerializedName("id") private int id_nilai;
#Expose
#SerializedName("name") private String name;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
And My view interface:
public interface NilaiView {
void showLoading();
void hideLoading();
void onGetNilai(List<modelNilai> scores);
}
Result on phone:
It should show something like 3 rows of name and 1 row of Admob, and repeat that again per 4 rows.
Parhaps, the getItemViewType() method should be like this:
#Override
public int getItemViewType(int position)
{
return (position + 1) % 4 == 0 ? 2 : 1;
}
You also have to modify the getItemCount() method. Because it should return the count of all of your mList rows and PLUS of your Admob rows.
#Override
public int getItemCount() {
return mList.size() + mList.size / 4;
}
In addition to that the onBindViewHolder method is affected:
#Override
public void onBindViewHolder(final RecyclerView.ViewHolder holder, final int position) {
modelNilai model = mList.get(holder.getAdapterPosition() - holder.getAdapterPosition() / 4);
if ((position + 1) % 4 != 0) {
MyViewHolder viewHolder = (MyViewHolder) holder;
viewHolder.name.setText(model.getName());
}
}
I am working with RecyclerView which support pagination with Firestore database.I want to showing into 10 items recylcerview an Ads,i try serveral times without succes,help me please to find the right code.
Here is my code of pagination.
//Initialize FirebasePagingOptions
DatabasePagingOptions<Pubs> options = new DatabasePagingOptions.Builder<Pubs>()
.setLifecycleOwner(this)
.setQuery(mDatabase, config, Pubs.class)
.build();
//Initialize Adapter
mAdapter = new FirebaseRecyclerPagingAdapter<Pubs, PubsViewHolder>(options) {
#Override
public int getItemViewType(int position)
{
if (position % 5 == 0)
return AD_TYPE;
return CONTENT_TYPE;
}
#NonNull
#Override
public PubsViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
return new PubsViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.item_pub, parent, false));
}
#Override
protected void onBindViewHolder(#NonNull PubsViewHolder holder,
int position,
#NonNull Pubs model) {
holder.setItem(model);
}
this is a full example to how to use multi type recyclerview with custom adapter with Model and Ads Type
and for paging issue you have to handle it outside adapter class it can be more easier.
public class SiteAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private List<SiteModel> dataList;
private Context context;
private static final int AD_TYPE = 1;
private static final int CONTENT_TYPE = 2;
public SiteAdapter(Context context) {
this.context = context;
dataList = new ArrayList<>();
}
#Override
public int getItemViewType(int position) {
if (dataList.get(position) == null)
return AD_TYPE;
return CONTENT_TYPE;
}
public List<SiteModel> getDataList() {
return dataList;
}
#NonNull
#Override
public RecyclerView.ViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View v = null;
RecyclerView.ViewHolder vh = null;
if (viewType == AD_TYPE) {
v = LayoutInflater.from(parent.getContext()).inflate(R.layout.ad_view_item, parent, false);
vh = new AdViewHolder(v);
} else {
v = LayoutInflater.from(parent.getContext()).inflate(R.layout.site_list_item, parent, false);
vh = new SitesViewHolder(v);
}
return vh;
}
#Override
public void onBindViewHolder(#NonNull final RecyclerView.ViewHolder holder, int position) {
holder.setIsRecyclable(false);
if (getItemViewType(position) == CONTENT_TYPE) {
} else {
AdViewHolder adViewHolder = (AdViewHolder) holder;
AdRequest request = new AdRequest.Builder().build();
adViewHolder.adView.loadAd(request);
}
}
#Override
public int getItemCount() {
return dataList.size();
}
public void add(SiteModel siteModel, int i) {
dataList.add(siteModel);
notifyItemInserted(i);
}
public void add(List<SiteModel> moreData) {
dataList.addAll(moreData);
notifyDataSetChanged();
}
public void updateItem(String desc, boolean isFavourites, int adapterPosition) {
dataList.get(adapterPosition).setDesc(desc);
notifyItemChanged(adapterPosition);
}
public class SitesViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
public SitesViewHolder(View itemView) {
super(itemView);
}
#Override
public void onClick(View v) {
if (clickListener != null) {
switch (v.getId()) {
}
}
}
private class AdViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
AdView adView;
public AdViewHolder(View itemView) {
super(itemView);
adView = itemView.findViewById(R.id.adView);
}
#Override
public void onClick(View v) {
}
}
}
My Title is kind of hard to understand but basically when I add items into my database is should display it in a RecyclerView. Now in my RecyclerView I have two layouts but the problem is the first item of my database goes behind my first item in my other layout. So if I have 3 items in my database, it shows only 2 items from the database and the first item hides behind my first item in the RecyclerView which is a different layout that does not use the database at all.
This is my code:
FirebaseRecyclerOptions<Event> firebaseRecyclerOptions = new FirebaseRecyclerOptions.Builder<Event>()
.setQuery(query1, Event.class).build();
AccAdapter = new FirebaseRecyclerAdapter<Event, RecyclerView.ViewHolder>(firebaseRecyclerOptions){
final static int TYPE_HEADER = 0;
final static int TYPE_ITEM = 1;
#Override
public int getItemViewType(int position) {
if (position == 0) return TYPE_HEADER;
return TYPE_ITEM;
}
#Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
if (viewType == TYPE_HEADER){
View view = LayoutInflater.from(getActivity()).inflate(R.layout.recycler_view_row_add_items,
parent, false);
return new ProdudctHolder3(view);
} else {
View view = LayoutInflater.from(getActivity()).inflate(R.layout.recycler_view_row_acc,
parent, false);
return new ProductHolder2(view);
}
}
#Override
protected void onBindViewHolder(final RecyclerView.ViewHolder holder, int position, final Event model) {
if (holder instanceof ProdudctHolder3){
((ProdudctHolder3) holder).addBackground.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
startActivity(new Intent(getActivity(), AccAddItems.class ));
}
});
} else{
final ProductHolder2 productHolder2 = (ProductHolder2) holder;
productHolder2.mName.setText(model.getName());
productHolder2.view.setBackgroundResource(getBackgroundDrawable(Integer.valueOf(model.getProductAmount())));
productHolder2.mbackground.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
dialog = new Dialog(getActivity());
dialog.setContentView(R.layout.popup_edit_product);
SeekBar amountSeekBar = dialog.findViewById(R.id.amountSeekBar);
amountSeekBar.setMax(100);
amountSeekBar.setProgress(Integer.valueOf(model.getProductAmount()));
amountSeekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
#Override
public void onProgressChanged(SeekBar seekBar, int i, boolean b) {
progress = i;
}
#Override
public void onStartTrackingTouch(SeekBar seekBar) {
}
#Override
public void onStopTrackingTouch(SeekBar seekBar) {
getRef(holder.getAdapterPosition()).child("productAmount").setValue(String.valueOf(progress));
dialog.dismiss();
}
});
dialog.show();
}
});
productHolder2.mbackground.setOnLongClickListener(new View.OnLongClickListener() {
#Override
public boolean onLongClick(View view) {
final PopupMenu popupMenu = new PopupMenu(getActivity(), productHolder2.mbackground);
popupMenu.inflate(R.menu.menu_acc);
popupMenu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
#Override
public boolean onMenuItemClick(MenuItem menuItem) {
switch (menuItem.getItemId()){
case R.id.deleteProduct:
getRef(productHolder2.getAdapterPosition()).removeValue();
popupMenu.dismiss();
return true;
default:
return false;
}
}
});
popupMenu.show();
return true;
}
});
}
}
};
mAccRecyclerViewRef.setAdapter(AccAdapter);
My two Product Holders
private class ProdudctHolder3 extends RecyclerView.ViewHolder{
private RelativeLayout addBackground;
public ProdudctHolder3(View itemView) {
super(itemView);
addBackground = itemView.findViewById(R.id.mBackground2);
}
}
private class ProductHolder2 extends RecyclerView.ViewHolder{
private TextView mName;
private RelativeLayout mbackground;
private View view;
public ProductHolder2(View itemView) {
super(itemView);
mName = itemView.findViewById(R.id.ItemName);
mbackground = itemView.findViewById(R.id.mBackground1);
view = itemView.findViewById(R.id.amountIndicator);
}
}
The ideal solution would have been to set two adapters on a single RecyclerView but unfortunatelly this is not possible.
However, you can make a single custom Adapter that handles two types of items. I will explain this by getting an example.
Let's assume you need to display objects of two types, humans and aliens. Your objects require completely different layouts and completely different ViewHolders. Please see the below code for the ViewHolders:
public class MyAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private static class HumanViewHolder extends RecyclerView.ViewHolder {
public HumanViewHolder(View itemView) {
super(itemView);
//Prepare your ViewHolder
}
public void bind(Human human) {
//Display your human object
}
}
private static class AlienViewHolder extends RecyclerView.ViewHolder {
public AlienViewHolder(View itemView) {
super(itemView);
//Prepare your ViewHolder
}
public void bind(Alien alien) {
//Display your alien object
}
}
}
First you need to add two different constants to your adapter representing both type of views:
private static final int ITEM_TYPE_HUMAN;
private static final int ITEM_TYPE_ALIEN;
To keep things simple, let's also assume you store your objects in a list:
private List<Object> items = new ArrayList<>();
public MyAdapter(List<Object> items) {
this.items.addAll(items);
//Other stuff if needed
}
Now, the first you need to do, is to implement getItemViewType() method:
#Override
public int getItemViewType(int position) {
if (items.get(position) instanceof Human) {
return ITEM_TYPE_HUMAN;
} else {
return ITEM_TYPE_ALIEN;
}
}
Second, you need to use the item type inside the onCreateViewHolder() method like this:
#Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
LayoutInflater layoutInflater = LayoutInflater.from(parent.getContext());
if (viewType == ITEM_TYPE_HUMAN) {
View view = layoutInflater.inflate(R.layout.item_human, parent, false);
return new HumanViewHolder(view);
} else {
View view = layoutInflater.inflate(R.layout.item_alien, parent, false);
return new AlienViewHolder(view);
}
}
In the end, you just need to bind the proper view holder like this:
#Override
public void onBindViewHolder(RecyclerView.ViewHolder viewHolder, int position) {
Object item = items.get(position);
if (viewHolder instanceof HumanViewHolder) {
((HumanViewHolder) viewHolder).bind((Human) item);
} else {
((AlienViewHolder) viewHolder).bind((Alien) item);
}
}
Why use the Firebase Recycler Adapter when you could easily make a custom one? If I understood well you want an item to be fixed at position 0 (header) while others will be added below the first one, right? If so, here is a solution I like to use:
public interface ViewType {
public int getViewType();
}
public interface ViewTypeDelegateAdapter {
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent);
public void onBindViewHolder(RecyclerView.ViewHolder holder, ViewType item);
}
public class ViewTypes {
public static int HEADER = 0
public static int ITEM = 1
}
public class ProductDelegateAdapter implements ViewTypeDelegateAdapter {
private int resID;
private Context context;
public ProductDelegateAdapter(int resID, Context context) {
this.resID = resID;
this.context = context;
}
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent) {
return new ProductHolder(LayoutInflater.from(parent.context).inflate(resID, parent, false));
}
#Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, ViewType item) {
(holder as ProductHolder).bind("test");
}
class ProductHolder extends RecyclerView.ViewHolder {
public ProductHolder(View view) {
super(view);
}
public void bind(String test) {
}
}
}
public class HeaderDelegateAdapter implements ViewTypeDelegateAdapter {
private int resID;
private Context context;
public ProductDelegateAdapter(int resID, Context context) {
this.resID = resID;
this.context = context;
}
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent) {
return new HeaderHolder(LayoutInflater.from(parent.context).inflate(resID, parent, false));
}
#Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, ViewType item) {
(holder as HeaderHolder).bind("test");
}
class HeaderHolder extends RecyclerView.ViewHolder {
public HeaderHolder(View view) {
super(view);
}
public void bind(String test) {
}
}
}
public class AccAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>() {
private Context context;
private List<ViewType> items;
private SparseArrayCompat<ViewTypeDelegateAdapter> delegateAdapters;
private ViewType headerItem;
public AccAdapter(Context context) {
this.context = context;
this.items = new ArrayList();
this.delegateAdapters = new SparseArrayCompat();
this.headerItem = new ViewType() {
#Override
public int getViewType() {
return ViewTypes.HEADER;
}
};
this.items.add(this.headerItem);
this.delegateAdapters.put(ViewTypes.HEADER, HeaderDelegateAdapter(R.id.test, this.context));
this.delegateAdapters.put(ViewTypes.ITEM, ProductDelegateAdapter(R.id.test, this.context));
}
#Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, Int viewType) {
return delegateAdapters.get(viewType).onCreateViewHolder(parent);
}
#Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, Int position) {
delegateAdapters.get(getItemViewType(position)).onBindViewHolder(holder, items[position])
}
#Override
public Int getItemViewType(Int position) {
return items.get(position).getViewType();
}
#Override
public Int getItemCount() {
return items.getSize();
}
public void add(ViewType viewType) {
val initPosition = this.items.size - 1
this.items.add(item)
notifyItemRangeChanged(initPosition, this.items.size + 1)
}
}
public class Event implements ViewType {
private String id;
#Override
public int getViewType() {
return ViewTypes.ITEM;
}
}
Excuse me for some syntax errors, I've translated to Java from Kotlin to help you. Hope it helps!
onCreateViewHolder is called every time an item in my list is first displayed and that causes lag the first time the user scrolls.
Is that how it should be? I thought onCreateViewHolder would be called only once per viewType.
Here is my adapter:
public class CompetitionTableAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private final CompetitionAdapterOnItemClickHandler mClickHandler;
private List<CompetitionTableItem> mTable;
int calls = 0; //Used to see how many times onCreateViewHolder is called
#Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) {
calls++;
if(viewType == CompetitionTableItem.TYPE_HEADER){
View view = LayoutInflater.from(mContext).inflate(R.layout.table_header, viewGroup, false);
Log.i("CompetitionTableAdapter", "onCreateViewHolder "+calls);
return new CompetitionAdapterHeaderViewHolder(view);
}else{
View view = LayoutInflater.from(mContext).inflate(R.layout.table_item, viewGroup, false);
view.setFocusable(true);
Log.i("CompetitionTableAdapter", "onCreateViewHolder "+calls);
return new CompetitionAdapterViewHolder(view);
}
}
#Override
public void onBindViewHolder(RecyclerView.ViewHolder viewHolder, int position) {
int type = getItemViewType(position);
if (type == CompetitionTableItem.TYPE_HEADER) {
HeaderItem header = (HeaderItem) mTable.get(position);
CompetitionAdapterHeaderViewHolder holder = (CompetitionAdapterHeaderViewHolder) viewHolder;
holder.headerTextView.setText(header.getTitle());
} else {
CompetitionAdapterViewHolder holder = (CompetitionAdapterViewHolder) viewHolder;
TeamItem currentTeamTableEntity = (TeamItem)mTable.get(position);
TableEntryEntity tableEntry = currentTeamTableEntity.getTableEntryEntity();
holder.teamNameTextView.setText(tableEntry.getTeam().getName());
holder.pointsTextView.setText(String.valueOf(tableEntry.getPoints()));
holder.positionTextView.setText(String.valueOf(tableEntry.getPosition()));
holder.playedTextView.setText(String.valueOf(tableEntry.getPlayedGames()));
holder.lostTextView.setText(String.valueOf(tableEntry.getLost()));
holder.drawnTextView.setText(String.valueOf(tableEntry.getDraw()));
holder.wonTextView.setText(String.valueOf(tableEntry.getWon()));
String crestUrl = NetworkUtils.getCrestUrl(tableEntry.getTeam().getId(),NetworkUtils.IMAGE_QUALITY_SD);
Picasso.get().load(crestUrl).placeholder(R.drawable.default_crest).error(R.drawable.default_crest).into(holder.crestView);
}
}
#Override
public long getItemId(int position) {
int type = getItemViewType(position);
if (type == CompetitionTableItem.TYPE_HEADER) {
return NO_ID;
}else{
return ((TeamItem)mTable.get(position)).getTableEntryEntity().getTeam().getId();
}
}
public void swapTable(final List<CompetitionTableItem> table) {
mTable = table;
notifyDataSetChanged();
}
#Override
public int getItemViewType(int position) {
return mTable.get(position).getType();
}
public interface CompetitionAdapterOnItemClickHandler {
void onItemClick(TableEntryEntity competition);
}
class CompetitionAdapterViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
final ImageView crestView;
final TextView teamNameTextView;
final TextView positionTextView;
final TextView pointsTextView;
final TextView playedTextView;
final TextView wonTextView;
final TextView drawnTextView;
final TextView lostTextView;
CompetitionAdapterViewHolder(View view) {
super(view);
crestView = view.findViewById(R.id.team_crest);
teamNameTextView = view.findViewById(R.id.team_name);
pointsTextView = view.findViewById(R.id.team_points);
positionTextView = view.findViewById(R.id.team_position);
playedTextView = view.findViewById(R.id.matches_played);
wonTextView = view.findViewById(R.id.matches_won);
drawnTextView = view.findViewById(R.id.matches_drawn);
lostTextView = view.findViewById(R.id.matches_lost);
view.setOnClickListener(this);
}
#Override
public void onClick(View v) {
int adapterPosition = getAdapterPosition();
TableEntryEntity tableEntryEntity = ((TeamItem)mTable.get(adapterPosition)).getTableEntryEntity();
mClickHandler.onItemClick(tableEntryEntity);
}
}
class CompetitionAdapterHeaderViewHolder extends RecyclerView.ViewHolder {
final TextView headerTextView;
CompetitionAdapterHeaderViewHolder(View view) {
super(view);
headerTextView = view.findViewById(R.id.headerText);
}
}
}
https://github.com/s6joui/football-data-android-java/blob/master/app/src/main/java/tech/joeyck/livefootball/ui/competition_detail/standings/adapter/CompetitionTableAdapter.java
And fragment where RecyclerView is: https://github.com/s6joui/football-data-android-java/blob/master/app/src/main/java/tech/joeyck/livefootball/ui/BaseListFragment.java
Full source code: https://github.com/s6joui/football-data-android-java
I'm using androidx recyclerview version 1.1.0-alpha01
My Title is kind of hard to understand but basically when I add items into my database is should display it in a RecyclerView. Now in my RecyclerView I have two layouts but the problem is the first item of my database goes behind my first item in my other layout. So if I have 3 items in my database, it shows only 2 items from the database and the first item hides behind my first item in the RecyclerView which is a different layout that does not use the database at all.
This is my code:
FirebaseRecyclerOptions<Event> firebaseRecyclerOptions = new FirebaseRecyclerOptions.Builder<Event>()
.setQuery(query1, Event.class).build();
AccAdapter = new FirebaseRecyclerAdapter<Event, RecyclerView.ViewHolder>(firebaseRecyclerOptions){
final static int TYPE_HEADER = 0;
final static int TYPE_ITEM = 1;
#Override
public int getItemViewType(int position) {
if (position == 0) return TYPE_HEADER;
return TYPE_ITEM;
}
#Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
if (viewType == TYPE_HEADER){
View view = LayoutInflater.from(getActivity()).inflate(R.layout.recycler_view_row_add_items,
parent, false);
return new ProdudctHolder3(view);
} else {
View view = LayoutInflater.from(getActivity()).inflate(R.layout.recycler_view_row_acc,
parent, false);
return new ProductHolder2(view);
}
}
#Override
protected void onBindViewHolder(final RecyclerView.ViewHolder holder, int position, final Event model) {
if (holder instanceof ProdudctHolder3){
((ProdudctHolder3) holder).addBackground.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
startActivity(new Intent(getActivity(), AccAddItems.class ));
}
});
} else{
final ProductHolder2 productHolder2 = (ProductHolder2) holder;
productHolder2.mName.setText(model.getName());
productHolder2.view.setBackgroundResource(getBackgroundDrawable(Integer.valueOf(model.getProductAmount())));
productHolder2.mbackground.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
dialog = new Dialog(getActivity());
dialog.setContentView(R.layout.popup_edit_product);
SeekBar amountSeekBar = dialog.findViewById(R.id.amountSeekBar);
amountSeekBar.setMax(100);
amountSeekBar.setProgress(Integer.valueOf(model.getProductAmount()));
amountSeekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
#Override
public void onProgressChanged(SeekBar seekBar, int i, boolean b) {
progress = i;
}
#Override
public void onStartTrackingTouch(SeekBar seekBar) {
}
#Override
public void onStopTrackingTouch(SeekBar seekBar) {
getRef(holder.getAdapterPosition()).child("productAmount").setValue(String.valueOf(progress));
dialog.dismiss();
}
});
dialog.show();
}
});
productHolder2.mbackground.setOnLongClickListener(new View.OnLongClickListener() {
#Override
public boolean onLongClick(View view) {
final PopupMenu popupMenu = new PopupMenu(getActivity(), productHolder2.mbackground);
popupMenu.inflate(R.menu.menu_acc);
popupMenu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
#Override
public boolean onMenuItemClick(MenuItem menuItem) {
switch (menuItem.getItemId()){
case R.id.deleteProduct:
getRef(productHolder2.getAdapterPosition()).removeValue();
popupMenu.dismiss();
return true;
default:
return false;
}
}
});
popupMenu.show();
return true;
}
});
}
}
};
mAccRecyclerViewRef.setAdapter(AccAdapter);
My two Product Holders
private class ProdudctHolder3 extends RecyclerView.ViewHolder{
private RelativeLayout addBackground;
public ProdudctHolder3(View itemView) {
super(itemView);
addBackground = itemView.findViewById(R.id.mBackground2);
}
}
private class ProductHolder2 extends RecyclerView.ViewHolder{
private TextView mName;
private RelativeLayout mbackground;
private View view;
public ProductHolder2(View itemView) {
super(itemView);
mName = itemView.findViewById(R.id.ItemName);
mbackground = itemView.findViewById(R.id.mBackground1);
view = itemView.findViewById(R.id.amountIndicator);
}
}
The ideal solution would have been to set two adapters on a single RecyclerView but unfortunatelly this is not possible.
However, you can make a single custom Adapter that handles two types of items. I will explain this by getting an example.
Let's assume you need to display objects of two types, humans and aliens. Your objects require completely different layouts and completely different ViewHolders. Please see the below code for the ViewHolders:
public class MyAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private static class HumanViewHolder extends RecyclerView.ViewHolder {
public HumanViewHolder(View itemView) {
super(itemView);
//Prepare your ViewHolder
}
public void bind(Human human) {
//Display your human object
}
}
private static class AlienViewHolder extends RecyclerView.ViewHolder {
public AlienViewHolder(View itemView) {
super(itemView);
//Prepare your ViewHolder
}
public void bind(Alien alien) {
//Display your alien object
}
}
}
First you need to add two different constants to your adapter representing both type of views:
private static final int ITEM_TYPE_HUMAN;
private static final int ITEM_TYPE_ALIEN;
To keep things simple, let's also assume you store your objects in a list:
private List<Object> items = new ArrayList<>();
public MyAdapter(List<Object> items) {
this.items.addAll(items);
//Other stuff if needed
}
Now, the first you need to do, is to implement getItemViewType() method:
#Override
public int getItemViewType(int position) {
if (items.get(position) instanceof Human) {
return ITEM_TYPE_HUMAN;
} else {
return ITEM_TYPE_ALIEN;
}
}
Second, you need to use the item type inside the onCreateViewHolder() method like this:
#Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
LayoutInflater layoutInflater = LayoutInflater.from(parent.getContext());
if (viewType == ITEM_TYPE_HUMAN) {
View view = layoutInflater.inflate(R.layout.item_human, parent, false);
return new HumanViewHolder(view);
} else {
View view = layoutInflater.inflate(R.layout.item_alien, parent, false);
return new AlienViewHolder(view);
}
}
In the end, you just need to bind the proper view holder like this:
#Override
public void onBindViewHolder(RecyclerView.ViewHolder viewHolder, int position) {
Object item = items.get(position);
if (viewHolder instanceof HumanViewHolder) {
((HumanViewHolder) viewHolder).bind((Human) item);
} else {
((AlienViewHolder) viewHolder).bind((Alien) item);
}
}
Why use the Firebase Recycler Adapter when you could easily make a custom one? If I understood well you want an item to be fixed at position 0 (header) while others will be added below the first one, right? If so, here is a solution I like to use:
public interface ViewType {
public int getViewType();
}
public interface ViewTypeDelegateAdapter {
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent);
public void onBindViewHolder(RecyclerView.ViewHolder holder, ViewType item);
}
public class ViewTypes {
public static int HEADER = 0
public static int ITEM = 1
}
public class ProductDelegateAdapter implements ViewTypeDelegateAdapter {
private int resID;
private Context context;
public ProductDelegateAdapter(int resID, Context context) {
this.resID = resID;
this.context = context;
}
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent) {
return new ProductHolder(LayoutInflater.from(parent.context).inflate(resID, parent, false));
}
#Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, ViewType item) {
(holder as ProductHolder).bind("test");
}
class ProductHolder extends RecyclerView.ViewHolder {
public ProductHolder(View view) {
super(view);
}
public void bind(String test) {
}
}
}
public class HeaderDelegateAdapter implements ViewTypeDelegateAdapter {
private int resID;
private Context context;
public ProductDelegateAdapter(int resID, Context context) {
this.resID = resID;
this.context = context;
}
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent) {
return new HeaderHolder(LayoutInflater.from(parent.context).inflate(resID, parent, false));
}
#Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, ViewType item) {
(holder as HeaderHolder).bind("test");
}
class HeaderHolder extends RecyclerView.ViewHolder {
public HeaderHolder(View view) {
super(view);
}
public void bind(String test) {
}
}
}
public class AccAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>() {
private Context context;
private List<ViewType> items;
private SparseArrayCompat<ViewTypeDelegateAdapter> delegateAdapters;
private ViewType headerItem;
public AccAdapter(Context context) {
this.context = context;
this.items = new ArrayList();
this.delegateAdapters = new SparseArrayCompat();
this.headerItem = new ViewType() {
#Override
public int getViewType() {
return ViewTypes.HEADER;
}
};
this.items.add(this.headerItem);
this.delegateAdapters.put(ViewTypes.HEADER, HeaderDelegateAdapter(R.id.test, this.context));
this.delegateAdapters.put(ViewTypes.ITEM, ProductDelegateAdapter(R.id.test, this.context));
}
#Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, Int viewType) {
return delegateAdapters.get(viewType).onCreateViewHolder(parent);
}
#Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, Int position) {
delegateAdapters.get(getItemViewType(position)).onBindViewHolder(holder, items[position])
}
#Override
public Int getItemViewType(Int position) {
return items.get(position).getViewType();
}
#Override
public Int getItemCount() {
return items.getSize();
}
public void add(ViewType viewType) {
val initPosition = this.items.size - 1
this.items.add(item)
notifyItemRangeChanged(initPosition, this.items.size + 1)
}
}
public class Event implements ViewType {
private String id;
#Override
public int getViewType() {
return ViewTypes.ITEM;
}
}
Excuse me for some syntax errors, I've translated to Java from Kotlin to help you. Hope it helps!