Update RecyclerView When Adding Comment - android

I'm making a CommentFragment. I have a RecyclerView to list comments and a Edittext to write comment. However when I add a comment it's sent to server but RecyclerView isn't updated. I use notifydatasetchanged to update. Code:
private void getComments(){
Call<List<CommentsModel>> call=restApiClass.getComments(post_id);
call.enqueue(new Callback<List<CommentsModel>>() {
#Override
public void onResponse(Call<List<CommentsModel>> call, Response<List<CommentsModel>> response) {
if(response.isSuccessful()){
list=response.body();
if(commentsAdapter==null) {
commentsAdapter = new CommentsAdapter(list, getContext());
}
else{
commentsAdapter.notifyDataSetChanged();
}
recyclerView.setAdapter(commentsAdapter);
}
}
#Override
public void onFailure(Call<List<CommentsModel>> call, Throwable t) {
}
});
}
I call this method when I click to sendCommentTextView:
sendCommentTextView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
//............send comment codes.........
getComments();
}
});

check this correct answer: notifyDataSetChanged example.
I think you should follow there the answer to make the adapter work as expected with notifyDataSetChanged(). Shortly: you have to update the list inside the adapter and then notify to it that the list has been updated, so it will render again on ui (recyclerview).
PS: after notifyDataSetChanged function, you don't have to set the adapter again on the recyclerview if already assigned.

Here you updated the list when Retrofit brings new data back, but actually you didn't feed your adapter with this data; you just called commentsAdapter.notifyDataSetChanged();, but you need first to add a method like updateList(List<CommentsModel> list) in your adapter, and call it with updateList(list); before using commentsAdapter.notifyDataSetChanged();
So, add updateList(List<CommentsModel> list) into your adapter to update its list internally like Below:
class CommentsAdapter extends RecyclerView.Adapter<CommentsAdapter.ViewHolder> {
...
List<CommentsModel> mList;
updateList(List<CommentsModel> list) {
this.mList.clear();
this.mList.addAll(list);
}
}
And then the change in your code could be something like:
call.enqueue(new Callback<List<CommentsModel>>() {
#Override
public void onResponse(Call<List<CommentsModel>> call, Response<List<CommentsModel>> response) {
if(response.isSuccessful()){
list=response.body();
if(commentsAdapter==null) {
commentsAdapter = new CommentsAdapter(list, getContext());
}
else{
commentsAdapter.updateList(list);
commentsAdapter.notifyDataSetChanged();
}
recyclerView.setAdapter(commentsAdapter);
}
}
#Override
public void onFailure(Call<List<CommentsModel>> call, Throwable t) {
}
});
Update
Yes it's working but recylerview return to first position and list
reload. But I want to load only last comment. Other comments must stay
same. So how can I do that ?
To just update the last comment in your list, then add a new method into your adapter that takes only that comment, and add it to the list like:
class CommentsAdapter extends RecyclerView.Adapter<CommentsAdapter.ViewHolder> {
...
List<CommentsModel> mList;
addComment(CommentsModel comment) {
this.mList.add(comment);
notifyItemInserted(mList.size()-1);
}
}
Then when the data comes in back by Retrofit:
call.enqueue(new Callback<List<CommentsModel>>() {
#Override
public void onResponse(Call<List<CommentsModel>> call, Response<List<CommentsModel>> response) {
if(response.isSuccessful()){
list = response.body();
if(commentsAdapter == null) {
commentsAdapter = new CommentsAdapter(list, getContext());
}
else{
// updating the adapter list with the last comment
commentsAdapter.addComment((CommentsModel) list.get(list.size()-1));
}
recyclerView.setAdapter(commentsAdapter);
}
}
#Override
public void onFailure(Call<List<CommentsModel>> call, Throwable t) {
}
});

Related

How to add list items to recyclerView dynamically?

I fetch data with Retrofit using. I have 10 results per page. When I scroll to the last result, there is no further possibility to view the туче results. So, I need to update the adapter. but nothing comes of it. Here is part of my code:
retrofit:
private final RestClient restClient;
private List<Data> newData;
private DataAdapter dataAdapter;
public void fetchData() {
Call<Data> callItems = restClient.searchData();
callItems.enqueue(new Callback<Data>() {
#Override
public void onResponse(#NonNull Call<Data> call, #NonNull Response<Data> response) {
newData = response.body().getPersons();
personAdapter.addPersons(newData );
}
#Override
public void onFailure(#NonNull Call<Data> call, #NonNull Throwable t) {
}
});
}
here is my method from adpter class where I add new items:
private List<Person> persons = new ArrayList<>();
..................
public void addIPersons(List<Person> newPerson) {
this.iersons= newIPeroon
persons.addAll(newIPerson;
notifyDataSetChanged();
}
You should use mutable list and should not overwrite it.
But the better way is to use listadapter
Just update your data source and call notifyDatasetChanged() on your RecyclerViewAdapter.
After adding to your list like this:
persons.add(newIPerson);
call:
dataAdapter.notifyDatasetChanged();

How to prevent Live date from duplication in on back pressed from another fragment and on recall

hello i have two problems regarding live data with view model and navigation component first one is when i go from fragment A with live data to fragment B and then from B to A the data in my list gets duplicated,
the other problem is one i re call viewModel.loadList() in my fragment after making and event to filter the data also gets duplicated
here is my view model
public class HomeViewModel extends ViewModel {
MutableLiveData<ArrayList<HomeResponseModel>> homeLiveData = new MutableLiveData<>();
ArrayList<HomeResponseModel> homeList = new ArrayList<>();
public MutableLiveData<ArrayList<HomeResponseModel>> geHomeList(HomeRequestModel homeRequestModel, Context context, ApiInterface apiInterface, LottieAnimationView lottieAnimationView) {
if (homeLiveData == null) {
homeLiveData = new MutableLiveData<ArrayList<HomeResponseModel>>();
loadHomeList(homeRequestModel);
}
return homeLiveData;
}
public void loadHomeList(HomeRequestModel homeRequestModel) {
Call<List<HomeResponseModel>> call = apiInterface.getHomeList(homeRequestModel, );
call.enqueue(new Callback<List<HomeResponseModel>>() {
#Override
public void onResponse(Call<List<HomeResponseModel>> call, Response<List<HomeResponseModel>> response) {
if (response.isSuccessful()) {
homeList.addAll(response.body());
homeLiveData.setValue(homeList);
}
}
#Override
public void onFailure(Call<List<HomeResponseModel>> call, Throwable t) {
}
});
}
my observer in onCreateView
viewModel.geHomeList(homeRequestModel).observe(getViewLifecycleOwner(), new Observer<ArrayList<HomeResponseModel>>() {
#Override
public void onChanged(ArrayList<HomeResponseModel> homeResponse) {
homeResponseModels.addAll(homeResponse);
homeAdapter.notifyDataSetChanged();
}
});
}
how i recall load method after a filter event
viewModel.loadHomeList(homeRequestModel);
Clear the list before adding the new models:
viewModel.geHomeList(homeRequestModel).observe(getViewLifecycleOwner(), new Observer<ArrayList<HomeResponseModel>>() {
#Override
public void onChanged(ArrayList<HomeResponseModel> homeResponse) {
homeResponseModels.clear();
homeResponseModels.addAll(homeResponse);
homeAdapter.notifyDataSetChanged();
}
});
}
Or, even better:
In case your adapter holds a List or HomeResponseModel you could create a method to update it:
public update(List<HomeResponseModel> homeResponse) {
this.homeResponseModels = homeResponse;
notifydatasetchanged();
}
and then change the observe method to call it:
viewModel.geHomeList(homeRequestModel).observe(getViewLifecycleOwner(), new Observer<ArrayList<HomeResponseModel>>() {
#Override
public void onChanged(ArrayList<HomeResponseModel> homeResponse) {
homeAdapter.update(homeResponse);
}
});
}
Besides that, in your ViewModel in the loadHomeList method in the onResponse callback you could assign the data received to the liveData:
if (response.isSuccessful()) {
homeLiveData.setValue(response.body());
}
no need to save it in the homeList var, you can get rid of that var. Otherwise, perform homeList.clear(); before adding to it all the received data to avoid duplicates.

Android Studio Retrofit OnResponse Problem

Im working on mvvm design but OnResponse is not saving the data in List. İts returning the emtpy List array. I cant reach the valued List. I realy dont know where is the incorrect piece of code. Here is the code.Help please.
public class RetroClass {
private static final String BASE_URL="--";
private List<ProductModel> productList=new ArrayList<>();
public static Retrofit getRetroInstance(){
return new Retrofit.Builder().baseUrl(BASE_URL).addConverterFactory(GsonConverterFactory.create()).build();
}
public static APIService getAPIService(){
return getRetroInstance().create(APIService.class);
}
public List<ProductModel> getProducts(){
APIService apiService=getAPIService();
apiService.getProducts().enqueue(new Callback<List<ProductModel>>() {
#Override
public void onResponse(Call<List<ProductModel>> call, Response<List<ProductModel>> response) {
productList.addAll(response.body());
for (int k=0;k<productList.size();k++) {
Log.d("onResponse: ", productList.get(k).getOrderName());//im getting the value here
}
}
#Override
public void onFailure(Call<List<ProductModel>> call, Throwable t) {
Log.d("onFailure: ",t.getMessage());
}
});
return productList;//but this is empty
}
}
Here is my view model.
public class ProductsVievModal extends ViewModel {
List<ProductModel> productList;
LiveData<List<ProductModel>> liveproductList;
RetroClass apiClass=new RetroClass();
public List<ProductModel> getProducts(){
productList=apiClass.getProducts();
for (int k=0;k<productList.size();k++) {
Log.d("onResponse: ", productList.get(k).getOrderName());
}
return productList;
}
}
.enqueue is asynchronously sending the request and notify callback of its response. It is asynchronous. onResponse() must complete before you return the product list.
I suspect the return productList; is executed before the onResponse() returned its value. Can you check by putting a log before return productList; to see which line is executed first?
Your data IS saved, but the moment your code needs it the .enqueue is probably not done retrieving the data yet. so it shows as empty
Easiest way to fix this is by having your follow up code in the onResponse so your basicly stuck waiting untill it either retrieved the information or failed
so something like this
public void onResponse(Call<List<ProductModel>> call, Response<List<ProductModel>> response) {
productList.addAll(response.body());
nextFunction();
}
}
#Override
public void onFailure(Call<List<ProductModel>> call, Throwable t) {
Log.d("onFailure: ",t.getMessage());
failFunction();
}
```

Retrofit handle multiple calls with response value stored an reused

I'm here with a new question about Android and Retrofit. I was wondering what is the correct way to handle multiple async calls on a Android Activity and each of this one, onResponse returns a value used by the next call, because if I understood fine, the calls runs on background which means that if the call didn't finish you returned value will be null until you get a successful response.
I was thinking to achieve that with something like this(only the basis):
private List<SomeModel> mylist;
final Call<List<SomeModel>> call1 = client.getSomeValues1();
final Call<List<SomeModel2>> call2 = client.getSomeValues2();
call1.enqueue(new Callback<SomeModel>() {
#Override
public void onResponse(SomeModel> call, Response<SomeModel> response) {
if (response.isSuccessful()) {
// Set mylist to response.body()
mylist = response.body();
}
}
#Override
public void onFailure(Call<SomeModel> call, Throwable t) {
mylist = null;
}
});
call2.enqueue(new Callback<SomeModel2>() {
#Override
public void onResponse(SomeModel2> call, Response<SomeModel2> response) {
if (response.isSuccessful()) {
// Do something with my list and also with call2 response
if(mylist != null) {
for (SomeModel singleObject: mylist) {
// Do something with each object
}
}
}
}
#Override
public void onFailure(Call<SomeModel2> call, Throwable t) {
// Do something with fail call
}
});
With something like the example before because the calls are running on background and maybe the call2 finish first then mylist value will be null because call1 hasn't finished yet.
Also I was thinking to put call2 inside call1 onResponse but I don't feel that right. I have to say that I'm still learning, I'm pretty rookie.
So, What is the correct why to handle this and how? Thanks. I hope my question is understandable.
Thanks for your suggestion #insa_c
I achieved that with RXJava2, here is how I did it explained general way:
First you need to define your api services as Observables
#GET("url-1/")
Observable<List<Model1>> service1();
#GET("url-2/")
Observable<List<Model2>> service2();
Now in your activity make the calls this way:
final Observable<List<Model1>> call1 = APIClient.getClient().create(APIService.class).service1();
final Observable<List<Model2>> call2 = APIClient.getClient().create(APIService.class).service2();
Now lets make an unique observable with zip (I used a List because I'm adding two different kind of objects to the list that I'll get when both calls finish):
<Observable<List<Object>> test = Observable.zip(call1, call2, new BiFunction<List<Model1>, List<Model2>, List<Object>>() {
#Override
public List<Object> apply(List<Model1> objects1, List<Model2> objects2) throws Exception {
List<Object> list = new ArrayList<>();
list.addAll(objects1);
list.addAll(objects2);
return list;
}
}).subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread());
Now the only thing left to do is to subscribe and decide what you want to do with the content of both responses:
test.subscribe(new Observer<List<?>>() {
#Override
public void onSubscribe(Disposable d) {
Log.d("TAG", "onSubscribe");
}
#Override
public void onNext(List<?> objects) {
// You can split the list by object in here with an instanceof to determine if it's Model1 or Model2
}
#Override
public void onError(Throwable e) {
e.printStackTrace();
}
#Override
public void onComplete() {
// Do something here, both calls finished, if you stored something in onNext method you can use it here.
}
});
I hope this info will be helpful for someone.

how to delete the recycler view item using retrofit or volley?

I want to delete the recyclerview item using retrofit or volley network library. Please post the code or example?
Firstable you do not have to remove the items on the RecyclerView. The main idea is provide the List of item, set it in the Adapter and load again the RecyclerView on the UI. If you have a RestCall using Retrofit all you have to do is:
Create an Update method and call it every time you need to show the changes on the UI. This method will do the RetrofitCall and it will give the List of items you need to pass to the adapter using a custom listener with the return onSuccess.
private RecyclerAdapter updateRecycler() {
getItemsFromApi(new RestApiListener() {
#Override
public void onSuccess(List<Items> items) {
recyclerAdapter = new RecyclerAdapter(this, items);
recyclerView.setAdapter(recyclerAdapter);
}
#Override
public void onError(String message) {
showError(message);
}
});
}
Here is how to do the CallBack in Retrofit with the listener
public Callback<Items> getItemsFromApi(final RestApiListener listener) {
return new Callback<Items>() {
#Override
public void onResponse(Call<Items> call, Response<Items> response) {
switch (response.code()) {
case 200:
listener.onSuccess(response.body().getItems());
break;
default:
listener.onError("Error " + response.message());
break;
}
}
#Override
public void onFailure(Call<Items> call, Throwable t) {
listener.onError(t.getMessage().toString());
}
};
}
public interface RestApiListener {
void onSuccess(List<Items> items);
void onError(String s);
}
Also here is an example code.

Categories

Resources