This is basically a notes app,in which we dynamically add data to our app by taking in title and description from the user,the problem is that when we search about some note by its title then instead of giving the possible notes the data set in the adapter vanishes,the logic is written in my filter() function in the adapter class
MainActivity.java
public class MainActivity extends AppCompatActivity implements SearchView.OnQueryTextListener {
private ArrayList<Notes> list;
private NotesAdapter notesAdapter;//this is our notes adapter
private RecyclerView recyclerView;
private LinearLayoutManager linearLayoutManager;
#Override //
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
list=new ArrayList<>();//this is the list which we have to pass into adapter
recyclerView=findViewById(R.id.rv);
notesAdapter=new NotesAdapter(this,list);
View dialogView= LayoutInflater.from(this).inflate(R.layout.dialog_main,null,false);
final EditText title=dialogView.findViewById(R.id.t);
final EditText description=dialogView.findViewById(R.id.d);
final AlertDialog alertDialog=new AlertDialog.Builder(this)
.setTitle("Enter the details:")
.setCancelable(false)
.setView(dialogView)
.setPositiveButton("add", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialogInterface, int i) {
list.add(new Notes(title.getText().toString(),description.getText().toString(),false));
notesAdapter.notifyItemChanged(list.size());
}
})
.setNegativeButton("no", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialogInterface, int i) {
dialogInterface.dismiss();
}
}).create();
FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
fab.setOnClickListener(new View.OnClickListener() {
#Override // on pressing the fab we will get an alert dialog box where we can add title and description and with the option to add it or not
public void onClick(View view) {
alertDialog.show();
}
});
recyclerView.setAdapter(notesAdapter);
linearLayoutManager=new LinearLayoutManager(this,LinearLayoutManager.VERTICAL,false);
recyclerView.setLayoutManager(linearLayoutManager);
}
#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 MenuItem searchItem = menu.findItem(R.id.search);
final SearchView searchView = (SearchView) MenuItemCompat.getActionView(searchItem);
searchView.setOnQueryTextListener(this);
return true;
}``
#Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
if (id == R.id.search) {
return true;
}
return super.onOptionsItemSelected(item);
}
#Override
public boolean onQueryTextSubmit(String s) {
notesAdapter.filter(s);
return true;
}
#Override
public boolean onQueryTextChange(String s) {
notesAdapter.filter(s);
return true;
}
NotesAdapter.java
public class NotesAdapter extends RecyclerView.Adapter<NotesAdapter.NotesHolder> {
private ArrayList<Notes> arrayList;
private ArrayList<Notes> arrayListCopy;
Context c;
NotesAdapter(Context context,ArrayList<Notes> list){
this.arrayList=list;
this.c=context;
this.arrayListCopy=new ArrayList<>(list);//this is where I store identical list which I get from Adapter
}
public class NotesHolder extends RecyclerView.ViewHolder {
TextView textView;
public NotesHolder(View itemView) {
super(itemView);
textView = itemView.findViewById(R.id.tv);
}
}
#Override
public NotesAdapter.NotesHolder onCreateViewHolder(ViewGroup parent, int viewType) {
return new NotesHolder(LayoutInflater.from(c).inflate(R.layout.item_row,parent,false));
}
#Override
public void onBindViewHolder(final NotesAdapter.NotesHolder holder, final int position) {
final Notes currentNote=arrayList.get(position);
holder.textView.setText(currentNote.getTitle());
holder.textView.setOnLongClickListener(new View.OnLongClickListener() {
#Override
public boolean onLongClick(View view) {
arrayList.remove(holder.getAdapterPosition());
notifyItemRemoved(holder.getAdapterPosition());
return true;
}
});
holder.textView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Intent intent=new Intent(c,AnotherActivity.class);
intent.putExtra("NAME",currentNote.getDescription());
c.startActivity(intent);
}
});
}
#Override
public int getItemCount() {
return arrayList.size();
}
public void filter(String text){//This is my filter function
arrayList.clear();
if(TextUtils.isEmpty(text)){
arrayList.addAll(arrayListCopy);
}
else{
text=text.toLowerCase();
for(Notes note:arrayListCopy){
if(note.getTitle().toLowerCase().contains(text)){
arrayList.add(note);
}
}
}
notifyDataSetChanged();//the data set is still not updated and instead it vanishes
}
}
As soon as I search something the whole list gets vanished ,where am I missing out on?How should I modify my filter function in adapter class?
Change your getItemCount :
#Override
public int getItemCount() {
return arrayListCopy.size();
}
Try this:
NotesAdapter(Context context,ArrayList<Notes> list){
this.arrayList = new ArrayList<>(list.size());
this.c=context;
this.arrayListCopy=new ArrayList<>(list);//this is where I store identical list which I get from Adapter
}
#Override
public int getItemCount() {
return arrayList.size();
}
public void filter(String text){//This is my filter function
arrayList.clear();
if(text.trim().isEmpty() || text == null){
arrayList.addAll(arrayListCopy);
}
else{
text=text.toLowerCase();
for(Notes note:arrayListCopy){
if(note.getTitle().toLowerCase().contains(text)){
arrayList.add(note);
}
}
}
notifyDataSetChanged();//the data set is still not updated and instead it vanishes
}
Original Answer:
Here you are referencing the same variable (i.e. arrayList and arrayListCopy ) are pointing to the same variable. Instead, initialize arrayList like this inside your constructor:
this.arrayList = new ArrayList<>(arrayListCopy.size());
The problem is that arrayList and arrayListCopy are references to the same list.
NotesAdapter(Context context,ArrayList<Notes> list){
this.arrayList=list;
this.c=context;
this.arrayListCopy=list;
}
Changes done to one of them, will be reflected in both. For example arrayList.clear() will also empty the arrayListCopy list.
What you could do is something like this:
List<Notes> originalList;
NotesAdapter(Context context,ArrayList<Notes> list){
this.arrayList=list;
this.c=context;
this.originalList= new ArrayList<>(list); // create a new List that contains all the elements of `list`.
}
And to filter, do this:
public void filter(String text){
arrayList.clear();
if(text.isEmpty()){
arrayList.addAll(originalList);
} else{
text=text.toLowerCase();
for(Notes note : originalList){
if(note.getTitle().toLowerCase().contains(text)){
arrayList.add(note);
}
}
}
notifyDataSetChanged();
}
It seems that you're adding items to the list inside the MainActivity after you create the adapter which means that you'll have to use some other mechanism for adding new items so that originalList will contain all the items. Something like:
public class NotesAdapter extends RecyclerView.Adapter<NotesAdapter.NotesHolder> {
public void addItem(Notes item){
originalList.add(item);
if(text.isEmpty() || item.getTitle().toLowerCase().contains(text.toLowerCase())){
arrayList.add(item);
}
}
}
Here, text is just a reference to the text variable passed to the filter method.
From MainActivity when a new item is created, do this:
adapter.addItem(new Notes(title.getText().toString(),description.getText().toString(),false));
Related
I am having trouble with shuffling images in home screen in a wallpaper app. i want like when ever a person opens my app the images in the home screen should be shuffled . i tried using Collections.shuffle() method, in using that what is happening is the images are getting duplicated and when i click on the shuffled image to open in fullscreen some other image opens
suppose in a list A(0,1,2,3) when i shuffle it only the display changes but when i open it itopens according to the index of list A
please help me with the code as to where and how i have to use the Collections.shuffle method
here is my code .
I am troubled for many days and not getting the solution so please help
Homescreen.java
public class Homescreen extends AppCompatActivity {
RecyclerView recyclerView;
List<WallpaperModel> list;
private WallpaperAdapter adapter;
DatabaseReference reference;
public static final String TAG = Homescreen.class.getSimpleName();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_homescreen);
init();
recyclerView.setHasFixedSize(true);
recyclerView.setLayoutManager(new GridLayoutManager(this,3));
list = new ArrayList<>();
adapter.shuffle();
adapter.notifyDataSetChanged();
adapter = new WallpaperAdapter(list);
recyclerView.setAdapter(adapter);
reference = FirebaseDatabase.getInstance().getReference().child("Wallpapers");
reference.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot snapshot) {
list.clear();
for (DataSnapshot dataSnapshot : snapshot.getChildren()){
WallpaperModel model = dataSnapshot.getValue(WallpaperModel.class);
list.add(model);
}
adapter.notifyDataSetChanged();
}
#Override
public void onCancelled(#NonNull DatabaseError error) {
Log.e(TAG,error.getMessage());
}
});
}
private void
init(){
Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
recyclerView = findViewById(R.id.recyclerView);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.menu,menu);
return true;
}
#Override
public boolean onOptionsItemSelected(#NonNull MenuItem item) {
int id = item.getItemId();
if (id == R.id.favourite){
startActivity(new Intent(Homescreen.this, FavouriteActivity.class));
}
return true;
}
}
and this is my wallpaperAdapter class
public class WallpaperAdapter extends
RecyclerView.Adapter<WallpaperAdapter.WallpaperHolder> {
private static List<WallpaperModel> list;
public WallpaperAdapter(List<WallpaperModel> list) {
WallpaperAdapter.list = list;
}
#NonNull
#Override
public WallpaperHolder onCreateViewHolder(#NonNull ViewGroup parent, int
viewType) {
View view =
LayoutInflater.from(parent.getContext())
.inflate(R.layout.wallpaper_items,parent,false);
return new WallpaperHolder(view);
}
#Override
public void onBindViewHolder(#NonNull
WallpaperAdapter.WallpaperHolder holder, int position) {
Random random = new Random();
int color = Color.rgb(0,0,0);
Glide.with(holder.itemView.getContext().getApplicationContext())
.load(list.get(position).getImage())
.timeout(7500)
.into(holder.imageView);
holder.setClickListener();
}
#Override
public int getItemCount() {
return list.size();
}
public void shuffle() {
Collections.shuffle(list,new Random(System.currentTimeMillis()));
}
static class WallpaperHolder extends RecyclerView.ViewHolder{
private ImageView imageView;
public WallpaperHolder(#NonNull View itemView) {
super(itemView);
imageView = itemView.findViewById(R.id.imageView);
}
void setClickListener(){
//set on click listener on wallpaper image
itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
int position = getAdapterPosition();
Intent intent = new Intent(itemView.getContext().getApplicationContext(),
SwiperActivity.class);
intent.putExtra("position",position);
itemView.getContext().startActivity(intent);
}
});
}
}
}
I am trying to delete multiple items from recyclerView. The items in the recyclerView has an attribute isSelected. I am setting the attribute isSelected to true when user clicks on the recyclerView item. After selection user can click delete button present in the options menu to delete the selected items. The code has unexpected behaviour, like when delete button is pressed, some of the selected items are deleted while some are not. Also some of the items get automatically selected at random positions.
Model.java
public class Model {
private String text;
private boolean isSelected = false;
public Model(String text) {
this.text = text;
}
public String getText() {
return text;
}
public void setSelected(boolean selected) {
isSelected = selected;
}
public boolean isSelected() {
return isSelected;
}
}
RecyclerViewAdapter.java
public class RecyclerViewAdapter extends RecyclerView.Adapter<RecyclerViewAdapter.MyViewHolder> {
private List<Model> mModelList;
private Context mCtx;
public RecyclerViewAdapter(Context ctx, List<Model> modelList) {
this.mModelList = modelList;
this.mCtx = ctx;
}
#Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
LayoutInflater inflater = LayoutInflater.from(mCtx);
View view = inflater.inflate(R.layout.item_row, parent, false);
return new MyViewHolder(view);
}
#Override
public void onBindViewHolder(final MyViewHolder holder, final int position) {
final Model model = mModelList.get(position);
holder.view.setBackgroundColor(model.isSelected() ? Color.CYAN : Color.WHITE);
holder.tvItems.setText(model.getText());
holder.tvItems.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
model.setSelected(!model.isSelected());
holder.tvItems.setBackgroundColor(model.isSelected() ? Color.CYAN : Color.WHITE);
notifyItemChanged(position);
}
});
}
#Override
public int getItemCount() {
return mModelList == null ? 0 : mModelList.size();
}
public class MyViewHolder extends RecyclerView.ViewHolder {
private TextView tvItems;
private View view;
public MyViewHolder(View itemView) {
super(itemView);
view = itemView;
tvItems = itemView.findViewById(R.id.tvItems);
}
}
}
MainActivity.java
public class MainActivity extends AppCompatActivity {
private List<Model> mModelList;
private RecyclerView mRecyclerView;
private RecyclerView.Adapter mAdapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mRecyclerView = (RecyclerView) findViewById(R.id.rvListItems);
mAdapter = new RecyclerViewAdapter(this, getListData());
LinearLayoutManager manager = new LinearLayoutManager(MainActivity.this);
mRecyclerView.setHasFixedSize(true);
mRecyclerView.setLayoutManager(manager);
mRecyclerView.setAdapter(mAdapter);
}
private List<Model> getListData() {
mModelList = new ArrayList<>();
for (int i = 1; i <= 25; i++) {
mModelList.add(new Model("TextView " + i));
}
return mModelList;
}
private void deleteSelectedItems() {
if (mModelList != null){
for (int i=0; i<mModelList.size(); i++){
if (mModelList.get(i).isSelected()){
Log.d("testingTAG", String.valueOf(i));
mModelList.remove(i);
mAdapter.notifyItemRemoved(i);
mAdapter.notifyItemRangeChanged(i, mModelList.size());
i--;
}
}
}
}
#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);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()){
case R.id.action_delete:
deleteSelectedItems();
break;
}
return super.onOptionsItemSelected(item);
}
}
Any kind of help will be greatly appreciated.
You should use holder.getAdapterPosition() inside your clicklistener .Change your onclick as given below and try.
public void onClick(View view) {
final Model model = mModelList.get(holder.getAdapterPosition());
model.setSelected(!model.isSelected());
holder.tvItems.setBackgroundColor(model.isSelected() ? Color.CYAN : Color.WHITE);
notifyItemChanged(holder.getAdapterPosition());
}
Answer from #pop selects items, change background color to CYAN if item is selected and inverse selected flag of Model class instance.
you should delete selected items from your mModelList using a iterator, you can't delete items from list inside for loop
Calling remove in foreach loop in Java
I am going through a tutorial which is using the Recycler View to display a list of weather for each day for a week.
There are two classes which I am confused in:
ForecastAdapter and MainActivity
Here is the code for the above two classes:
ForecastAdapter.java
public class ForecastAdapter extends RecyclerView.Adapter<ForecastAdapter.ForecastAdapterViewHolder> {
private String[] mWeatherData;
final private ForecastAdapterOnClickListener mClickHandler;
//Why do we need to create an interface here.
public interface ForecastAdapterOnClickListener {
void onClick(String weatherForDay);
}
public ForecastAdapter(ForecastAdapterOnClickListener forecastAdapterOnClickListener) {
mClickHandler = forecastAdapterOnClickListener;
}
public class ForecastAdapterViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener{
public final TextView mWeatherTextView;
public ForecastAdapterViewHolder(View view) {
super(view);
mWeatherTextView = (TextView) view.findViewById(R.id.tv_weather_data);
view.setOnClickListener(this);
}
#Override
public void onClick(View v) {
int adapterPosition = getAdapterPosition();
String weatherForDay = mWeatherData[adapterPosition];
//Why are we calling onClick from mClickHandler here. Why can't we just display Toast here.
mClickHandler.onClick(weatherForDay);
/*Why can't we just display the Toast from here like this:
Toast.makeText(v.getContext(), weatherForDay, Toast.LENGTH_SHORT).show()
*/
}
}
#Override
public ForecastAdapterViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) {
Context context = viewGroup.getContext();
int layoutIdForListItem = R.layout.forecast_list_item;
LayoutInflater inflater = LayoutInflater.from(context);
boolean shouldAttachToParentImmediately = false;
View view = inflater.inflate(layoutIdForListItem, viewGroup, shouldAttachToParentImmediately);
return new ForecastAdapterViewHolder(view);
}
#Override
public void onBindViewHolder(ForecastAdapterViewHolder forecastAdapterViewHolder, int position) {
String weatherForThisDay = mWeatherData[position];
forecastAdapterViewHolder.mWeatherTextView.setText(weatherForThisDay);
}
#Override
public int getItemCount() {
if (null == mWeatherData) return 0;
return mWeatherData.length;
}
public void setWeatherData(String[] weatherData) {
mWeatherData = weatherData;
notifyDataSetChanged();
}
}
MainActivity.java
//Why are implementing ForecastAdapterOnClickListener here?
public class MainActivity extends AppCompatActivity implements ForecastAdapter.ForecastAdapterOnClickListener{
private RecyclerView mRecyclerView;
private ForecastAdapter mForecastAdapter;
private TextView mErrorMessageDisplay;
private ProgressBar mLoadingIndicator;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_forecast);
mRecyclerView = (RecyclerView) findViewById(R.id.recyclerview_forecast);
mErrorMessageDisplay = (TextView) findViewById(R.id.tv_error_message_display);
LinearLayoutManager layoutManager
= new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false);
mRecyclerView.setLayoutManager(layoutManager);
mRecyclerView.setHasFixedSize(true);
mForecastAdapter = new ForecastAdapter(this);
mRecyclerView.setAdapter(mForecastAdapter);
mLoadingIndicator = (ProgressBar) findViewById(R.id.pb_loading_indicator);
loadWeatherData();
}
private void loadWeatherData() {
showWeatherDataView();
String location = SunshinePreferences.getPreferredWeatherLocation(this);
new FetchWeatherTask().execute(location);
}
#Override
public void onClick(String weatherForDay) {
Context context = this;
Toast.makeText(context, weatherForDay, Toast.LENGTH_SHORT)
.show();
}
private void showWeatherDataView() {
mErrorMessageDisplay.setVisibility(View.INVISIBLE);
mRecyclerView.setVisibility(View.VISIBLE);
}
private void showErrorMessage() {
mRecyclerView.setVisibility(View.INVISIBLE);
mErrorMessageDisplay.setVisibility(View.VISIBLE);
}
public class FetchWeatherTask extends AsyncTask<String, Void, String[]> {
#Override
protected void onPreExecute() {
super.onPreExecute();
mLoadingIndicator.setVisibility(View.VISIBLE);
}
#Override
protected String[] doInBackground(String... params) {
if (params.length == 0) {
return null;
}
String location = params[0];
URL weatherRequestUrl = NetworkUtils.buildUrl(location);
try {
String jsonWeatherResponse = NetworkUtils
.getResponseFromHttpUrl(weatherRequestUrl);
String[] simpleJsonWeatherData = OpenWeatherJsonUtils
.getSimpleWeatherStringsFromJson(MainActivity.this, jsonWeatherResponse);
return simpleJsonWeatherData;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
#Override
protected void onPostExecute(String[] weatherData) {
mLoadingIndicator.setVisibility(View.INVISIBLE);
if (weatherData != null) {
showWeatherDataView();
mForecastAdapter.setWeatherData(weatherData);
} else {
showErrorMessage();
}
}
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.forecast, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
if (id == R.id.action_refresh) {
mForecastAdapter.setWeatherData(null);
loadWeatherData();
return true;
}
return super.onOptionsItemSelected(item);
}
}
The adapter, view holder and recycler view is working as expected. We are now supposed to implement Click Handling on the rows of the recycler view. Whenever a particular row is clicked, we are supposed to display a toast.
As you can see, we are implementing OnClickListener in the ForecastAdapterViewHolder and in the onClick function we are calling the onClick of the interface "ForecastAdapterOnClickListener".
In the MainActivity.java, we are implementing this "ForecastAdapterOnClickListener" and then displaying the toast.
Why can't we just display the toast in the onClick that is defined for the "ForecastAdapterViewHolder" class. I have tried it and it works. What is the point of doing what is being done in the code?
Is there some advantage in setting the click listener like that?
Because you'll have to display information afterwards and isn't role of ViewHolder neither Adapter. Activity/fragment must do that.
It's to keep your code organized.
My Activity is called, so the User should select some Songs, he want to add to a Playlist. How do I make a RecyclerView selectable (the Background-Color should be an Accent Color) and how do I receive the List or Array of the selected Songs from my RecyclerView?
My SelectSongsActivity:
public class SelectSongsActivity extends AppCompatActivity {
private Song[] sSongs;
private RecyclerView recyclerView;
private RecyclerView.LayoutManager layoutManager;
private SelectSongRecyclerViewAdapter adapter;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Bundle bundle = getIntent().getExtras();
sSongs = (Song[]) bundle.get(Constants.IntentExtra.SONGS);
Initialize();
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu_selectsongs, menu);
return super.onCreateOptionsMenu(menu);
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
if (item.getItemId() == R.id.mi_Add) {
Intent i = getIntent();
i.putExtra(Constants.IntentExtra.SONGS, adapter.getSelectedSongs());
setResult(RESULT_OK, i);
finish();
}
return super.onOptionsItemSelected(item);
}
#Override
public void onBackPressed() {
setResult(RESULT_CANCELED);
super.onBackPressed();
}
#Override
public boolean onSupportNavigateUp() {
setResult(RESULT_CANCELED);
return super.onSupportNavigateUp();
}
private void Initialize() {
setContentView(R.layout.activity_selectsongs);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
recyclerView = (RecyclerView) findViewById(R.id.recyclerView);
recyclerView.addItemDecoration(new RecyclerViewDivider(this));
layoutManager = new LinearLayoutManager(this);
recyclerView.setLayoutManager(layoutManager);
adapter = new SelectSongRecyclerViewAdapter(sSongs);
recyclerView.setAdapter(adapter);
}
}
And my RecyclerViewAdapter:
public class SelectSongRecyclerViewAdapter extends RecyclerView.Adapter<SelectSongRecyclerViewAdapter.Holder> {
private Song[] sSongs;
private List<Song> selectedSongs;
public SelectSongRecyclerViewAdapter(Song[] songs) {
sSongs = songs;
selectedSongs = new ArrayList<>();
}
#Override
public Holder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.adapter_songview, parent, false);
Holder holder = new Holder(view);
return holder;
}
#Override
public void onBindViewHolder(Holder holder, int position) {
//holder.imvSong.setImageResource(R.drawable.standardartwork);
holder.txvSongTitle.setText(sSongs[position].getTitle());
holder.txvSongInfo.setText(sSongs[position].getArtists());
}
#Override
public int getItemCount() {
return sSongs != null ? sSongs.length : 0;
}
public Song[] getSelectedSongs() {
Song[] songs = new Song[selectedSongs.size()];
return selectedSongs.toArray(songs);
}
public class Holder extends RecyclerView.ViewHolder {
LinearLayout linearLayout;
ImageView imvSong;
TextView txvSongTitle;
TextView txvSongInfo;
public Holder(View layout) {
super(layout);
linearLayout = (LinearLayout) layout;
imvSong = (ImageView) layout.findViewById(R.id.imvSong);
txvSongTitle = (TextView) layout.findViewById(R.id.adap_txvSongtitle);
txvSongInfo = (TextView) layout.findViewById(R.id.txvSongInfo);
}
}
}
Thanks!
You mean when you click on the linearlayout?
What you can do is in the onbindviewholder-
holder.linearlayout.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
selectedSongs.add(sSongs[position]);
}
});
To display already selected songs in a different color-
if (selectedSongs.contains(sSongs[position])) {
holder.linearlayout.setBackgroundColor(R.color.color_accent);
} else {
//else as viewholders are reused
holder.linearlayout.setBackgroundColor(R.color.default_color);
}
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