remove duplicates from List? - android

I am getting duplicate items from an API in my adapter but I want to remove those duplicates from my side means from my adapter and print it once any idea how? Thanks in advance.
got: duplicate rows in my cardview but through an API.
want: just want to print it once and remove those duplicates.
MyAdapter:
#Override
public void onBindViewHolder(#NonNull catView holder, int position) {
holder.id.setText(oilResponses.get(position).getId());
}
#Override
public int getItemCount() {
if (oilResponses.size() != 0) {
return oilResponses.size();
}
return 0;
}
MainActivity:
private void oilList() {
Api.getClient().do_oil(CAR_ID)
.observeOn(AndroidSchedulers.mainThread())
.subscribeOn(Schedulers.io())
.subscribe(new Observer<List<OilResponse>>() {
#Override
public void onSubscribe(Disposable d) {
}
#Override
public void onNext(#NotNull List<OilResponse> responses) {
oilAdapter = new OilAdapter(responses);
oilRecycler.setAdapter(oilAdapter);
}
#Override
public void onError(#NotNull Throwable e) {
}
#Override
public void onComplete() {
}
});
}

you can try to save them in a Set instead of a List, it is basically the same thing but in a set each object can be saved one time, so you can't have duplicates even if you'd like to.

Related

How to get limited no. of data in recycler view

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));

RecyclerView with BottomNavigationView won't show changes in showing items

I've got problem with my "RecyclerView" and "BottomNavigationView" when I've tried to refactor my app and use Dependency Injection. The problem is when i click on items in Navigation View, "RecyclerView" won't change items in list. I have a code status for my HTTP request and base on that request I'm getting items. I've checked API and worked fine, also in "LOGCAT" got 200 Code. here's the code for the parts. when activity open app will show data with 0 status code, then when we change status code with bottom, nothing gonna change and still I'm getting same list.
This is not a duplicate since I'm using dependency injection and MVP, and I've also added dependency injection tag because this is happening when i use dependency injection and i'm beginner.
Activity: I'm calling methods in onCreate for data and View Here's the data.
private void setupData() {
bottomNavigation.setOnNavigationItemSelectedListener(new BottomNavigationView.OnNavigationItemSelectedListener() {
#Override
public boolean onNavigationItemSelected(#NonNull MenuItem item) {
if (item.getItemId() == R.id.new_request) {
mPresenter.setupLoadOrders("0");
} else if (item.getItemId() == R.id.canceled_request) {
mPresenter.setupLoadOrders("-1");
} else if (item.getItemId() == R.id.submited_request) {
mPresenter.setupLoadOrders("1");
} else if (item.getItemId() == R.id.added_request) {
mPresenter.setupLoadOrders("2");
}
return true;
}
});
mPresenter.setupLoadOrders("0");
}
private void setupView() {
recyclerRequests.setLayoutManager(new LinearLayoutManager(this));
recyclerRequests.setHasFixedSize(true);
}
#Override
public void displayOrders(List<Requests> requests) {
requestAdapter.setData(requests);
recyclerRequests.setAdapter(requestAdapter);
}
And Presenter :
#Override
public void setupLoadOrders(String statusReq) {
compositeDisposable.add(atlasApiReference.getRequest(Common.currentUser.getPhone(), statusReq)
.observeOn(AndroidSchedulers.mainThread())
.subscribeOn(Schedulers.io())
.subscribe(new Consumer<List<Requests>>() {
#Override
public void accept(List<Requests> requests) throws Exception {
mView.displayOrders(requests);
}
}, new Consumer<Throwable>() {
#Override
public void accept(Throwable throwable) throws Exception {
Log.e("Log",throwable.getMessage());
}
}));
}
public void unSubscribe()
{
AtlasRxJavaUtil.unsubscribeClear(compositeDisposable);
}
And Adapter :
private List<Requests> requestsList;
#Inject
public RequestAdapter() {
requestsList = new ArrayList<>();
}
#NonNull
#Override
public RequestAdapterViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
return new RequestAdapterViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.request_detail_layout, parent, false));
}
#Override
public void onBindViewHolder(#NonNull RequestAdapterViewHolder holder, final int position) {
holder.request_number.setText(new StringBuilder(" ").append(requestsList.get(position).getId()));
holder.request_name.setText(new StringBuilder(" ").append(requestsList.get(position).getNameReq()));
}
public class RequestAdapterViewHolder extends RecyclerView.ViewHolder {
public PsTextView request_number,request_name;
CardView request_detail_layout;
public RequestAdapterViewHolder(final View itemView) {
super(itemView);
request_number = (PsTextView)itemView.findViewById(R.id.request_number);
request_name = (PsTextView)itemView.findViewById(R.id.request_name);
request_detail_layout = (CardView)itemView.findViewById(R.id.request_detail_layout);
request_detail_layout.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Common.currentRequest = requestsList.get(getAdapterPosition());
itemView.getContext().startActivity(new Intent(itemView.getContext(), ShowDetail.class));
}
});
}
}
#Override
public int getItemCount() {
return requestsList.size();
}
public void setData(List<Requests> requestsList){
this.requestsList.addAll(requestsList);
notifyDataSetChanged();
}
Try removing the following line:
recyclerRequests.setHasFixedSize(true);
More info on this post.

RecyclerView onBindViewHolder is called too many times for one cell

I am using RecyclerView with GridLayoutManager. For each item in the grid, I need to call a REST api to retrieve data. Then, after get data asynchronously from remote,I use UIL to load/display image.
Everything seems to be fine. But i find onBindViewHolder is called too too too many times for specific items.
logcat log
Talk is cheap, let me show you the code:
#Override
public void onBindViewHolder(RecyclerView.ViewHolder viewHolder, int position) {
EditCourseImageAttachmentHolder holder = (EditCourseImageAttachmentHolder) viewHolder;
holder.itemView.setLayoutParams(getLayoutParams(position));
holder.attachmentView.initData(dataSource.get(headerView == null ? position : position - 1), urlMap);
}
public static class EditCourseImageAttachmentHolder extends RecyclerView.ViewHolder {
public final AttachmentView attachmentView;
public EditCourseImageAttachmentHolder(AttachmentView itemView) {
super(itemView);
this.attachmentView = itemView;
}
}
-----------AttachmentView.Java-----------------
#Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
subscription = tryLoadLocalImage(data)
.subscribeOn(Schedulers.io())
.flatMap(new Func1<String, Observable<String>>() {
#Override
public Observable<String> call(String localImageUrl) {
if (StringUtils.isNotBlank(localImageUrl)) {
return Observable.just(localImageUrl);
}
if (urlMap.containsKey(data.getUid())) {
return Observable.just(urlMap.get(data.getUid()));
} else {
//Remote API call
String qiNiuUrl = getQiNiuUrl(data);
urlMap.put(data.getUid(), qiNiuUrl);
return Observable.just(qiNiuUrl);
}
}
})
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Action1<String>() {
#Override
public void call(String localImageUrl) {
showImage(localImageUrl);
}
}, new Action1<Throwable>() {
#Override
public void call(Throwable throwable) {
}
});
}
#Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
if (subscription != null && subscription.isUnsubscribed()) {
subscription.unsubscribe();
}
}
Root cause is I changed the LayoutParam of the ItemView....
It works well after i remove those code.
But, it's quite strange that only the item at specific position would re-bind.
if (subscription != null && !subscription.isUnsubscribed()) {
subscription.unsubscribe();
}
your code should be this...

Is it possible to get 2 values in onNext() of subscriber in rxjava android?

I've an observable like this
Observable.zip(observable, extObs, new Func2<List<UserProfile>, ArrayList<Extension>, UserProfile>() {
#Override
public UserProfile call(List<UserProfile> userProfiles, ArrayList<Extension> extensions) {
return userProfiles.get(0);
}
}).subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).unsubscribeOn(Schedulers.io()).subscribe(new Subscriber<UserProfile>() {
#Override
public void onCompleted() {
}
#Override
public void onError(Throwable e) {
e.printStackTrace();
}
#Override
public void onNext(UserProfile userProfile) {
profileListener.onProfileSet(userProfile);
}
});
}
I need to pass the ArrayList in the methodprofileListener.onProfileSet(userProfile); as profileListener.onProfileSet(userProfile,extensions);
Is it possible to do so in zip or is there any other methods of rxjava to solve such type of problems?
You have to do exactly what cricket_007 suggested in the comment.
For example like this:
Create a class that would represent combined results of your observables:
class CombinedResults {
public UserProfile userProfile;
public List<Extension> extensions;
public CombinedResults(UserProfile userProfile, List<Extension> extensions) {
this.userProfile = userProfile;
this.extensions = extensions;
}
}
(Alternatively you could use Pair class)
Use an object of CombinedResults (or Pair) in your Observable.zip Func2.
Observable.zip(observable, extObs,
new Func2<List<UserProfile>, ArrayList<Extension>, CombinedResults>() {
#Override
public CombinedResults call(List<UserProfile> userProfiles, ArrayList<Extension> extensions) {
return new CombinedResults(userProfiles.get(0), extensions);
}
})
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.unsubscribeOn(Schedulers.io())
.subscribe(new Subscriber<CombinedResults>() {
#Override
public void onCompleted() {
}
#Override
public void onError(Throwable e) {
e.printStackTrace();
}
#Override
public void onNext(CombinedResults combined) {
profileListener.onProfileSet(combined.userProfile, combined.extensions);
}
});

OnCompleted calls not tidy

i'm new in Rx programming (and I'm having a lot of fun so far ^^).
I'm trying to transform a AsyncTask call into an Rx function.
My function :
Get all the installed apps
normalize the labels
sort everything alphabetically
arrange them by group of letter (it was a Multimap(letter, list of apps)) and pass the result to an adapter to display everything.
Here is how I'm doing so far with Rx :
Observable.from(getInstalledApps(getActivity(), false))
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.map(new Func1<ResolvedActivityInfoWrapper, ResolvedActivityInfoWrapper>() {
#Override
public ResolvedActivityInfoWrapper call(ResolvedActivityInfoWrapper act) {
// Normalize labels
act.setLabel(Normalizer.normalize(act.getLabel(getPackageManager()).replace(String.valueOf((char) 160), "").trim(), Normalizer.Form.NFD).replaceAll("\\p{M}", ""));
return act;
}
})
.toList()
.subscribe(new Observer<List<ResolvedActivityInfoWrapper>>() {
List<ResolvedActivityInfoWrapper> list;
#Override
public void onCompleted() {
Observable.from(list).groupBy(new Func1<ResolvedActivityInfoWrapper, String>() {
#Override
public String call(ResolvedActivityInfoWrapper input) {
//Get groups by letter
String label = input.getLabel(getPackageManager());
if (!TextUtils.isEmpty(label)) {
String firstChar = label.substring(0, 1);
if (pattern.matcher(firstChar).matches()) {
return firstChar.toUpperCase();
}
}
return "#";
}
}).subscribe(this); // implementation below
}
#Override
public void onError(Throwable e) {
}
#Override
public void onNext(List<ResolvedActivityInfoWrapper> list) {
Collections.sort(list, new Comparator<ActivityInfoWrapper>() {
#Override
// Sort all the apps in the list, not sure it's a good way to do it
public int compare(ActivityInfoWrapper info1, ActivityInfoWrapper info2) {
return info1.getLabel(getPackageManager()).compareToIgnoreCase(info2.getLabel(getPackageManager()));
}
});
this.list = list;
}
});
Once I groupedBy letters, on complete I subscribe with this :
#Override
public void onCompleted() {
//display the apps
}
#Override
public void onError(Throwable e) {
}
#Override
public void onNext(GroupedObservable<String, ResolvedActivityInfoWrapper> input) {
//For each list of apps by letter i subscribe with an observer that will handle those apps (observer code below)
input.subscribe(new TestObserver(input.getKey()));
}
Observer :
private class TestObserver implements Observer<ResolvedActivityInfoWrapper> {
List<ResolvedActivityInfoWrapper> list;
String letter;
public TestObserver(String letter) {
list = new ArrayList<>();
this.letter = letter;
}
#Override
public void onCompleted() {
adapter.addData(letter, list);
}
#Override
public void onError(Throwable e) {
}
#Override
public void onNext(ResolvedActivityInfoWrapper input) {
list.add(input);
}
}
Everything works correctly excpets for one problem : the observer's onCompleted are called not in the right order. So I got all my apps, sorted by letter, but the groups are nots displayed in the right order (C first, then Y, then M etc ...).
I guess there are plenty of errors in the code, can you help me with this probleme and maybe understanding how all this works please ?
Thanks
UPDATE :
Following the advices in the commentary section (thanks people), here is what I'm trying after normalizing the labels :
Observable.from(list).groupBy(new Func1<ResolvedActivityInfoWrapper, String>() {
#Override
public String call(ResolvedActivityInfoWrapper input) {
String label = input.getLabel(getPackageManager());
if (!TextUtils.isEmpty(label)) {
String firstChar = label.substring(0, 1);
if (pattern.matcher(firstChar).matches()) {
return firstChar.toUpperCase();
}
}
return "#";
}
})
.toSortedList(new Func2<GroupedObservable<String, ResolvedActivityInfoWrapper>, GroupedObservable<String, ResolvedActivityInfoWrapper>, Integer>() {
#Override
public Integer call(GroupedObservable<String, ResolvedActivityInfoWrapper> obs1, GroupedObservable<String, ResolvedActivityInfoWrapper> obs2) {
return obs1.getKey().compareToIgnoreCase(obs2.getKey());
}
})
.subscribe(new Observer<List<GroupedObservable<String, ResolvedActivityInfoWrapper>>>() {
#Override
public void onCompleted() {
}
#Override
public void onError(Throwable e) {
}
#Override
public void onNext(List<GroupedObservable<String, ResolvedActivityInfoWrapper>> input) {
String test = input.get(0).getKey();
}
});
But it never goes into the Compare function.

Categories

Resources