Search filter using rxjava1 android(java) - java

I have a list and i got search filter. I have done using EditText listeners and using for loop. But i want the filter should handle by rxjava
#Override
public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
Log.i(TAG, "Search text: " + charSequence);
List<AllAttendance> list = new ArrayList<>();
//filter from all List
if (rbtnAll.isChecked())
list = filter(mAttendanceList, charSequence);
else if (rbtnPending.isChecked())
list = filter(mPendingAttendanceList, charSequence);
setAdapterData(list);
rvAttendance.scrollToPosition(0);
}
private List<AllAttendance> filter(List<AllAttendance> mAttendanceList, CharSequence charSequence) {
String text = String.valueOf(charSequence);
text = text.toLowerCase();
List<AllAttendance> filteredList = new ArrayList<>();
for (AllAttendance attendance : mAttendanceList){
if (attendance.getMandalName().toLowerCase().contains(text) || attendance.getSabhaName().toLowerCase().contains(text) || attendance.getSabhaDate().toLowerCase().contains(text))
filteredList.add(attendance);
}
return filteredList;
}

Here is a piece of code i have used for searching with AndroidRx.
NOTE : In this example i am making a network call on every character change after waiting for 1000 ms.
PublishSubject<String> subject = PublishSubject.create();
subject.debounce(1000, TimeUnit.MILLISECONDS)
.filter(new Predicate<String>() {
#Override
public boolean test(#NonNull String s) throws Exception {
return s.length() > 0;
}
})
.switchMap(new Function<String, Observable<SearchViewResponseModel>>() {
#Override
public Observable<SearchViewResponseModel> apply(#NonNull String o) throws Exception {
return api.getSearchResult(PrefsManager.getToken(SearchActivity.this), o, 0, 10);
}
})
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribeWith(new DisposableObserver<SearchViewResponseModel>() {
#Override
public void onNext(#NonNull SearchViewResponseModel s) {
adapter.clear();
for (SearchViewResponseModel.Data model : s.getData())
adapter.add(new SearchViewModel(model.get_id(), model.getThumbnail(), model.getTitle()));
}
#Override
public void onError(#NonNull Throwable e) {
e.printStackTrace();
}
#Override
public void onComplete() {
Log.i("Completed", "");
}
});
searchView.setOnQueryTextListener(new MaterialSearchView.OnQueryTextListener() {
#Override
public boolean onQueryTextSubmit(String query) {
return false;
}
#Override
public boolean onQueryTextChange(final String newText) {
subject.onNext(newText);
return true;
}
});
}

Related

How to update total no of child from firebase child node everytime onDataChange from AddSingleValueEventListner?

Below image shows my Firebase database structure:
All data retrieved successfully. Here is my model class.
public class Post
{
public String lastname;
public String postid;
public long timestamp;
public HashMap<String,Boolean> count;
public Post()
{
}
public Post(String lastname, long timestamp, String postid,HashMap count)
{
this.lastname=lastname;
this.timestamp=timestamp;
this.postid=postid;
this.count=count;
}
public HashMap<String, Boolean> getCounts() {
return count;
}
public void setCounts(HashMap<String, Boolean> count) {
this.count = count;
}
In Main Activity i used to get data
mAdapter = new PostAdapter(MainActivity.this);
getAllPost(null);
postList.addOnScrollListener(new RecyclerView.OnScrollListener() {
#Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
if (!recyclerView.canScrollVertically(1))
{
loaded=loaded+10;
if (totalPost== mAdapter.getItemCount())
{
Toast.makeText(MainActivity.this, "no more post", Toast.LENGTH_SHORT).show();
}
else
{
getAllPost(mAdapter.getLastItemId());
}
}
}
});
postList.setAdapter(mAdapter);
private void getAllPost(final String nodeId)
{
final Query query;
final int left= (int) (totalPost-mAdapter.getItemCount());
Toast.makeText(this, String .valueOf(left), Toast.LENGTH_SHORT).show();
if (nodeId == null)
{
query = PostRef
.orderByChild("timestamp")
.limitToLast(mPostsPerPage);
}
else
{
if (left<10)
{
query = PostRef
.orderByChild("timestamp")
.limitToFirst(left);
}
else
{
Long time=Long.parseLong(nodeId);
query = PostRef
.orderByChild("timestamp").endAt(time)
.limitToLast(10);
}
}
query.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
List<Post> userModels = new ArrayList<>();
for (DataSnapshot userSnapshot : dataSnapshot.getChildren())
{
userModels.add(userSnapshot.getValue(Post.class));
}
if (!(nodeId ==null))
{
if (left>10)
{
userModels.remove(9);
}
}
Collections.reverse(userModels);
mAdapter.addAll(userModels);
}
#Override
public void onCancelled(DatabaseError databaseError) {
throw databaseError.toException();
}
});
}
And in adapter:
public class PostAdapter extends RecyclerView.Adapter<PostHolder>
{
List<Post> mPost;
Context mContext;
public PostAdapter(Context c) {
this.mPost = new ArrayList<>();
mContext=c;
}
#NonNull
#Override
public PostHolder onCreateViewHolder(#NonNull ViewGroup viewGroup, int i) {
return new PostHolder(LayoutInflater.from(viewGroup.getContext())
.inflate(R.layout.all_post_layout, viewGroup, false));
}
#Override
public void onBindViewHolder(#NonNull final PostHolder postHolder, final int i) {
final String PostKey=mPost.get(i).getPostid();
FirebaseAuth mAuth=FirebaseAuth.getInstance();
final String currentUserID=mAuth.getCurrentUser().getUid();
final DatabaseReference post=FirebaseDatabase.getInstance().getReference().child("Posts");
showCounts(postHolder,i);
setCountsButton(postHolder,i,currentUserID);
tapOnCounts(postHolder,i,currentUserID,post,PostKey);
}
private void tapOncounts(final PostHolder postHolder, final int i, final String currentUserID, final DatabaseReference post, final String postKey)
{
postHolder.countsButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v)
{
if (mPost.get(i).getCounts() !=null)
{
if(mPost.get(i).getCounts().containsKey(currentUserID))
{
post.child(postKey).child("counts").child(currentUserID).removeValue();
postHolder.countsButton.setImageResource(R.drawable.discounts);
}
else
{
postHolder.countsButton.setImageResource(R.drawable.counts);
post.child(postKey).child("counts").child(currentUserID).setValue(true);
}
}
else
{
postHolder.countsButton.setImageResource(R.drawable.counts);
post.child(postKey).child("counts").child(currentUserID).setValue(true);
}
}
});
}
private void setcountsButton(final PostHolder postHolder, int i, String currentUserID)
{
if (mPost.get(i).getCounts() !=null)
{
if(mPost.get(i).getCounts().containsKey(currentUserID))
{
postHolder.countsButton.setImageResource(R.drawable.counts);
}
else
{
postHolder.countsButton.setImageResource(R.drawable.discounts);
}
}
}
private void showCounts(PostHolder postHolder, int i)
{
if((mPost.get(i).getCounts() !=null))
{
postHolder.noOfcounts.setText(String.valueOf(mPost.get(i).getCounts().size()));
}
else
{
postHolder.noOfcounts.setText("0");
}
}
#Override
public int getItemCount() {
return mPost.size();
}
public void addAll(List<Post> newPost) {
int initialSize = mPost.size();
mPost.addAll(newPost);
notifyItemRangeInserted(initialSize, newPost.size());
}
public String getLastItemId() {
return String.valueOf(mPost.get(mPost.size() - 1).getTimestamp());
}
}
All is successfully but whenever total no. of child change(new child added OR old child removed) in count node recylerview is not update. It will only update when i tried to go another activity and come to rerun in MainActivity.
To get realtime updates, you should use Query's addValueEventListener(ValueEventListener listener) method:
Add a listener for changes in the data at this location.
When using addListenerForSingleValueEvent(ValueEventListener listener):
Add a listener for a single change in the data at this location.
Edit:
To get the size of your list, please change the following line of code:
holder.count.setText(String.valueOf(mPost.get(i).getCount().size));
to
holder.count.setText(String.valueOf(getItemCount());
Whenever total number of child changes then your list of Post modal also changes i.e. userModels in your case. Hence whenever your list of model changes your adapter needs to be notified. Hence my guess is to add notifyDataSetChanged to adapter.
Try this:
query.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
List<Post> userModels = new ArrayList<>();
for (DataSnapshot userSnapshot : dataSnapshot.getChildren()) {
userModels.add(userSnapshot.getValue(Post.class));
}
mAdapter.notifyDataSetChanged(); //<<changes made HERE
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
})
For this to work I hope userModels is instance variable to your MainActivity and is set to mAdapter during initialization.

Android retrieving data from Firebase doesn't work for data models even it works for other data model in the project with similar codes

I am new in Android and working on an Android app which can retrieve data from firebase. There is a weird problem. I already successfully implemented the retrieving function for one data model of my program, and I used same codes just changed the variables but it doesn't work for another data model. I did many tests and I think the problem is in FirebaseHelper cuz there is no any data returned from the data snapshot. The error is
java.lang.NullPointerException: Attempt to invoke virtual method 'void android.widget.ListView.setAdapter(android.widget.ListAdapter)' on a null object reference
The codes are shown below:
The Activity that shows the retrieved data in a listview.
public class TimeTableActivity extends AppCompatActivity {
DatabaseReference db;
FirebaseHelper firebasehelper;
TimeTableAdapter adapter;
ListView lv_CourseList;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_time_table);
//GET INTENT
Intent intent = this.getIntent();
String majorID = intent.getStringExtra("MAJOR_ID");
lv_CourseList = (ListView) findViewById(R.id.lv_CourseList);
//INITIALIZE FIREBASE DB
db= FirebaseDatabase.getInstance().getReference();
firebasehelper=new FirebaseHelper(db);
//ADAPTER
adapter = new TimeTableAdapter(getApplicationContext(),firebasehelper.retrieveCourse(majorID, new CourseCallbacks() {
#Override
public void onCourseCallback(ArrayList<CourseInfo> courseInfos) {
lv_CourseList.setAdapter(adapter);
}
}));
lv_CourseList.setAdapter(adapter);
}
}
FirebaseHelper:
public class FirebaseHelper{
private DatabaseReference db;
private ArrayList<Major> majors = new ArrayList<>();
private ArrayList<CourseInfo> courseInfos = new ArrayList<>();
public FirebaseHelper(DatabaseReference db) {
this.db = db;
}
//Save the Major info. into db
public Boolean saveMajor(Major major)
{
Boolean saved = null;
if(major==null)
{
saved =false;
}else
{
try
{
db.child("Major").push().setValue(major);
saved =true;
}catch (DatabaseException e)
{
e.printStackTrace();
saved =false;
}
}
return saved;
}
//Save the Course info. into db
public Boolean saveCourse(CourseInfo courseInfo)
{
Boolean saved = null;
if(courseInfo==null)
{
saved =false;
}else
{
try
{
db.child("CourseInfo").push().setValue(courseInfo);
saved =true;
}catch (DatabaseException e)
{
e.printStackTrace();
saved =false;
}
}
return saved;
}
public ArrayList<Major> retrieveMajor(final MajorCallbacks majorCallbacks){
ChildEventListener childEventListener = new ChildEventListener() {
#Override
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
for (DataSnapshot ds : dataSnapshot.getChildren()) {
Major major = ds.getValue(Major.class);
if (major != null && major.getMajor_id() != null) {
majors.add(major);
}
}
majorCallbacks.onMajorCallback(majors);
}
#Override
public void onChildChanged(DataSnapshot dataSnapshot, String s) {
for (DataSnapshot ds : dataSnapshot.getChildren()) {
Major major = ds.getValue(Major.class);
if (major != null && major.getMajor_id() != null) {
majors.add(major);
}
}
majorCallbacks.onMajorCallback(majors);
}
#Override
public void onChildRemoved(DataSnapshot dataSnapshot) {
}
#Override
public void onChildMoved(DataSnapshot dataSnapshot, String s) {
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
};
db.addChildEventListener(childEventListener);
if (!majors.isEmpty()){
db.removeEventListener(childEventListener);
}
return majors;
}
public ArrayList<CourseInfo> retrieveCourse(String majorID, final CourseCallbacks courseCallbacks){
ChildEventListener childEventListener = new ChildEventListener() {
#Override
public void onChildAdded(DataSnapshot dataSnapshot, String prevChildKey) {
for (DataSnapshot ds : dataSnapshot.getChildren()) {
CourseInfo courseInfo = ds.getValue(CourseInfo.class);
if (courseInfo != null && courseInfo.getCourse_id() != null) {
courseInfos.add(courseInfo);
}
}
courseCallbacks.onCourseCallback(courseInfos);
}
#Override
public void onChildChanged(DataSnapshot dataSnapshot, String prevChildKey) {
for (DataSnapshot ds : dataSnapshot.getChildren()) {
CourseInfo courseInfo = ds.getValue(CourseInfo.class);
if (courseInfo != null && courseInfo.getCourse_id() != null) {
courseInfos.add(courseInfo);
}
}
courseCallbacks.onCourseCallback(courseInfos);
}
#Override
public void onChildRemoved(DataSnapshot dataSnapshot) {
}
#Override
public void onChildMoved(DataSnapshot dataSnapshot, String prevChildKey) {
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
};
db.child("CourseInfo").orderByChild("major_id").equalTo(majorID).addChildEventListener(childEventListener);
return courseInfos;
}
}
The retrieveMajor method works well even though it returns many null data and repetitive data, and I used the codes of retrieveMajor in retrieveCourse. It doesn't work, the courseInfos is always null. Even though I changed db.child("CourseInfo").orderByChild("major_id").equalTo(majorID).addChildEventListener(childEventListener);
to
db.addChildEventListener(childEventListener);
,still nothing is retrieved which means the problem is not the query (Probably the query is also wrong).
Adapter:
public class TimeTableAdapter extends BaseAdapter {
Context context;
ArrayList<CourseInfo> courseInfos;
public TimeTableAdapter(Context context, ArrayList<CourseInfo> courseInfos) {
this.context = context;
this.courseInfos = courseInfos;
}
#Override
public int getCount() {
return courseInfos.size();
}
#Override
public Object getItem(int pos) {
return courseInfos.get(pos);
}
#Override
public long getItemId(int pos) {
return pos;
}
#Override
public View getView(int position, View convertView, ViewGroup viewGroup) {
LayoutInflater inflater = LayoutInflater.from(context);
if(convertView == null)
{
convertView= LayoutInflater.from(context).inflate(R.layout.model_timetable,viewGroup,false);
}
TextView tv_courseid= (TextView) convertView.findViewById(R.id.tv_courseid);
TextView tv_coursename= (TextView) convertView.findViewById(R.id.tv_coursename);
TextView tv_courseinstructor= (TextView) convertView.findViewById(R.id.tv_courseinstructor);
TextView tv_courseavailable= (TextView) convertView.findViewById(R.id.tv_courseavailable);
final CourseInfo courseInfo= (CourseInfo) this.getItem(position);
tv_courseid.setText(courseInfo.getCourse_id());
tv_coursename.setText(courseInfo.getCourse_name());
tv_courseinstructor.setText(courseInfo.getCourse_instructor());
tv_courseavailable.setText(courseInfo.getCourse_available());
return convertView;
}
}
Data model:
#IgnoreExtraProperties
public class CourseInfo {
public String course_id;
public String course_name;
public int course_section;
public String course_type;
public double course_crdhrs;
public String course_days;
public String course_times;
public String course_location;
public int course_max;
public int course_cur;
public int course_available;
public int course_wl;
public double course_per;
public String course_instructor;
public String course_description;
public String course_prerequire;
public String major_id;
public CourseInfo() {
}
public CourseInfo(String course_id, String course_name, int course_section, String course_type, double course_crdhrs, String course_days, String course_times, String course_location, int course_max, int course_cur, int course_available, int course_wl, double course_per, String course_instructor, String course_description, String course_prerequire, String major_id) {
this.course_id = course_id;
this.course_name = course_name;
this.course_section = course_section;
this.course_type = course_type;
this.course_crdhrs = course_crdhrs;
this.course_days = course_days;
this.course_times = course_times;
this.course_location = course_location;
this.course_max = course_max;
this.course_cur = course_cur;
this.course_available = course_available;
this.course_wl = course_wl;
this.course_per = course_per;
this.course_instructor = course_instructor;
this.course_description = course_description;
this.course_prerequire = course_prerequire;
this.major_id = major_id;
}
public String getCourse_id() {
return course_id;
}
public String getCourse_name() {
return course_name;
}
public int getCourse_section() {
return course_section;
}
public String getCourse_type() {
return course_type;
}
public double getCourse_crdhrs() {
return course_crdhrs;
}
public String getCourse_days() {
return course_days;
}
public String getCourse_times() {
return course_times;
}
public String getCourse_location() {
return course_location;
}
public int getCourse_max() {
return course_max;
}
public int getCourse_cur() {
return course_cur;
}
public int getCourse_available() {
return course_available;
}
public int getCourse_wl() {
return course_wl;
}
public double getCourse_per() {
return course_per;
}
public String getCourse_instructor() {
return course_instructor;
}
public String getCourse_description() {
return course_description;
}
public String getCourse_prerequire() {
return course_prerequire;
}
public String getMajor_id() {
return major_id;
}
}
If you need more codes or information, please comment and let me know. I will really appreciate if you can also help me solve the null data and repetitive data problem cuz it makes the listview show many blank and repetitive items.
You cannot return something now that hasn't been loaded yet. With other words, you cannot just simply create a method that as a return type, an ArrayList<Major> and in the same time return that object. This is happening because those methods, onChildAdded(), onChildChanged() and so on, have an asynchronous behaviour, which means that are called even before you are getting/updating the data from/in the database. To solve this, you can move the declaration of that ArrayList inside one method and do what you need to do with it or dive into asynchronous world and use the last part of my answer from this post. You can take also a look at this video for a better understanding.

Sort List by Integer

I get the Latitude and Longtitude from my Database and I calculate the distance between two persons in the RecyclerView Adapter.
I want to sort these items by distance, but I have no clue how I can do this.
My Adapter:
public class HomeAdapter extends RecyclerView.Adapter<HomeAdapter.ViewHolder>{
Context context;
List<HomeGetter> homeGetters;
HomeCallback homeCallback;
public HomeAdapter(Context context, List<HomeGetter> homeGetters, HomeCallback homeCallback) {
this.context = context;
this.homeGetters = homeGetters;
this.homeCallback = homeCallback;
}
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(context).inflate(R.layout.custom_home_profil,parent,false);
return new ViewHolder(view);
}
#Override
public void onBindViewHolder(final ViewHolder holder, final int position) {
calculate_age calculate_age = new calculate_age();
final HomeGetter homeGetter = homeGetters.get(position);
String[] splittedAge = homeGetter.getBirthday().split("\\.");
try {
String age = calculate_age.getAge(context,Integer.valueOf(splittedAge[0]),Integer.valueOf(splittedAge[1]),Integer.valueOf(splittedAge[2]));
String username = homeGetter.getUsername().substring(0,1).toUpperCase() + homeGetter.getUsername().substring(1);
holder.textViewUsername.setText(username + "," + age);
} catch (ParseException e) {
e.printStackTrace();
}
Picasso.with(context).load(homeGetter.getImageURL()).resize(600,700).centerCrop().into(holder.imageView);
holder.cardView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
homeCallback.getPosition(position);
}
});
holder.textViewLocation.setText(homeGetter.getLocation());
if(homeGetter.getStatus().equals("0")){
holder.status.setImageDrawable(context.getResources().getDrawable(R.drawable.offline));
}else {
holder.status.setImageDrawable(context.getResources().getDrawable(R.drawable.online));
}
}
#Override
public int getItemCount() {
return homeGetters.size();
}
public class ViewHolder extends RecyclerView.ViewHolder {
ImageView imageView;
TextView textViewUsername;
CardView cardView;
TextView textViewLocation;
ImageView status;
public ViewHolder(View itemView) {
super(itemView);
imageView = itemView.findViewById(R.id.imageViewThumb);
textViewUsername = itemView.findViewById(R.id.textViewProfilUsername);
cardView = itemView.findViewById(R.id.cardViewProfil);
textViewLocation = itemView.findViewById(R.id.textViewLocation);
status = itemView.findViewById(R.id.imageViewOnlinestatus);
}
}
}
On this line I get the distance in km:
holder.textViewLocation.setText(homeGetter.getLocation());
e.g 544
Is it possible to sort the list in the adapter?
Or how can I sort this?
So, how can I achive this?
The Activity
pullData.getData(USERNAME, "1", new Pullcallback() {
#Override
public void getSingleData(String data) {
}
#Override
public void getMultipleData(String[] multipledatas) {
GENDER = multipledatas[5];
GENDERSEARCH = multipledatas[6];
GetStrangers getStrangers = new GetStrangers(Home.this);
Map<String,String> map = new HashMap<>();
map.put("USERNAME",USERNAME);
map.put("GENDER",GENDER);
map.put("SEARCH",GENDERSEARCH);
getStrangers.strangers(map, "7", new Pullcallback() {
#Override
public void getSingleData(String data) {
}
#Override
public void getMultipleData(final String[] multipledatas) {
// username,imagelink,position,birthday
// imageURL,username,birthday,location
pullData.getData(USERNAME, "2", new Pullcallback() {
#Override
public void getSingleData(String data) {
}
#Override
public void getMultipleData(String[] multipledatas2) {
String[] split1 = multipledatas2[1].split(",");
String[] split2 = multipledatas[2].split(",");
float lat1 = Float.valueOf(split1[0]);
float lng1 = Float.valueOf(split1[1]);
float lat2 = Float.valueOf(split2[0]);
float lng2 = Float.valueOf(split2[1]);
Collections.sort(getterList, new Comparator<HomeGetter>() {
public int compare(HomeGetter s1, HomeGetter s2) {
return Integer.compare(Integer.parseInt(s1.getLocation()), Integer.parseInt(s2.getLocation()));
}
});
homeGetter = new HomeGetter(multipledatas[1],multipledatas[0],multipledatas[3],String.valueOf(Math.round(Calculator.calculateDistance(lat1,lng1,lat2,lng2))),multipledatas[4]);
getterList.add(homeGetter);
homeAdapter.notifyDataSetChanged();
loading.setVisibility(View.GONE);
content.setVisibility(View.VISIBLE);
}
#Override
public void onError(String errormessage) {
}
});
}
#Override
public void onError(String errormessage) {
}
});
}
#Override
public void onError(String errormessage) {
}
});
pullData.getData(USERNAME, "2", new Pullcallback() {
#Override
public void getSingleData(String data) {
}
#Override
public void getMultipleData(String[] multipledatas) {
if(multipledatas[7].equals("0")){
Intent intentFirststep = new Intent(Home.this,Firststep.class);
startActivity(intentFirststep);
finish();
}else {
}
}
#Override
public void onError(String errormessage) {
}
});
recyclerViewHome = findViewById(R.id.recyclerViewHome);
homeAdapter = new HomeAdapter(Home.this, getterList, new HomeCallback() {
#Override
public void getPosition(int position) {
Intent stranger = new Intent(Home.this,Stranger.class);
stranger.putExtra("USERNAME",getterList.get(position).getUsername());
startActivity(stranger);
finish();
}
});
recyclerViewHome.setHasFixedSize(true);
recyclerViewHome.setLayoutManager(new GridLayoutManager(Home.this,3));
recyclerViewHome.setItemAnimator(new DefaultItemAnimator());
recyclerViewHome.setAdapter(homeAdapter);
}
But it is not working correctly it shows me 4,14,507 and 12
but it shoild sort 4,12,14,507
In your activity where you are passing your ArrayList just do this before passing it.
Collections.sort(homeGetter, new Comparator<HomeGetter>() {
public int compare(HomeGetter s1, HomeGetter s2) {
return Integer.compare(Integer.parseInt(s1.getLocation()), Integer.parseInt(s2.getLocation()));
}
});
P.S. Don't use parse if you are already storing as integers.
Happy to help.
EDIT:
Put it here-
getterList.add(homeGetter);
Collections.sort(homeGetter, new Comparator<HomeGetter>() {
public int compare(HomeGetter s1, HomeGetter s2) {
return Integer.compare(Integer.parseInt(s1.getLocation()), Integer.parseInt(s2.getLocation()));
}
});
homeAdapter.notifyDataSetChanged();
You can also sort the List<HomeGetter> homegetters using a Comparator & then initialize HomeAdapter with sorted homegetters list.
An Example:
homegetters.sort((hG1, hG2) -> hG1.getLocation().compareTo(hG2.getLocation()));
Above line will sort homegetters list based on getLocation().
Edit:
In your activity, you are sorting the List first and then adding an item into it.
You should instead add all the items first & then sort the List.

Recyclerview DiffUtil scrolls my list to top when updated

I've decided to give DiffUtil a try instead of notifyDataSetChanged in my EndlessRecyclerView.
The problem is, after the first or second fling my list is scrolled to top, but the items are added to the list.
Here's my DiffUtil:
public class MovieDiffCallback extends DiffUtil.Callback {
List<Movie> mOldMovieList;
List<Movie> mNewMovieList;
public MovieDiffCallback(List<Movie> oldMovieList, List<Movie> newMovieList) {
this.mOldMovieList = oldMovieList;
this.mNewMovieList = newMovieList;
}
#Override
public int getOldListSize() {
return mOldMovieList != null ? mOldMovieList.size() : 0;
}
#Override
public int getNewListSize() {
return mNewMovieList != null ? mNewMovieList.size() : 0;
}
#Override
public boolean areItemsTheSame(int oldItemPosition, int newItemPosition) {
return mOldMovieList.get(oldItemPosition).getId().equals(mNewMovieList.get(newItemPosition).getId());
}
#Override
public boolean areContentsTheSame(int oldItemPosition, int newItemPosition) {
return mOldMovieList.get(oldItemPosition).equals(mNewMovieList.get(newItemPosition));
}
#Nullable
#Override
public Object getChangePayload(int oldItemPosition, int newItemPosition) {
return super.getChangePayload(oldItemPosition, newItemPosition);
}
}
And this is where I use it in my Fragment:
#Override
public void getMovies(List<Movie> moviesList) {
mDiffCallback = new MovieDiffCallback(mMoviesList, moviesList);
mDiffResult = DiffUtil.calculateDiff(mDiffCallback);
mMoviesList.addAll(moviesList);
mDiffResult.dispatchUpdatesTo(mAdapter);
isLoadedLandscape = true;
}
And this is in the EndlessRecyclerScroll:
#Override
public void onLoadMore(int page, int totalItemsCount, RecyclerView view) {
scrollPage++;
populateMap(scrollPage);
mPresenter.getSuggestedMovies(searchParamsMap);
}

Implement a TransformList that holds distinct values?

I'm trying to create an implementation of TransformList that maintains a list of distinct values off a source list. However, I'm a little puzzled on how the implementation should add the distinct values to my hashmap and distinct list that are contained internally. I think my ListChangeListener.change should work though. But how do I intercept any new or removed distinct values and add/remove them to the distinct map and list?
public class DistinctList<E> extends TransformationList<E,E> {
private final ObservableList<E> distinctList = FXCollections.observableArrayList();
private final ConcurrentHashMap<E,E> distinctValues = new ConcurrentHashMap<>();
private final ObservableList<E> source;
public DistinctList(ObservableList<E> source) {
super(source);
this.source = source;
source.stream().filter(s -> attemptAdd(s)).forEach(s -> distinctList.add(s));
}
private boolean attemptAdd(E e) {
final boolean result = distinctValues.putIfAbsent(e,e) == null;
if (result) {
distinctList.add(e);
}
return result;
}
private boolean attemptRemove(E e) {
final boolean result = distinctValues.remove(e, e);
if (result) {
distinctList.remove(e);
}
return result;
}
#Override
protected void sourceChanged(ListChangeListener.Change<? extends E> c) {
fireChange(new ListChangeListener.Change<E>(this) {
#Override
public boolean wasAdded() {
if (c.getAddedSubList().stream().filter(v -> distinctValues.contains(v) == false).findAny().isPresent()) {
return true;
}
else {
return false;
}
}
#Override
public boolean wasRemoved() {
if (c.getRemoved().stream().filter(v -> !source.contains(v)).findAny().isPresent()) {
return true;
}
else {
return false;
}
}
#Override
public boolean wasPermutated() {
return false;
}
#Override
protected int[] getPermutation() {
throw new AssertionError("getPermutation() not implemented");
}
#Override
public List<E> getRemoved() {
return c.getRemoved().stream().filter(v -> !source.contains(v)).collect(Collectors.toList());
}
#Override
public int getFrom() {
return 0;
}
#Override
public int getTo() {
return 0;
}
#Override
public boolean next() {
return c.next();
}
#Override
public void reset() {
c.reset();
}
});
}
#Override
public int getSourceIndex(int index) {
return IntStream.range(0,source.size()).filter(i -> source.get(i).equals(this.get(i))).findAny().orElse(-1);
}
#Override
public E get(int index) {
return distinctList.get(index);
}
#Override
public int size() {
return distinctList.size();
}
}
UPDATE
I kept working with this and I think I figured out where to interact source changes with the distinct value map and list. But when my source list removes a value (and other values with same hashcode/equals still exists), it wrongly removes the value from the distinct values. What am I doing wrong?
public class DistinctList<E> extends TransformationList<E,E> {
private final ObservableList<E> distinctList = FXCollections.observableArrayList();
private final ConcurrentHashMap<E,E> distinctValues = new ConcurrentHashMap<>();
private final ObservableList<E> source;
public DistinctList(ObservableList<E> source) {
super(source);
this.source = source;
source.stream().forEach(s -> attemptAdd(s));
}
private boolean attemptAdd(E e) {
final boolean result = distinctValues.putIfAbsent(e,e) == null;
if (result) {
distinctList.add(e);
}
return result;
}
private boolean attemptRemove(E e) {
final boolean result = distinctValues.remove(e, e);
if (result) {
distinctList.remove(e);
}
return result;
}
#Override
protected void sourceChanged(ListChangeListener.Change<? extends E> c) {
ListChangeListener.Change<E> change = new ListChangeListener.Change<E>(this) {
#Override
public boolean wasAdded() {
if (c.getAddedSubList().stream().filter(v -> source.contains(v)).findAny().isPresent()) {
return true;
}
else {
return false;
}
}
#Override
public boolean wasRemoved() {
if (c.getRemoved().stream().filter(v -> source.contains(v) == false).findAny().isPresent()) {
return true;
}
else {
return false;
}
}
#Override
public boolean wasPermutated() {
return false;
}
#Override
protected int[] getPermutation() {
throw new AssertionError("getPermutation() not implemented");
}
#Override
public List<E> getRemoved() {
return c.getRemoved().stream().filter(v -> source.contains(v) == false)
.collect(Collectors.toList());
}
#Override
public int getFrom() {
return 0;
}
#Override
public int getTo() {
return 0;
}
#Override
public boolean next() {
return c.next();
}
#Override
public void reset() {
c.reset();
}
};
while (c.next()) {
if (c.wasAdded()) {
c.getAddedSubList().stream().filter(v -> !distinctValues.containsKey(v)).peek(a -> System.out.println("ADDING FROM MAP " + a)).forEach(a -> attemptAdd(a));
}
if (c.wasRemoved()) {
c.getRemoved().stream().filter(v -> distinctValues.containsKey(v)).peek(a -> System.out.println("REMOVING FROM MAP " + a)).forEach(a -> attemptRemove(a));
}
}
fireChange(change);
}
#Override
public int getSourceIndex(int index) {
return IntStream.range(0,source.size()).filter(i -> source.get(i).equals(this.get(i))).findAny().orElse(-1);
}
#Override
public E get(int index) {
return distinctList.get(index);
}
#Override
public int size() {
return distinctList.size();
}
}
I think I got it. Let me know if I'm missing anything.
public class DistinctList<E> extends TransformationList<E,E> {
private final ObservableList<E> distinctList = FXCollections.observableArrayList();
private final ConcurrentHashMap<E,E> distinctValues = new ConcurrentHashMap<>();
private final ObservableList<E> source;
public DistinctList(ObservableList<E> source) {
super(source);
this.source = source;
source.stream().forEach(s -> attemptAdd(s));
}
private boolean attemptAdd(E e) {
final boolean result = distinctValues.putIfAbsent(e,e) == null;
if (result) {
distinctList.add(e);
}
return result;
}
private boolean attemptRemove(E e) {
final boolean result = distinctValues.remove(e, e);
if (result) {
distinctList.remove(e);
}
return result;
}
#Override
protected void sourceChanged(ListChangeListener.Change<? extends E> c) {
while (c.next()) {
ListChangeListener.Change<E> change = new ListChangeListener.Change<E>(this) {
#Override
public boolean wasAdded() {
if (c.getAddedSubList().stream().filter(v -> distinctValues.contains(v) == false).findAny().isPresent()) {
return true;
} else {
return false;
}
}
#Override
public List<E> getAddedSubList() {
return c.getAddedSubList().stream().filter(v -> distinctValues.contains(v) == false).collect(Collectors.toList());
}
#Override
public boolean wasRemoved() {
if (c.getRemoved().stream().filter(v -> source.contains(v) == false).findAny().isPresent()) {
return true;
} else {
return false;
}
}
#Override
public boolean wasPermutated() {
return false;
}
#Override
protected int[] getPermutation() {
throw new AssertionError("getPermutation() not implemented");
}
#Override
public List<E> getRemoved() {
return c.getRemoved().stream().filter(v -> source.contains(v) == false)
.collect(Collectors.toList());
}
#Override
public int getFrom() {
return 0;
}
#Override
public int getTo() {
return 0;
}
#Override
public boolean next() {
return c.next();
}
#Override
public void reset() {
c.reset();
}
};
if (change.wasAdded()) {
change.getAddedSubList().stream().filter(v -> !distinctValues.containsKey(v)).peek(a -> System.out.println("ADDING FROM MAP " + a)).forEach(a -> attemptAdd(a));
}
if (change.wasRemoved()) {
change.getRemoved().stream().filter(v -> distinctValues.containsKey(v)).peek(a -> System.out.println("REMOVING FROM MAP " + a)).forEach(a -> attemptRemove(a));
}
fireChange(change);
}
}
#Override
public int getSourceIndex(int index) {
return IntStream.range(0,source.size()).filter(i -> source.get(i).equals(this.get(i))).findAny().orElse(-1);
}
#Override
public E get(int index) {
return distinctList.get(index);
}
#Override
public int size() {
return distinctList.size();
}
}

Categories