Get data in my RecyclerView - java

I started to work with Retrofit. In my application i have one RecyclerView with two ViewHolder's, where trying to get data from my models, in logs coming type:
#Override
public void onResponse(Call<DropDown> call, Response<DropDown> response) {
DropDown jsonResponse = response.body();
Log.d("type",jsonResponse.getForm().getmGroupss().get(1).getmControls().get(2).getTitle()+"");
adapter = new DataAdapter(response.body());
recyclerView.setAdapter(adapter);
}
How can I display this type in my RecyclerView, if there will be a few types?
Now i get next message:
09-13 09:20:40.958 2798-2798/com.random.secondproject E/RecyclerView: No adapter attached; skipping layout
DataAdapter:
public class DataAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
public static final String TYPE_TEXTVIEW = "0";
public static final String TYPE_EDITVIEW = "1";
private DropDown mList;
public DataAdapter(DropDown list) {
this.mList = list;
}
#Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view;
switch (viewType) {
case 0:
view = LayoutInflater.from(parent.getContext()).inflate(R.layout.text_numeric, parent, false);
return new NumericViewHolder(view);
case 1:
view = LayoutInflater.from(parent.getContext()).inflate(R.layout.drop_down_options, parent, false);
return new DropDownViewHolder(view);
}
return null;
}
#Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
DropDown object = mList.get(position);
if (object != null) {
switch (object.getTitle()){
case TYPE_TEXTVIEW:
((NumericViewHolder) holder).title.setText(String.valueOf(object.getTitle()));
break;
case TYPE_EDITVIEW:
((DropDownViewHolder) holder).title_options.setText(String.valueOf(object.getTitle()));
break;
}
}
}
#Override
public int getItemCount() {
if (mList == null)
return 0;
return mList.size();
}
#Override
public int getItemViewType(int position) {
DropDown object = mList.get(position);
if (object.getTitle().equals("drop_down_options"))
return 0;
else return 1;
}
public class NumericViewHolder extends RecyclerView.ViewHolder {
private TextView title;
public NumericViewHolder(View itemView) {
super(itemView);
title = (TextView) itemView.findViewById(R.id.title);
}
}
public class DropDownViewHolder extends RecyclerView.ViewHolder {
private EditText title_options;
public DropDownViewHolder(View itemView) {
super(itemView);
title_options = (EditText) itemView.findViewById(R.id.title_options);
}
As you can see, I'm going to take two types (TextView and EditText)
so I will write a few ways to model(array i think). For example, as I wrote in Log.d .

Everything seem ok to me in your adapter. Try to call recyclerView.invalidate(). The idea is that you draw your RecyclerView before calling the onResponse method. Thus, you have empty view. The invalidate() method will try to redraw the view.

There are some error so that onResponse function not call, or you do with element in recyclerview before onResponse called.
You need create an adapter with empty Dropdown
adapter = new DataAdapter(new Dropdown());
When onResponse called you only notifyDatasetChange to adapter, don't setAdapter again.
Or you put the code that pratice with element of recyclerview to onResponse.

Related

change value of textview in a recyclerview item

guys I'm using multiple api request with the same response and displaying it into a recycling
view
but in those response I get a user_id instead of user name but I need to display the user name into the recyclerview
this image breaks down what i need to do : https://i.stack.imgur.com/IdQ6e.png
so this is my adapter class where I tried to make a hashmap using another api request and making a hashmap with <user_id,user_name> and trying to use it in the holder class to display the user name but it didn't work :
public class FollowupAdapter extends RecyclerView.Adapter {
Map<String, String> userMap1 = new HashMap<>();
private Context Context1 ;
private List<TraitementTicketModel> followuplist;
public FollowupAdapter(Context mContext, List<TraitementTicketModel> followuplist) {
this.Context1 = mContext;
this.followuplist = followuplist;
}
#Override
public int getItemViewType(int position) {
if(followuplist.get(position).getTaskcategories_id()!=null) {
return 3;
}else if (followuplist.get(position).getSolutiontypes_id()!=null){
return 2;
}
return 1;
}
#NonNull
#Override
public RecyclerView.ViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view;
LayoutInflater layoutInflater=LayoutInflater.from(Context1);
if (viewType==1){
view = layoutInflater.inflate(R.layout.followupitem, parent,false);
return new ViewHolderFollowup(view);
}else if (viewType==2){
view = layoutInflater.inflate(R.layout.solutionitem, parent,false);
return new ViewHolderSolution(view);
}
else
view = layoutInflater.inflate(R.layout.taskitem, parent,false);
return new ViewHolderTask(view);
}
#Override
public void onBindViewHolder(#NonNull RecyclerView.ViewHolder holder, int position) {
displayusers();
if(followuplist.get(position).getTaskcategories_id()!=null) {
ViewHolderTask viewHolderTask = (ViewHolderTask) holder;
viewHolderTask.users_id.setText(userMap1.get(followuplist.get(position).getUsers_id()));
viewHolderTask.date.setText(followuplist.get(position).getDate());
viewHolderTask.content.setText(html2text(followuplist.get(position).getContent()));
}else if(followuplist.get(position).getSolutiontypes_id()!=null){
ViewHolderSolution viewHolderSolution = (ViewHolderSolution) holder;
viewHolderSolution.users_id.setText(userMap1.get(followuplist.get(position).getUsers_id()));
viewHolderSolution.date.setText(followuplist.get(position).getDate());
viewHolderSolution.content.setText(html2text(followuplist.get(position).getContent()));
}
else {
ViewHolderFollowup viewHolderFollowup = (ViewHolderFollowup) holder;
viewHolderFollowup.users_id.setText(userMap1.get(followuplist.get(position).getUsers_id()));
viewHolderFollowup.content.setText(html2text(followuplist.get(position).getContent()));
viewHolderFollowup.titre.setText(followuplist.get(position).getTitre());
viewHolderFollowup.date.setText(followuplist.get(position).getDate());
}
}
#Override
public int getItemCount() { return followuplist.size(); }
public static class ViewHolderFollowup extends RecyclerView.ViewHolder{
TextView users_id;
TextView date;
TextView content;
TextView titre;
public ViewHolderFollowup(#NonNull View itemView) {
super(itemView);
users_id=itemView.findViewById(R.id.user_id_followup);
date =itemView.findViewById(R.id.date_followup);
content=itemView.findViewById(R.id.contenu_followup);
titre=itemView.findViewById(R.id.titre_followup);
}
}
public static class ViewHolderTask extends RecyclerView.ViewHolder {
TextView users_id;
TextView date;
TextView content;
public ViewHolderTask(#NonNull View itemView) {
super(itemView);
users_id=itemView.findViewById(R.id.user_id_task);
date =itemView.findViewById(R.id.date_task);
content=itemView.findViewById(R.id.contenu_task);
}
}
public static class ViewHolderSolution extends RecyclerView.ViewHolder{
TextView users_id;
TextView date;
TextView content;
public ViewHolderSolution(#NonNull View itemView) {
super(itemView);
users_id=itemView.findViewById(R.id.user_id_solution);
date =itemView.findViewById(R.id.date_solution);
content=itemView.findViewById(R.id.contenu_solution);
}
}
public static String html2text(String html) {
return Jsoup.parse(Jsoup.parse(html).text()).text();
}
public List addToList(List<TraitementTicketModel> list) {
if(this.followuplist.addAll(list)){
Sort(followuplist);
}
notifyDataSetChanged();
return this.followuplist;
}
private List Sort (List<TraitementTicketModel> datalist){
Collections.sort(datalist, new Comparator<TraitementTicketModel>() {
#Override
public int compare(TraitementTicketModel o1, TraitementTicketModel o2) {
return o2.getDate().compareTo(o1.getDate());
}
});
return datalist;
}
private void displayusers() {
SharedPreferences sp =Context1.getApplicationContext().getSharedPreferences("tokenPref", Context.MODE_PRIVATE);
String sestoken = sp.getString("token","");
Retrofit retrofit= RetrofitInstance.getRetrofitInstance();
final Api api= retrofit.create(Api.class);
Call<List<User>> call = api.getUser(sestoken);
call.enqueue(new Callback<List<User>>() {
#Override
public void onResponse(Call<List<User>> call, Response<List<User>> response) {
if (response.code() != 200){
Log.e("TAG", "onResponse: something is wrong"+response.code() );
}
List<User> users = response.body();
for (User user : users) {
if (userMap.get(user.getId()) == null)
userMap.put(user.getId(), user.getName());
}
}
#Override
public void onFailure(Call<List<User>> call, Throwable t) {
}
});
}
private Map<String, String> PutMap(HashMap<String, String> userMap) {
userMap1=userMap;
return userMap1;
}
}
this hashmap I tried didn't work appreciate any solution or idea I'm really stuck in this
Your adapter's job is to adapt a data model into a series of view holders, not to transform, combine, fetch, mutate, etc. a different series of data coming from different sources.
Ask yourself this question: if you could "magically" call an object like this repository.getList() that would return a List of Something and that Something had three fields:
class Something {
String id;
String userName;
String content;
String type; //maybe useful for the Adapter to pick what type...
... anything else you need
}
So you have a List<Something>() that you can pass to your adapter, wouldn't your adapter suddenly be super simple?
That's what you need to do; remove all the logic that does not belong in the adapter (I expect only to have a onCreateViewHolder onBindViewHolder getItemViewType and that's it).
You're making a big problem into your adapter, which already has a lot of other responsibilities to carry. This data problem (putting the user + id + content) in a single object is a problem of your data source/repository, and not the adapter of a recycler view.
Transform your data before you pass it to your adapter. Your life, your fellow developers, and the future you, will be grateful.

Two recyclerView and one onClick showing the content of the clicked element of the respective recyclerView

Problem
In my acitvity i have two recyclerViews showing popular movies and top rated movies respectively.
When I click on a movie in a recyclerView, that movie is sent to an activity showing its details.
I go back to the home and if I click on a movie of another recyclerView, the previously clicked movie is shown.
I need to show the details of any clicked movie in any recyclerView.
I have a single viewHolder (MovieViewHolder)
public class MovieViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
//Widgets
TextView title, rating;
ImageView imageView;
//Click listener
OnMovieListener onMovieListener ;
public MovieViewHolder(#NonNull View itemView, OnMovieListener onMovieListener) {
super(itemView);
this.onMovieListener = onMovieListener;
title = itemView.findViewById(R.id.movie_title);
imageView = itemView.findViewById(R.id.movie_img);
rating = itemView.findViewById(R.id.rating_bar);
itemView.setOnClickListener(this);
}
#Override
public void onClick(View v) {
onMovieListener.onMovieClick(getAdapterPosition());
}
An interface
public interface OnMovieListener {
void onMovieClick(int position);
void onCategoryClick(String category);
}
This two Adapter:
This for popular movies
public class MovieRecyclerView extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private List<MovieModel> mMovies;
private final OnMovieListener onMovieListener;
public MovieRecyclerView(OnMovieListener onMovieListener) {
this.onMovieListener = onMovieListener;
}
#NonNull
#Override
public RecyclerView.ViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.movie_item,
parent, false);
return new MovieViewHolder(view, onMovieListener);
}
#Override
public void onBindViewHolder(#NonNull RecyclerView.ViewHolder holder, int position) {
((MovieViewHolder) holder).title.setText(mMovies.get(position).getTitle());
((MovieViewHolder) holder).rating.setText(String.valueOf((float) (mMovies.get(position).getVote_average())));
//ImageView: Using Glide Library
Glide.with(holder.itemView.getContext())
.load("https://image.tmdb.org/t/p/w500/"
+ mMovies.get(position).getPoster_path())
.into(((MovieViewHolder) holder).imageView);
}
#Override
public int getItemCount() {
if (mMovies != null) {
return mMovies.size();
}
return 0;
}
public void setmMovies(List<MovieModel> mMovies) {
this.mMovies = mMovies;
notifyDataSetChanged();
}
//Getting the id of the movie clicked
public MovieModel getSelectedMovie(int position) {
if (mMovies != null) {
if (mMovies.size() > 0) {
return mMovies.get(position);
}
}
return null;
}
This for top_rated
public class MovieLatestRecyclerView extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private List<MovieModel> mMoviesLatest;
private OnMovieListener onMovieListener;
public MovieLatestRecyclerView(OnMovieListener onMovieListener) {
this.onMovieListener = onMovieListener;
}
#NonNull
#Override
public RecyclerView.ViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.movie_item,
parent, false);
return new MovieViewHolder(view, onMovieListener);
}
#Override
public void onBindViewHolder(#NonNull RecyclerView.ViewHolder holder, int position) {
((MovieViewHolder)holder).title.setText(mMoviesLatest.get(position).getTitle());
((MovieViewHolder)holder).rating.setText(String.valueOf((float) (mMoviesLatest.get(position).getVote_average())));
//ImageView: Using Glide Library
Glide.with(holder.itemView.getContext())
.load("https://image.tmdb.org/t/p/w500/"
+ mMoviesLatest.get(position).getPoster_path())
.into(((MovieViewHolder)holder).imageView);
}
#Override
public int getItemCount() {
if(mMoviesLatest != null) {
return mMoviesLatest.size();
}
return 0;
}
public void setmMoviesLatest(List<MovieModel> mMoviesLatest) {
this.mMoviesLatest = mMoviesLatest;
notifyDataSetChanged();
}
//Getting the id of the movie clicked
public MovieModel getSelectedMovie(int position){
if(mMoviesLatest != null){
if(mMoviesLatest.size() > 0){
return mMoviesLatest.get(position);
}
}
return null;
}
In MainActivity i configure the recyclerViews with this method
private void ConfigureRecyclerView() {
movieRecyclerViewAdapter = new MovieRecyclerView(this);
movieLatestRecyclerViewAdapter = new MovieLatestRecyclerView(this);
recyclerView_popular.setAdapter(movieRecyclerViewAdapter);
recyclerView_popular.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, false));
recyclerView_latest.setAdapter(movieLatestRecyclerViewAdapter);
recyclerView_latest.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, false));
//RecyclerView Pagination
//Loading next page of api response
recyclerView_popular.addOnScrollListener(new RecyclerView.OnScrollListener() {
#Override
public void onScrollStateChanged(#NonNull RecyclerView recyclerView, int newState) {
if (!recyclerView.canScrollVertically(1)) {
//Here we need to display the next search result
movieListViewModel.searchNextPage();
}
}
});
recyclerView_latest.addOnScrollListener(new RecyclerView.OnScrollListener() {
#Override
public void onScrollStateChanged(#NonNull RecyclerView recyclerView, int newState) {
if (!recyclerView.canScrollVertically(1)) {
//Here we need to display the next search result
movieListViewModel.searchNextPage();
}
}
});
}
And i use this for passing the selected movie to another activity
#Override
public void onMovieClick(int position) {
//WE don't need position of the movie in recyclerView
// We need the ID of the movie in order to get all it's details
Intent intent = new Intent(this, MovieDetails.class);
intent.putExtra("movie", movieRecyclerViewAdapter.getSelectedMovie(position));
startActivity(intent);
}
Whoever you are reading my question I thank you for your time and I apologize for the certain banality and length.
At this line:
intent.putExtra("movie", movieRecyclerViewAdapter.getSelectedMovie(position));
You are getting a movie from movieRecyclerViewAdapter. This adapter is only used with the 'Popular' movie recycler view.
onMovieClick is used for both the 'Popular' and the 'Top Rated' recycler views. So, clicking an item from 'Top Rated' will attempt to use an item from 'Popular'.
To fix this, a click from 'Top Rated' should not attempt to get an item from movieRecyclerViewAdapter.
You could do something like change onMovieClick(int position) to onMovieClick(MovieModel movie), so you don't have to worry about knowing which adapter to get the movie from.

Adding new data to Adapter affects initial values

I'm trying to build a simple chat interface. When a user click enter their message is sent to the server, added to the DB and simultaneously inserted into the MessageAdapter that's on the client's device so it appears on their screen.
Messages from the user are right-aligned and vice-versa for non-users.
When a user sends a message, as opposed to all the messages shifting up one spot, the text shifts up but not the actual message objects.
I'm trying to have a user send a message and all previous messages effectively shift up so the new message can appear below.
Initially the non-user message is Hello but after I send the user's message, the message below the non-user, Hey takes its place.
This is my code for the MessageAdapter:
public class MessageAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
List<Message> data= Collections.emptyList();
List<Integer> message_type= Collections.emptyList();
// create constructor to initialize context and data sent from MainActivity
public MessageAdapter(List<Message> data, List<Integer> message_type) {
this.data=data;
this.message_type=message_type;
}
public void addItem(Message item, int message_type){
this.data.add(item);
this.message_type.add(0, message_type);
}
// Inflate the layout when ViewHolder created
#Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
switch (i) {
case 0:
View v = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.message_non_user, viewGroup, false);
return new ViewHolder0(v);
case 2:
View q = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.message_user, viewGroup, false);
return new ViewHolder1(q);
}
View v = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.message_non_user, viewGroup, false);
return new ViewHolder1(v);
}
// Bind data
#Override
public void onBindViewHolder(RecyclerView.ViewHolder viewHolder, final int position) {
switch (viewHolder.getItemViewType()) {
case 0:
ViewHolder0 viewHolder0 = (ViewHolder0)viewHolder;
Message current0 = data.get(position);
viewHolder0.body.setText(current0.message);
break;
case 2:
ViewHolder1 viewHolder1 = (ViewHolder1)viewHolder;
Message current1 = data.get(position);
viewHolder1.body.setText(current1.message);
break;
}
}
// return total item from List
#Override
public int getItemCount() {
return data.size();
}
#Override
public int getItemViewType(int position) {
int temp = message_type.get(position);
if(temp == 0 ){
return 0;
}
return 2;
}
class ViewHolder0 extends RecyclerView.ViewHolder {
TextView body;
public ViewHolder0(final View itemView) {
super(itemView);
body = (TextView) itemView.findViewById(R.id.message_body);
}
}
class ViewHolder1 extends RecyclerView.ViewHolder {
TextView body;
public ViewHolder1 (final View itemView) {
super(itemView);
body = (TextView) itemView.findViewById(R.id.message_body);
}
}
}
And then this is the code for the send-message action:
Message user_input = new Message();
user_input.message = chat_input.getText().toString();
messageAdapter.addItem(user_input, 0);
messageAdapter.notifyItemInserted(messageAdapter.getItemCount()+1);
MessagesRecyclerview.scrollToPosition(messageAdapter.getItemCount() - 1);
messageAdapter.notifyDataSetChanged();
chat_input.getText().clear();
Thanks for your help :)
It may be because you are adding your data like this:
this.data.add(item);
this.message_type.add(0, message_type);
you are adding your types at the begining of the list but you are adding your data at the end of the list, so it looks like there is a shift in your data.
use this:
this.data.add(0,item);
this.message_type.add(0, message_type);
Or this:
this.data.add(item);
this.message_type.add(message_type);

How to call scrollToPosition(position) inside recyclerView's adapter?

I have a setOnClick listener inside my onBindViewHolder
#Override
public void onBindViewHolder(final RecyclerView.ViewHolder holder, final int position) {
((ViewHolder) holder).txtType.setText(object.text);
((ViewHolder) holder).checkBox.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Toast.makeText(mContext, ""+position, Toast.LENGTH_SHORT).show();
//???.scrolltoPosition(position+1);
}
});
on click, I would be scrolling the viewport to the next recycler view item. I've done this inside my MainActivity java by recyclerView.scrollToPosition(position);. But inside Adapter Class on onBindViewHolder, I have no idea how to call my recyclerView on the Main Java Class.
How should I do this?
edit:
For simplification purposes, I revised this previous code, because I have used a multiview adapter for my recycler. Here is the multiview adapter:
public class MultiViewTypeAdapter extends RecyclerView.Adapter {
private ArrayList<InstructionModel>dataSet;
Context mContext;
int total_types;
private LinearLayoutManager manager;
public MultiViewTypeAdapter(LinearLayoutManager manager)
{
this.manager=manager;
}
public static class SimpleTextViewHolder extends RecyclerView.ViewHolder {
TextView txtType;
CardView cardView;
CheckBox checkBox;
public SimpleTextViewHolder(View itemView) {
super(itemView);
this.txtType = (TextView) itemView.findViewById(R.id.type);
this.cardView = (CardView) itemView.findViewById(R.id.card_view);
this.checkBox = (CheckBox) itemView.findViewById(R.id.checkBox);
}
}
public static class TimeTextViewHolder extends RecyclerView.ViewHolder {
TextView txtType;
CardView cardView;
CheckBox checkBox;
public TimeTextViewHolder(View itemView) {
super(itemView);
this.txtType = (TextView) itemView.findViewById(R.id.type);
this.cardView = (CardView) itemView.findViewById(R.id.card_view);
this.checkBox = (CheckBox) itemView.findViewById(R.id.checkBox);
}
}
public MultiViewTypeAdapter(ArrayList<InstructionModel> data, Context context) {
this.dataSet = data;
this.mContext = context;
total_types = dataSet.size();
}
#Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view;
switch (viewType) {
case InstructionModel.SIMPLE_TYPE:
view = LayoutInflater.from(parent.getContext()).inflate(R.layout.simple, parent, false);
return new SimpleTextViewHolder(view);
case InstructionModel.TIME_TYPE:
view = LayoutInflater.from(parent.getContext()).inflate(R.layout.time, parent, false);
return new TimeTextViewHolder(view);
}
return null;
}
#Override
public int getItemViewType(int position) {
switch (dataSet.get(position).type) {
case 0:
return InstructionModel.SIMPLE_TYPE;
case 1:
return InstructionModel.TIME_TYPE;
default: return -1;
}
}
#Override
public void onBindViewHolder(final RecyclerView.ViewHolder holder, final int listPosition) {
InstructionModel object = dataSet.get(listPosition);
if (object != null) {
switch (object.type) {
case InstructionModel.SIMPLE_TYPE:
((SimpleTextViewHolder) holder).txtType.setText(object.text);
break;
case InstructionModel.TIME_TYPE:
((TimeTextViewHolder) holder).txtType.setText(object.text);
break;
}
}
}
#Override
public int getItemCount() {
return dataSet.size();
}
P.S.
If you see some random useless stuff, I was trying something.
Pass the LayoutManger with constuctor
class Adapter extends RecyclerView.Adapter<Adapter.ViewHolder> {
private LinearLayoutManager manager;
public Adapter(LinearLayoutManager manager)
{
this.manager=manager;
}
#Override
public void onBindViewHolder(final RecyclerView.ViewHolder holder, final int position) {
((ViewHolder) holder).txtType.setText(object.text);
((ViewHolder) holder).checkBox.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Toast.makeText(mContext, ""+position, Toast.LENGTH_SHORT).show();
manager.scrollToPosition(position+1);
}
});
}
I think you should define a interface to notify your parent RecyclerView to do scroll operation, the RecyclerView into ViewHodler inside operation, resulting in the coupling
You can pass a listener object in the constructor which implements by Fragment OR Activity.
/**
* item click interface of adapter
*/
public interface MultiViewTypeAdapterListener {
void onScroll(int position)
}
This interface implements by Fragment OR Activity
/**
* On Scroll Implement Method from adapter listener.
*
* #param position
*/
#Override
public void onScroll(int position) {
// Here you can call that method
recyclerview.scrolltoPosition(position)
}
Then you pass this listener in the constructor of the adapter.
private void buildRecyclerView() {
multiViewTypeAdapter = new MultiViewTypeAdapter(this);
recyclerView.setAdapter(multiViewTypeAdapter);
}
In the constructor, you can assign like this
private MultiViewTypeAdapterListener mMultiViewTypeAdapterListener;
public OfferAdapter(MultiViewTypeAdapterListener mMultiViewTypeAdapterListener) {
this.mMultiViewTypeAdapterListener = mMultiViewTypeAdapterListener
}
}
Now you can use this listener by setting click listener on anyViwe like this
((ViewHolder) holder).checkBox.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Toast.makeText(mContext, ""+position, Toast.LENGTH_SHORT).show();
//???.scrolltoPosition(position+1);
mMultiViewTypeAdapterListener.onScroll(position+1);
}
});
It returns to call the method of onItemClick which implements this method.
private int getScrollRange() {
int scrollRange = 0;
if (parent.getChildCount() > 0) {
View child = parent.getChildAt(0);
scrollRange = Math.max(0,
child.getHeight() - (parent.getHeight()));
}
return scrollRange;
}
ScrollView parent=findViewById(R.id.scroll_Recipe_Detail);
parent.scrollTo(0,getScrollRange());
if you want to scroll on new items added, you must override "onItemsAdded".
Here is how I did it:
recyclerView.apply {
setHasFixedSize(true)
layoutManager = MyLinearLayoutManager(this#MainActivity)
...
}
private class MyLinearLayoutManager(private val context: Context) :
LinearLayoutManager(context) {
// Force new items appear at the top
override fun onItemsAdded(recyclerView: RecyclerView, positionStart: Int, itemCount: Int) {
super.onItemsAdded(recyclerView, positionStart, itemCount)
scrollToPosition(findLastVisibleItemPosition())
}
}

Android RecyclerView, recycling not working properly

I have a RecyclerView that I am using. I have used RecyclerView before but never had this problem.
When I scroll up and down some of the items disappear, and some of the items that disappear appear again in the bottom.
Code:
ViewHolder:
public class ViewHolder extends RecyclerView.ViewHolder {
public TextView txt;
public ViewHolder(View view) {
super(view);
txt = (TextView) view.findViewById(R.id.txt);
}
}
Adapter:
public class MyAdapter extends RecyclerView.Adapter<ViewHolder> {
private final Activity activity;
private final ArrayList<HashMap<String, String>> mItems;
public MyAdapter (Activity activity, ArrayList<HashMap<String, String>> mItems) {
this.activity = activity;
this.mItems= mItems;
}
#Override
public ViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
return new ViewHolder(LayoutInflater.from(activity).inflate(R.layout.items, viewGroup, false));
}
#Override
public void onBindViewHolder(ViewHolder viewHolder, int position) {
HashMap<String, String> item = mItems.get(position);
String info = item.get("info ");
if (info!= null) {
viewHolder.txt.setText(info);
} else {
viewHolder.txt.setVisibility(View.GONE);
}
}
#Override
public int getItemCount() {
return (null != mItems? mItems.size() : 0);
}
}
onBindViewHolder reuses Views so let's say the first time onBindViewHolder() is called, info is null. This will cause that row to have visibility of View.GONE.
When onBindViewHolder is called again to bind a new row, the view for that row is still View.GONE - nothing is reset between rows being bound.
Therefore your if statement should reset the state completely:
if (info!= null) {
viewHolder.txt.setText(info);
viewHolder.txt.setVisibility(View.VISIBLE);
} else {
viewHolder.txt.setVisibility(View.GONE);
}
This will ensure that each row's visibility is set correctly.

Categories