Viewmodel shows empty recyclerview when activity rotated - java

I am pretty new to the Android architecture components and have been trying out room for data storage from my server. Problem is no data is being shown on the recycler view IMMEDIATELY. There's a searchview(no logic implemented just there) right above my recyclerview and when I click searchview for input, the recyclerview shows all the data which was supposed to be shown earlier.
RestaurantsAdapter:
public class RestaurantsAdapter extends RecyclerView.Adapter<RestaurantsAdapter.MyViewHolder> {
private List<Restaurant> data;
private Context context;
private LayoutInflater layoutInflater;
private final Random r = new Random();
public RestaurantsAdapter(Context context) {
this.data = new ArrayList<>();
this.context = context;
this.layoutInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
#Override
public RestaurantsAdapter.MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_restaurant, parent, false);
return new RestaurantsAdapter.MyViewHolder(view);
}
#Override
public void onBindViewHolder(#NonNull RestaurantsAdapter.MyViewHolder holder, int position) {
holder.rName.setText(data.get(position).getName());
}
public void setData(List<Restaurant> newData) {
if (data != null) {
RestaurantDiffCallback restaurantDiffCallback = new RestaurantDiffCallback(data, newData);
DiffUtil.DiffResult diffResult = DiffUtil.calculateDiff(restaurantDiffCallback);
data.clear();
data.addAll(newData);
diffResult.dispatchUpdatesTo(this);
} else {
// first initialization
data = newData;
}
}
#Override
public int getItemCount() {
return data.size();
}
public class MyViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
TextView rName;
public MyViewHolder(View itemView) {
super(itemView);
rName = (TextView) itemView.findViewById(R.id.restaurant_name);
itemView.setOnClickListener(this);
}
#Override
public void onClick(View view) {
}
}
class RestaurantDiffCallback extends DiffUtil.Callback {
private final List<Restaurant> oldRestaurants, newRestaurants;
public RestaurantDiffCallback(List<Restaurant> oldPosts, List<Restaurant> newPosts) {
this.oldRestaurants = oldPosts;
this.newRestaurants = newPosts;
}
#Override
public int getOldListSize() {
return oldRestaurants.size();
}
#Override
public int getNewListSize() {
return newRestaurants.size();
}
#Override
public boolean areItemsTheSame(int oldItemPosition, int newItemPosition) {
return oldRestaurants.get(oldItemPosition).getIdentifier().equals(newRestaurants.get(newItemPosition).getIdentifier());
}
#Override
public boolean areContentsTheSame(int oldItemPosition, int newItemPosition) {
return oldRestaurants.get(oldItemPosition).equals(newRestaurants.get(newItemPosition));
}
}}
MainActivity:
public class MainActivity extends AppCompatActivity {
private RestaurantsAdapter restaurantsAdapter;
private RestaurantViewModel restaurantViewModel;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
restaurantsAdapter = new RestaurantsAdapter(this);
restaurantViewModel = ViewModelProviders.of(this).get(RestaurantViewModel.class);
restaurantViewModel.getAllRestaurants().observe(this, restaurants -> restaurantsAdapter.setData(restaurants));
RecyclerView recyclerView = findViewById(R.id.recyclerView);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
recyclerView.setHasFixedSize(true);
recyclerView.setItemAnimator(new DefaultItemAnimator());
recyclerView.setAdapter(restaurantsAdapter);
}}
ViewModel:
public class RestaurantViewModel extends AndroidViewModel {
private RestaurantDao restaurantDao;
private ExecutorService executorService;
private ApiInterface webService;
public RestaurantViewModel(#NonNull Application application) {
super(application);
restaurantDao = RestaurantsDatabase.getInstance(application).restaurantDao();
executorService = Executors.newSingleThreadExecutor();
webService = ApiClient.getApiClient().create(ApiInterface.class);
}
LiveData<List<Restaurant>> getAllRestaurants() {
refreshUser();
return restaurantDao.findAll();
}
private void refreshUser() {
executorService.execute(() -> {
int numOfRestaurants = restaurantDao.totalRestaurants();
if (numOfRestaurants < 30) {
Call<RestaurantsModel> call = webService.getRestaurants();
call.enqueue(new Callback<RestaurantsModel>() {
#Override
public void onResponse(#NonNull Call<RestaurantsModel> call, #NonNull Response<RestaurantsModel> response) {
restaurantDao.saveAll(response.body().getData().getData());
}
#Override
public void onFailure(#NonNull Call<RestaurantsModel> call, #NonNull Throwable t) {
}
});
}
});
}}

If you don't use the DiffUtil with its diffResult.dispatchUpdatesTo(this); you should do notifyDataSetChanged(). In your case, in RestaurantsAdapter.setData add one line:
// first initialization
data = newData;
notifyDataSetChanged();

You have an issue in your setData method:
public void setData(List<Restaurant> newData) {
if (data != null) {
RestaurantDiffCallback restaurantDiffCallback = new RestaurantDiffCallback(data, newData);
DiffUtil.DiffResult diffResult = DiffUtil.calculateDiff(restaurantDiffCallback);
data.clear();
data.addAll(newData);
diffResult.dispatchUpdatesTo(this);
} else {
// first initialization
data = newData;
}
}
When your newData is null your change the data source of your adapter, but you don't call notifyDataSetChanged.
This way the data that you are seeing on the screen will not be updated.
So in order to fix it:
public void setData(List<Restaurant> newData) {
if (data != null) {
RestaurantDiffCallback restaurantDiffCallback = new RestaurantDiffCallback(data, newData);
DiffUtil.DiffResult diffResult = DiffUtil.calculateDiff(restaurantDiffCallback);
data.clear();
data.addAll(newData);
diffResult.dispatchUpdatesTo(this);
} else {
// first initialization
data = newData;
notifyDataSetChanged();
}
}
Another thing, if not a very good practice setting your adapter dataset has null. So my suggestion is to set your data as an empty list instead of null:
data = new ArrayList<>();

The issue: you're using ViewModels incorrectly. You are only returning data from the ViewModel, but never saving data in the ViewModel
Start by reading how ViewModels work here: https://developer.android.com/topic/libraries/architecture/viewmodel

Related

Unable to get data from Retrofit when used in for loop

I'm using MVVM and I'm trying to loop over a list of integers that has some IDs for movies genres, I'm using retrofit and I have a function that should return a list of movies based on the id, but it's working for some reason.
I tried to pass the id to the function and it worked, however when I tried to loop over a list of ids to get different results and put them in a RecyclerView it didn't work
MainActivity:
public class MainActivity extends AppCompatActivity {
RecyclerView mMainRecycler;
MoviesViewModel moviesViewModel;
MainRecyclerAdapter mainRecyclerAdapter;
Context context = this;
List<String> genresNames = new ArrayList<>();
List<Integer> genresIds = new ArrayList<>();
List<Movies.Result> listResults = new ArrayList<>();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mMainRecycler = findViewById(R.id.main_recycler);
mMainRecycler.setLayoutManager(new LinearLayoutManager(this));
moviesViewModel = new ViewModelProvider(this).get(MoviesViewModel.class);
moviesViewModel.getMoviesGenres();
moviesViewModel.mutableMoviesGenres.observe(this, new Observer<List<MoviesGenres.GenresBean>>() {
#Override
public void onChanged(List<MoviesGenres.GenresBean> genresBeans) {
for (int i = 0; i < genresBeans.size(); i++) {
genresIds.add(genresBeans.get(i).getId());
genresNames.add(genresBeans.get(i).getName());
}
mainRecyclerAdapter.addNames(genresNames);
}
});
for(int i = 0; i < genresIds.size(); i++) {
moviesViewModel.getMovieWithGenre(genresIds.get(i));
}
moviesViewModel.mutableMoviesWithGenre.observe(this, new Observer<List<Movies.Result>>() {
#Override
public void onChanged(List<Movies.Result> results) {
listResults.addAll(results);
mainRecyclerAdapter.addResults(listResults);
}
});
mMainRecycler.setLayoutManager(new LinearLayoutManager(this));
mainRecyclerAdapter = new MainRecyclerAdapter(context, genresNames, listResults);
mMainRecycler.setAdapter(mainRecyclerAdapter);
}
}
ViewModel:
public class MoviesViewModel extends ViewModel {
public MutableLiveData<List<Movies.Result>> mutablePopularMovies = new MutableLiveData<>();
public void getPopular(){
MoviesClient.getInstance().getPopular().enqueue(new Callback<Movies>() {
#Override
public void onResponse(#NonNull Call<Movies> call, #NonNull Response<Movies> response) {
if(response.isSuccessful() && response.body() != null) {
mutablePopularMovies.setValue(response.body().getResults());
}
}
#Override
public void onFailure(#NonNull Call<Movies> call, #NonNull Throwable t) {
t.printStackTrace();
}
});
}
public MutableLiveData<List<Movies.Result>> mutableMoviesWithGenre = new MutableLiveData<>();
public void getMovieWithGenre(int i){
MoviesClient.getInstance().getMoviesWithGenre(i).enqueue(new Callback<Movies>() {
#Override
public void onResponse(#NonNull Call<Movies> call, #NonNull Response<Movies> response) {
if(response.isSuccessful() && response.body() != null) {
mutableMoviesWithGenre.setValue(response.body().getResults());
}
}
#Override
public void onFailure(#NonNull Call<Movies> call, #NonNull Throwable t) {
t.printStackTrace();
}
});
}
public MutableLiveData<List<MoviesGenres.GenresBean>> mutableMoviesGenres = new MutableLiveData<>();
public void getMoviesGenres() {
MoviesClient.getInstance().getMoviesByGenre().enqueue(new Callback<MoviesGenres>() {
#Override
public void onResponse(#NonNull Call<MoviesGenres> call, #NonNull Response<MoviesGenres> response) {
if(response.isSuccessful() && response.body() != null) {
mutableMoviesGenres.setValue(response.body().getGenres());
}
}
#Override
public void onFailure(#NonNull Call<MoviesGenres> call, #NonNull Throwable t) {
t.printStackTrace();
}
});
}
}
MainRecyclerViewAdapter:
public class MainRecyclerAdapter extends RecyclerView.Adapter<MainRecyclerAdapter.MainViewHolder> {
private Context mContext;
private List<Movies.Result> moviesResults;
private List<String> moviesNames;
public MainRecyclerAdapter(Context context, List<String> moviesNames, List<Movies.Result> moviesResults) {
this.mContext = context;
this.moviesNames = moviesNames;
this.moviesResults = moviesResults;
}
#NonNull
#Override
public MainRecyclerAdapter.MainViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
return new MainViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.category_rv_item, parent, false));
}
#Override
public void onBindViewHolder(#NonNull final MainRecyclerAdapter.MainViewHolder holder, int position) {
holder.genresTv.setText(moviesNames.get(position));
setCatItemRecycler(holder.mRecycler, moviesResults);
}
#Override
public int getItemCount() {
return moviesNames.size();
}
public void addNames(List<String> moviesGenres) {
moviesNames.addAll(moviesGenres);
notifyDataSetChanged();
}
public void addResults(List<Movies.Result> listResults) {
moviesResults.addAll(listResults);
notifyDataSetChanged();
}
public class MainViewHolder extends RecyclerView.ViewHolder {
TextView genresTv;
RecyclerView mRecycler;
public MainViewHolder(#NonNull View itemView) {
super(itemView);
genresTv = itemView.findViewById(R.id.cat_title);
mRecycler = itemView.findViewById(R.id.item_recycler);
}
}
private void setCatItemRecycler(RecyclerView recyclerView, List<Movies.Result> moviesResults){
MovieAdapter movieAdapter = new MovieAdapter(mContext, moviesResults);
recyclerView.setLayoutManager(new LinearLayoutManager(mContext, RecyclerView.HORIZONTAL, false));
recyclerView.setAdapter(movieAdapter);
}
}
Chile (inner) RecyclerView:
public class MovieAdapter extends RecyclerView.Adapter<MovieAdapter.MovieViewHolder> {
private List<Movies.Result> moviesResult;
private Context mContext;
public MovieAdapter(Context context, List<Movies.Result> moviesResult) {
this.moviesResult = moviesResult;
this.mContext = context;
}
#NonNull
#Override
public MovieAdapter.MovieViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
return new MovieViewHolder(LayoutInflater.from(mContext).inflate(R.layout.movie_item, parent, false));
}
#Override
public void onBindViewHolder(#NonNull MovieAdapter.MovieViewHolder holder, int position) {
String imageUrl = MoviesClient.IMAGE_URL + moviesResult.get(position).getPosterPath();
Glide.with(holder.mPosterImage.getContext()).load(imageUrl).into(holder.mPosterImage);
}
#Override
public int getItemCount() {
return moviesResult.size();
}
public class MovieViewHolder extends RecyclerView.ViewHolder {
ImageView mPosterImage;
public MovieViewHolder(#NonNull View itemView) {
super(itemView);
mPosterImage = itemView.findViewById(R.id.poster_image);
}
}
}
first of all you didn't share the ViewModel class, I thing you may have a problem with the observers, because your listResults will only be updated after the Retrofit returns the result, so when you call mMainRecycler.setAdapter(mainRecyclerAdapter) you are doing it with your empty list.
Another thing that may be causing this is because your data does not know it has returned, so when you use listResults.addAll(results), make sure that inside the adapter you call .notifyDataSetChanged()
A function like this should do the trick (inside the adapter):
public void updateGenres(List<Genres> genres){
listResults.addAll(genres);
this.notifyDataSetChanged();
}

How to load data into recyclerView

In my application i want get some data from server and show into recyclerView. For application architecture i used MVP
I wrote below codes, but after loaded data from server, not show any data into recyclerView!
I used debug mode and show me data in this break point
public void add(List<DataItem> list) {
list.addAll(list);
notifyDataSetChanged();
}
but not show me data into recyclerView!
My Activity codes :
public class ListFragment extends Fragment implements ActiveTestsContract.View {
#Nullable
#Override
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
view = inflater.inflate(R.layout.fragment_tester_active_tests, container, false);
//Initialize
init();
//User token log
if (!App.isEmptyString(App.getPrefs("JWT")) || !App.getPrefs("JWT").equals(ConstKeys.EMPTY)) {
userToken = App.getPrefs("JWT");
}
//Load data
getData();
return view;
}
#Override
public void updateTestsList(Data data, int page) {
testerDashboard_emptyLay.setVisibility(View.GONE);
activeTests_pullToLoader.setVisibility(View.VISIBLE);
//Get lasted page
if (page == data.getLastPage()) {
isHasLoadedAll = true;
activeTests_pullToLoader.setComplete();
}
adapter.add(data.getData());
//Complete items
isLoading = false;
nextPage = page + 1;
activeTests_pullToLoader.setComplete();
}
#Override
public void init() {
context = getActivity();
handler = new Handler(Looper.getMainLooper());
testsPresenter = new ActiveTestsPresenter(this, 3);
testerDashboard_loader = view.findViewById(R.id.testerDashboard_loader);
activeTests_pullToLoader = view.findViewById(R.id.activeTests_pullToLoader);
testerDashboard_emptyLay = view.findViewById(R.id.testerDashboard_emptyLay);
emptyLayout_editProfileBtn = view.findViewById(R.id.emptyLayout_editProfileBtn);
layoutManager = new LinearLayoutManager(context);
recyclerView = activeTests_pullToLoader.getRecyclerView();
//Adapter
adapter = new TesterActiveRecyclerAdapter(activeModel, context);
//Init recycler and adapter
recyclerView.setLayoutManager(layoutManager);
recyclerView.setAdapter(adapter);
activeTests_pullToLoader.setColorSchemeResources(R.color.colorPrimary);
}
private void getData() {
activeTests_pullToLoader.isLoadMoreEnabled(true);
activeTests_pullToLoader.setPullCallback(new PullCallback() {
#Override
public void onLoadMore() {
isLoading = true;
//Call api
testsPresenter.testsListResponse(App.recipesApi, userToken, nextPage);
}
#Override
public void onRefresh() {
adapter.clear();
isHasLoadedAll = false;
isLoading = true;
//Call api
testsPresenter.testsListResponse(App.recipesApi, userToken, 1);
}
#Override
public boolean isLoading() {
return isLoading;
}
#Override
public boolean hasLoadedAllItems() {
return isHasLoadedAll;
}
});
activeTests_pullToLoader.initLoad();
}
Adapter codes:
public class TesterActiveRecyclerAdapter extends RecyclerView.Adapter<TesterActiveRecyclerAdapter.ViewHolder> {
private List<DataItem> list;
private Context context;
public TesterActiveRecyclerAdapter(List<DataItem> list, Context context) {
this.list = list;
this.context = context;
}
#NonNull
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.adapter_tester_test_list, parent, false);
return new ViewHolder(view);
}
#SuppressLint("SetTextI18n")
#Override
public void onBindViewHolder(ViewHolder holder, int position) {
DataItem item = list.get(position);
//Name
holder.txt_name.setText(item.getTitle());
//Conditions
if (!App.isEmptyString(item.getOs()) && !App.isEmptyString(item.getType()) && !App.isEmptyString(item.getBrowser())) {
holder.txt_condition.setText(item.getType() + " | " + item.getOs() + " | " + item.getBrowser());
}
//Button actions
holder.setState(item.getState(), position);
//Price
holder.rowTests_priceTxt.setText(item.getPrice() + " Dollar");
//Animate items
Animation animation = AnimationUtils.loadAnimation(App.context,
(position > list.size() - 1) ? R.anim.down_from_top : R.anim.up_from_bottom);
holder.itemView.startAnimation(animation);
Toast.makeText(context, ""+list.get(0).getId(), Toast.LENGTH_SHORT).show();
}
#Override
public int getItemCount() {
return list.size();
}
public void add(List<DataItem> list) {
list.addAll(list);
notifyDataSetChanged();
}
public void clear() {
list.clear();
notifyDataSetChanged();
}
class ViewHolder extends RecyclerView.ViewHolder {
private ViewGroup root;
private TextView txt_name, txt_value, txt_condition, rowTests_priceTxt;
private RoundTextView rowTests_button;
ViewHolder(View view) {
super(view);
root = (ViewGroup) view;
txt_name = view.findViewById(R.id.txtTestListTitle);
txt_value = view.findViewById(R.id.txtTestListSublist);
txt_condition = view.findViewById(R.id.txtTestListSublist2);
rowTests_priceTxt = view.findViewById(R.id.rowTests_priceTxt);
rowTests_button = view.findViewById(R.id.rowTests_button);
}
}
How can i fix it?
You are adding data again in the same list passed in the parameter. Try to replace the below code
public void add(List<DataItem> list) {
list.addAll(list);
notifyDataSetChanged();
}
with
public void add(List<DataItem> list) {
this.list.addAll(list);
notifyDataSetChanged();
}
Clear the current list
Add the data to the adapter's list.
public void add(List<DataItem> list) {
clear();
this.list.addAll(list);
notifyDataSetChanged();
}
Your approach didn't work because you were updating the very list that you were passing in the function and not the adapter's list.
First add all data into list & than notify your adapter , after this set your adapter to recyclerview.
list.addAll(data)
adapter.notifyDataSetChanged()
val layoutManager = LinearLayoutManager(activity)
recyclerview.isNestedScrollingEnabled = false
recyclerview.layoutManager = layoutManager
recyclerview.itemAnimator = DefaultItemAnimator()
recyclerview.adapter = mAdapter

recyclerview for chat app doesn't show any data or views

Hi I'm building chat app UI with android but it runs without showing any data or views,
I interact with a bot server that should return text after I send a text. I'm using retrofit for http connections.
the model class showing are the response from json
please help me and ask me any details you want
My adapter
public class MessageListAdapter extends
RecyclerView.Adapter<RecyclerView.ViewHolder> {
private static final int VIEW_TYPE_MESSAGE_SENT = 1;
private static final int VIEW_TYPE_MESSAGE_RECEIVED = 2;
private List<Messages> data;
private Context mContext;
// constructor
public MessageListAdapter(List<Messages> data, Context mContext) {
this.data = data;
this.mContext = mContext;
}
#Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View itemView;
if (viewType == VIEW_TYPE_MESSAGE_SENT) {
return new SentMessageHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.user_message, parent, false));
} else {
return new RecvdMessageHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.bot_message, parent, false));
}
}
#Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
int type = getItemViewType(position);
Messages messages = data.get(position);
if (type == VIEW_TYPE_MESSAGE_SENT) {
SentMessageHolder sentMessageHolder = (SentMessageHolder) holder;
sentMessageHolder.messageBody.setText(messages.getText());
} else {
RecvdMessageHolder recvdMessageHolder = (RecvdMessageHolder) holder;
recvdMessageHolder.messageBody.setText(messages.getText());
}
}
public int getItemViewType(int position) {
Messages messages = data.get(position);
if (messages.getRecipientId() == ("default")) {
return VIEW_TYPE_MESSAGE_SENT;
} else
return VIEW_TYPE_MESSAGE_RECEIVED;
}
#Override
public int getItemCount() {
if (data != null) {
return data.size();
} else return 0;
}
class SentMessageHolder extends RecyclerView.ViewHolder {
public TextView messageBody;
public SentMessageHolder(View itemView) {
super(itemView);
messageBody = (TextView) itemView.findViewById(R.id.text_message_body);
}
}
class RecvdMessageHolder extends RecyclerView.ViewHolder {
public TextView messageBody;
public RecvdMessageHolder(View itemView) {
super(itemView);
messageBody = (TextView) itemView.findViewById(R.id.text_message_body);
}
}
My activity
public class MainActivity extends AppCompatActivity {
private EditText editText;
private RecyclerView mMessageRecycler;
private RecyclerView.LayoutManager layoutManager;
private RecyclerView.Adapter MessageListAdapter;
List<Messages> data;
//init client
Retrofit retrofit = RetrofitClient.getRetrofitClient();
//contact with the interface
APIService apiService = retrofit.create(APIService.class);
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
editText = findViewById(R.id.my_msg);
data = new ArrayList<>();
mMessageRecycler = (RecyclerView) findViewById(R.id.reyclerview_message_list);
MessageListAdapter = new MessageListAdapter(data , this);
// messageListAdapter.notifyDataSetChanged();
mMessageRecycler.setAdapter(MessageListAdapter);
mMessageRecycler.setLayoutManager(new LinearLayoutManager(this));
mMessageRecycler.setHasFixedSize(true);
}
public void clickedbtn(View view) {
fetchMessages();
}
private void fetchMessages() {
Call<List<Messages>> res = apiService.getBotResponse(editText.getText().toString());
res.enqueue(new Callback<List<Messages>>() {
#Override
public void onResponse(Call<List<Messages>> call, Response<List<Messages>> response) {
List<Messages> messages = response.body();
data.addAll(messages);//Changed here
MessageListAdapter.notifyDataSetChanged();//Changed here
mMessageRecycler.smoothScrollToPosition(messages.size()-1);
}
#Override
public void onFailure(Call<List<Messages>> call, Throwable t) {
}
});
}
My model class
public class Messages {
#SerializedName("recipient_id")
#Expose
private String recipientId;
#SerializedName("text")
#Expose
private String text;
public Messages(String text) {
this.text = text;
}
public String getRecipientId() {
return recipientId;
}
public void setRecipientId(String recipientId) {
this.recipientId = recipientId;
}
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
Try adding both the instantiation of the Adapter and the RecyclerView.setAdapter() to the retrofit onResponse():
Like this:
Call<List<Messages>> res = apiService.getBotResponse(editText.getText().toString());
res.enqueue(new Callback<List<Messages>>() {
#Override
public void onResponse(Call<List<Messages>> call, Response<List<Messages>> response) {
List<Messages> messages = response.body();
//Init the Adpater here!!
MessageListAdapter = new MessageListAdapter(data , this);
//SetAdapter here!!
mMessageRecycler.setAdapter(MessageListAdapter);
data.addAll(messages);//Changed here
MessageListAdapter.notifyDataSetChanged();//Changed here
mMessageRecycler.smoothScrollToPosition(messages.size()-1);
}
#Override
public void onFailure(Call<List<Messages>> call, Throwable t) {
}
});
EDIT:
In addition to the above, your clickedbtn() should look like this:
public void clickedbtn(View view) {
Messages msg = new Messages(editText.getText().toString());
msg.setRecipientId("default");
data.add(msg);
MessageListAdapter.notifyDataSetChanged();
fetchMessages();
}

How to set data in recyclerView with Retrofit in Android

I want to show some data into recyclerview and for this I am using the code displayed below.
When I run the application, it's not showing me any data into recyclerview and ListData.size() is 0, but in PostMan
I write below code for set into recyclerView :
InterfaceApi api = ApiClient.getClient().create(InterfaceApi.class);
Call<CommentResponse> call = api.getComments(sendData);
call.enqueue(new Callback<CommentResponse>() {
#Override
public void onResponse(Call<CommentResponse> call, Response<CommentResponse> response) {
if (response.body().getData() != null) {
commentModel.clear();
commentModel.addAll(response.body().getData());
commentsListAdapter.notifyDataSetChanged();
content_newsCommentsRecyclerView.setAdapter(commentsListAdapter);
}
}
#Override
public void onFailure(Call<CommentResponse> call, Throwable t) {
}
});
My Adapter codes:
public class CommentsListAdapter extends RecyclerView.Adapter<CommentsListAdapter.ViewHolder> {
private Context context;
private List<CommentData> model;
public CommentsListAdapter(Context context, List<CommentData> model) {
this.context = context;
this.model = model;
}
#Override
public CommentsListAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.row_comment, parent, false);
return new CommentsListAdapter.ViewHolder(view);
}
#Override
public void onBindViewHolder(final CommentsListAdapter.ViewHolder holder, final int position) {
holder.row_commentNameTxt.setText(Html.fromHtml(model.get(position).getOwner().getName()));
holder.row_commentCommentTxt.setText(Html.fromHtml(model.get(position).getText()));
Glide.with(context)
.load(model.get(position).getOwner().getImageUrl())
.placeholder(R.drawable.default_image)
.diskCacheStrategy(DiskCacheStrategy.ALL)
.listener(new RequestListener<String, GlideDrawable>() {
#Override
public boolean onException(Exception e, String model, Target<GlideDrawable> target, boolean isFirstResource) {
return false;
}
#Override
public boolean onResourceReady(GlideDrawable resource, String model,
Target<GlideDrawable> target, boolean isFromMemoryCache, boolean isFirstResource) {
return false;
}
})
.into(holder.row_commentProfileImage);
holder.row_commentLikeTxt.setText(model.get(position).getLikeCount() + "");
holder.row_commentReplayTxt.setText(model.get(position).getRepliesCount() + "");
holder.row_commentDateTxt.setText(model.get(position).getSubmitDate() + " " + model.get(position).getSubmitTime());
}
#Override
public int getItemCount() {
return model.size();
}
public void addNewItem(List<CommentData> newContent) {
int start = this.model.size();
int end = newContent.size();
model.addAll(newContent);
notifyDataSetChanged();
}
public void clear() {
model.clear();
notifyDataSetChanged();
}
public class ViewHolder extends RecyclerView.ViewHolder {
private CircleImageView row_commentProfileImage;
private TextView row_commentNameTxt, row_commentCommentTxt, row_commentLikeTxt, row_commentReplayTxt, row_commentDateTxt;
public ViewHolder(View itemView) {
super(itemView);
row_commentProfileImage = (CircleImageView) itemView.findViewById(R.id.row_commentProfileImage);
row_commentNameTxt = (TextView) itemView.findViewById(R.id.row_commentNameTxt);
row_commentCommentTxt = (TextView) itemView.findViewById(R.id.row_commentCommentTxt);
row_commentLikeTxt = (TextView) itemView.findViewById(R.id.row_commentLikeTxt);
row_commentReplayTxt = (TextView) itemView.findViewById(R.id.row_commentReplayTxt);
row_commentDateTxt = (TextView) itemView.findViewById(R.id.row_commentDateTxt);
}
}
}
How can I display the data into recyclerView?
Create a method inside your Adapter class
//This will add all the items in the adapter's list
public void addAllItems(List<CommentData> items) {
model.addAll(items);
notifyDataSetChanged();
}
//In Adapter's Constructor do the following changes
public CommentsListAdapter(Context context, List<CommentData> model) {
this.context = context;
this.model = new ArrayList<>;
}
and when you are fetching your response you can call this by
//Inside your onCreate add the below code
mAdapter = new CommentsListAdapter (this);
content_newsCommentsRecyclerView.setLayoutManager(new LinearLayoutManager(this));
content_newsCommentsRecyclerView.setAdapter(mAdapter);
//Call this inside your success of onResponse
commentsListAdapter.addAllItems(commentModel);
This will update the content of recyclerView and notify the changes made, do try this and let me know if you have any issue.
Before the API call initialize the Adapter
mLayoutManager = new LinearLayoutManager(getActivity());
mLayoutManager.setOrientation(LinearLayoutManager.VERTICAL);
mRVCommentList.setLayoutManager(mLayoutManager);
CommentsListAdapter commentsListAdapter= new CommentsListAdapter(this)
mRVCommentList.setAdapter(commentsListAdapter)
Then call the API
public void onResponse(Call<CommentResponse> call, Response<CommentResponse> response) {
if (response.body().getData() != null) {
List<CommentData> list= response.body().getData().getCommentData();
commentsListAdapter.setData(list);
}
}
Small changes in Adapter Class
private List<CommentData> commentData;
public CommentsListAdapter(Context context) {
this.context = context;
this.commentData = new ArrayList<>();
}
public void setData(List<CommentData> commentData) {
this.commentData= commentData;
notifyDataSetChanged();
}

How to pass id instead of position using recyclerView in android

I have pass position in recyclerView click but some kind of problem pass to position to display wrong data so how can i pass people id in recyclerView.
I m new in android programming
recyclerView Item Click
recyclerView = (RecyclerView) findViewById(R.id.recycler_view);
buildCustomAdapter = new BuildCustomAdapter(this, peopleList);
RecyclerView.LayoutManager mLayoutManager = new LinearLayoutManager(getApplicationContext());
recyclerView.setLayoutManager(mLayoutManager);
buildCustomAdapter.notifyDataSetChanged();
recyclerView.setItemAnimator(new DefaultItemAnimator());
recyclerView.setAdapter(buildCustomAdapter);
buildCustomAdapter.setOnItemClickListener(new BuildCustomAdapter.OnItemClickListener() {
#Override
public void onItemClick(View view, int position) {
detailPeople(position);
}
});
private void detailPeople(int position) {
Intent intent = new Intent(this, AddDetail.class);
intent.putExtra("peopleID", position);
startActivity(intent);
}
Model.class
public class People implements Serializable {
private String peopleImage;
private String peopleName;
private String id;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public void setPeopleName(String peopleName) {
this.peopleName = peopleName;
}
public String getPeopleName() {
return peopleName;
}
public void setPeopleImage(String peopleImage) {
this.peopleImage = peopleImage;
}
public String getPeopleImage() {
return peopleImage;
}
}
Adapter code
public class BuildCustomAdapter extends RecyclerView.Adapter<BuildCustomAdapter.MyViewHolder> implements Filterable {
private List<People> peopleList;
private List<People> peopleListCopy;
private ItemFilter mFilter = new ItemFilter();
private OnItemClickListener mOnItemClickListener;
private Context mContext;
public BuildCustomAdapter(Context context, List<People> buildList) {
mContext = context;
this.peopleList = buildList;
this.peopleListCopy = new ArrayList<>();
peopleListCopy.addAll(buildList);
}
#Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View itemView = LayoutInflater.from(parent.getContext())
.inflate(R.layout.build_list_row, parent, false);
return new MyViewHolder(itemView);
}
#Override
public void onBindViewHolder(final MyViewHolder holder, final int position) {
People people = peopleList.get(position);
byte[] decodedString = Base64.decode(people.getPeopleImage(), Base64.DEFAULT);
Bitmap decodedByte = BitmapFactory.decodeByteArray(decodedString, 0, decodedString.length);
holder.ivPeopleImage.setImageBitmap(decodedByte);
holder.tvPersonName.setText(people.getPeopleName());
holder.button.setSelected(people.getStatus() == 1);
holder.button.setOnClickListener(new onSelectListener(position));
}
#Override
public int getItemCount() {
return peopleList.size();
}
#Override
public Filter getFilter() {
if (mFilter == null) {
mFilter = new ItemFilter();
}
return mFilter;
}
public class MyViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
public TextView tvPersonName;
public Button button;
public CircularImageView ivPeopleImage;
public MyViewHolder(View itemView) {
super(itemView);
mContext = itemView.getContext();
ivPeopleImage = (CircularImageView) itemView.findViewById(R.id.ivPerson);
tvPersonName = (TextView) itemView.findViewById(R.id.tvPersonName);
button = (Button) itemView.findViewById(R.id.addbn);
tvPersonName.setOnClickListener(this);
ivPeopleImage.setOnClickListener(this);
}
#Override
public void onClick(View v) {
if (mOnItemClickListener != null)
mOnItemClickListener.onItemClick(v, getPosition());
}
}
public void setOnItemClickListener(OnItemClickListener onItemClickListener) {
mOnItemClickListener = onItemClickListener;
}
public interface OnItemClickListener {
void onItemClick(View view, int position);
}
private class ItemFilter extends Filter {
protected FilterResults performFiltering(CharSequence constraint) {
FilterResults results = new FilterResults();
if (constraint != null && constraint.length() > 0) {
List<People> filterList = new ArrayList<>();
for (int i = 0; i < peopleListCopy.size(); i++) {
if ((peopleListCopy.get(i).getPeopleName().toUpperCase())
.contains(constraint.toString().toUpperCase())) {
People peopleName = peopleListCopy.get(i);
filterList.add(peopleName);
}
}
results.count = filterList.size();
results.values = filterList;
} else {
results.count = peopleListCopy.size();
results.values = peopleListCopy;
}
return results;
}
#Override
protected void publishResults(CharSequence constraint, FilterResults results) {
peopleList = (List<People>) results.values;
notifyDataSetChanged();
}
}
private class onSelectListener implements View.OnClickListener {
int mPosition;
public onSelectListener(int position) {
mPosition = position;
}
#Override
public void onClick(View view) {
People people = peopleList.get(mPosition);
view.setSelected(!view.isSelected());
people.setStatus(view.isSelected() ? 1 : 0);
notifyDataSetChanged();
}
}
}
Next Activity to get intent
Bundle bundle = getIntent().getExtras();
if (bundle != null) {
int peopleID = bundle.getInt("peopleID");
peopleList.clear();
BuildDataa();
People peopleDetailsObj = peopleList.get(peopleID);
}
Please replace
#Override
public void onClick(View v) {
if (mOnItemClickListener != null)
mOnItemClickListener.onItemClick(v, getPosition());
}
to
#Override
public void onClick(View v) {
if (mOnItemClickListener != null)
mOnItemClickListener.onItemClick(v, peopleList.get(getPosition()).getId());
}
in your adapter. And change signature of method onItemClick from
onItemClick(View v, int position)
to
onItemClick(View v, String id)
and use this to get People according to ID
People peopleDetailsObj=null;
for(People ple:peopleList)
{
if(ple.getId().equals(peopleID)){
peopleDetailsObj=ple;
break;
}}
Take the id from position.
String id=peopleList.get(position).getId();
detailPeople(id);
Pass that id in your method and you are done.
Use position to get People object from ArrayList. Change detailPeople() method with below code.
private void detailPeople(int position) {
Intent intent = new Intent(this, AddDetail.class);
intent.putExtra("peopleID", peopleList.get(position).getId());
startActivity(intent);
}
intent.putExtra("id", peopleList.get(position).getId());

Categories