searchview with recycler view is not working properly - android

hi i am developing one app where i have implemented recycler view and searchview in fregement.i get the filter product first time according to text change.
But when i delete text one by one all list will be empty.Notheing can display at the end .
Here is my code from my fragement

You are continuously operating on single array named plistarray
here in filter() method you have cleared plistarray and again used the same to find the records. so you should use some other array for you adapter rather than plistarray
public void filter(String text) {
if (text.isEmpty()) {
plistarray.clear();
plistarray.addAll(plistarray);
} else {
ArrayList<ProductList> result = new ArrayList<>();
text = text.toLowerCase();
//after clearing the array again you are using same array to find the items from
for (ProductList item : plistarray) {
if (item.getPtitle().toLowerCase().contains(text)) {
result.add(item);
}
}
//you have cleared all the contains here
plistarray.clear();
// and added only result related items here
plistarray.addAll(result);
}
notifyDataSetChanged();
}

I think the problem is in the if (text.isEmpty()) { block of filter method.
Here you clear the plistarray list and add that empty list in plistarray.addAll(plistarray);
Instead of this add your original datalist for the plistarray.addAll(); This will resolve your empty list problem.
Remember this, when you perform the search always first make a dummy/copy of original list in constructor of adapter, and use this dummy to restore the data.
Hope, this will solve your problem.

As i see the main problem is you're manipulating the List your adapter is populated from, but you do not have a "copy" of the original dataset.
Something like this should work:
ArrayList<ProductList> plistarray; // these are instance variables
ArrayList<ProductList> plistarrayCopy; // in your adapter
// ...
public void filter(String text) {
if (plistarrayCopy == null) {
plistarrayCopy = new ArrayList<>(plistarray);
}
if (text.isEmpty()) {
plistarray.clear();
plistarray.addAll(plistarrayCopy);
plistarrayCopy = null;
} else {
text = text.toLowerCase();
ArrayList<Device> filteredList = new ArrayList<>();
for (ProductList pList : plistarrayCopy) {
if (pList.getPtitle().toLowerCase().contains(text)) {
filteredList.add(pList);
}
}
plistarray.clear();
plistarray.addAll(filteredList);
}
notifyDataSetChanged();
}

Related

How to show the last item from room database at top in recyclerview

i am pulling data from a room database when ever i add new objects to the database and try to display them using Recyclerview they appear at the bottom of recycler view i am not using add(data,Position) function of list in the recyclerview adapter as it duplicates the data in recyclerview for example if data is already present in the recyclerview and user tries to saerch the same data again using a search view it gets duplicated also i have tried to reverse the list using layout-manager but then it scrolls the list to last item in recyclerview i have also tried smoothscroll to position 0 but it is not working either.
I am using a search view to first search the data from the database if data is not present in the database i fetch it from the server through the API insert it to the database and notify the recyclerview of changes all works fine except that data appears at the bottom
Main Activity code
private SearchView.OnQueryTextListener onQueryTextListener =
new SearchView.OnQueryTextListener() {
#Override
public boolean onQueryTextSubmit(String query) {
if (query.length() >= 3) {
getDealsFromDb(query);
}
return true;
}
#Override
public boolean onQueryTextChange(String newText) {
if (newText.length() >= 3) {
getDealsFromDb(newText);
}
return true;
}
private void getDealsFromDb(String searchText) {
searchText = "%" + searchText + "%";
final String finalSearchText = searchText;
model.getDevicenames(searchText).observe(MainActivity.this, new Observer<List<MobileDataBaseObjectClass>>() {
#Override
public void onChanged(#Nullable List<MobileDataBaseObjectClass> mobileDataBaseObjectClasses) {
if (mobileDataBaseObjectClasses != null) {
if (mobileDataBaseObjectClasses.size() == 0) {
Log.i("Test", "Main Activity not found in database fetching from api: ");
model.insertSingleObject(finalSearchText);
} else {
mAdapter.setWords(mobileDataBaseObjectClasses);
}
}
}
});
}
};
You must be passing the list to the adapter. First you get the list from database which will be sorted in a way like the last item at last index. After fetching the list just call the method to reverse the list.
List<DailyConsumption> mList = myDataBase.dailyConsumptionDao().findByDate(date);
Collections.reverse(mList); // inverses the list and shows last item at first index
// now pass this list to the adapter

How to prevent listArray from populating multiple times?

I have a spinner populated from an API call.
At first loading of fragment, the list is correctly populated, with differents items, one for row.
After a submit (I need a submit in this fragment) the List is re-populated several times.
This is the onCreate method:
#Override
public void onCreate(Bundle savedInstanceState) {
mItemSubscriptionList = new ArrayList<>();
super.onCreate(savedInstanceState);
}
And this is the method that populate the array list
private void loadItemSubscription() {
ApiMapper mapper = new ApiMapper();
mapper.getBalance(new ApiMapper.VolleyCallback<JSONArray>() {
#Override
public void onSuccess(JSONArray balance) {
if (balance != null) {
Log.d(LOGTAG , balance.toString());
mItemSubscriptionList.clear();
for (int i = 0; i < balance.length(); i++) {
Log.d(LOGTAG , "Popolo lo spinner "+i);
try {
JSONObject obj = balance.getJSONObject(i);
String quantity = obj.getString("balance");
quantity = quantity.replace(".00","");
int id_item = obj.getInt("id_item");
String item = obj.getString("item");
item = item + ' '+'('+quantity+')';
Log.d(LOGTAG , quantity);
Log.d(LOGTAG , item);
ModelItemSubscription modelItemSubscription = new ModelItemSubscription();
modelItemSubscription.setMItemId(id_item);
modelItemSubscription.setMItemName(item);
modelItemSubscription.setMItemQuantity(quantity);
mItemSubscriptionList.add(modelItemSubscription);
mBaseApp.setItemSubscription(modelItemSubscription);
mLoadingDialog.dismiss();
} catch (JSONException e) {
e.printStackTrace();
}
}
}
mItemSubscriptionList = mBaseApp.getItemSubscription();
if ( mItemSubscriptionList!=null ) {
renderSpinnerItemSubscription(mItemSubscriptionList);
}
}
}, mToken, mIdMemberCard, mIdCampaign);
}
In real scenario, I have 4 items to populate. The Log "Popolo lo spinner" is printed exactly 4 times, but this is the ugly finaly result.
Instead this is the right behaviour after the first loading (only 1 item for type)
Fyi this is the array that populates:
[{"balance":"0.00","item":"Lampada","id_item":"540"},{"balance":"0.00","item":"Taglio","id_item":"541"},{"balance":"1.00","item":"Piega","id_item":"542"},{"balance":"11.00","item":"Gelati","id_item":"543"}]
Thank you very much
The problem with your code is the list is getting populated every time the API call is made. Means if the call is made 4 times then your list would be populated 4 times with the same data.
mItemSubscriptionList.add(modelItemSubscription); will not override but it will add the items no matter it the items are already present in the list.
Now what I suggest is you should clear your list before you make a call to API. Just add mItemSubscriptionList.clear() after ApiMapper mapper = new ApiMapper();
I can't see where you are populating your Spinner adapter so I will describe how it should be done with no code.
First everytime you fetch your data from you API you should clear your main ArrayList which holds the data and update the Spinner's adapter:
adapter.notifySetDataChanged(); // Depending on the adapter
After that populate your ArrayList with the new fetched data and call
adapter.notifySetDataChanged();
again so your data get refreshed.
Try this and tell if it works. If not, please add more code so we can see how you are populating your adapter after fetching the data.

How to retreive items back in arraylist once it is cleared: Android

I have an array list that displays a list of companies. Each of these companies is having corresponding town names. Further, I am creating buttons for each of the town names such that when I click on any of the town names, the ArrayList should be filtered and only the companies with that town name should be displayed.
The buttons are like,
stringList.add(tempList.get(n).getTownName());
btnTag.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT, 60));
btnTag.setText(stringList.get(k));
btnTag.setBackgroundResource(R.drawable.alpha_button_selector);
btnTag.setClickable(true);
townLayout.addView(btnTag);
On clicking the button, I am fetching the text in the button as it displays the town name and then I am calling the method to filter the data,
btnTag.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
CharSequence name = btnTag.getText();
locationFilter(name);
}
});
For filtering the data, I am creating a new ArrayList to store the filtered data such as,
ArrayList<CompanySearchResult> filtered = new ArrayList<CompanySearchResult>();
for (CompanySearchResult town : tempList) {
if (town.getTownName().equals(name)) {
filtered.add(town);
}
}
tempList.clear();
tempList.addAll(filtered);
listAdapter.notifyDataSetChanged();
The data is getting filtered properly, but my issue here is when I filter the data for the first time, my tempList(which is the main ArrayList containing the data) gets updated by the contents of the filtered ArrayList.
Then when I click on the second button with another town name and try to filter that, it tries to filter the tempList which is already updated with the filtered data and the result displayed is blank.
Thus, how can I populate my tempList with the original data again each time a button with the town name is being clicked and then filter it out in a similar manner.
I have researched on this but couldn't find anything relevant. I have also tried the solution mentioned in the link:
android filter custom array adapter and bring back old items again
How can i take a backup of an ArrayList in Java after i call .clear()?
However, it didn't help. can anyone please help on how can I achieve this?
#Traxdata answer is correct. Here is my explain in code
Modify your adapter like
public class YourAdapter extends RecyclerView.Adapter {
YourAdapter(List<CompanySearchResult> filterList){
}
}
In your Activity
YourAdapter listAdapter = new YourAdapter(filterList);
At first time you display the list
filterList = new ArrayList<>(tempList);
listAdapter.notifyDataSetChanged();
When you filter
ArrayList < CompanySearchResult > filtered = new ArrayList < CompanySearchResult > ();
for (CompanySearchResult town: tempList) {
if (town.getTownName().equals(name)) {
filtered.add(town);
}
}
filterList.clear();
filterList.addAll(filtered);
listAdapter.notifyDataSetChanged();
You need to store the original set of items in the adapter as a backup list.
The adapter should always only display the contents of the filtered list.
If you add data to the adapter, add them to the backup and filtered list.
When you click a button, clear the filtered list and then add only the matching items from the backup list to the filtered list.
public class SomeAdapter extends RecyclerView.Adapter<SomeAdapter.SomeViewHodler> {
static class SomeViewHodler extends RecyclerView.ViewHolder {
public SomeViewHodler(final View itemView) {
super(itemView);
}
void bind(String data) {
// FIll views here
}
}
private final List<String> displayedList = new ArrayList<>();
private final List<String> originalList = new ArrayList<>();
private String filterString = "";
#Override
public int getItemCount() {
return displayedList.size();
}
#Override
public void onBindViewHolder(final SomeViewHodler holder, final int position) {
holder.bind(displayedList.get(position));
}
#Override
public SomeViewHodler onCreateViewHolder(final ViewGroup parent, final int viewType) {
View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.view, parent, false);
return new SomeViewHodler(view);
}
/**
* Call from outside to send data into this adapter
*/
public void replaceData(#NonNull final List<String> data) {
// Store new data in original list
originalList.clear();
originalList.addAll(data);
filter();
notifyDataSetChanged();
}
private void filter() {
// Clear display first
displayedList.clear();
// If filter is empty, show all items
if (filterString == null || filterString.isEmpty()) {
displayedList.addAll(originalList);
} else {
// if filter is not empty, check if item matches query
for (String obj : originalList) {
if (obj.contains(filterString)) {
displayedList.add(obj);
}
}
}
}
}
Create one more list(eg.mainList) where you created tempList and put tempList into that like this
mainList.addAll(tempList)
and then update this method like this
ArrayList<CompanySearchResult> filtered = new ArrayList<CompanySearchResult>();
for (CompanySearchResult town : mainList) {
if (town.getTownName().equals(name)) {
filtered.add(town);
}
}
tempList.clear();
tempList.addAll(filtered);
listAdapter.notifyDataSetChanged();

RecyclerView item style applying to all items after filter

I'm having a little problem with a RecyclerView.
On the method OnBindViewHolder of it's Adapter I'm making a test, to define or not if the item of the RecyclerView should use a custom background color.
Up to this point everything is working fine, the problem is, after using a filter with a SearchView if I filter the one result with the custom background color, after cleaning the filter/collapse the SearchView, all other items are getting the same background color.
Here is some code from my adapter:
#Override
public void onBindViewHolder (MyAdapter.VieHolder holder, int position){
holder.textViewName.setText(myVisibleList.get(position).getName());
// myVisibleList is the list that is show in the recyclerView
// If true, is birthday, then change the item background color
if(myVisibleList.get(position).isBirthDay){
holder.layout.setBackgroundResource(R.drawable.recycler_view_selector_colored_item);
}
}
#Override
public Filter getFilter(){return null;}
public void setFilter(String query){
myVisibleList = new ArrayList<>();
// Contact is the object show in the recyclerView / allContacts is the list if all the contacts
for (Contact c : allContacts){
if(c.getName().contains(query)){
myVisibleList.add(c);
}
}
notifyDataSetChanged();
}
// Method to clear the filter / Called when the searchView is closed
public void clearFilter(){
myVisibleList = new ArrayList<>();
myVisibleList.addAll(allContacts);
notifyDataSetChanged
}
I think that you need to add an else clause here:
if (myVisibleList.get(position).isBirthDay){
holder.layout.setBackgroundResource(R.drawable.recycler_view_selector_colored_item);
} else {
holder.layout.setBackgroundResource(R.drawable.my_default_recycler_view_color_item);
// or holder.layout.setBackgroundResource(0);
}
See docs where it says that
0 [is] to remove the background
Hope this helps...

Comments Listview in Android

I have an Activity which contains different items, one of those item is ListView.
I created a custom list adapter and sending to it a json array.
The data for the list arrives from the server.
The list purpose is to make comments list. I allowed the user to insert
a comment and then I show it in the ListView.
When I have some items in the list it works, and the items are shown.
The problem is when listview is empty and the user post a comment.
I see that that data is changed but I don't see the item, means the list is not refreshed..
So I tried to add to the listview an empty view but it doesn't work.
Here is an updated code: (UPDATE)
if (!s.isEmpty() && !s.equals("{}")) {
try {
if (commentsListAdapter == null) {
commentsList.setEmptyView(findViewById(R.id.dummy));
commentsListAdapter = new CommentsListAdapter(PostView.this);
}
JSONObject resObj = new JSONObject(s);
list.add(resObj);
commentsListAdapter.setDataSet(list);
cmntTxt.setText("");
inputManager.hideSoftInputFromWindow(getCurrentFocus().getWindowToken(),
InputMethodManager.HIDE_NOT_ALWAYS);
commentCounter.setText(Integer.toString(list.size()));
} catch (JSONException e) {
e.printStackTrace();
}
}
And inside the Adapter I have this function:
public void setDataSet(List<JSONObject> list){
commentsList = list;
notifyDataSetChanged();
}
But the problem is not fixed..
I notice the code list.add(resObj) appears after new CommentsListAdapter when the list is empty and appears before new CommentsListAdapter when the list is NOT empty.
I suspect the Adapter CommentsListAdapter is not using the object list for the data storage. In that case, you need to make a public method in the adapter to make updates. Another words, the adapter is using another object for data storage.
It may help to post the code for CommentsListAdapter also. But I hope I am correct about my statements.
I hope that is clear...
Please change the following code:
public void setDataSet(List<JSONObject> list){
commentsList = list;
notifyDataSetChanged();
}
to :
private List<JSONObject> commentsList = new ArrayList<>();
public void setDataSet(List<JSONObject> list){
commentsList.clear();
commentsList.addAll(list);
notifyDataSetChanged();
}
And use commentsList for all other methods in your adapter. This is a better way for notifyDataSetChanged() to work.
Hope it helps! :)
if you are adding your comment from the outside i.e from activity and not from adapter than whenever you set the adapter do this.
youradapterobject.notifyDataSetChanged();
and dont do commentsListAdapter == null than setemptyview
it automatically sets the emptyview if its null
correct usage
list.setEmptyView(findViewById(R.id.erromsg));

Categories

Resources