ViewPager like of thing in BrowseFragment in AndroidTV - android

I am new in Android TV. Please have a look to the below attached image.
on the top of this picture there is a crousel and all the red marked area are the images.
i want to make this screen in Android TV. i have use BrowseFragment for this. I have use two Presenter one for First Row and another for other row.
The code which i have used :
HomeFragment.java
private CustomListRowPresenter mListRowPresenter;
private void loadRows() {
List<Movie> list = MovieList.setupMovies();
mListRowPresenter = new CustomListRowPresenter(getActivity(),this);
mRowsAdapter = new ArrayObjectAdapter(mListRowPresenter);
CardPresenter cardPresenter = new CardPresenter(getActivity());
mNumberOfRows = NUM_ROWS;
HeaderItem gridHeader = new HeaderItem(0, "");
GridItemPresenter mGridPresenter = new GridItemPresenter();
ArrayObjectAdapter gridRowAdapter = new ArrayObjectAdapter(mGridPresenter);
gridRowAdapter.add(getResources().getString(R.string.grid_view));
gridRowAdapter.add(getString(R.string.error_fragment));
gridRowAdapter.add(getResources().getString(R.string.personal_settings));
mRowsAdapter.add(new ListRow(gridHeader, gridRowAdapter));
int i;
for (i = 1; i < NUM_ROWS; i++) {
if (i != 0) {
Collections.shuffle(list);
}
ArrayObjectAdapter listRowAdapter = new ArrayObjectAdapter(cardPresenter);
for (int j = 1; j < NUM_COLS; j++) {
listRowAdapter.add(list.get(j % 5));
}
HeaderItem header = new HeaderItem(i, MovieList.MOVIE_CATEGORY[i]);
mRowsAdapter.add(new ListRow(header, listRowAdapter));
}
setAdapter(mRowsAdapter);
}
CardPresenter.java
public class CardPresenter extends Presenter {
private static final String TAG = "CardPresenter";
private static int CARD_WIDTH = 360;
private static int CARD_HEIGHT = 160;
private static int sSelectedBackgroundColor;
private static int sDefaultBackgroundColor;
private Drawable mDefaultCardImage;
private Activity mActivity;
public CardPresenter(Activity activity){
mActivity = activity;
}
public CardPresenter(){
}
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent) {
Log.d(TAG, "onCreateViewHolder");
sDefaultBackgroundColor = parent.getResources().getColor(R.color.default_background);
sSelectedBackgroundColor = parent.getResources().getColor(R.color.selected_background);
mDefaultCardImage = parent.getResources().getDrawable(R.drawable.movie);
/*
ImageCardView cardView = new ImageCardView(parent.getContext()) {
#Override
public void setSelected(boolean selected) {
updateCardBackgroundColor(this, selected);
super.setSelected(selected);
}
};
cardView.setFocusable(true);
cardView.setFocusableInTouchMode(true);
cardView
.setBackgroundResource(R.drawable.gridview_cell_border);
updateCardBackgroundColor(cardView, false);*/
View view = mActivity.getLayoutInflater().inflate(R.layout.gridview_cell_rows, parent,
false);
LinearLayout linearLayout = (LinearLayout)view.findViewById(R.id.container_grid_view_item);
linearLayout.setBackgroundResource(R.drawable.gridview_cell_border);
view.setFocusable(true);
ViewHolder viewHolder = new ViewHolder(view);
return viewHolder;
}
private static void updateCardBackgroundColor(ImageCardView view, boolean selected) {
int color = selected ? sSelectedBackgroundColor : sDefaultBackgroundColor;
// Both background colors should be set because the view's background is temporarily visible
// during animations.
view.setBackgroundColor(color);
view.findViewById(R.id.info_field).setBackgroundColor(color);
}
#Override
public void onBindViewHolder(Presenter.ViewHolder viewHolder, Object item) {
Movie movie = (Movie) item;
View cardView = (View) viewHolder.view;
ImageView imageView = (ImageView)cardView.findViewById(R.id.imageView);
LinearLayout linearLayout = (LinearLayout)cardView.findViewById(R.id.container_grid_view_item);
linearLayout.setBackgroundResource(R.drawable.gridview_cell_border);
Log.d(TAG, "onBindViewHolder");
if (movie.getCardImageUrl() != null) {
/* cardView.setTitleText(movie.getTitle());
cardView.setContentText(movie.getStudio());
cardView.setMainImageDimensions(CARD_WIDTH, CARD_HEIGHT);*/
Glide.with(viewHolder.view.getContext())
.load(movie.getCardImageUrl())
.centerCrop()
.error(mDefaultCardImage)
.into(imageView);
}
}
#Override
public void onUnbindViewHolder(Presenter.ViewHolder viewHolder) {
Log.d(TAG, "onUnbindViewHolder");
View cardView = (View) viewHolder.view;
// Remove references to images so that the garbage collector can free up memory
}
So for first row i have used CardPresenter and for other row i have used GridPresenter.
My Requirment is that this viewpager type of thing should be auto rotate in every 5 second.
So Please help me how can i design this fragment.

As discussed in Creating a Catalog Browser, if you wish to customize the header views between fragments, use a Presenter and implement the abstract methods to create, bind, and unbind the view holder. In the BrowseFragment implementation that displays the catalog browser, use the setHeaderPresenterSelector() method to set the presenter for the row header or setOnItemViewSelectedListener() method to set an item selection listener, as shown in the following example.
setHeaderPresenterSelector(new PresenterSelector() {
#Override
public Presenter getPresenter(Object o) {
return new IconHeaderItemPresenter();
}
});
Then, set time duration of each page presenter using Timer as shown in this GitHub post.
For sample code implementation, this tutorial might also help.

Related

Compare Old Data with New Data in Recyclerview

I am new in Android Development and working on a project where I need to call an API after every one second, in that API there is field "Amount"(dBID) which keeps on changing, so I need to update the latest Amount (dBID) in recyclerview.
In order to do so, I have called this API in a service after every interval of one second.
The data is Showing Properly no Issue.
But for Now I need to perform some action on the Old Amount and New Amount.
Action Required : I need to compare the old value (dBID) with the New Value (dBID).
If the New Value is greater then I need to change the Text Color of Amount (dBID) to BLUE.
If the New Value is smaller then I need to change the Text Color of Amount (dBID) to RED.
Tried to achieve this by storing the old data in a Variable and then Comparing it to the new Value.
Issue : This logic is working fine until there are 5 or less Items in recyclerview as soon as the sixth item is added the same logic does not work.
Help me if anyone knows how I can achieve this.
For Example you can refer an App Vertexfx : Quotes Tab.
Below is the Code which I Tried.
Adapter class of the RecyclerView:
public class QuoteAdapter extends RecyclerView.Adapter <QuoteAdapter.MyViewHolder>{
Context context;
List<QuoteData> data;
public QuoteAdapter(Context context,List<QuoteData> data)
{
this.data = data;
this.context = context;
}
class MyViewHolder extends RecyclerView.ViewHolder{
TextView time,symbol,sellmax,selllow,buymax,buylow,buy,sell,spread,lowtext,hightext;
LinearLayout layout,layoutbid,layoutask;
float currentbid,lastbid,currentask,lastask;
public MyViewHolder(#NonNull View itemView) {
super(itemView);
time = itemView.findViewById(R.id.TVTime);
symbol = itemView.findViewById(R.id.TVSymbol);
sellmax = itemView.findViewById(R.id.TVSELLMAX);
selllow = itemView.findViewById(R.id.TVSELLLOW);
buymax = itemView.findViewById(R.id.TVBUYMAX);
buylow = itemView.findViewById(R.id.TVBUYHIGH);
buy = itemView.findViewById(R.id.TVBUY);
sell = itemView.findViewById(R.id.TVSELL);
spread = itemView.findViewById(R.id.TVSpread1);
lowtext = itemView.findViewById(R.id.low);
hightext = itemView.findViewById(R.id.high);
layout = itemView.findViewById(R.id.layout);
layoutbid = itemView.findViewById(R.id.LLBid);
layoutask = itemView.findViewById(R.id.LLAsk);
currentbid = 0;
lastbid = 0;
currentask = 0;
lastask = 0;
}
}
#NonNull
#Override
public MyViewHolder onCreateViewHolder(#NonNull ViewGroup viewGroup, int i) {
View view = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.quotelist,viewGroup,false);
return new MyViewHolder(view);
}
#SuppressLint("ResourceAsColor")
#Override
public void onBindViewHolder(#NonNull final MyViewHolder myViewHolder, final int i) {
final QuoteData data1 = data.get(i);
myViewHolder.time.setText(data1.dLut);
myViewHolder.symbol.setText(data1.dSymbol);
myViewHolder.sellmax.setText(data1.dBid); //Bid
myViewHolder.selllow.setText(data1.dLow);
myViewHolder.buymax.setText(data1.dAsk); //ask
myViewHolder.buylow.setText(data1.dHigh);
myViewHolder.currentbid = Float.parseFloat((data1.dBid));
myViewHolder.currentask = Float.parseFloat((data1.dAsk));
if (myViewHolder.currentbid > myViewHolder.lastbid)
{
myViewHolder.sellmax.setTextColor(Color.BLUE);
}
if (myViewHolder.currentbid < myViewHolder.lastbid)
{
myViewHolder.sellmax.setTextColor(Color.RED);
}
myViewHolder.lastbid = myViewHolder.currentbid;
myViewHolder.lastask = myViewHolder.currentask;
}
});
}
I suggest you take a look at those classes from the Android SDK:
DiffUtil
AsyncListDiffer
ItemAnimator
DiffUtil
DiffUtil is designed to compare existing and new recycler view items and fires appropriate events. You need to pass a callback that can tell if two items are the same and if their content has changed.
AsyncListDiffer
It wraps the DiffUtil and executes it's logic asynchronously, giving better performance.
ItemAnimator
The ItemAnimator for a given RecyclerView is called by default when change events are fired on it's items. You can provide an implementation of the animateChange method to change your color accordingly.
For Future reference I have resolved the above mentioned issue using the below code.
Defined two ArrayList of String in Adapter
public class QuoteAdapter extends RecyclerView.Adapter <QuoteAdapter.MyViewHolder>{
Context context;
List<QuoteData> data;
List<String> olddatabid = new ArrayList<String>();
List<String> newdatabid = new ArrayList<String>();
List<String> olddataask = new ArrayList<String>();
List<String> newdataask = new ArrayList<String>();
class MyViewHolder extends RecyclerView.ViewHolder{
TextView time,symbol,sellmax,selllow,buymax,buylow,buy,sell,spread,lowtext,hightext;
LinearLayout layout,layoutbid,layoutask;
public MyViewHolder(#NonNull View itemView) {
super(itemView);
time = itemView.findViewById(R.id.TVTime);
symbol = itemView.findViewById(R.id.TVSymbol);
sellmax = itemView.findViewById(R.id.TVSELLMAX);
selllow = itemView.findViewById(R.id.TVSELLLOW);
buymax = itemView.findViewById(R.id.TVBUYMAX);
buylow = itemView.findViewById(R.id.TVBUYHIGH);
buy = itemView.findViewById(R.id.TVBUY);
sell = itemView.findViewById(R.id.TVSELL);
spread = itemView.findViewById(R.id.TVSpread1);
lowtext = itemView.findViewById(R.id.low);
hightext = itemView.findViewById(R.id.high);
layout = itemView.findViewById(R.id.layout);
layoutbid = itemView.findViewById(R.id.LLBid);
layoutask = itemView.findViewById(R.id.LLAsk);
}
}
public QuoteAdapter(Context context,List<QuoteData> data)
{
this.data = data;
this.context = context;
}
#NonNull
#Override
public MyViewHolder onCreateViewHolder(#NonNull ViewGroup viewGroup, int i) {
View view = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.quotelist,viewGroup,false);
return new MyViewHolder(view);
}
#SuppressLint("ResourceAsColor")
#Override
public void onBindViewHolder(#NonNull final MyViewHolder myViewHolder, final int i) {
final QuoteData data1 = data.get(i);
myViewHolder.time.setText(data1.dLut);
myViewHolder.symbol.setText(data1.dSymbol);
myViewHolder.sellmax.setText(data1.dBid); //Bid
myViewHolder.selllow.setText(data1.dLow);
myViewHolder.buymax.setText(data1.dAsk); //ask
myViewHolder.buylow.setText(data1.dHigh);
if (newdatabid.size()< data.size())
{
newdatabid.add(data1.dBid); //Insert Value in array for the first time
}
if (olddatabid.size()< data.size())
{
olddatabid.add(data1.dBid); //Insert Value in array for the first time
}
if (newdataask.size()< data.size())
{
newdataask.add(data1.dAsk); //Insert Value in array for the first time
}
if (olddataask.size()< data.size()) //Insert Value in array for the first time
{
olddataask.add(data1.dAsk);
}
newdatabid.set(i,data1.dBid); //Store Value in array
newdataask.set(i,data1.dAsk); //Store Value in array
//Compare and perform Logic
if (Float.valueOf(newdatabid.get(i)) > Float.valueOf(olddatabid.get(i)))
{
myViewHolder.sellmax.setTextColor(Color.BLUE);
}
if (Float.valueOf(newdatabid.get(i)) < Float.valueOf(olddatabid.get(i)))
{
myViewHolder.sellmax.setTextColor(Color.RED);
}
if (Float.valueOf(newdataask.get(i)) > Float.valueOf(olddataask.get(i)))
{
myViewHolder.buymax.setTextColor(Color.BLUE);
}
if (Float.valueOf(newdataask.get(i)) < Float.valueOf(olddataask.get(i)))
{
myViewHolder.buymax.setTextColor(Color.RED);
}
olddatabid.set(i,newdatabid.get(i));
olddataask.set(i,newdataask.get(i));
}
});
}
}
#Override
public int getItemCount() {
return data.size();
}
}

Loading large number of items in recycler view

I have a recycler view within a fragment and basically I m trying to load song list in the recycler view .Each row of recycler view contains an imageview (for album art) and textview ( for song name). I am having trouble when the size of the dataset is huge, that is when there are too many songs, the recycler view lags and the app ends up giving an ANR.I am using Glide to load album arts in each row's imageview.
How is google music player able to show such large number of songs without any lag?
Edit:
This is my SongsFragment
public class SongsFragment extends Fragment {
static {
AppCompatDelegate.setCompatVectorFromResourcesEnabled(true);
}
ProgressBar progressBar; // progress bar to show after every 30 items
NestedScrollView nestedScrollView; //for smooth scrolling of recyclerview as well as to detect the end of recyclerview
RecyclerView recyclerView;
ArrayList<Song> songMainList = new ArrayList<>(); //partial list in which items are added
ArrayList<Song> songAllList = new ArrayList<>(); //Complete List of songs
SongAdapter songsAdapter;
private LinearLayoutManager layoutManager;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_songs, container, false);
nestedScrollView = (NestedScrollView) rootView.findViewById(R.id.nestedScrollView);
progressBar = (ProgressBar) rootView.findViewById(R.id.progressBar);
String songJson = getActivity().getIntent().getStringExtra("songList");
songAllList = new Gson().fromJson(songJson, new TypeToken<ArrayList<Song>>() {
}.getType());
//Getting list of all songs in songAllList
if (songAllList.size() > 30) {
songMainList = new ArrayList<>(songAllList.subList(0,30));
} else {
songMainList = songAllList;
}
//if size of fetched songAllList>30 then add only 30 rows to songMainList
recyclerView = (RecyclerView) rootView.findViewById(R.id.songs);
int spanCount = 1; // 2 columns
int spacing = 4; // 50px
recyclerView.addItemDecoration(new GridItemDecoration(spanCount, spacing, true));
recyclerView.setHasFixedSize(true);
recyclerView.setNestedScrollingEnabled(false);
recyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
songsAdapter = new SongAdapter(getActivity(), songMainList, recyclerView);
nestedScrollView.getViewTreeObserver().addOnScrollChangedListener(new ViewTreeObserver.OnScrollChangedListener() {
#Override
public void onScrollChanged() {
View view = (View) nestedScrollView.getChildAt(nestedScrollView.getChildCount() - 1);
int diff = (view.getBottom() - (nestedScrollView.getHeight() + nestedScrollView
.getScrollY()));
if (diff == 0) { //NestedScrollView scrolled to bottom
progressBar.setVisibility(View.VISIBLE); //show progressbar
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
if (songMainList.size() < songAllList.size()) {
int x = 0, y = 0;
if ((songAllList.size() - songMainList.size()) >= 30) {
x = songMainList.size();
y = x + 30;
} else {
x = songMainList.size();
y = x + songAllList.size() - songMainList.size();
}
for (int i = x; i < y; i++) {
songMainList.add(songAllList.get(i)); //Adding new items from songAllList to songMainList one by one
songsAdapter.notifyDataSetChanged();
}
}
progressBar.setVisibility(View.GONE);
}
}, 1500);
}
}
});
recyclerView.setAdapter(songsAdapter);
return rootView;
}
}
And this is my RecyclerViewAdapter along with viewholder
public class SongAdapter extends RecyclerView.Adapter {
private List<Song> songsList;
private Context c;
private RecyclerView.ViewHolder holder;
public SongAdapter(Context context) {
mainActivityContext = context;
}
public SongAdapter(Context context, List<Song> songs, RecyclerView recyclerView) {
songsList = songs;
LinearLayoutManager linearLayoutManager = (LinearLayoutManager) recyclerView.getLayoutManager();
c = context;
}
public SongAdapter getInstance() {
return SongAdapter.this;
}
#Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.song_list_row, parent, false);
return new SongViewHolder(view,c);
}
#Override
public void onBindViewHolder(final RecyclerView.ViewHolder holder, int position) {
if (holder instanceof SongViewHolder) {
Song song = songsList.get(position);
this.holder = holder;
String name = song.getName();
String artist = song.getArtist();
String imagepath = song.getImagepath();
((SongViewHolder) holder).name.setText(name);
((SongViewHolder) holder).artist.setText(artist);
if (!imagepath.equalsIgnoreCase("no_image")) //if the album art has valid imagepath for this song
Glide.with(c).load(imagepath)
.centerCrop()
.into(((SongViewHolder) holder).iv);
else
((SongViewHolder) holder).iv.setImageResource(R.drawable.empty);
((SongViewHolder) holder).song = song;
}
}
#Override
public int getItemCount() {
return songsList.size();
}
static class SongViewHolder extends RecyclerView.ViewHolder{
ImageView iv;
TextView name, artist;
CardView songListCard;
private Context ctx;
private OnLongPressListener mListener;
SongViewHolder(View v, Context context) {
super(v);
this.ctx = context;
iv= (ImageView) v.findViewById(R.id.album_art);
name= (TextView) v.findViewById(R.id.name);
artist= (TextView) v.findViewById(R.id.artist_mini);
songListCard = (CardView) v.findViewById(R.id.song_list_card);
}
}
The recyclerview works fine when there are only 150-200 items but when reaching to 600-700 items , the whole app slows down. Could this be because of the way I have used glide in onBindViewHolder?
Sort answer:
LinearLayoutManager(context).apply { isAutoMeasureEnabled = false }
// or in Java
layoutManager.setAutoMeasureEnabled(false)
UPDATE 2020.08.14
Deprecated RecyclerView.LayoutManager#setAutoMeasureEnabled
This method was deprecated in API level 27.1.0.
Implementors of LayoutManager should define whether or not it uses AutoMeasure by overriding isAutoMeasureEnabled()
From the doc of RecyclerView.LayoutManager#setAutoMeasureEnabled() we know :
This method is usually called by the LayoutManager with value {#code true} if it wants to support WRAP_CONTENT
It works by calling {#link LayoutManager#onLayoutChildren(Recycler, State)} during an {#link RecyclerView#onMeasure(int, int)} call, then calculating desired dimensions based on children's positions.
If we set mAutoMeasure = true, it will call LayoutManager#onLayoutChildren(Recycler, State) during an RecyclerView#onMeasure(int, int) call. Every child view's onMeasure() method will be called, this cost too much time.
Let's look at LinearLayoutManager's constructor
public LinearLayoutManager(Context context, int orientation, boolean reverseLayout) {
setOrientation(orientation);
setReverseLayout(reverseLayout);
setAutoMeasureEnabled(true);
}
So, after we set mAutoMeasure = false, everything will be ok.
Solved the problem by removing the NestedScrollView over the recyclerview.
The nestedscrollview was not allowing the recyclerview.addOnScrollListener() to be called because of which I was getting a lag on loading more items.
Here is how i implemented the loadOnScroll for RecyclerView-
recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
#Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
if (!recyclerView.canScrollVertically(1))
onScrolledToBottom();
}
});
private void onScrolledToBottom() {
if (songMainList.size() < songAllList.size()) {
int x, y;
if ((songAllList.size() - songMainList.size()) >= 50) {
x = songMainList.size();
y = x + 50;
} else {
x = songMainList.size();
y = x + songAllList.size() - songMainList.size();
}
for (int i = x; i < y; i++) {
songMainList.add(songAllList.get(i));
}
songsAdapter.notifyDataSetChanged();
}
}
Do you load the data all at once? RecycleView should not have problem, I think if you have too much data the processing itself can take too much time. You should load the data in chunks and check the scroll state of the user and load the next batch etc. kinda how Instagram or Facebook does it.
you may achieve this by using AndroidX Room & Paging
cache your data from network to local Room Database
using Paging to load your data from Room Database

Recyclervew clear viewholder when deleting item

file with working code to test my issue, you have to add 2 items, then delete any of those and then add a new one to see how the deleted gets on top of the newly addded
https://www.dropbox.com/s/ojuyz5g5f3kaz0h/Test.zip?dl=0
I have a problem when deleting an item from the recyclerview, when ever I delete an item, IF I add a new item, the deleted item will appear in top of the newly added item, how could I get a fresh view or avod this from happening as is a big issue.
this is how i add items from my main activity
if (!resta || (diff > (3*60*1000)))
{
Ri.add(dataroot);
Integer position = adapter.getItemCount() + 1;
adapter.notifyItemInserted(position);
}
here my Adapter
public class ComandaAdapter extends RecyclerView.Adapter<ComandaAdapter.ComandaAdapterViewHolder>{
private Context mContext;
private ArrayList<Integer> lista_entradas = new ArrayList<>();
private ArrayList<Integer> lista_fondos = new ArrayList<>();
private ArrayList<Integer> lista_postres= new ArrayList<>();
private Boolean primeritem;
private ArrayList<DataRoot> Rir;
private TextView txt_comandas;
private TextView txt_entracola;
private TextView txt_fondocola;
private TextView txt_postrecola;
public ComandaAdapter(Context context, TextView tx_entracola, TextView tx_fondocola, TextView tx_postrecola, TextView tx_comandas, ArrayList<DataRoot> Rir)
{
this.mContext = context;
this.txt_comandas = tx_comandas;
this.txt_entracola = tx_entracola;
this.txt_fondocola = tx_fondocola;
this.txt_postrecola = tx_postrecola;
this.Rir= Rir;
}
#Override
public ComandaAdapter.ComandaAdapterViewHolder onCreateViewHolder(ViewGroup parent, int viewType)
{
return new ComandaAdapter.ComandaAdapterViewHolder(LayoutInflater.from(mContext).inflate(R.layout.row,parent,false));
}
#Override
public void onBindViewHolder(final ComandaAdapter.ComandaAdapterViewHolder holder, final int position)
{
DataRoot Rdata = Rir.get(position);
holder.setdata(Rdata);
}
public void delete(int position)
{
Rir.remove(position);
notifyItemRemoved(position);
}
public class ComandaAdapterViewHolder extends RecyclerView.ViewHolder
{
Button btn_cerrar;
public ComandaAdapterViewHolder(View itemView)
{
super(itemView);
btn_cerrar = (Button) itemView.findViewById(R.id.btn_cerrar);
void setData(final DataRoot Rdata)
{
btn_cerrar.setOnClickListener(new View.OnClickListener()
{
#Override
public void onClick(View view)
{
btn_cerrar.setEnabled(false);
btn_cerrar.setBackgroundTintList(mContext.getColorStateList(R.color.cboff));
updateRetrofitEstadoorden(Rdata.get_id());
updateRetrofitNrocomanda(Rdata.get_id(), txt_comanda.getText().toString());
delete(getAdapterPosition());
}
});
Rdata.gerOrder();
creaboton():
and here my recyler
private void setAdapter()
{
adapter = new ComandaAdapter(this, txt_entracola, txt_fondocola, txt_postrecola, txt_comandas, Ri);
recyclerView.getRecycledViewPool().setMaxRecycledViews(-1, Ri.size());//va en 0 supuestamente -1 es default
recyclerView.setItemViewCacheSize(Ri.size()); //ver si hay que cambiar con cada item
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this);
linearLayoutManager.setOrientation(LinearLayoutManager.HORIZONTAL);
recyclerView.setLayoutManager(linearLayoutManager);
recyclerView.setItemAnimator(new DefaultItemAnimator());
recyclerView.setAdapter(adapter);
}
Thanks in advance for any help.
Images to show the problem
You are using the Recyclerview in a very non standard way. The issue you are seeing is because the views are being recycled (as they should be in a Recyclerview) but you are not clearing out the items from the previous view.
The problem in in this method:
public void setData(String value) {
container.removeAllViews(); // Remove all previously added views
textview.setText(value);
Random r = new Random();
int i1 = r.nextInt(5 - 1) + 1;
for (int i = 0; i < i1; i++) {
be = new Button(mContext);
be.setText("Boton " + i);
be.setLayoutParams(new LinearLayout.LayoutParams(240, LinearLayout.LayoutParams.WRAP_CONTENT));
container.addView(be);
}
}
By calling container.addView(be), you are manually adding extra views to the views that the Recyclerview creates. When you remove these views, they are cached and reused the next time you press "Add". The problem is that the cached view still contains all of the manually added views so you are then adding more views under the existing ones.
As you can see in the code above, i added container.removeAllViews(); which removes the views that were added previously ensuring that "Container" is empty before you start adding your extra views to it.
Also, unless you have a very specific reason for doing so, I would removes these lines as I believe you are hurting performance by having them:
list.getRecycledViewPool().setMaxRecycledViews(-1, index);
list.setItemViewCacheSize(index);

Change the visibility of a View while repeating data

I am populating OrderHistory by retrieving data from Server in my app. Here I need to populate listitem depends on OrderId. If OrderId repeats I need to hide the LinearLayout which is marked in green in screenshot. Otherwise the Layout has to be usual view.Please help me.
MyAdapter Class:
public class MyOrderAdapter extends RecyclerView.Adapter<MyOrderAdapter.ViewHolder> {
Context mContext;
List<CartRes> mOrderList = new ArrayList<>();
private ImageLoader imageLoader;
public MyOrderAdapter(Context context, List<CartRes> orderList) {
mContext = context;
mOrderList = orderList;
Log.e("Json Adapter", "" + mOrderList);
}
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.my_order_history, parent, false);
ViewHolder viewHolder = new ViewHolder(v);
return viewHolder;
}
#Override
public void onBindViewHolder(ViewHolder holder, int position) {
holder.cartResOrder = mOrderList.get(position);
imageLoader = CustomVolleyRequest.getInstance(mContext).getImageLoader();
String IMAGE_URL = "http://" + Config.IMAGE_URL + holder.cartResOrder.ORDER_IMAGE;
Log.e("Image URL", IMAGE_URL + " " + holder.cartResOrder.ORDER_IMAGE);
imageLoader.get(IMAGE_URL, ImageLoader.getImageListener(holder.orderImage, 0, 0));
holder.orderImage.setImageUrl(IMAGE_URL, imageLoader);
holder.txtOrderId.setText(holder.cartResOrder.ORDER_ID);
holder.txtOrderProduct.setText(holder.cartResOrder.ORDER_PRODUCT);
holder.txtorderedDate.setText(holder.cartResOrder.ORDER_DATE);
holder.txtDeliveredDate.setText(holder.cartResOrder.ORDER_DELIVERY_DATE);
}
#Override
public int getItemCount() {
return mOrderList.size();
}
public class ViewHolder extends RecyclerView.ViewHolder {
TextView txtOrderId, txtOrderProduct, txtorderedDate, txtDeliveredDate;
Button butDetail, butRemove;
NetworkImageView orderImage;
CartRes cartResOrder;
public ViewHolder(View itemView) {
super(itemView);
txtOrderId = (TextView) itemView.findViewById(R.id.orderId);
txtOrderProduct = (TextView) itemView.findViewById(R.id.orderProduct);
txtorderedDate = (TextView) itemView.findViewById(R.id.orderedDate);
txtDeliveredDate = (TextView) itemView.findViewById(R.id.orderDeliveredDate);
butDetail = (Button) itemView.findViewById(R.id.orderViewDetail);
butRemove = (Button) itemView.findViewById(R.id.orderRemove);
orderImage = (NetworkImageView) itemView.findViewById(R.id.OrderproductImage);
}
}
}
UPDATE:
public void onBindViewHolder(ViewHolder holder, int position) {
holder.cartResOrder = mOrderList.get(position);
imageLoader = CustomVolleyRequest.getInstance(mContext).getImageLoader();
String IMAGE_URL = "http://" + Config.IMAGE_URL + holder.cartResOrder.ORDER_IMAGE;
Log.e("Image URL", IMAGE_URL + " " + holder.cartResOrder.ORDER_IMAGE);
imageLoader.get(IMAGE_URL, ImageLoader.getImageListener(holder.orderImage, 0, 0));
holder.orderImage.setImageUrl(IMAGE_URL, imageLoader);
holder.txtOrderId.setText(holder.cartResOrder.ORDER_ID);
holder.txtOrderProduct.setText(holder.cartResOrder.ORDER_PRODUCT);
holder.txtorderedDate.setText(holder.cartResOrder.ORDER_DATE);
holder.txtDeliveredDate.setText(holder.cartResOrder.ORDER_DELIVERY_DATE);
if (position > 0 && mOrderList.get(position).ORDER_ID == mOrderList.get(position - 1).ORDER_ID) {
//make sure it is not the first one, and make sure it has the same ID as previous.
holder.OrderLinear.setVisibility(View.GONE); //hide it, you need to set the reference first.
holder.txtOrderId.setVisibility(View.GONE);
}
}
One way you could do it:
Have a new holder variable that refers to your LinearLayout you want to hide.
In your onBindViewHolder()
#Override
public void onBindViewHolder(ViewHolder holder, int position) {
//setup everything else above...
if (position > 0 && mOrderList.get(position).ORDER_ID == mOrderList.get(position - 1).ORDER_ID){
//make sure it is not the first one, and make sure it has the same ID as previous.
holder.thelinearlayout.setVisibility(View.GONE); //hide it, you need to set the reference first.
}else holder.thelinearlayout.setVisibility(View.VISIBLE);
//if somehow order gets changed.(e.g. previous row is deleted).
}
EDIT:
I'm assuming that the data inside is sorted by ORDER_ID, so there won't be a case where there are two elements with the same ORDER_ID that is not next to each other.
You might want to sort them based on ORDER_ID before passing the list into adapter.
EDIT2:
Added else condition as suggested in the comment.
The screenshot does not tell that but if your view is RecyclerView or ListView then I'd preprocess the data prior feeding it to the adapter (i.e. by wrapping your model into another class with additional attributes).
Alternatively you can try checking previous row (by fetching it from your data source or adapter) while populating current one and adjust the view
maybe just add field boolean repeatOrderId to your CartRes class and in constructor do some for loop and flag all items? you may check also in runtime, but you have pretty fixed list, preparing in construtor this flag is better for performance
for(int i=0; i<mOrderList.getCount(); i++){
CartRes cr = mOrderList.get(i);
cr.repeatOrderId=true;
for(int j=0; j<i; j++){
if(cr.ORDER_ID==mOrderList.get(j).ORDER_ID){
cr.repeatOrderId=false; //default true
break;
}
}
}
then inside onBindViewHolder check this flag and setVisibility(cr.repeatOrderId); for desired layout

RecyclerView nested ViewHolder child views

I have problems with RecyclerView when I try to loop adding more child views to the parent view. When I scroll, it appears blank for a second. Is from Data binding or the view rendering?
Here is my code:
public class TournamentFixtureAdapter extends LoadMoreRecyclerViewAdapter<FixtureGroup> {
private OnFixtureClickListener onFixtureClickListener = null;
public TournamentFixtureAdapter(List<FixtureGroup> data) {
super(data);
}
#Override
protected RecyclerView.ViewHolder onCreateContentItemViewHolder(ViewGroup parent, int contentViewType) {
return new TournamentFixtureHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.list_item_tournament_fixture, parent, false));
}
#Override
protected void onBindContentItemViewHolder(RecyclerView.ViewHolder holder, int position) {
super.onBindContentItemViewHolder(holder, position);
FixtureGroup fixtureGroup = data.get(position);
((TournamentFixtureHolder) holder).onFixtureClickListener = onFixtureClickListener;
((TournamentFixtureHolder) holder).parentPos = position;
((TournamentFixtureHolder) holder).binding.setFixtureGroup(fixtureGroup);
((TournamentFixtureHolder) holder).addFixtures(fixtureGroup.getFixtures());
}
public void setOnFixtureClickListener(OnFixtureClickListener onFixtureClickListener) {
this.onFixtureClickListener = onFixtureClickListener;
}
static class TournamentFixtureHolder extends FixtureHolder {
ListItemTournamentFixtureBinding binding = null;
public TournamentFixtureHolder(View itemView) {
super(itemView);
binding = DataBindingUtil.bind(itemView);
}
}
}
public class FixtureHolder extends BaseAdapter.BaseHolder {
LinearLayout layoutMain = null;
OnFixtureClickListener onFixtureClickListener = null;
int parentPos;
public FixtureHolder(View itemView) {
super(itemView);
layoutMain = (LinearLayout) itemView.findViewById(R.id.layout_main);
setIsRecyclable(layoutMain.getChildCount() > 0);
}
public void addFixtures(final ArrayList<Fixture> fixtures) {
for (final Fixture fixture : fixtures) {
LinearLayout parent = (LinearLayout) LayoutInflater.from(itemView.getContext()).inflate(R.layout.view_fixture, null);
Utils.getDefaultClubLogo((NetworkImageViewPlus) parent.findViewById(R.id.netview_home_img)).setImageUrl(fixture.getHome().getImg(), AppController.getInstance().getImageLoader());
Utils.getDefaultClubLogo((NetworkImageViewPlus) parent.findViewById(R.id.netview_away_img)).setImageUrl(fixture.getAway().getImg(), AppController.getInstance().getImageLoader());
ViewFixtureBinding binding = DataBindingUtil.bind(parent);
layoutMain.addView(parent);
binding.setFixture(fixture);
parent.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
onFixtureClickListener.onFixtureClick(parentPos, findFixturePosById(fixtures, fixture.getId()));
}
});
}
}
private int findFixturePosById(ArrayList<Fixture> fixtures, int id) {
for (int i = 0; i < fixtures.size(); i++) {
if (fixtures.get(i).getId() == id) {
return i;
}
}
return 0;
}
}
If the problem was more on the data side (adapter), then it would probably be showing up on the normal layout, not just during scrolling. For instance, if you were loading images from a slow server, the initial display would be slow. Since it's only happening when you scroll, that points more to a problem with the layout manager.
For every new view, you have to get it from the adapter, and add it to the layout. If you allow maximum dx in horizontal/vertical scrolling, and have recycled views outside of the screen display cached, it's likely that things will appear blank prior the layout manager getting the new views from the adapter and laying them out.
So there are two factors - horizontal and/or vertical dx is too large, too soon, and the number of recycled (or scrapped) views is too small. So the solution is to either slow down scrolling, or to increase the number of views you are adding off-screen.

Categories

Resources