Show items starting from specific row in android listview - java

I have a list view with 100 items. On creating the ListView shows first 10 items. If the user clicks ShowRemainingItems option from the menu, I want to display items from 11 to 100. I tried with the below code, but it did not work.The list view is not getting lodaed on clicking the menu. Can some one help?
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Init user list
ListView list = (ListView) this.findViewById(R.id.dataList);
this.listAdapter = new DataListAdapter(this, R.layout.list_view_cell);
list.setAdapter(listAdapter);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.options_menu,menu);
return super.onCreateOptionsMenu(menu);
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
if (id == R.id.ShowRemainingItems) {
Toast.makeText(this,"refresh clicked",Toast.LENGTH_SHORT).show();
listAdapter.clear();
// Update the 'listData' according to your preferences like displaying the items from 11 to 100
// Notify the adapter about the change
updateDataList();
listAdapter.notifyDataSetChanged();
}
return super.onOptionsItemSelected(item);
}
public void updateDataList() {
Toast.makeText(this,"Update data list called",Toast.LENGTH_SHORT).show();
ListView list = (ListView) this.findViewById(R.id.dataList);
list.setSelectionFromTop(11,12);
Toast.makeText(this,"setSelectionFromTop selected",Toast.LENGTH_SHORT).show();
}
And the Datalistadapter.java
public class DataListAdapter extends ArrayAdapter {
private Context context;
private ArrayList<User> userList;
private int layoutRessource;
public ArrayList<User> getUserList() {
return userList;
}
public DataListAdapter(Context ctx, int layoutResourceId) {
super(ctx, layoutResourceId);
this.userList = new ArrayList<User>();
this.layoutRessource = layoutResourceId;
this.context = ctx;
}
public void addUser(User usr) {
this.userList.add(usr);
}
public void removeUser(String usrId) {
for (User usr : userList) {
if (usr.getId().equals(usrId)) {
this.userList.remove(usr);
}
}
}
#Override
public void clear() {
super.clear();
if(userList != null)
userList.clear();
}
#Override
public int getCount() {
//return this.userList.size();
return Math.min(10, this.userList.size());
}
#Override
public User getItem(int position) {
return this.userList.get(position);
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View row = convertView;
if (row == null) {
LayoutInflater li = (LayoutInflater) this.context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
row = li.inflate(this.layoutRessource, null);
}
// Get row user
User currentUser = getItem(position);
Log.d(TAG, "SIZE: " + this.userList.get(position));
// Id
TextView idLabel = (TextView) row.findViewById(R.id.id);
return row;
}
}

You need to first clear the update the dataset of the adapter and then then notify the adapter about the change so that it can update the UI accordingly. Also don't fetch the ListView each time you are using it and set the Adapter to it, instead make it as global.
ListView list;
ArrayList<String> listData = new ArrayList<String>();
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Init user list
list = (ListView) this.findViewById(R.id.dataList);
this.listAdapter = new DataListAdapter(this, R.layout.list_view_cell, listData);
list.setAdapter(listAdapter);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.options_menu,menu);
return super.onCreateOptionsMenu(menu);
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
if (id == R.id.ShowRemainingItems)
{
Toast.makeText(this,"refresh clicked",Toast.LENGTH_SHORT).show();
listData.clear();
// Update the 'listData' according to your preferences like displaying the items from 11 to 100
updateDataList();
// Notify the adapter about the change
listAdapter.notifyDataSetChanged();
}
else if(id == R.id.action_settings)
{
Toast.makeText(this,"Settings clicked",Toast.LENGTH_SHORT).show();
}
return super.onOptionsItemSelected(item);
}

You have several problems in your code. However, I took the responsibility of fixing and here's the modified code. Please note that the code is not tested, so please modify as per your further requirement.
I have added comments where you have done mistakes. Please check them carefully. Thanks.
private ArrayList<User> userList;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Initialize the userList here
userList = new ArrayList<User>();
userList = getFirst10Items();
// Initialize ListView and pass the userList into your adapter
ListView list = (ListView) this.findViewById(R.id.dataList);
this.listAdapter = new DataListAdapter(this, R.layout.list_view_cell, userList);
list.setAdapter(listAdapter);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.options_menu,menu);
return super.onCreateOptionsMenu(menu);
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
if (id == R.id.ShowRemainingItems) {
// Remove the following. This will not be needed
// listAdapter.clear();
updateDataList();
// Not necessary. As the updateDataList has already the notifyDataSetChanged command
// listAdapter.notifyDataSetChanged();
}
return super.onOptionsItemSelected(item);
}
public void updateDataList() {
// Do not initiate the ListView again. Just use the ListView that is already created.
// ListView list = (ListView) this.findViewById(R.id.dataList);
// This is not the way of selecting items in your ListView. I think your knowledge of how adapter works is wanting
// list.setSelectionFromTop(11,12);
// Here's the new implementation.
ArrayList<User> userListFor11To100 = getTheRemainingUsers();
userList.addAll(userListFor11To100);
listAdapter.notifyDataSetChanged();
}
public List<User> getTheRemainingUsers() {
// You need to implement the getTheRemainingUsers function yourself which will get the data for the position 11 to 100 in the ListView
// Just use userList.add(user) function instead of using listAdapter.addUser() function
}
public List<User> getFirst10Items() {
// You need to implement the getFirst10Items function yourself which will get the data for the position 0 to 10 in the ListView
// Just use userList.add(user) function instead of using listAdapter.addUser() function
}
Now you need to modify your adapter like the following.
public class DataListAdapter extends ArrayAdapter {
private Context context;
private ArrayList<User> userList;
private int layoutRessource;
// Modify the constructor to get the userList passed from the activity to the adapter.
public DataListAdapter(Context ctx, int layoutResourceId, ArrayList<User> userList) {
super(ctx, layoutResourceId);
this.userList = userList;
this.layoutRessource = layoutResourceId;
this.context = ctx;
}
public void addUser(User usr) {
this.userList.add(usr);
// Call the notifyDataSetChanged after adding each user to the list
notifyDataSetChanged();
}
public void removeUser(String usrId) {
for (User usr : userList) {
if (usr.getId().equals(usrId)) {
this.userList.remove(usr);
break;
}
}
// Call the notifyDataSetChanged after removing each user to the list
notifyDataSetChanged();
}
#Override
public void clear() {
super.clear();
if(userList != null) {
userList.clear();
// Call the notifyDataSetChanged after removing all user from the list
notifyDataSetChanged();
}
}
#Override
public int getCount() {
return this.userList.size();
// The following statement is wrong!! Return the actual size of the list all the time.
// return Math.min(10, this.userList.size());
}
#Override
public User getItem(int position) {
return this.userList.get(position);
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View row = convertView;
if (row == null) {
LayoutInflater li = (LayoutInflater) this.context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
row = li.inflate(this.layoutRessource, null);
}
// Get row user
User currentUser = getItem(position);
Log.d(TAG, "SIZE: " + this.userList.get(position));
// Id
TextView idLabel = (TextView) row.findViewById(R.id.id);
// Set something to the TextView. Now its showing nothing.
idLabel.setText(currentUser.getId());
return row;
}
}

Related

Passing an object to AsyncTask method cannot be applied to given type

I am trying to use AsyncTask to add objects to my SQLite database. I have 4classes: MainActivity, DBHelper, ToDo_Item, and an AsyncTask inner class named DatabaseAsyncAdd
class ToDo_Item {
//MEMBER ATTRIBUTES
private int _id;
private String description;
private int is_done;
public ToDo_Item() {
}
public ToDo_Item(String desc, int done) {
description = desc;
is_done = done;
}
public int getId() {
return _id;
}
public void setId(int id) {
_id = id;
}
public String getDescription () {
return description;
}
public void setDescription (String desc) {
description = desc;
}
public int getIs_done() {
return is_done;
}
public void setIs_done(int done) {
is_done = done;
}
}
Here is the method from DBHelper I am trying to use:
public void addToDoItem(ToDo_Item task) {
SQLiteDatabase db = this.getWritableDatabase();
ContentValues values = new ContentValues();
//ADD KEY-VALUE PAIR INFORMATION FOR THE TASK DESCRIPTION
values.put(KEY_DESCRIPTION, task.getDescription()); // task name
//ADD KEY-VALUE PAIR INFORMATION FOR
//IS_DONE VALUE: 0- NOT DONE, 1 - IS DONE
values.put(KEY_IS_DONE, task.getIs_done());
// INSERT THE ROW IN THE TABLE
db.insert(DATABASE_TABLE, null, values);
taskCount++;
// CLOSE THE DATABASE CONNECTION
db.close();
}
and my main including AsyncTask
public class MainActivity extends Activity {
protected DBHelper mDBHelper;
private List<ToDo_Item> list;
private MyAdapter adapt;
private EditText myTask;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// TASK 1: LAUNCH THE LAYOUT REPRESENTING THE MAIN ACTIVITY
setContentView(R.layout.activity_main);
// TASK 2: ESTABLISH REFERENCES TO THE UI
// ELEMENTS LOCATED ON THE LAYOUT
myTask = (EditText) findViewById(R.id.editText1);
// TASK 3: SET UP THE DATABASE
mDBHelper = new DBHelper(this);
/*
list = mDBHelper.getAllTasks();
adapt = new MyAdapter(this, R.layout.todo_item, list);
ListView listTask = (ListView) findViewById(R.id.listView1);
listTask.setAdapter(adapt);
*/
}
#Override
protected void onResume(){
super.onResume();
list = mDBHelper.getAllTasks();
adapt = new MyAdapter(this, R.layout.todo_item, list);
ListView listTask = (ListView) findViewById(R.id.listView1);
listTask.setAdapter(adapt);
}
//BUTTON CLICK EVENT FOR ADDING A TODO TASK
public void addTaskNow(View view) {
String s = myTask.getText().toString();
if (s.isEmpty()) {
Toast.makeText(getApplicationContext(), "A TODO task must be entered.", Toast.LENGTH_SHORT).show();
} else {
//BUILD A NEW TASK ITEM AND ADD IT TO THE DATABASE
ToDo_Item task = new ToDo_Item(s, 0);
mDBHelper.addToDoItem(task);
new DatabaseAsyncAdd().execute(task);
// CLEAR OUT THE TASK EDITVIEW
myTask.setText("");
// ADD THE TASK AND SET A NOTIFICATION OF CHANGES
adapt.add(task);
adapt.notifyDataSetChanged();
}
}
//BUTTON CLICK EVENT FOR DELETING ALL TODO TASKS
public void clearTasks(View view) {
mDBHelper.clearAll(list);
adapt.notifyDataSetChanged();
}
private class DatabaseAsyncAdd extends AsyncTask<ToDo_Item, String, Void> {
int progress_status;
#Override
protected void onPreExecute() {
// UPDATE THE UI IMMEDIATELY BEFORE BACKGROUND WORK IS PERFORMED
super.onPreExecute();
Toast.makeText(MainActivity.this, "Accessing Database",
Toast.LENGTH_SHORT).show();
}
#Override
protected Void doInBackground(ToDo_Item... task) {
String s = myTask.getText().toString();
mDBHelper.addToDoItem(task);
return null;
}
#Override
protected void onPostExecute(Void result) {
super.onPostExecute(result);
}
}
//******************* ADAPTER ******************************
private class MyAdapter extends ArrayAdapter<ToDo_Item> {
Context context;
List<ToDo_Item> taskList = new ArrayList<ToDo_Item>();
public MyAdapter(Context c, int rId, List<ToDo_Item> objects) {
super(c, rId, objects);
taskList = objects;
context = c;
}
//******************* TODO TASK ITEM VIEW ******************************
/**
* THIS METHOD DEFINES THE TODO ITEM THAT WILL BE PLACED
* INSIDE THE LIST VIEW.
*
* THE CHECKBOX STATE IS THE IS_DONE STATUS OF THE TODO TASK
* AND THE CHECKBOX TEXT IS THE TODO_ITEM TASK DESCRIPTION.
*/
#Override
public View getView(int position, View convertView, ViewGroup parent) {
CheckBox isDoneChBx = null;
if (convertView == null) {
LayoutInflater inflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = inflater.inflate(R.layout.todo_item, parent, false);
isDoneChBx = (CheckBox) convertView.findViewById(R.id.chkStatus);
convertView.setTag(isDoneChBx);
isDoneChBx.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
CheckBox cb = (CheckBox) view;
ToDo_Item changeTask = (ToDo_Item) cb.getTag();
changeTask.setIs_done(cb.isChecked() == true ? 1 : 0);
mDBHelper.updateTask(changeTask);
}
});
} else {
isDoneChBx = (CheckBox) convertView.getTag();
}
ToDo_Item current = taskList.get(position);
isDoneChBx.setText(current.getDescription());
isDoneChBx.setChecked(current.getIs_done() == 1 ? true : false);
isDoneChBx.setTag(current);
return convertView;
}
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu.
getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
}
I am trying to create a ToDo_Item on the addtasknow method which is a button click method. That object is then passed to the execute method in DatabaseASyncAdd. mDBHelper.addToDoItem(task) is saying "ToDo_Item cannot be applied to ToDo_Item[]" although it works outside of the AsyncTask class. Am I not calling execute correctly?
Change the mDBHelper.addToDoItem(task) to mDBHelper.addToDoItem(task[0])
private class DatabaseAsyncAdd extends AsyncTask<ToDo_Item, String, Void> {
int progress_status;
#Override
protected void onPreExecute() {
// UPDATE THE UI IMMEDIATELY BEFORE BACKGROUND WORK IS PERFORMED
super.onPreExecute();
Toast.makeText(MainActivity.this, "Accessing Database",
Toast.LENGTH_SHORT).show();
}
#Override
protected Void doInBackground(ToDo_Item... task) {
//String s = myTask.getText().toString();
mDBHelper.addToDoItem(task[0]);
return null;
}
#Override
protected void onPostExecute(Void result) {
super.onPostExecute(result);
}
}
in
mDBHelper.addToDoItem(task);
task is a ToDo_Item[]. That's what ToDo_Item... means in the signature. It's called a varargs, for "variable arguments".

ItemView may not be null

I'm trying to retrieve all the checkboxes from my RecyclerView in order to uncheck them. However, this error is shown. Below are the classes that LogCat points to.
java.lang.IllegalArgumentException: itemView may not be null
at android.support.v7.widget.RecyclerView$ViewHolder.<init>(RecyclerView.java:10314)
at br.com.ufrn.marceloaugusto.tasklist.adapter.ProdutoAdapter$ProdutosViewHolder.<init>(ProdutoAdapter.java:0)
at br.com.ufrn.marceloaugusto.tasklist.MainActivity.onOptionsItemSelected(MainActivity.java:93)
MainActivity.java
public class MainActivity extends BaseActivity {
//private SQLiteDatabase banco;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
setUpToolbar();
if (savedInstanceState == null) {
FragmentProdutos frag = new FragmentProdutos();
getSupportFragmentManager().beginTransaction().add(R.id.container, frag).commit();
}
//FAB
findViewById(R.id.fab).setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
snack(view, "Adicionar produto");
}
});
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
if (item.getItemId() == R.id.action_desmarkAll) {
RecyclerView recycler = (RecyclerView) findViewById(R.id.recyclerView);
ProdutoAdapter.ProdutosViewHolder holder = null;
int id = 0;
for (int i = 0; i < recycler.getAdapter().getItemCount(); i++) {
holder = new ProdutoAdapter.ProdutosViewHolder(recycler.getChildAt(i)); **//Line 93**
if (holder.checkBox.isChecked()) {
holder.checkBox.setChecked(false);
}
}
return true;
}
return super.onOptionsItemSelected(item);
}}
ProdutoAdapter.java
public class ProdutoAdapter extends RecyclerView.Adapter<ProdutoAdapter.ProdutosViewHolder> {
private final Context context;
private final List<Produto> produtos;
//Interface para expor os eventos de toque na lista
private ProdutoOnClickListener produtoOnClickListener;
private ProdutoOnCheckListener produtoOnCheckListener;
public ProdutoAdapter(Context context, List<Produto> produtos, ProdutoOnClickListener produtoOnClickListener, ProdutoOnCheckListener produtoOnCheckListener) {
this.context = context;
this.produtos = produtos;
this.produtoOnClickListener = produtoOnClickListener;
this.produtoOnCheckListener = produtoOnCheckListener;
}
#Override
public int getItemCount() {
return this.produtos != null ? this.produtos.size() : 0;
}
#Override
public ProdutosViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(context).inflate(R.layout.adapter_produto, parent, false);
ProdutosViewHolder holder = new ProdutosViewHolder(view);
return holder;
}
#Override
public void onBindViewHolder(final ProdutosViewHolder holder, final int position) {
Produto p = produtos.get(position);
holder.tNome.setText(p.getNome());
//holder.tPreco.setText(String.valueOf(p.getPreco()));
if (produtoOnClickListener != null) {
holder.itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
produtoOnClickListener.onClickProduto(view, position);
}
});
}
if (produtoOnCheckListener != null) {
holder.checkBox.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
produtoOnCheckListener.onCheckProduto(view, position);
}
});
}
}
public interface ProdutoOnClickListener {
public void onClickProduto(View view, int idx);
}
public interface ProdutoOnCheckListener {
public void onCheckProduto(View view, int position);
}
public static class ProdutosViewHolder extends RecyclerView.ViewHolder {
public TextView tNome;
//public TextView tPreco;
CardView cardView;
public CheckBox checkBox;
public ProdutosViewHolder(View view) {
super(view);
tNome = (TextView) view.findViewById(R.id.nomeProduto);
//tPreco = (TextView) view.findViewById(R.id.precoProduto);
cardView = (CardView) view.findViewById(R.id.card_view);
checkBox = (CheckBox) view.findViewById(R.id.checkProduto);
}
}
}
Method getChildAt is method of ViewGroup, so recycler.getChildAt(i) will be null for you. In your case you should use produtos list, iterate over it and set its field associated to "checked" state to "false", invoke notifyDataSetChanged() method of your adapter and then onBindViewHolder() will automatically change holder's checkBox values.
So instead of
for (int i = 0; i < recycler.getAdapter().getItemCount(); i++) {
holder = new ProdutoAdapter.ProdutosViewHolder(recycler.getChildAt(i)); **//Line 93**
if (holder.checkBox.isChecked()) {
holder.checkBox.setChecked(false);
}
}
use this one:
for (Product product : produtos){
product.setChecked(false);
}
recycler.getAdapter().notifyDataSetChanged();
I supppose your class Project has such method.
In a RecyclerView the item views are recycled so you dont have as many itemviews as item in your List. Instead those itemviews are recycled and shows differents elements of your productos List.
Your problem is that you are in a for loop with the length of the List but inside you are using that index to access itemviews wich has not that much elements.
Instead, you should define a variable in Producto.class and update every time that check/uncheck the CheckBox of the item. And set this variable to false when you want to uncheck all and call
adapter.notifyDataSetChanged();
UPDATE:
ProdutoAdapter.java
Define a method to access list produtos and update onBindViewHolder like this:
if (produtoOnCheckListener != null) {
holder.checkBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
#Override
public void onCheckedChanged(CompoundButton compoundButton, boolean b) {
produtos.get(position).setCheckBoxState(b);
produtoOnCheckListener.onCheckProduto(view, position);
}
});
}
MainActivity.class Define a ProductoAdapter variable and access to list productos to update the boolean value of each producto
[...]
ProductoAdapter productoAdapter = new ProductoAdapter();
[...]
for (int i = 0; i < productoAdapter.getItemCount(); i++) {
productoAdapter.getListProductos().get(i).setCheckBoxState(false);
}
productoAdapter.notifyDataSetChanged();

Updating listView without duplication

I am writing a music player application with playlists, and I am trying to display the songs that have been chosen. All of the code for that works fine, but when a song is added, the listView won't update. I have searched extensively online, but cannot figure out how to fix it. I ended up trying to call leftAdapter.notifyDataSetChanged(); to update the list, but it throws the error:
Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'void android.widget.ArrayAdapter.notifyDataSetChanged()' on a null object reference
I have also tried calling the initializing method (createLeftList()) but it duplicates all of the items in the list.
Method called to initialize listview:
public void createLeftList() {
DatabaseHandler db = new DatabaseHandler(this);
leftSongView = (ListView) findViewById(R.id.left_playlistView);
db.getAllsongs();
ArrayAdapter<String> leftAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, ArrayofName);
leftSongView.setAdapter(leftAdapter);
leftSongView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
public void onItemClick(AdapterView<?> parent, View v, int position, long id) {
Toast.makeText(getApplicationContext(), ((TextView) v).getText(), Toast.LENGTH_SHORT).show();
}
});
}
Method to fetch list and send to listview
public List<LeftPlaylist> getAllsongs() {
List<LeftPlaylist> leftPlaylistList = new ArrayList<LeftPlaylist>();
// Select All Query
String selectQuery = "SELECT * FROM " + TABLE_PLAYLIST;
SQLiteDatabase db = this.getWritableDatabase();
Cursor cursor = db.rawQuery(selectQuery, null);
// looping through all rows and adding to list
if (cursor.moveToFirst()) {
do {
LeftPlaylist leftPlaylist = new LeftPlaylist();
leftPlaylist.setID(Integer.parseInt(cursor.getString(0)));
leftPlaylist.setName(cursor.getString(1));
leftPlaylist.setPath(cursor.getString(2));
String name = cursor.getString(1) +"\n"+ cursor.getString(2);
ListenPage.ArrayofName.add(name);
// Adding song to list
leftPlaylistList.add(leftPlaylist);
} while (cursor.moveToNext());
}
Method called to update the listview after modifying it:
public void updateLeftList(){
leftAdapter.notifyDataSetChanged();
}
Any help would be greatly appreciated!
Here is my SongAdapter code:
public class SongAdapter extends BaseAdapter {
private ArrayList<Song> songs;
private LayoutInflater songInf;
public SongAdapter(Context c, ArrayList<Song>theSongs){
songs=theSongs;
songInf=LayoutInflater.from(c);
}
#Override
public int getCount() {
return songs.size();
}
#Override
public Object getItem(int arg0) {
return null;
}
#Override
public long getItemId(int arg0) {
return 0;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
//map to song layout
LinearLayout songLay = (LinearLayout)songInf.inflate
(R.layout.song, parent, false);
//get title and artist views
TextView songView = (TextView)songLay.findViewById(R.id.song_title);
TextView artistView = (TextView)songLay.findViewById(R.id.song_artist);
//get song using position
Song currSong = songs.get(position);
//get title and artist strings
songView.setText(currSong.getTitle());
artistView.setText(currSong.getArtist());
//set position as tag
songLay.setTag(position);
return songLay;
}
}
Do this in your Activity Class.
public class MyActivity extends Activity {
private SongListAdapter _songListAdapter;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
createLeftList();
}
private void createLeftList(){
DatabaseHandler db = new DatabaseHandler(this);
ListView leftSongView = (ListView) findViewById(R.id.left_playlistView);
_songListAdapter = new SongListAdapter(this, db.getAllsongs());
leftSongView.setAdapter(_songListAdapter);
}
//TODO use this whenever you wanna update your list.
public void updateSongView(List<String> songsList){
if(_songListAdapter != null && songsList != null){
_songListAdapter.updateMusicList(songsList);
}
}
}
Then create and Adapter class and follow the pattern.
public class SongListAdapter extends BaseAdapter{
private Context _context;
private List<String> musicList = new ArrayList();
public SongListAdapter(Context context, List<String> musicList){
_context = context;
this.musicList.clear();
this.musicList.addAll(musicList);
}
public void updateMusicList(List<String> musicList){
this.musicList.clear();
this.musicList.addAll(musicList);
notifyDataSetChanged();
}
#Override
public int getCount() {
return musicList.size();
}
#Override
public Object getItem(int position) {
return musicList.get(position);
}
#Override
public long getItemId(int position) {
return position;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
if(convertView == null){
convertView = LayoutInflater.from(_context).inflate(R.layout.music_view, parent, false);
// TODO folow view holder pattern.
}
String music = (String) getItem(position);
if(music != null){
//TODO update your views Here
}
return convertView;
}
#Override
public void notifyDataSetChanged() {
super.notifyDataSetChanged();
//TODO peform any custon action when this is called if needed.
}
}

Searchview in Android working but displaying incorrect result when clicked on.

So i have a custom adapter with a searchview. I got my searchview to display the correct results whenever I search for a particular person. But when I click on the item in the searchview it returns a result from the original list.
So for example, I have items ab,cd,ef and i search for ef. The searchview returns the 1 item ef. But if I click on it, I will get the data for ab.
How do I fix this? Or do i need to override a method for a onclick for the searchview?
Thank you. (I will post my code (I will take out the nonrelated code), my custom adapter has the searchview code in it. The other is my fragment that contains my searchview and listview list).
My Custom Adapater.
public class oncallAdapter extends ArrayAdapter<OnCallContact> implements SectionIndexer
{
private ArrayList<OnCallContact> contactList;
private Context context;
//For our searchview
private MyFilter filter;
private ArrayList<OnCallContact> mcontactListFilter;
//OUr adapter constructor
//WE have an arraylist which represents the bulletin objects
public oncallAdapter(ArrayList<OnCallContact> ONCALLLIST, Context ctx)
{
super(ctx, R.layout.list_item_oncall, ONCALLLIST);
this.contactList = ONCALLLIST;
this.context= ctx;
this.mcontactListFilter = ONCALLLIST;
}
//This is what sets up the textviews or one item in the listview.
//We are overiding the orignial method
#Override
public View getView(int position, View convertView, ViewGroup parent)
{
//if null then inflate the view which is the row for the bulletins
if(convertView == null)
{
LayoutInflater inflator = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = inflator.inflate(R.layout.list_item_oncall,parent,false);
}
TextView mgroup = (TextView) convertView.findViewById(R.id.oncall_group);
TextView mname = (TextView) convertView.findViewById(R.id.oncall_name);
TextView mCircleText = (TextView) convertView.findViewById(R.id.circleText);
OnCallContact b = contactList.get(position);
//Setting the textviews.
mgroup.setText(b.getMgroup());
mname.setText(b.getMname());
mCircleText.setText(b.getMgroup().substring(0,1).toUpperCase());
return convertView;
}
#Override
public android.widget.Filter getFilter()
{
if(filter == null)
{
filter = new MyFilter();
}
return filter;
}
private class MyFilter extends android.widget.Filter
{
#Override
protected android.widget.Filter.FilterResults performFiltering(CharSequence constraint)
{
FilterResults results = new FilterResults();
if(constraint!= null && constraint.length()>0)
{
//Arraylist where we will add the items (oncallConcacts) that have the letter
ArrayList<OnCallContact> filterList = new ArrayList<>();
for(int i=0; i < mcontactListFilter.size();i++)
{
//CHecking if the letter is in the name
if(mcontactListFilter.get(i).getMname().toUpperCase().contains(constraint.toString().toUpperCase()))
{
OnCallContact contact = new OnCallContact();
contact.setMname(mcontactListFilter.get(i).getMname());
contact.setMgroup(mcontactListFilter.get(i).getMgroup());
contact.setMtitle(mcontactListFilter.get(i).getMtitle());
contact.setMbusinessPhone(mcontactListFilter.get(i).getMbusinessPhone());
contact.setMemail(mcontactListFilter.get(i).getMemail());
contact.setMpager(mcontactListFilter.get(i).getMpager());
contact.setmManagerName(mcontactListFilter.get(i).getmManagerName());
contact.setmManagerBusinessPhone(mcontactListFilter.get(i).getmManagerBusinessPhone());
contact.setmManagerPager(mcontactListFilter.get(i).getmManagerPager());
contact.setmManagerEmail(mcontactListFilter.get(i).getmManagerEmail());
filterList.add(contact);
}
}
results.count = filterList.size();
results.values = filterList;
Log.v("HEre is the filtersize " , "" +filterList.size());
}
else
{
results.count = mcontactListFilter.size();
results.values = mcontactListFilter;
}
return results;
}
#Override
protected void publishResults(CharSequence constraint, FilterResults results)
{
contactList = (ArrayList<OnCallContact>) results.values;
notifyDataSetChanged();
}
}
}
My fragment class
public class OnCallFragment extends android.support.v4.app.Fragment implements SearchView.OnQueryTextListener{
oncallAdapter adapter;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_on_call, container, false);
//Parsing the xml file and getting the data we need which is an arraylist of oncallContacts
OnCallXMLParser b = new OnCallXMLParser();
final ArrayList<OnCallContact> list = b.parse(getContext());
//HEre the custom adapter is making the listviews
adapter = new oncallAdapter(list, getContext());
final ListView listView = (ListView) rootView.findViewById(R.id.onCallListView);
SearchView search = (SearchView)rootView.findViewById(R.id.onCall_searchView);
search.setOnQueryTextListener(this);
//displaying the listview by setting the adapter.
listView.setAdapter(adapter);
listView.setFastScrollEnabled(true);
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
//The contact we are passing through. (Item that was clicked on)
OnCallContact temp = list.get(position);
// Intent i = new Intent(getActivity(), DetailActivity.class).putExtra("extra", ForecastAdapter.getItem(position));
Intent i = new Intent(getActivity(), OnCallDetail.class).putExtra("ContactInformation", temp);
startActivity(i);
}
});
// Inflate the layout for this fragment
return rootView;
}
#Override
public boolean onQueryTextChange(String newText) {
adapter.getFilter().filter(newText);
return false;
}
#Override
public boolean onQueryTextSubmit(String query) {
return false;
}
}
Thank You!!
It may most likely because the position of the result ef within all filtered results, and the position of the result ef within all available items are different. You need to use another variable like a self-defined identifier instead of using position. Refer to this for more information: Wrong item from the listview is selected and ListView custom filter gives wrong item selected when filtered
For anyone that runs into this issue, make sure you override your getcount, getitem. GetItemId should stay as return 0; The other 2 methods you must override them. Hope that helps anyone that may run into this.

How to filter ArrayAdapter?

I'm working on a homework planner app, and I'm looking for a way to display only certain elements in an ArrayList that holds Task objects. After the user clicks on a course from a list of course titles, the list of tasks that pertain to that course should be displayed. Currently, it shows a list of all tasks, no matter which course has been selected. Each Task object stores the course that it belongs to, in a field called mBelongsToCourse. I would like to be able to filter the ArrayList of all tasks that is used in my TaskAdapter to only show the tasks which belong to a specific course, but all my attempts have been fruitless.
Below is my TaskListFragment Class, which includes the TaskAdapter:
public class TaskListFragment extends ListFragment {
private ArrayList<Task> mTasks;
private static String courseName;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setHasOptionsMenu(true);
courseName = getActivity().getIntent().getStringExtra("name");
getActivity().setTitle(courseName);
mTasks = TaskLab.get(getActivity()).getTasks();
TaskAdapter adapter = new TaskAdapter(mTasks);
setListAdapter(adapter);
}
#Override
public void onListItemClick(ListView l, View v, int position, long id) {
//Get the Task from the adapter
Task t = ((TaskAdapter)getListAdapter()).getItem(position);
// Start TaskActivity for this task
Intent i = new Intent(getActivity(), TaskActivity.class);
i.putExtra(TaskFragment.EXTRA_TASK_ID, t.getId());
startActivity(i);
}
#Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
super.onCreateOptionsMenu(menu, inflater);
inflater.inflate(R.menu.fragment_task_list, menu);
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.menu_item_new_task:
Task task = new Task();
task.setBelongsToCourse(courseName);
TaskLab.get(getActivity()).addTask(task);
Intent i = new Intent(getActivity(), TaskActivity.class);
i.putExtra(TaskFragment.EXTRA_TASK_ID, task.getId());
//i.putExtra("cn", task.getBelongsToCourse());
startActivityForResult(i, 0);
return true;
default:
return super.onOptionsItemSelected(item);
}
}
#Override
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
getActivity().getMenuInflater().inflate(R.menu.task_list_item_context, menu);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup parent,
Bundle savedInstanceState) {
View v = super.onCreateView(inflater, parent, savedInstanceState);
ListView listView = (ListView)v.findViewById(android.R.id.list);
listView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE_MODAL);
listView.setMultiChoiceModeListener(new MultiChoiceModeListener() {
public void onItemCheckedStateChanged(ActionMode mode, int position,
long id, boolean checked) {
// Required, but not used in this implementation
}
// ActionMode.Callback methods
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
MenuInflater inflater = mode.getMenuInflater();
inflater.inflate(R.menu.task_list_item_context, menu);
return true;
}
public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
return false;
// Required, but not used in this implementation
}
public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
switch (item.getItemId()) {
case R.id.menu_item_delete_task:
TaskAdapter adapter = (TaskAdapter)getListAdapter();
TaskLab taskLab = TaskLab.get(getActivity());
for (int i = adapter.getCount() - 1; i >= 0; i--) {
if (getListView().isItemChecked(i)) {
taskLab.deleteTask(adapter.getItem(i));
}
}
mode.finish();
adapter.notifyDataSetChanged();
return true;
default:
return false;
}
}
public void onDestroyActionMode(ActionMode mode) {
// Required, but not used in this implementation
}
});
return v;
}
#Override
public boolean onContextItemSelected(MenuItem item) {
AdapterContextMenuInfo info = (AdapterContextMenuInfo)item.getMenuInfo();
int position = info.position;
TaskAdapter adapter = (TaskAdapter)getListAdapter();
Task task = adapter.getItem(position);
switch (item.getItemId()) {
case R.id.menu_item_delete_task:
TaskLab.get(getActivity()).deleteTask(task);
adapter.notifyDataSetChanged();
return true;
}
return super.onContextItemSelected(item);
}
#Override
public void onResume() {
super.onResume();
((TaskAdapter)getListAdapter()).notifyDataSetChanged();
}
private class TaskAdapter extends ArrayAdapter<Task> {
public TaskAdapter(ArrayList<Task> tasks) {
super(getActivity(), 0, tasks);
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
// If we weren't given a view, inflate one
if (convertView == null) {
convertView = getActivity().getLayoutInflater()
.inflate(R.layout.list_item_task, null);
}
// Configure the view for this Task
Task t = getItem(position);
TextView titleTextView =
(TextView)convertView.findViewById(R.id.task_list_item_titleTextView);
titleTextView.setText(t.getTitle());
TextView dateTextView =
(TextView)convertView.findViewById(R.id.task_list_item_dateTextView);
dateTextView.setText(t.getDate().toString());
CheckBox completedCheckBox =
(CheckBox)convertView.findViewById(R.id.task_list_item_completedCheckBox);
completedCheckBox.setChecked(t.isCompleted());
return convertView;
}
}
}
Any help would be greatly appreciated.
EDIT: I've followed the advice of Ravind Maurya and Embattled Swag and updated my TaskAdapter:
private class TaskAdapter extends ArrayAdapter<Task> implements Filterable {
private ArrayList<Task> taskList;
private Filter taskFilter;
public TaskAdapter(ArrayList<Task> tasks) {
super(getActivity(), 0, tasks);
this.taskList = tasks;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
// If we weren't given a view, inflate one
if (convertView == null) {
convertView = getActivity().getLayoutInflater()
.inflate(R.layout.list_item_task, null);
}
// Configure the view for this Task
Task t = getItem(position);
TextView titleTextView =
(TextView)convertView.findViewById(R.id.task_list_item_titleTextView);
titleTextView.setText(t.getTitle());
TextView dateTextView =
(TextView)convertView.findViewById(R.id.task_list_item_dateTextView);
dateTextView.setText(t.getDate().toString());
CheckBox completedCheckBox =
(CheckBox)convertView.findViewById(R.id.task_list_item_completedCheckBox);
completedCheckBox.setChecked(t.isCompleted());
return convertView;
}
#Override
public Filter getFilter() {
if (taskFilter == null)
taskFilter = new TaskFilter();
return taskFilter;
}
private class TaskFilter extends Filter {
#Override
protected FilterResults performFiltering (CharSequence constraint) {
FilterResults results = new FilterResults();
if (constraint == null | constraint.length() == 0) {
results.values = taskList;
results.count = taskList.size();
} else {
ArrayList<Task> newTaskList = new ArrayList<Task>();
for (Task t : taskList) {
if (t.getBelongsToCourse().toUpperCase().startsWith(constraint.toString().toUpperCase())) {
newTaskList.add(t);
}
}
results.values = newTaskList;
results.count = newTaskList.size();
} return results;
}
#SuppressWarnings("unchecked")
#Override
protected void publishResults(CharSequence constraint,
FilterResults results) {
// Now we have to inform the adapter about the new list filtered
if (results.count == 0)
notifyDataSetInvalidated();
else {
taskList = (ArrayList<Task>)results.values;
notifyDataSetChanged();
}
}
}
}
Now the problem I have is I don't know where to call .getFilter().filter(courseName) in order to filter the ArrayList.
I followed this example literally yesterday to come up with a solid filter: http://www.survivingwithandroid.com/2012/10/android-listview-custom-filter-and.html
However; this example doesn't cover the case where you use the backspace and therefore the listview has to repopulate. You can follow the actual source code for the generic Filter here (it's at the bottom...essentially you'll just create a copy and then reduce the items of one of the lists): http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/1.5_r4/android/widget/ArrayAdapter.java#ArrayAdapter.0mOriginalValues

Categories

Resources