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.
Related
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();
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.
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) {
}
});
I am fetching data using api for that I am using Retrofit2 and RxJava2 data is fetching successfully but I don't want to show whole items.I just want to show 5 items in a list.
Below is my code:
Retrofit retrofit = RetrofitClient.getInstance();
ApiService myApi = retrofit.create(ApiService.class);
myApi.getHindiNews(data).subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<List<HomeHindiModel>>() {
#Override
public void onSubscribe(Disposable d) {
}
#Override
public void onNext(List<HomeHindiModel> homeHindiModels) {
if(homeHindiModels.size() > 0){
homeHindiList.addAll(homeHindiModels);
homeHindiAdapter = new HomeHindiAdapter(homeHindiList,getActivity());
hindiRecycler.setAdapter(homeHindiAdapter);
}
}
#Override
public void onError(Throwable e) {
Toast.makeText(getActivity(),e.getMessage(),Toast.LENGTH_SHORT).show();
}
#Override
public void onComplete() {
}
});
Someone please let me know how can I get desired output.Any help would be appreciated.
THANKS
When you get data from remote resources then you can push only 5 items into your data source which you are going to send an adapter.
Retrofit retrofit = RetrofitClient.getInstance();
ApiService myApi = retrofit.create(ApiService.class);
myApi.getHindiNews(data).subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<List<HomeHindiModel>>() {
#Override
public void onSubscribe(Disposable d) {
}
#Override
public void onNext(List<HomeHindiModel> homeHindiModels) {
if(homeHindiModels.size() > 0){
homeHindiList.addAll(homeHindiModels.subList(0, 5));
// homeHindiList.addAll(homeHindiModels);
homeHindiAdapter = new HomeHindiAdapter(homeHindiList,getActivity());
hindiRecycler.setAdapter(homeHindiAdapter);
}
}
#Override
public void onError(Throwable e) {
Toast.makeText(getActivity(),e.getMessage(),Toast.LENGTH_SHORT).show();
}
#Override
public void onComplete() {
}
})
into RecyclerView Adapter class
#Override
public int getItemCount() {
if(homeHindiList != null) {
if(homeHindiList.size() > 5) {
return 5;
} else
return homeHindiList.size();
} else
return 0;
}
Instead of adding all the items from homeHindiModels list, you can use the sublist method of arraylist to add only the required items. Here first param indicates the starting index from where the sublist would create and the second param indicates the number of items.
homeHindiList.addAll(homeHindiModels.subList(0, 5));
So I'll try to keep this question as to-the-point as possible, but it will involve code snippets that traverse an entire codepath.
For context, I am fairly new and completely self-taught for Android dev, so please notify me of any clear misunderstandings/poor organization throughout. The main focus of the question is bug I am experiencing now, which is that, after a network request, the variable that was supposed to be set as a result of that network request is null, because the code moved forward before the network request completed.
Here is my activity method. It is supposed to populate the mFriends variable with the result of mUserPresenter.getUserList(), which is (unfortunately) null:
/**
* Grabs a list of friends, populates list with UserAdapter
*/
#Override
public void onResume(){
super.onResume();
mUserPresenter = new UserPresenter();
mFriends = mUserPresenter.getUserList();
if (mGridView.getAdapter() == null) {
UserAdapter adapter = new UserAdapter(getActivity(), mFriends);
mGridView.setAdapter(adapter);
}
else{
((UserAdapter)mGridView.getAdapter()).refill(mFriends);
}
}
Here is how I am structuring my UserPresenter method getUserList:
public List<User> getUserList()
{
ApiService.get_friends(this);
return mUserList;
}
The real magic happens in the ApiService class:
public static void get_friends(final UserPresenter userPresenter){
ApiEndpointInterface apiService = prepareService();
apiService.get_friends().
observeOn(AndroidSchedulers.mainThread())
.subscribe(
new Action1<List<User>>()
{
#Override
public void call(List<User> users) {
userPresenter.setList(users);
}
}
);
}
My thinking was, that by calling userPresenter.setList(users) in ApiService, that would set mUserList to the response from the api request. However, instead, mUserList == null at the time that getUserList responds.
Any ideas of how I can structure this?
I have also started to learn something similar. Here, I would rather use callbacks.
In your presenter,
public void setList(List<User> users) {
yourView.setUserList(users);
}
And your activity which implements a view (MVP)
#Override
public void setUserList(List<User> users) {
((UserAdapter)mGridView.getAdapter()).refill(mFriends);
}
Also, check that retrofit is not returning null list.
I have a made a small app when I was learning about all this. It fetches user data from GitHub and shows in a list. I was also working with ORMLite and Picasso so some db stuff is there. Dagger Dependency is also used (but you can ignore that). Here's the link.
Here's how my Presenter behaves:
private DataRetrieverImpl dataRetriever;
#Override
public void getUserList(String name) {
dataRetriever.getUserList(name);
}
#Override
public void onEvent(DataRetrieverEvent event) {
UserList userList = (UserList)event.getData();
mainView.setItems(userList);
}
DataRetrieverImpl works as a module (sort of).
private DataRetriever dataRetriever;
restAdapter = new RestAdapter.Builder().setEndpoint(SERVER_END_POINT).build();
dataRetriever = restAdapter.create(DataRetriever.class);
public void getUserList(final String name) {
Log.i(TAG, "getting user list for: " + name);
Observable<UserList> observable = dataRetriever.getUserList(name);
Log.i(TAG, "subscribe to get userlist");
observable.subscribe(new Action1<UserList>() {
#Override
public void call(UserList userList) {
eventBus.post(new DataRetrieverEvent("UserList", userList));
// save to database
for (User user : userList.getItems()) {
Log.i(TAG, user.getLogin());
try {
dbHelper.create(user);
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}, new Action1<Throwable>() {
#Override
public void call(Throwable throwable) {
throwable.printStackTrace();
}
});
}
And DataRetriever is interface for retrofit. I'm sorry for the naming confusion.
public interface DataRetriever {
#GET("/search/users")
public Observable<UserList> getUserList(#Query("q") String name);
}
Any my Activity,
#Override
public void setItems(final UserList userList) {
runOnUiThread(new Runnable() {
#Override
public void run() {
UserAdapter userAdapter = (UserAdapter)recyclerView.getAdapter();
userAdapter.setUserList(userList);
userAdapter.notifyItemRangeInserted(0, userAdapter.getItemCount());
}
});
}