SearchView not updating items, only text - java

I'm using SearchView to filter music items. But when I search for an item the title of the song updates but not the actual song. Originally I had listSongs = musicFiles which worked but didn't update the items only the title. Then I changed it to listSongs = mFiles, which throws a nullPointerException.
MusicAdapter
public class MusicAdapter extends RecyclerView.Adapter<MusicAdapter.MyVieHolder> {
private Context mContext;
static ArrayList<MusicFiles> mFiles = new ArrayList<>();
MusicAdapter(Context mContext, ArrayList<MusicFiles> mFiles){
MusicAdapter.mFiles = mFiles;
this.mContext = mContext;
}
#NonNull
#Override
public MyVieHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(mContext).inflate(R.layout.music_items, parent, false);
return new MyVieHolder(view);
}
#Override
public void onBindViewHolder(#NonNull MyVieHolder holder, final int position) {
holder.file_name.setText(mFiles.get(position).getTitle());
byte[] image = getAlbumArt(mFiles.get(position).getPath());
if (image != null){
Glide.with(mContext).asBitmap()
.load(image)
.into(holder.album_art);
}
else{
Glide.with(mContext).asBitmap()
.load(R.drawable.something_3)
.into(holder.album_art);
}
holder.itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent intent = new Intent(mContext, MainActivity.class);
intent.putExtra("position" , position);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
mContext.startActivity(intent);
notifyDataSetChanged();
}
});
}
#Override
public int getItemCount() {
return mFiles.size();
}
public class MyVieHolder extends RecyclerView.ViewHolder{
TextView file_name;
ImageView album_art;
public MyVieHolder(#NonNull View itemView) {
super(itemView);
file_name = itemView.findViewById(R.id.music_file_name);
album_art = itemView.findViewById(R.id.music_img);
}
}
private byte[] getAlbumArt(String uri){
MediaMetadataRetriever retriever = new MediaMetadataRetriever();
retriever.setDataSource(uri);
byte[] art = retriever.getEmbeddedPicture();
retriever.release();
return art;
}
public void updateList(ArrayList<MusicFiles> musicFilesArrayList){
mFiles = new ArrayList<>();
mFiles.addAll(musicFilesArrayList);
notifyDataSetChanged();
}
MainActivity
This is the code I'm having trouble with
public void getInentMethod() {
position = getIntent().getIntExtra("position", 0);
listSongs = mFiles; //bug occurs when listSongs = mFiles
if (listSongs != null) {
playBtn.setBackgroundResource(R.drawable.ic_pause);
uri = Uri.parse(listSongs.get(position).getPath());
}
if (mediaPlayer != null) {
mediaPlayer.stop();
mediaPlayer.release();
mediaPlayer = MediaPlayer.create(getApplicationContext(), uri);
mediaPlayer.start();
}
else {
mediaPlayer = MediaPlayer.create(getApplicationContext(), uri);
playBtn.setBackgroundResource(R.drawable.ic_play);
mediaPlayer.stop();
}
seekBar.setMax(mediaPlayer.getDuration()/1000);
metaData(uri);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.search, menu);
MenuItem menuItem = menu.findItem(R.id.search_option);
SearchView searchView = (SearchView) menuItem.getActionView();
searchView.setOnQueryTextListener(this);
return super.onCreateOptionsMenu(menu);
}
#Override
public boolean onQueryTextSubmit (String query){
return false;
}
#Override
public boolean onQueryTextChange (String newText){
String userInput = newText.toLowerCase();
ArrayList<MusicFiles> musicFilesArrayList = new ArrayList<>();
for (MusicFiles mFiles : musicFiles){
if(mFiles.getTitle().toLowerCase().contains(userInput)){
musicFilesArrayList.add(mFiles);
}
}
musicAdapter.updateList(musicFilesArrayList);
return true;
}
When listSongs = mFiles I receive a nullPointerException, uri param cannot be null. I don't know what's causing this?
I'm also receiving an IndexOutOfBoundsException.
Caused by: java.lang.IndexOutOfBoundsException: Index: 0, Size: 0.
Any help will be appreciated.

<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="#+id/search_bar"
android:title="search"
android:icon="#drawable/ic_baseline_search_24"
app:showAsAction="always|collapseActionView"
app:actionViewClass="android.widget.SearchView" />
</menu>
Inside onCreateOptionsMenu
getMenuInflater().inflate(R.menu.main_menu,menu);
MenuItem searchItem=menu.findItem(R.id.search_bar);
MenuItem settingsItem=menu.findItem(R.id.action_settings);
SearchView searchView= (SearchView) searchItem.getActionView();
searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
#Override
public boolean onQueryTextSubmit(String query) {
return false;
}
#Override
public boolean onQueryTextChange(String newText) {
//do filter here
adapter.getFilter().filter(newText);
return false;
}
});
return true;
}
#Override
public boolean onOptionsItemSelected(#NonNull MenuItem item) {
if (item.getItemId()==R.id.search_bar) return true;
return super.onOptionsItemSelected(item);
}
In the Adapter class, create two arraylists
class Adapter implements Filterable{
private List<TotalItems> totalItems; //original
private List<TotalItems> totalItemsAll; //copy
Context context;
public Adapter(ArrayList<TotalItems> totalItems,Context context){
this.totalItems=totalItems;
this.context=context;
this.totalItemsAll=new ArrayList<>(totalItems);
}
#Override
public Filter getFilter() {
return filter;
}
private Filter filter=new Filter() {
#Override
protected FilterResults performFiltering(CharSequence charSequence) {
//TotalItems is my model class
List<TotalItems> filteredList=new ArrayList<>();
if (charSequence==null||charSequence.length()==0)
filteredList.addAll(totalItemsAll);
else {
String filterPattern=charSequence.toString().toLowerCase().trim();
for (TotalItems productList:totalItemsAll){
if (productList.getiName().toLowerCase().contains(filterPattern)){
filteredList.add(productList);
}else Toast.makeText(context,"No results found",Toast.LENGTH_LONG).show();
}
}
FilterResults filterResults=new FilterResults();
filterResults.values=filteredList;
return filterResults;
}
#Override
protected void publishResults(CharSequence charSequence, FilterResults filterResults) {
totalItems.clear();
totalItems.addAll((List)filterResults.values);
notifyDataSetChanged();
}
};
}
Let me know if this works for you

Related

Expand Recyclerview on Search

I nearly achieved what I wanted but 1 thing is still missing. I have a recyclerview and each item has it's own recyclerview. But in the beginning, every item's own recyclerview isn't shown. It expands as soon as you press the button.
But I also want to expand it, when I start filtering the recyclerview using the Searchbar.
That's my Adapter:
public class SchrankAdapter extends RecyclerView.Adapter<SchrankAdapter.ViewHolder> implements Filterable {
private Context context;
ArrayList<CategoryName> categoryTopic = new ArrayList<>();
ArrayList<CategoryName> categoryTopicFull;
public SchrankAdapter(Context context, ArrayList<CategoryName> categoryTopic){
this.context = context;
this.categoryTopic = categoryTopic;
categoryTopicFull = new ArrayList<>(categoryTopic);
}
#NonNull
#Override
public ViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_schrank, parent, false);
return new ViewHolder(view);
}
#Override
public void onBindViewHolder(#NonNull ViewHolder holder, int position) {
CategoryName parentItem = categoryTopic.get(position);
holder.categoryName.setText(parentItem.categoryName);
setCatItemRecycler(holder.childRecView, categoryTopic.get(position).getChildViewList());
holder.btFolderPlus.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
holder.btFolderMinus.setVisibility(View.VISIBLE);
holder.childView.setVisibility(View.VISIBLE);
holder.btFolderPlus.setVisibility(View.GONE);
}
});
holder.btFolderMinus.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
holder.btFolderPlus.setVisibility(View.VISIBLE);
holder.btFolderMinus.setVisibility(View.GONE);
holder.childView.setVisibility(View.GONE);
}
});
}
#Override
public int getItemCount() {
return categoryTopic.size();
}
private void setCatItemRecycler(RecyclerView recyclerView, ArrayList<CategoryChild> categoryChildrenList) {
SchrankChildAdapter childAdapter = new SchrankChildAdapter(context, categoryChildrenList);
recyclerView.setLayoutManager(new LinearLayoutManager(context));
recyclerView.setAdapter(childAdapter);
}
#Override
public Filter getFilter() {
return filter;
}
private Filter filter = new Filter() {
#Override
protected FilterResults performFiltering(CharSequence constraint) {
ArrayList<CategoryName> filteredList = new ArrayList<>();
ArrayList<CategoryChild> filteredSubList = new ArrayList<>();
boolean containsSubItems = false;
if(constraint == null || constraint.length() == 0) {
filteredList.addAll(categoryTopicFull);
} else {
String filterPattern = constraint.toString().toLowerCase().trim();
for (CategoryName item: categoryTopicFull) {
for(CategoryChild subItem: item.getChildViewList()) {
if(subItem.getCategoryAttribute().toLowerCase().contains(filterPattern)) {
filteredSubList.add(subItem);
containsSubItems = true;
}
}
if(containsSubItems) {
filteredList.add(new CategoryName(item.getCategoryName(), filteredSubList));
containsSubItems = false;
filteredSubList = new ArrayList<>();
}
}
}
FilterResults results = new FilterResults();
results.values = filteredList;
return results;
}
#Override
protected void publishResults(CharSequence constraint, FilterResults results) {
categoryTopic.clear();
categoryTopic.addAll((ArrayList) results.values);
notifyDataSetChanged();
}
};
public class ViewHolder extends RecyclerView.ViewHolder{
TextView categoryName;
RelativeLayout childView;
RecyclerView childRecView;
Button btFolderPlus, btFolderMinus;
public ViewHolder(#NonNull View itemView) {
super(itemView);
categoryName = itemView.findViewById(R.id.categoryName);
childView = itemView.findViewById(R.id.childView);
childRecView = itemView.findViewById(R.id.childRecView);
btFolderPlus = itemView.findViewById(R.id.btFolderPlus);
btFolderMinus = itemView.findViewById(R.id.btFolderMinus);
}
}
}
That's my SearchView in the activity:
SearchView searchView = findViewById(R.id.searchView);
searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
#Override
public boolean onQueryTextSubmit(String query) {
return false;
}
#Override
public boolean onQueryTextChange(String newText) {
schrankAdapter.getFilter().filter(newText);
return false;
}
});
The variable childView is responsible for the subItems. I want to set it's Visibility to VISIBLE whenever I enter something in the searchbar.
It's all working, I just want to improve my current program.
UPDATE:
Ok, I found a solution for my problem.
I created a boolean which is set to false from the beginning.
I added this code to onBindViewHolder method:
if(isSearching) {
holder.btFolderMinus.setVisibility(View.VISIBLE);
holder.childView.setVisibility(View.VISIBLE);
holder.btFolderPlus.setVisibility(View.GONE);
}
else if(!isSearching) {
holder.btFolderPlus.setVisibility(View.VISIBLE);
holder.btFolderMinus.setVisibility(View.GONE);
holder.childView.setVisibility(View.GONE);
}
And I edited my Filter:
private Filter filter = new Filter() {
#Override
protected FilterResults performFiltering(CharSequence constraint) {
ArrayList<CategoryName> filteredList = new ArrayList<>();
ArrayList<CategoryChild> filteredSubList = new ArrayList<>();
boolean containsSubItems = false;
if(constraint == null || constraint.length() == 0) {
filteredList.addAll(categoryTopicFull);
isSearching = false;
} else {
String filterPattern = constraint.toString().toLowerCase().trim();
for (CategoryName item: categoryTopicFull) {
for(CategoryChild subItem: item.getChildViewList()) {
if(subItem.getCategoryAttribute().toLowerCase().contains(filterPattern)) {
filteredSubList.add(subItem);
containsSubItems = true;
}
}
if(containsSubItems) {
filteredList.add(new CategoryName(item.getCategoryName(), filteredSubList));
containsSubItems = false;
filteredSubList = new ArrayList<>();
}
}
isSearching = true;
}
FilterResults results = new FilterResults();
results.values = filteredList;
return results;
}
Maybe someone will search for this solution one-day.

java.lang.NullPointerException: Attempt to invoke interface method 'java.util.Iterator java.util.List.iterator()' on a null object reference

I m currently working on a android apps which fetch data from parse server. I wanted to filter my recyclerView by using searchview. But it shows me nothing while search. It gives me error in this line*for (ParseObject parseObject : mRooms){ * Please help me to edit my code regarding this issues.
roomcardrecyclerviewadapter
private List<ParseObject> mRooms = new ArrayList<>();
private ArrayList<ParseObject> filterlist;
private ParseObject room;
private String mSection;
private Context context;
public RoomCardRecyclerViewAdapter(){
super(DIFF_CALLBACK);
}
public static final DiffUtil.ItemCallback<ParseObject> DIFF_CALLBACK = new
DiffUtil.ItemCallback<ParseObject>() {
#Override
public boolean areItemsTheSame(#NonNull ParseObject oldItem, #NonNull ParseObject newItem) {
return oldItem.getObjectId() == newItem.getObjectId();
}
#Override
public boolean areContentsTheSame(#NonNull ParseObject oldItem, #NonNull ParseObject newItem) {
return (oldItem.getUpdatedAt().equals(newItem.getUpdatedAt()) &&
oldItem.getCreatedAt().equals(newItem.getCreatedAt()));
}
};
public RoomCardRecyclerViewAdapter(String section) {
this();
this.mSection = section;
}
public RoomCardRecyclerViewAdapter(Context context, List<ParseObject>arrayList) {
this();
this.context = context;
mRooms = arrayList;
filterlist = (ArrayList<ParseObject>) arrayList;
}
public class RoomViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener{
protected ImageView mRoomImage;
protected TextView mRoomPrice;
protected TextView mInclusiveOrNot;
protected TextView mPropertyType;
protected TextView mNumOfBeds;
protected TextView mNumOfBaths;
protected TextView mRoomLocation;
private Context context;
public RoomViewHolder(Context context, View itemView) {
super(itemView);
mRoomImage = itemView.findViewById(R.id.room_image);
mRoomPrice = itemView.findViewById(R.id.price_label);
mInclusiveOrNot = itemView.findViewById(R.id.incl_excl_label);
mPropertyType = itemView.findViewById(R.id.propertyType_label);
mNumOfBeds = itemView.findViewById(R.id.num_beds_label);
mNumOfBaths = itemView.findViewById(R.id.details_num_baths_label);
mRoomLocation = itemView.findViewById(R.id.location_label);
this.context = context;
//set onclick listener
itemView.setOnClickListener(this);
}
#Override
public void onClick(View v) {
Log.i("Click event: ", "My room has been clicked.");
int pos = getAdapterPosition();
Intent intent;
ParseObject room = getCurrentList().get(pos);
//create the ParseObject proxy
ParseProxyObject roomProxy = new ParseProxyObject(room);
Toast.makeText(context, room.getString("roomSuburb"), Toast.LENGTH_LONG).show();
//fork to corresponding activity
if(mSection != null) {
Log.i("mSection text: ", "mSection text is: " + mSection);
if (mSection.equals("My Rooms")) {
//start my rooms detail activity
Log.i("My room: ", "Room selected " + roomProxy.getObjectId());
intent = new Intent(context, MyRoomDetailActivity.class);
//add the room to the intent
intent.putExtra("currentSelectedRoomObject", room);
Log.i("Selected room", "Put Extra, " + room);
intent.putExtra("roomObject", roomProxy);
context.startActivity(intent);
}
}else {
Log.i("My room:", "RoomDetailActivity loaded for MyRoomDetail Activity instead");
intent = new Intent(context, RoomDetailActivity.class);
//add the proxy to the intent
intent.putExtra("roomObject", roomProxy);
context.startActivity(intent);
}
}
}
#Override
public RoomViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
//inflating the viewholder with the appropriate views
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.room_cardview, parent,
false);
return new RoomViewHolder(parent.getContext(), view);
}
#Override
public void onBindViewHolder(#NonNull RoomViewHolder holder, int position) {
room = getItem(position);
holder.mRoomLocation.setText(room.getString("roomSuburb"));
holder.mRoomPrice.setText(Integer.toString(room.getInt("roomMonthlyRent")));
holder.mInclusiveOrNot.setText(room.getString("roomRentInclusiveOfBills"));
holder.mPropertyType.setText(room.getString("roomPropertyType"));
holder.mNumOfBeds.setText(Integer.toString(room.getInt("roomBedrooms")));
holder.mNumOfBaths.setText(Integer.toString(room.getInt("roomBathrooms")));
#Override
public Filter getFilter(){
return new Filter() {
#Override
protected FilterResults performFiltering(CharSequence charSequence) {
String charString = charSequence.toString();
if (charString.isEmpty()){
room = (ParseObject) mRooms;
}else {
List<ParseObject> filteredList = new ArrayList<>();
for (ParseObject parseObject : mRooms){
if (parseObject.getString("roomSuburb").toLowerCase().contains(charString.toLowerCase())){
filteredList.add(parseObject);
}
}
room = (ParseObject) filteredList;
}
FilterResults filterResults = new FilterResults();
filterResults.values = room;
return filterResults;
}
#Override
protected void publishResults(CharSequence charSequence, FilterResults filterResults) {
room = (ParseObject) filterResults.values;
notifyDataSetChanged();
}
};
}
mainActivity
mHomeSectionsPagerAdapter = new
HomeSectionsPagerAdapter(getSupportFragmentManager());
roomCardRecyclerViewAdapter = new RoomCardRecyclerViewAdapter(this,
mRooms);
mRooms = new ArrayList<>();
// Set up the ViewPager with the sections adapter.
mViewPager = findViewById(R.id.container);
mViewPager.setAdapter(mHomeSectionsPagerAdapter);
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_main, menu);
final ParseQuery<ParseUser> query = ParseUser.getQuery();
//get the search view and set the searchable configuration
SearchManager searchManager = (SearchManager)
getSystemService(Context.SEARCH_SERVICE);
MenuItem item = menu.findItem(R.id.search);
SearchView searchView = (SearchView) MenuItemCompat.getActionView(item);
//assumes the current activity is the searchable activity
searchView.setSearchableInfo(searchManager.getSearchableInfo
(getComponentName());
searchView.setSubmitButtonEnabled(true);
searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
#Override
public boolean onQueryTextSubmit(String query) {
roomCardRecyclerViewAdapter.getFilter().filter(query);
return false;
}
#Override
public boolean onQueryTextChange(String newText) {
roomCardRecyclerViewAdapter.getFilter().filter(newText);
return false;
}
});
return true;
}
#Override
public boolean onSearchRequested() {
//pauseSomeStuff();
//roomCardRecyclerViewAdapter.getFilter().filter(query);
return super.onSearchRequested();
}
I think problem is here:
You haven't shared first lines of MainActivity where you declare your variables. So, I assume that you have some code like this:
List mRooms;
Then I assume that, before assigning value to this mRooms you have passed it to RoomCardRecyclerViewAdapter:
roomCardRecyclerViewAdapter = new RoomCardRecyclerViewAdapter(this, mRooms);
mRooms = new ArrayList<>();
Then you have assigned value to mRooms. That's why you get NPE. You can solve this problem just like this:
mRooms = new ArrayList<>();
roomCardRecyclerViewAdapter = new RoomCardRecyclerViewAdapter(this, mRooms);

Android Searchview filter recyclerview volley implementation

i am implementing search filter using search view i loaded list
successfully and when i clicked on searchview and type word
application crash below is error is Here's the code :
public class MainActivity extends AppCompatActivity
implements NavigationView.OnNavigationItemSelectedListener {
// private static final String url = "http://example.com/OnlineDoctor/mobileapp/doctors_list.php?";
private List<ListItems> listItemses;
private RecyclerView recyclerView;
private MainFilteredAdapter mrecyclerViewAdapter;
private LinearLayoutManager linearLayoutManager;
private static final String TAG = MainActivity.class.getSimpleName();
private RelativeLayout ownerlayout;
private SearchView searchView;
private String logintype, property_id;
private String userid;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
recyclerView = findViewById(R.id.recyclerview);
listItemses = new ArrayList<>();
mrecyclerViewAdapter = new
MainFilteredAdapter(listItemses,getApplicationContext());
linearLayoutManager = new LinearLayoutManager(this);
recyclerView.setLayoutManager(linearLayoutManager);
recyclerView.setItemAnimator(new DefaultItemAnimator());
recyclerView.setAdapter(mrecyclerViewAdapter);
loadRenterList();
}
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
SearchManager searchManager = (SearchManager) getSystemService(Context.SEARCH_SERVICE);
searchView = (SearchView) menu.findItem(R.id.action_search)
.getActionView();
searchView.setSearchableInfo(searchManager
.getSearchableInfo(getComponentName()));
searchView.setMaxWidth(Integer.MAX_VALUE);
searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
#Override
public boolean onQueryTextSubmit(String query) {
mrecyclerViewAdapter.getFilter().filter(query);
return false;
}
#Override
public boolean onQueryTextChange(String query) {
mrecyclerViewAdapter.getFilter().filter(query);
return false;
}
});
return true;
}
public void loadRenterList() {
JsonObjectRequest jsonObjReq = new JsonObjectRequest(Request.Method.GET,
url, null,
new Response.Listener<JSONObject>() {
#Override
public void onResponse(JSONObject response) {
JSONArray jsonArray = null;
JSONObject jsonObject = null;
try {
jsonArray = response.getJSONArray("data");
for (int i = 0; i < jsonArray.length(); i++) {
JSONObject mjsonObject = (JSONObject) jsonArray.get(i);
ListItems newslist = new ListItems();
newslist.setId(mjsonObject.getString("id"));
listItemses.add(newslist);
mrecyclerViewAdapter.notifyDataSetChanged();
}
} catch (JSONException e) {
e.printStackTrace();
Toast.makeText(getApplicationContext(),
"Error: " + e.getMessage(),
Toast.LENGTH_LONG).show();
}
}
// adapter.notifyDataSetChanged();
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
VolleyLog.d(TAG, "Error: " + error.getMessage());
}
});
AppController.getInstance().addToRequestQueue(jsonObjReq);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
SearchManager searchManager = (SearchManager) getSystemService(Context.SEARCH_SERVICE);
searchView = (SearchView) menu.findItem(R.id.action_search)
.getActionView();
searchView.setSearchableInfo(searchManager
.getSearchableInfo(getComponentName()));
searchView.setMaxWidth(Integer.MAX_VALUE);
searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
#Override
public boolean onQueryTextSubmit(String query) {
mrecyclerViewAdapter.getFilter().filter(query);
return false;
}
#Override
public boolean onQueryTextChange(String query) {
mrecyclerViewAdapter.getFilter().filter(query);
return false;
}
});
return true;
}
public class MainFilteredAdapter extends RecyclerView.Adapter<MainFilteredAdapter.MyViewHolder> implements Filterable {
private List<ListItems> doctorlist;
private List<ListItems> doctorlistFiltered;
Context context;
public class MyViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener{
public TextView spec_name,placeName,property_status;
public ImageView imageView;
LinearLayout lllistrow;
public MyViewHolder(View itemView) {
super(itemView);
property_status = itemView.findViewById(R.id.duration);
spec_name = itemView.findViewById(R.id.spec_name);
placeName = itemView.findViewById(R.id.placeName);
imageView = itemView.findViewById(R.id.placeImage);
lllistrow= itemView.findViewById(R.id.mainHolder);
lllistrow.setOnClickListener(this);
}
#Override
public void onClick(View v) {
int position = getLayoutPosition();
switch (v.getId()) {
case R.id.mainHolder:
break;
}
}
}
public MainFilteredAdapter(List<ListItems> boardList, Context context) {
this.doctorlist = boardList;
this.doctorlistFiltered=boardList;
this.context = context;
}
#Override
public MainFilteredAdapter.MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View itemView = LayoutInflater.from(parent.getContext())
.inflate(R.layout.listitem, parent, false);
return new MainFilteredAdapter.MyViewHolder(itemView);
}
#Override
public void onBindViewHolder(MainFilteredAdapter.MyViewHolder holder, int position) {
ListItems listItems = doctorlistFiltered.get(position);
/*Picasso.with(context).load("http://neweraprime.com/SFDS/faculty/Upload/Books/" + newslist.get(position).getThumbnailUrl())
.placeholder(R.drawable.ic_pdffile).error(R.drawable.ic_pdffile).resize(256, 256).onlyScaleDown() //Url of the image to load.
.into(holder.thumbNail);*/
holder.property_status.setText(listItems.getPayment_status());
holder.spec_name.setText(listItems.getAddress());
holder.placeName.setText(listItems.getTitle());
}
#Override
public Filter getFilter()
{
return new Filter() {
#Override
protected FilterResults performFiltering(CharSequence charSequence) {
String charString = charSequence.toString();
if (charString.isEmpty()) {
doctorlistFiltered = doctorlist;
} else {
List<ListItems> filteredList = new ArrayList<>();
for (ListItems row : doctorlist) {
// name match condition. this might differ depending on your requirement
// here we are looking for name or phone number match
if (row.getCity().toLowerCase().contains(charString.toLowerCase()) || row.getAddress().contains(charSequence)) {
filteredList.add(row);
}
}
doctorlistFiltered = filteredList;
}
FilterResults filterResults = new FilterResults();
filterResults.values = doctorlistFiltered;
return filterResults;
}
#Override
protected void publishResults(CharSequence charSequence, FilterResults filterResults) {
doctorlistFiltered = (ArrayList<ListItems>) filterResults.values;
notifyDataSetChanged();
}
};
}
#Override
public int getItemCount() {
if(doctorlist != null){
return doctorlistFiltered.size();
} else {
return 0;
}
}
and here is the error
java.lang.NullPointerException: Attempt to invoke interface method 'int java.util.List.size()' on a null object reference
at com.www.homerent.MainFilteredAdapter.getItemCount(MainFilteredAdapter.java:129)
at androidx.recyclerview.widget.RecyclerView.dispatchLayoutStep1(RecyclerView.java:4025)
at androidx.recyclerview.widget.RecyclerView.dispatchLayout(RecyclerView.java:3830)
at androidx.recyclerview.widget.RecyclerView.onLayout(RecyclerView.java:4385)
at android.view.View.layout(View.java:19659)
at android.view.ViewGroup.layout(ViewGroup.java:6075)
at android.widget.RelativeLayout.onLayout(RelativeLayout.java:1083)
at android.view.View.layout(View.java:19659)
at android.view.ViewGroup.layout(ViewGroup.java:6075)
I'd suspect your problem is here:
#Override
protected void publishResults(CharSequence charSequence, FilterResults filterResults) {
doctorlistFiltered = (ArrayList<ListItems>) filterResults.values;
notifyDataSetChanged();
}
Try using this instead:
#Override
protected void publishResults(CharSequence charSequence, FilterResults filterResults) {
doctorlistFiltered = new ArrayList<ListItems>();
if (filterResults.values != null) {
doctorlistFiltered.addAll((ArrayList<ListItems>) filterResults.values);
}
notifyDataSetChanged();
}
I haven't seen anything that guarantees that filterResults.values does contain a non null value(e.g. in case of an error during filtering).
Ps.:
Adjusting the getItemCount() as metionend in the comments should be a given.

A Search doesn't update my RecyclerView

I'm currently developing an Android application which can either load information from my website or use the information stored in an SQLite database. I'm trying to implement a search feature into it but I ran into a problem.
The data in my recyclerview doesn't update when a search is made. I've looked it up on Google many times but I still haven't found a solution. Is there a bright person here willing to help me?
MainActivity.java
public class MainActivity extends AppCompatActivity implements DienstAdapter.ListItemClickListener, NavigationView.OnNavigationItemSelectedListener {
private static final String DIENST_URL = "https://mywebsite.com/apps/test/dienstenapi.php";
private RecyclerView recyclerView;
private DienstAdapter adapter;
private List<Dienst> dienstList;
private SQLiteDatabase mDb;
private Cursor cursor;
private SharedPreferences sharedPreferences;
private NavigationView navigationView;
private View headerView;
private TextView gebruikersnaam;
private Resources res;
private SwipeRefreshLayout swiper;
private static Toast mToast = null;
private SearchView searchView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
ActionBar actionBar = this.getSupportActionBar();
if (actionBar != null) {
actionBar.setTitle(R.string.app_name);
}
DrawerLayout drawer = findViewById(R.id.drawer_layout);
ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(
this, drawer, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close);
drawer.addDrawerListener(toggle);
toggle.syncState();
navigationView = findViewById(R.id.nav_view);
navigationView.setNavigationItemSelectedListener(this);
headerView = navigationView.getHeaderView(0);
gebruikersnaam = headerView.findViewById(R.id.gebruikersnaam);
res = getResources();
sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this);
sharedPreferences.registerOnSharedPreferenceChangeListener(sharedPreferenceChangeListener);
setupPreferenceGebruikersnaam();
swiper = findViewById(R.id.swiper);
swiper.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
#Override
public void onRefresh() {
dienstList.clear();
loadDiensten();
}
});
dienstList = new ArrayList<>();
recyclerView = findViewById(R.id.recyclerView);
recyclerView.setHasFixedSize(true);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
DienstDbHelper dbHelper = new DienstDbHelper(this);
mDb = dbHelper.getWritableDatabase();
loadDiensten();
}
#Override
protected void onDestroy() {
sharedPreferences.unregisterOnSharedPreferenceChangeListener(sharedPreferenceChangeListener);
super.onDestroy();
}
SharedPreferences.OnSharedPreferenceChangeListener sharedPreferenceChangeListener = new SharedPreferences.OnSharedPreferenceChangeListener() {
#Override
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
if (key.equals("example_text")){
setupPreferenceGebruikersnaam();
}
}
};
private void loadDienstenOnline() {
String moetInfoOphalen = sharedPreferences.getString("example_list", "1");
if (moetInfoOphalen.equals("1") || moetInfoOphalen.equals("0")) {
StringRequest stringRequest = new StringRequest(Request.Method.GET, DIENST_URL, new Response.Listener<String>() {
#Override
public void onResponse(String response) {
try {
JSONArray diensten = new JSONArray(response);
for (int i = 0; i < diensten.length(); i++) {
JSONObject dienstObject = diensten.getJSONObject(i);
int id = dienstObject.getInt("id");
String naam = dienstObject.getString("naam");
String beschrijving = dienstObject.getString("beschrijving");
String categorie = dienstObject.getString("categorie");
double prijs = dienstObject.getDouble("prijs");
String afbeelding = dienstObject.getString("afbeelding");
dienstList.add(new Dienst(id, naam, beschrijving, categorie, prijs, afbeelding));
}
voegDienstenToeAanDb(mDb, dienstList);
adapter = new DienstAdapter(MainActivity.this, dienstList, MainActivity.this);
recyclerView.setAdapter(adapter);
} catch (JSONException e) {
e.printStackTrace();
}
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
Toast.makeText(MainActivity.this, error.getMessage(), Toast.LENGTH_LONG).show();
}
});
Volley.newRequestQueue(this).add(stringRequest);
} else {
loadDienstenOffline();
Toast.makeText(MainActivity.this, R.string.instelling_blokkeert_ophalen_diensten, Toast.LENGTH_LONG).show();
}
}
private void loadDienstenOffline() {
cursor = getAlleDiensten();
if ((cursor != null) && (cursor.getCount() > 0)) {
omzettenCursorNaarDiensten(cursor);
adapter = new DienstAdapter(MainActivity.this, dienstList, MainActivity.this);
recyclerView.setAdapter(adapter);
} else {
dienstList.add(new Dienst(0, "", "", "", 0, ""));
adapter = new DienstAdapter(MainActivity.this, dienstList, MainActivity.this);
recyclerView.setAdapter(adapter);
recyclerView.setVisibility(View.GONE);
if (mToast != null)
mToast.cancel();
mToast.makeText(this, R.string.internet_werkt_niet, Toast.LENGTH_LONG).show();
}
}
private boolean internetIsBeschikbaar() {
ConnectivityManager cm =(ConnectivityManager) this.getSystemService(CONNECTIVITY_SERVICE);
assert cm != null;
NetworkInfo activeNetwork = cm.getActiveNetworkInfo();
return activeNetwork != null && activeNetwork.isConnectedOrConnecting();
}
private void loadDiensten() {
recyclerView.setVisibility(View.VISIBLE);
if (internetIsBeschikbaar()) {
loadDienstenOnline();
} else {
loadDienstenOffline();
}
swiper.setRefreshing(false);
}
#Override
public void onListItemClick(String url, String naam) {
Intent intent = new Intent(MainActivity.this, DienstActivity.class);
intent.putExtra(Intent.EXTRA_TEXT, url);
intent.putExtra("DienstNaam", naam);
startActivity(intent);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.main_menu, menu);
inflater.inflate(R.menu.search_menu, menu);
// Associate searchable configuration with the SearchView
SearchManager searchManager = (SearchManager) getSystemService(SEARCH_SERVICE);
searchView = (SearchView) menu.findItem(R.id.action_search).getActionView();
searchView.setSearchableInfo(searchManager != null ? searchManager.getSearchableInfo(getComponentName()) : null);
searchView.setMaxWidth(Integer.MAX_VALUE);
// listening to search query text change
searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
#Override
public boolean onQueryTextSubmit(String query) {
// filter recycler view when query submitted
adapter.getFilter().filter(query);
return false;
}
#Override
public boolean onQueryTextChange(String query) {
// filter recycler view when text is changed
adapter.getFilter().filter(query);
return false;
}
});
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
if (id == R.id.action_settings) {
Intent startSettingsActivity = new Intent(this, SettingsActivity.class);
startActivity(startSettingsActivity);
return true;
} else if (id == R.id.action_search) {
return true;
}
return super.onOptionsItemSelected(item);
}
#SuppressWarnings("StatementWithEmptyBody")
#Override
public boolean onNavigationItemSelected(#NonNull MenuItem item) {
// Handle navigation view item clicks here.
int id = item.getItemId();
if (id == R.id.nav_camera) {
// Handle the camera action
} else if (id == R.id.nav_gallery) {
} else if (id == R.id.nav_slideshow) {
} else if (id == R.id.nav_manage) {
} else if (id == R.id.nav_share) {
} else if (id == R.id.nav_send) {
}
DrawerLayout drawer = findViewById(R.id.drawer_layout);
drawer.closeDrawer(GravityCompat.START);
return true;
}
#Override
public void onBackPressed() {
DrawerLayout drawer = findViewById(R.id.drawer_layout);
if (drawer.isDrawerOpen(GravityCompat.START)) {
drawer.closeDrawer(GravityCompat.START);
return;
}
if (!searchView.isIconified()) {
searchView.setIconified(true);
return;
}
super.onBackPressed();
}
private static void voegDienstenToeAanDb(SQLiteDatabase db, List<Dienst> diensten){
if(db == null){
return;
}
List<ContentValues> list = new ArrayList<>();
ContentValues cv;
for (Dienst d : diensten) {
cv = new ContentValues();
cv.put(DienstContract.DienstEntry.COLUMN_NAAM, d.getNaam());
cv.put(DienstContract.DienstEntry.COLUMN_BESCHRIJVING, d.getBeschrijving());
cv.put(DienstContract.DienstEntry.COLUMN_CATEGORIE, d.getCategorie());
cv.put(DienstContract.DienstEntry.COLUMN_PRIJS, d.getPrice());
cv.put(DienstContract.DienstEntry.COLUMN_AFBEELDING, d.getAfbeelding());
list.add(cv);
}
try
{
db.beginTransaction();
//clear the table first
db.delete (DienstContract.DienstEntry.TABLE_NAME,null,null);
//go through the list and add one by one
for(ContentValues c : list){
db.insert(DienstContract.DienstEntry.TABLE_NAME, null, c);
}
db.setTransactionSuccessful();
}
catch (SQLException e) {
//too bad :(
}
finally
{
db.endTransaction();
}
}
private Cursor getAlleDiensten() {
return mDb.query(
DienstContract.DienstEntry.TABLE_NAME,
null,
null,
null,
null,
null,
DienstContract.DienstEntry._ID
);
}
private void omzettenCursorNaarDiensten(Cursor c) {
int teller = 0, id;
String naam, beschrijving, categorie, afbeelding;
double prijs;
while (c.moveToPosition(teller)) {
id = Integer.parseInt(c.getString(c.getColumnIndex(DienstContract.DienstEntry._ID)));
naam = c.getString(c.getColumnIndex(DienstContract.DienstEntry.COLUMN_NAAM));
beschrijving = c.getString(c.getColumnIndex(DienstContract.DienstEntry.COLUMN_BESCHRIJVING));
categorie = c.getString(c.getColumnIndex(DienstContract.DienstEntry.COLUMN_CATEGORIE));
prijs = c.getDouble(c.getColumnIndex(DienstContract.DienstEntry.COLUMN_PRIJS));
afbeelding = c.getString(c.getColumnIndex(DienstContract.DienstEntry.COLUMN_AFBEELDING));
dienstList.add(new Dienst(id, naam, beschrijving, categorie, prijs, afbeelding));
teller++;
}
}
private void setupPreferenceGebruikersnaam() {
String text = String.format(res.getString(R.string.welkomsbericht), sharedPreferences.getString("example_text", "gebruiker"));
gebruikersnaam.setText(text);
}
}
DienstAdapter.java
public class DienstAdapter extends RecyclerView.Adapter<DienstAdapter.DienstViewHolder> implements Filterable {
private Context mContext;
private List<Dienst> dienstList;
private List<Dienst> dienstListFiltered;
private final ListItemClickListener mOnClickListener;
#Override
public Filter getFilter() {
return new Filter() {
#Override
protected FilterResults performFiltering(CharSequence charSequence) {
String charString = charSequence.toString();
if (charString.isEmpty()) {
dienstListFiltered = dienstList;
} else {
List<Dienst> filteredList = new ArrayList<>();
for (Dienst row : dienstList) {
// name match condition. this might differ depending on your requirement
// here we are looking for name or phone number match
if (row.getNaam().toLowerCase().contains(charString.toLowerCase()) || row.getBeschrijving().contains(charSequence)) {
filteredList.add(row);
}
}
dienstListFiltered = filteredList;
}
FilterResults filterResults = new FilterResults();
filterResults.values = dienstListFiltered;
return filterResults;
}
#Override
protected void publishResults(CharSequence charSequence, FilterResults filterResults) {
dienstListFiltered = (ArrayList<Dienst>) filterResults.values;
notifyDataSetChanged();
}
};
}
public interface ListItemClickListener {
void onListItemClick(String url, String naam);
}
DienstAdapter(Context mContext, List<Dienst> dienstList, ListItemClickListener listener) {
this.mContext = mContext;
this.dienstList = dienstList;
this.dienstListFiltered = dienstList;
mOnClickListener = listener;
}
#Override
public DienstViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
LayoutInflater inflater = LayoutInflater.from(mContext);
View view = inflater.inflate(R.layout.list_layout, null);
return new DienstViewHolder(view);
}
#Override
public void onBindViewHolder(DienstViewHolder holder, int position) {
Dienst dienst = dienstList.get(position);
holder.tv_naam.setText(dienst.getNaam());
holder.tv_beschrijving.setText(dienst.getBeschrijving());
holder.tv_categorie.setText(String.valueOf(dienst.getCategorie()));
holder.tv_prijs.setText(String.valueOf(dienst.getPrice()));
if (dienst.getPrice() != 0)
holder.tv_prijs.setText(String.format("€ %.2f", dienst.getPrice()));
else
holder.tv_prijs.setText("");
Glide.with(mContext).load(dienst.getAfbeelding()).into(holder.iv_afbeelding);
}
#Override
public int getItemCount() {
return dienstList.size();
}
public class DienstViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
ImageView iv_afbeelding;
TextView tv_naam, tv_beschrijving, tv_categorie, tv_prijs;
DienstViewHolder(View itemView) {
super(itemView);
iv_afbeelding = itemView.findViewById(R.id.iv_afbeelding);
tv_naam = itemView.findViewById(R.id.tv_naam);
tv_beschrijving = itemView.findViewById(R.id.tv_beschrijving);
tv_categorie = itemView.findViewById(R.id.tv_categorie);
tv_prijs = itemView.findViewById(R.id.tv_prijs);
itemView.setOnClickListener(this);
}
#Override
public void onClick(View view) {
int clickedPosition = getAdapterPosition();
String url = dienstList.get(clickedPosition).getAfbeelding().replace(".png", ".html");
String naam = dienstList.get(clickedPosition).getNaam();
mOnClickListener.onListItemClick(url, naam);
}
}
}
Firstly, getItemCount() and onBindViewHolder() should use the filtered list dienstListFiltered.
And You forgot to update the count of the FilterResults.
#Override
public Filter getFilter() {
return new Filter() {
#Override
protected FilterResults performFiltering(CharSequence charSequence) {
// Filter data ...
// ...
FilterResults filterResults = new FilterResults();
filterResults.values = dienstListFiltered;
filterResults.count = dienstListFiltered.size();
return filterResults;
}
#Override
protected void publishResults(CharSequence charSequence, FilterResults filterResults) {
dienstListFiltered = (ArrayList<Dienst>) filterResults.values;
notifyDataSetChanged();
}
};
}
See: Custom Listview Adapter with filter Android
Can you add
notifyDataSetChanged();
immediately after
filteredList.add(row);
?

Crash when tapping search button in action bar (Android)

I have been following this tutorial to find out how to add a search bar to my activity. Unfortunately at the moment, each time I tap on the search icon, the app crashes and restarts immediately (so I can't see an error). The only difference I can see between their code and mine, is that I am using a standard activity, whereas they are using fragments. I have tried to change my code accordingly.
This is the code in my activity:
public class AttractionsListActivity extends AppCompatActivity implements SearchView.OnQueryTextListener {
public static AttractionRowAdapter adapter;
private RecyclerView mRecyclerView;
public static SwipeRefreshLayout swipeContainer;
public static Park parkPassed;
private List<Attraction> attractionsList;
#Override
protected void onPause() {
super.onPause();
adapter.clearAdaptor();
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_attractions_list);
final Intent intent = getIntent();
parkPassed = intent.getParcelableExtra("parkPassed");
DataManager.loadAttractions(getBaseContext(), parkPassed.name.replaceAll("\\s+",""));
swipeContainer = (SwipeRefreshLayout) findViewById(R.id.swipeContainer);
swipeContainer.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
#Override
public void onRefresh() {
DataManager.loadAttractions(getBaseContext(), parkPassed.name.replaceAll("\\s+",""));
adapter.clearAdaptor();
}
});
swipeContainer.setColorSchemeColors(Color.parseColor("#FF2F92"),
Color.parseColor("#0080FF"));
this.setupRecycler();
this.setupImageLoader();
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.action_search, menu);
final MenuItem item = menu.findItem(R.id.action_search);
final SearchView searchView = (SearchView) MenuItemCompat.getActionView(item);
searchView.setOnQueryTextListener(this);
MenuItemCompat.setOnActionExpandListener(item, new MenuItemCompat.OnActionExpandListener() {
#Override
public boolean onMenuItemActionCollapse(MenuItem item) {
adapter.setFilter(attractionsList);
return true;
}
#Override
public boolean onMenuItemActionExpand(MenuItem item) {
return true;
}
});
return super.onCreateOptionsMenu(menu);
}
#Override
public boolean onQueryTextChange(String newText) {
final List<Attraction> filteredModelList = filter(attractionsList, newText);
adapter.setFilter(filteredModelList);
return true;
}
#Override
public boolean onQueryTextSubmit(String query) {
return false;
}
private List<Attraction> filter(List<Attraction> models, String query) {
query = query.toLowerCase();
final List<Attraction> filteredModelList = new ArrayList<>();
for (Attraction model : models) {
final String text = model.name.toLowerCase();
if (text.contains(query)) {
filteredModelList.add(model);
}
}
return filteredModelList;
}
private void setupRecycler() {
mRecyclerView = (RecyclerView) findViewById(R.id.attractions_recycler);
final LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this);
mRecyclerView.setLayoutManager(linearLayoutManager);
adapter = new AttractionRowAdapter(AttractionsListActivity.this, DataManager.attractionArrayList);
mRecyclerView.setAdapter(adapter);
}
}
And in the adapter:
public class AttractionRowAdapter extends RecyclerView.Adapter<AttractionRowHolder> {
private List<Attraction> attractionsList;
private Context context;
public AttractionRowAdapter(Context context, List<Attraction> attractionsArrayList) {
this.attractionsList = attractionsArrayList;
this.context = context;
}
#Override
public int getItemCount() {
return (null != attractionsList ? attractionsList.size() : 0);
}
public void setFilter(List<Attraction> attractions) {
attractionsList = new ArrayList<>();
attractionsList.addAll(attractions);
notifyDataSetChanged();
}
}
I've only posted the relevant code. All of the necessary methods are there. Everything works fine up until I tap the search icon.
Any ideas?
This is never initialized in the Activity
private List<Attraction> attractionsList;
This list is being passed around as null, and most likely results in a NullPointerException at this
adapter.setFilter(attractionsList);
Which calls this
public void setFilter(List<Attraction> attractions) {
attractionsList = new ArrayList<>();
attractionsList.addAll(attractions);
And addAll throws a NullPointerException

Categories