I have a list view which uses a base adapter, this is how I initialise it:
if (mBuses.size() < 1) {
// Initialising and loading data into adapter
mBuses = buses;
mBusesAdapter = new BusesArrayAdapter(BusesActivity.this, mBuses);
mBusesView.setAdapter(mBusesAdapter);
} else {
mBuses.addAll(buses);
mBusesAdapter.notifyDataSetChanged();
}
I am using a listener to check when the user scrolls to the bottom it fetches more data from the server the server and appends to the existing set instead of using pagination. It loads 100 items per page.
Now my problem is when I try to filter the data it always only filters the first 100 items, it does not include the other items.
This is my base adapter:
public class BusesArrayAdapter extends BaseAdapter implements Filterable {
private Context context;
private int altColour;
private ArrayList<BusModel> buses;
private BusModel bus;
private ValueFilter valueFilter;
private ArrayList<BusModel> filterList;
private static class ViewHolder{
RelativeLayout container;
TextView id;
TextView busType;
TextView registrationNo;
TextView vehicleModel;
TextView driverName;
TextView driverContact;
ImageButton btnEdit;
ImageButton btnRemove;
}
public BusesArrayAdapter(#NonNull Context context, #NonNull ArrayList<BusModel> buses) {
this.context = context;
this.buses = buses;
this.filterList = new ArrayList<>(buses);
}
#Override
public int getCount() {
return buses.size();
}
#Override
public BusModel getItem(int position) {
return buses.get(position);
}
#Override
public long getItemId(int position) {
return getItem(position).getId();
}
public void remove(BusModel bus) {
buses.remove(bus);
}
#NonNull
#TargetApi(Build.VERSION_CODES.JELLY_BEAN)
#Override
public View getView(final int position, View convertView, #NonNull ViewGroup parent) {
// Get the data item for this position
bus = getItem(position);
// Check if an existing view is being reused, otherwise inflate the view
final ViewHolder viewHolder; // view lookup cache stored in tag
if (convertView == null) {
// If there's no view to re-use, inflate a brand new view for row
viewHolder = new ViewHolder();
LayoutInflater inflater = LayoutInflater.from(context);
convertView = inflater.inflate(R.layout.row_buses, parent, false);
viewHolder.container = (RelativeLayout) convertView.findViewById(R.id.row_buses_ll_container);
viewHolder.id = (TextView) convertView.findViewById(R.id.row_buses_tv_id);
viewHolder.busType = (TextView) convertView.findViewById(R.id.row_buses_tv_bus_type);
viewHolder.registrationNo = (TextView) convertView.findViewById(R.id.row_buses_tv_registration_no);
viewHolder.vehicleModel = (TextView) convertView.findViewById(R.id.row_buses_tv_vehicle_model);
viewHolder.driverName = (TextView) convertView.findViewById(R.id.row_buses_tv_driver_name);
viewHolder.driverContact = (TextView) convertView.findViewById(R.id.row_buses_tv_driver_contact);
viewHolder.btnEdit = (ImageButton) convertView.findViewById(R.id.row_buses_btn_edit);
viewHolder.btnEdit.setTag(position);
viewHolder.btnRemove = (ImageButton) convertView.findViewById(R.id.row_buses_btn_trash);
viewHolder.btnRemove.setTag(position);
// Cache the viewHolder object inside the fresh view
convertView.setTag(viewHolder);
} else {
// View is being recycled, retrieve the viewHolder object from tag
viewHolder = (ViewHolder) convertView.getTag();
}
// Populate the data from the data object via the viewHolder object
// into the template view.
if (altColour == 0) {
viewHolder.container.setBackgroundColor(Color.parseColor("#FFFFFF"));
altColour = 1;
} else {
viewHolder.container.setBackgroundColor(Color.parseColor("#EFEFEF"));
altColour = 0;
}
viewHolder.id.setText(String.valueOf(bus.getId()));
viewHolder.busType.setText(bus.getBusType());
viewHolder.registrationNo.setText(bus.getRegistrationNo());
viewHolder.vehicleModel.setText(bus.getVehicleModel());
viewHolder.driverName.setText(bus.getDriverName());
viewHolder.driverContact.setText(bus.getDriverContact());
viewHolder.btnEdit.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
int position = Integer.parseInt(viewHolder.btnRemove.getTag().toString());
BusModel bus = getItem(position);
if (bus != null) {
Intent editBusIntent = new Intent(context, EditBusActivity.class);
editBusIntent.putExtra("bus", bus);
((Activity) context).startActivityForResult(editBusIntent, 200);
}
}
});
viewHolder.btnRemove.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
int position = Integer.parseInt(viewHolder.btnRemove.getTag().toString());
removeBus(position);
}
});
// Return the completed view to render on screen
return convertView;
}
private void removeBus(final int position) {
AlertDialog.Builder builder = new AlertDialog.Builder(context);
builder.setTitle("Confirm");
builder.setMessage("Are you sure you want to delete this item?");
builder.setPositiveButton("YES", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
BusesRequest busesRequest = new BusesRequest(context);
busesRequest.remove(getItem(position).getId(), mTrashOnSuccessListener, mTrashOnErrorListener);
remove(getItem(position));
notifyDataSetChanged();
}
});
builder.setNegativeButton("NO", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
// Do nothing
dialog.dismiss();
}
});
AlertDialog alert = builder.create();
alert.show();
}
private Response.Listener<JSONObject> mTrashOnSuccessListener = new Response.Listener<JSONObject>() {
#Override
public void onResponse(JSONObject response) {
//
}
};
Response.ErrorListener mTrashOnErrorListener = new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
Utils.showNetworkResponse(context, error);
}
};
#Override
public Filter getFilter() {
// TODO Auto-generated method stub
if (valueFilter == null) {
valueFilter = new ValueFilter();
}
return valueFilter;
}
private class ValueFilter extends Filter {
//Invoked in a worker thread to filter the data according to the constraint.
#Override
protected FilterResults performFiltering(CharSequence constraint) {
FilterResults results = new FilterResults();
if(constraint != null && constraint.length() > 0){
ArrayList<BusModel> filterList = new ArrayList<BusModel>();
for(int i = 0; i < BusesArrayAdapter.this.filterList.size(); i++)
{
BusModel bus = BusesArrayAdapter.this.filterList.get(i);
if((bus.getRegistrationNo().toLowerCase())
.contains(constraint.toString().toLowerCase())
|| (bus.getDriverName().toLowerCase())
.contains(constraint.toString().toLowerCase()) ) {
filterList.add(new BusModel(
bus.getId(),
bus.getBusType(),
bus.getRegistrationNo(),
bus.getVehicleModel(),
bus.getDriverName(),
bus.getDriverContact()
));
}
}
results.count = filterList.size();
results.values = filterList;
} else{
results.count = filterList.size();
results.values = filterList;
}
return results;
}
//Invoked in the UI thread to publish the filtering results in the user interface.
#SuppressWarnings("unchecked")
#Override
protected void publishResults(CharSequence constraint,
FilterResults results) {
buses = (ArrayList<BusModel>) results.values;
notifyDataSetChanged();
}
}
}
because filterList init only once while you are creating an instance of Adapter. you have to put new 100 items in filterList also.
this.filterList = new ArrayList<>(buses);
stores only 100 records when you are creating a new instance like this.
mBusesAdapter = new BusesArrayAdapter(BusesActivity.this, mBuses);
try to add every fetched items filterList also.
Related
i really need help debugging this android app i am building. I have a custom adapter. when i dont use it with simpleSectionAdapter it displays list items correctly, but when i use SimpleSectionAdapter from adapter kit, it displays blank list. I want to have sections in my list according to names. Thanks in advance.
Heres's my adapter
public class CustomContriAdapter extends BaseAdapter implements Filterable{
List<Contributions> contributions;
LayoutInflater inflater;
Context context;
public List<Contributions> orig;
public CustomContriAdapter(Context context, List<Contributions> contributions) {
this.contributions = contributions;
this.context = context;
inflater = LayoutInflater.from(this.context);
}
#Override
public int getCount() {
return contributions.size();
}
#Override
public Object getItem(int position) {
return contributions.get(position);
}
#Override
public long getItemId(int position) {
return 0;
}
public Filter getFilter() {
return new Filter() {
#Override
protected FilterResults performFiltering(CharSequence constraint) {
final FilterResults oReturn = new FilterResults();
final List<Contributions> results = new ArrayList<Contributions>();
if (orig == null)
orig = contributions;
if (constraint != null) {
if (orig != null && orig.size() > 0) {
for (final Contributions g : orig) {
if (g.getContributor_name().toLowerCase()
.contains(constraint.toString()))
results.add(g);
}
}
oReturn.values = results;
}
return oReturn;
}
#SuppressWarnings("unchecked")
#Override
protected void publishResults(CharSequence constraint,
Filter.FilterResults results) {
contributions = (ArrayList<Contributions>) results.values;
notifyDataSetChanged();
}
};
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
MyViewHolder mViewHolder;
if (convertView == null) {
convertView = inflater.inflate(R.layout.contri_list_item_layout, parent, false);
mViewHolder = new MyViewHolder(convertView);
convertView.setTag(mViewHolder);
} else {
mViewHolder = (MyViewHolder) convertView.getTag();
}
Contributions currentListData = (Contributions) getItem(position);
mViewHolder.tvTitleName.setText(currentListData.getContributor_name());
//date created at
Date createdAt = currentListData.getCreated();
DateFormat df = new SimpleDateFormat("yyyy-MM-dd");
String createdDate = df.format(createdAt);
mViewHolder.tvDescDate.setText(createdDate);
return convertView;
}
private class MyViewHolder {
TextView tvTitleName, tvDescDate;
public MyViewHolder(View item) {
tvTitleName = (TextView) item.findViewById(R.id.name_view);
tvDescDate = (TextView) item.findViewById(R.id.contri_created_date);
}
}
}
here's how am calling it in the onCreate()
Collections.sort(allContributions, new Comparator<Contributions>() {
#Override
public int compare(Contributions lhs, Contributions rhs) {
return lhs.getContributor_name().compareTo(rhs.getContributor_name());
}
});
InstantAdapter<Contributions> contribu = new InstantAdapter<Contributions>(
this,R.layout.contri_list_item_layout, Contributions.class, allContributions);
//wrap adapter to simple section adapter
SimpleSectionAdapter<Contributions> sectionAdapter = new SimpleSectionAdapter<Contributions>(
this, contribu, R.layout.section_header, R.id.section_text , new ContributionsSectionizer());
listView.setAdapter(sectionAdapter);
here's the sectionizer,
public class ContributionsSectionizer implements Sectionizer<Contributions> {
#Override
public String getSectionTitleForItem(Contributions contributions) {
return contributions.getContributor_name();
}
}
and the items
protected List<Contributions> allContributions = new ArrayList<>();
I am using a custom adapter with a search filter in a fragment, however the results don't get filtered on a search, I debugged and stepped through my code and find that it is saying that the args.listenere = null!. What does this mean and how do I correct it? My code is below:
---------Custom Adapter -------
public class SalesPartAdapter extends BaseAdapter implements Filterable {
private ArrayList<SalesPartItem> listData;
private ArrayList<SalesPartItem> filteredData;
private SalesPartFilter filter;
private Context _context;
private LayoutInflater layoutInflater;
public SalesPartAdapter(Context context, ArrayList<SalesPartItem> listData) {
this.listData = listData;
layoutInflater = LayoutInflater.from(context);
_context = context;
}
#Override
public int getCount() {
return listData.size();
}
#Override
public Object getItem(int position) {
return listData.get(position);
}
#Override
public long getItemId(int position) {
return position;
}
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder;
//set background colour
if (convertView == null) {
//set up holder
convertView = layoutInflater.inflate(R.layout.salespart_item, null);
holder = new ViewHolder();
holder.salesPartCodeView = (TextView) convertView.findViewById(R.id.salesPartCode);
holder.salesPartDescView = (TextView) convertView.findViewById(R.id.salesPartDescription);
holder.salesPartColourBar= (ImageView) convertView.findViewById(R.id.colourBar);
convertView.setTag(holder);
} else {
//use existing holder
holder = (ViewHolder) convertView.getTag();
}
SalesPartItem salespartView = (SalesPartItem) listData.get(position);
holder.salesPartCodeView.setText(salespartView.SalesPartCode);
holder.salesPartDescView.setText(salespartView.SalesPartDescription);
holder.salesPartColourBar.setBackgroundColor(Color.parseColor(salespartView.Colour));//String.valueOf(salespartView.Colour);
return convertView;
}
/********* holder Class to contain previously inflated xml file elements *********/
static class ViewHolder {
TextView salesPartCodeView;
TextView salesPartDescView;
ImageView salesPartColourBar;
}
public Filter getFilter() {
if (filter == null){
filter = new SalesPartFilter();
}
return filter;
}
ArrayList<SalesPartItem> filteredItems;
ArrayList<Integer>countFilteredItems;
private class SalesPartFilter extends Filter {
#Override
protected FilterResults performFiltering(CharSequence constraint) {
constraint = constraint.toString().toLowerCase();
FilterResults result = new FilterResults();
if(constraint != null && constraint.toString().length() > 0)
{
filteredItems = new ArrayList<SalesPartItem>();
// countFilteredItems = new ArrayList<Integer>();
for(int i = 0, l = listData.size(); i < l; i++)
{
SalesPartItem salesPartItem = listData.get(i);
if(salesPartItem.SalesPartDescription.toString().toLowerCase().contains(constraint))
filteredItems.add(salesPartItem);
// countFilteredItems.add(i);
}
result.count = filteredItems.size();
result.values = filteredItems;
}
else
{
synchronized(this)
{
result.values = listData;
result.count = listData.size();
}
}
return result;
}
#SuppressWarnings("unchecked")
#Override
protected void publishResults(CharSequence constraint, FilterResults results) {
// notifyDataSetChanged();
if (results.count > 0) {
listData =(ArrayList<SalesPartItem>)results.values;
notifyDataSetChanged();
} else {
notifyDataSetInvalidated();
}
}
}
}
----------------Fragment code that deals with the list view -------------------
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
//USE SAMPLE ID TO GET SALES PARTS LIST FROM DATABASE
addSalesParts.setEnabled(false);
//ListViewModel (SalesPartId,salesPartName,NotUsed)
final int numberOfAddedSalesParts = 3;
SalesPartItem sp;
// fill with some dummy data for now.
for (long i = 1; i < numberOfAddedSalesParts; i++) {
sp = new SalesPartItem();
sp.SalesPartItemId = i;
sp.SalesPartCode = "LEU" + i;
if(i!=2){
sp.SalesPartDescription = "Sales Part " + i;
}
else{
sp.SalesPartDescription = "TSalZes Part " + i;
}
sp.Colour = "#cccccc";
salesPartListViewItems.add(sp);
}
// Start of Search filtering
mListView = (ListView) getActivity().findViewById(R.id.salespartsList);
//click on item - edit order
mListView.setTextFilterEnabled(true);
//display the list via our custom adapter
mListView.setAdapter(new SalesPartAdapter(getActivity(), salesPartListViewItems);
EditText searchField = (EditText) getActivity().findViewById(R.id.typeFindSalesPart);
searchField.addTextChangedListener(new TextWatcher() {
public void afterTextChanged(Editable s) {
//TODO Search Lists from Database and filter accordingly
SalesPartAdapter SA = new SalesPartAdapter(getActivity(), salesPartListViewItems);
SA.getFilter().filter(s.toString());
Toast.makeText(getActivity(), s, Toast.LENGTH_SHORT).show();
// salesPartListViewItems.contains(s);
}
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
#Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
});
I have now resolved this, the issue was that I was creating a new instance of the adapter in the text watcher. Once I set it to use the adapter that created the original list then it worked fine
every one! I am a new bie in android...In my app after clicking the button on fragment I switch to new Activity which shows the list then I filtered the list and now I want to get details of selected filtered list item back to calling fragment...I tried for onClick Listener in the getView method of adapter class which extends base adapter but it not switch to calling fragment..it remains there only
My Adapter classs
public class user_list_Adapter extends BaseAdapter {
private Context context;
public static ArrayList<user_list_item> user_arraylist;
private ArrayList<user_list_item> arraylist;
public static String selected_code;
public user_list_Adapter(Context context, ArrayList<user_list_item> user_array) {
this.context = context;
this.user_arraylist = user_array;
this.arraylist = new ArrayList<user_list_item>();
this.arraylist.addAll(user_array);
}
#Override
public int getCount() {
return user_arraylist.size();
}
#Override
public Object getItem(int position) {
return user_arraylist.get(position);
}
#Override
public long getItemId(int position) {
return position;
}
#Override
public View getView(final int position, View convertView, ViewGroup parent) {
if (convertView == null) {
LayoutInflater mInflater = (LayoutInflater)
context.getSystemService(Activity.LAYOUT_INFLATER_SERVICE);
convertView = mInflater.inflate(R.layout.user_row, null);
}
TextView txtname = (TextView) convertView.findViewById(R.id.dname);
TextView txtcode = (TextView) convertView.findViewById(R.id.dcode);
txtname.setText(user_arraylist.get(position).getCust_name());
txtcode.setText(user_arraylist.get(position).getCode());
// Listen for ListView Item Click
convertView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View arg0) {
Deposite df = new Deposite();
MainActivity activity = (MainActivity) context; //this line gives class cast exception
FragmentTransaction transaction = activity.getSupportFragmentManager().beginTransaction();
Bundle b = new Bundle();
b.putString("search_name ", search_name);
b.putString("search_code ", search_code);
df.setArguments(b);
transaction.replace(R.id.content_frame, df);
transaction.addToBackStack(null);
transaction.commit();
}
});
return convertView;
}
// Filter Class
public void filter(String charText) {
charText = charText.toLowerCase(Locale.getDefault());
user_arraylist.clear();
if (charText.length() == 0) {
user_arraylist.addAll(arraylist);
}
else
{
for (user_list_item item : arraylist)
{
if (item.getCust_name().toLowerCase(Locale.getDefault()).contains(charText))
{
user_arraylist.add(item);
}
if (item.getCode().toLowerCase(Locale.getDefault()).contains(charText))
{
user_arraylist.add(item);
}
}
}
notifyDataSetChanged();
}
}
My Adpater class with inner class filter
public class user_list_Adapter extends ArrayAdapter<user_list_item> implements Filterable
{
private Filter mfilter;
private Context context;
private ArrayList<user_list_item> filter_user_list;
private ArrayList<user_list_item> alluserlist;
//public static String selected_code;
public user_list_Adapter(Context context, ArrayList<user_list_item> user_array) {
super(context,R.layout.user_row,user_array);
this.context = context;
this.filter_user_list = user_array;
this.alluserlist = new ArrayList<user_list_item>();
this.alluserlist.addAll(user_array);
}
#Override
public int getCount() {
return filter_user_list.size();
}
#Override
public user_list_item getItem(int position) {
return filter_user_list.get(position);
}
#Override
public long getItemId(int position) {
return filter_user_list.get(position).hashCode();
}
public void resetData() {
filter_user_list = alluserlist;
}
/* *********************************
* We use the holder pattern
* It makes the view faster and avoid finding the component
* **********************************/
private static class UserHolder {
public TextView txtname;
public TextView txtcode;
}
#Override
public View getView(final int position, View convertView, ViewGroup parent) {
UserHolder uholder=new UserHolder();
// First let's verify the convertView is not null
if (convertView == null) {
// This a new view we inflate the new layout
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = inflater.inflate(R.layout.user_row, null);
// Now we can fill the layout with the right values
TextView tvname = (TextView) convertView.findViewById(R.id.dname);
TextView tvcode = (TextView) convertView.findViewById(R.id.dcode);
uholder.txtname = tvname;
uholder.txtcode = tvcode;
convertView.setTag(uholder);
}
else
uholder = (UserHolder) convertView.getTag();
user_list_item p = filter_user_list.get(position);
uholder.txtname.setText(p.getCust_name());
uholder.txtcode.setText(p.getCode());
return convertView;
}
/*
* We create our filter
*/
#Override
public Filter getFilter() {
if (mfilter == null)
mfilter = new userFilter();
return mfilter;
}
private class userFilter extends Filter {
#Override
protected FilterResults performFiltering(CharSequence charText) {
FilterResults results = new FilterResults();
// We implement here the filter logic
if (charText == null || charText.length() == 0) {
// No filter implemented we return all the list
results.values = alluserlist;
results.count = alluserlist.size();
}
else {
// We perform filtering operation
List<user_list_item> uList = new ArrayList<user_list_item>();
for (user_list_item p : filter_user_list) {
if (p.getCust_name().toLowerCase(Locale.getDefault()).contains(charText)) {
uList.add(p);
}
if (p.getCode().toLowerCase(Locale.getDefault()).contains(charText)) {
uList.add(p);
}
}
results.values = uList;
results.count = uList.size();
}
return results;
}
#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 {
filter_user_list = (ArrayList<user_list_item>) results.values;
notifyDataSetChanged();
}
}
}
}
In My search_window Activity class ie.List class which calls adapter class
set onItemclick listener as
// Binds the Adapter to the ListView
list.setAdapter(adapter);
list.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long l) {
// We know that each row in the adapter is a Map
user_list_item row = adapter.getItem(position);
//Toast.makeText(getApplicationContext(),"You Clicked On.."+row.getCust_name(),Toast.LENGTH_LONG).show();
MainActivity.deposite_search_flag = true; //global static variable
MainActivity.search_name = row.getCust_name(); //global
MainActivity.search_code =row.getCode(); //global
for (int i=0;i<RecordList.size();i++){ //user_list_item only contains name n code
if (row.getCode()==Code_Array[i]){
MainActivity.search_available = avail_bal_Array[i];
}
}
finish(); //switch to caller fragment and executes OnResume method of fragment
}
});
by setting global variables on MainActivity class I switched to caller fragment by directly finishing this activity(finish();)
//In caller fragment class
#Override
public void onResume() {
super.onResume();
if (MainActivity.deposite_search_flag){
txtname.setText(MainActivity.search_name);
txtcode.setText(MainActivity.search_code);
txt_available_bal.setText(MainActivity.search_available);
}
}
I want to make a listview item selected and the text "select" to be made to "selected", but when i click an item mutiple items get selected if I select an item at position 0 , items get selected at at a pattern, that is 0,7,14,21 and if i change the view to landscape: it will be 0 ,5,10,15, etc.
my main activity is:
public class two extends Activity implements OnQueryTextListener,OnItemClickListener {
GroupAdapter grpAdapter;
public static ArrayList<GroupsModel> arrayOfList;
public static ListView listView;
public static String base_url = "myurl";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.two);
arrayOfList = new ArrayList<GroupsModel>();
listView = (ListView) findViewById(R.id.group_listview);
listView.setOnItemClickListener(this);
listView.setTextFilterEnabled(true);
new ProgressTask(two.this).execute();
}
private class ProgressTask extends AsyncTask<String, Void, Boolean> {
private ProgressDialog dialog;
#SuppressWarnings("unused")
private two activity;
public ProgressTask(two two) {
this.activity = two;
context = two;
dialog = new ProgressDialog(context);
}
private Context context;
protected void onPreExecute() {
this.dialog.setMessage("Progress start");
this.dialog.show();
}
#Override
protected void onPostExecute(final Boolean success) {
if (dialog.isShowing()) {
dialog.dismiss();
}
grpAdapter = new GroupAdapter(two.this, R.layout.two_row,arrayOfList);
listView.setAdapter(grpAdapter);
}
protected Boolean doInBackground(final String... args) {
//arrayOfList = new ArrayList<GroupsModel>();
List<NameValuePair> params = new ArrayList<NameValuePair>();
//params.add(new BasicNameValuePair("",""));
JSONParser jp = new JSONParser();
JSONArray groups_obj = jp.makeHttpRequest(base_url + "groups/all", "GET", params);
for (int i = 0; i < groups_obj.length(); i++) {
GroupsModel group = new GroupsModel();
try {
JSONObject grp = groups_obj.getJSONObject(i);
group.setGroupId(grp.getInt("id"));
group.setGroupname(grp.getString("name"));
arrayOfList.add(group);
}
catch (JSONException e) {
e.printStackTrace();
}
}
return null;
}
}
#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 = (SearchView) menu.findItem(R.id.menu_item_search).getActionView();
searchView.setSearchableInfo(searchManager.getSearchableInfo(getComponentName()));
searchView.setSubmitButtonEnabled(false);
searchView.setOnQueryTextListener(this);
return super.onCreateOptionsMenu(menu);
}
#Override
public boolean onQueryTextChange(String newText)
{
// this is your adapter that will be filtered
if (TextUtils.isEmpty(newText))
{
listView.clearTextFilter();
}
grpAdapter.getFilter().filter(newText.toString());
return true;
}
#Override
public boolean onQueryTextSubmit(String query) {
// TODO Auto-generated method stub
return false;
}
#Override
public void onItemClick(AdapterView<?> parent, View view, int position,long id) {
// TODO Auto-generated method stub
view.setBackgroundColor(Color.CYAN);
}}
My adapter is:
public class GroupAdapter extends ArrayAdapter<GroupsModel> implements Filterable{
private Context activity;
private ArrayList<GroupsModel> items ;
private List<GroupsModel> arrayList;
private ArrayFilter mFilter;
private int resource;
public GroupAdapter(Activity act, int resource, ArrayList<GroupsModel> arrayList) {
super(act, resource, arrayList);
this.activity = act;
this.resource = resource;
this.items = new ArrayList<GroupsModel>();
this.items.addAll(arrayList);
this.arrayList = new ArrayList<GroupsModel>();
this.arrayList.addAll(arrayList);
}
public View getView(final int position, View convertView,final ViewGroup parent) {
final ViewHolder holder;
LayoutInflater inflater = ((Activity) activity).getLayoutInflater();
if (convertView == null) {
convertView = inflater.inflate(resource,parent, false);
holder = new ViewHolder();
holder.group_name = (TextView) convertView.findViewById(R.id.group_name);
holder.select = (TextView) convertView.findViewById(R.id.select);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
try{
GroupsModel groups = items.get(position);
holder.group_name.setText(groups.getGroupName());
}catch(Exception e){
e.printStackTrace();
}
holder.select.setOnClickListener(new View.OnClickListener() {
public void onClick(View arg0) {
// TODO Auto-generated method stub
holder.select.setText("my new text");
}
});
return convertView;
}
public class ViewHolder {
public TextView group_name,select;
}
#Override
public int getCount() {
// Total count includes list items and ads.
return items.size();
}
#Override
public GroupsModel getItem(int position)
{
// TODO Auto-generated method stub
return items.get(position);
}
#Override
public long getItemId(int position)
{
// TODO Auto-generated method stub
return position;
}
#Override
public Filter getFilter() {
if (mFilter == null) {
mFilter = new ArrayFilter();
}
return mFilter;
}
private class ArrayFilter extends Filter {
#Override
protected FilterResults performFiltering(CharSequence prefix) {
FilterResults results = new FilterResults();
if (arrayList == null) {
synchronized (this) {
arrayList = new ArrayList<GroupsModel>(items);
}
}
if (prefix == null || prefix.length() == 0) {
ArrayList<GroupsModel> list;
synchronized (this) {
list = new ArrayList<GroupsModel>(arrayList);
}
results.values = list;
results.count = list.size();
} else {
String prefixString = prefix.toString().toLowerCase();
ArrayList<GroupsModel> values;
synchronized (this) {
values = new ArrayList<GroupsModel>(arrayList);
}
final int count = values.size();
final ArrayList<GroupsModel> newValues = new ArrayList<GroupsModel>();
for (int i = 0; i < count; i++) {
final String value = values.get(i).getGroupName();
final String valueText = value.toLowerCase();
// First match against the whole, non-splitted value
if (valueText.startsWith(prefixString)) {
newValues.add(values.get(i));
} else {
final String[] words = valueText.split(" ");
final int wordCount = words.length;
// Start at index 0, in case valueText starts with space(s)
for (int k = 0; k < wordCount; k++) {
if (words[k].startsWith(prefixString)) {
newValues.add(values.get(i));
break;
}
}
}
}
results.values = newValues;
results.count = newValues.size();
}
return results;
}
#SuppressWarnings("unchecked")
#Override
protected void publishResults(CharSequence constraint, FilterResults results) {
items = (ArrayList<GroupsModel>) results.values;
if (results.count > 0) {
notifyDataSetChanged();
} else {
notifyDataSetInvalidated();
}
}
}}
I cant figure this out. Please help
You need to maintain the selected item in adapter and use it to change the text :
Adapter Code
private int selectedIndex;
#Override
public View getView(int position, View convertView, ViewGroup parent)
{
final ViewHolder holder;
LayoutInflater inflater = ((Activity) activity).getLayoutInflater();
if (convertView == null) {
convertView = inflater.inflate(resource,parent, false);
holder = new ViewHolder();
holder.group_name = (TextView) convertView.findViewById(R.id.group_name);
holder.select = (TextView) convertView.findViewById(R.id.select);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
if(selectedIndex!= -1 && position == selectedIndex)
{
convert_view.setBackgroundColor(Color.CYAN);
holder.select.setText("selected");
}
else
{
convert_vie.wsetBackgroundColor(default_color);
holder.select.setText("Select");
}
//Your other code .....
return convertView ;
}
public void setSelectedIndex(position)
{
selectedIndex = position;
}
Now set the selectedIndex variable when a list item clicked.
public class MainActivity extends Activity implements OnItemClickListener
{
// Implemented onItemClickListener
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id)
{
adapter.setSelectedIndex(position);
}
}
You can add a member "checked" in GroupsModel, and initial it assign false;
In activity
#Override
public void onItemClick(AdapterView<?> parent, View view, int position,long id) {
final boolean isChecked = listView.getItem(position).isChecked();
listView.get(position).setChecked(!isChecked);
}
In getView() in adapter:
public View getView(...) {
...
if(getItem(position).isChecked()) {
// You must set root view in holder
holder.getBackground().setBackgroundColor(Color.CYAN);
}
...
}
Your problem is that Android is reusing your views, so when you scroll, the first view disappears and appears at the bottom with the same state.
What you need to do is everytime you check an item, you need to store de id/position of the item checked (maybe ArrayList<Integer>), this way everytime your getView method is getting called you will look at this class/structure you have created and see it the row needs to be checked or not.
Note: If the row is not checked you will have to call to myCheck->setChecked(false); in order to assure that the row is in a coherent state.
You must use a array or option object to record which position is selected.
And detect the array or option object in getView() in adapter.
So, your need move the code: "view.setBackgroundColor(Color.CYAN)" to getView() method.
You have been bitten by what they say "recycling" issues.
When re-using your views, this kind of problems happens.
There are several methods(for example saving checked positions in an arraylist, ...) to deal with it, but in my opinion the simplest and straight forward solution is using tags.
setTag() and getTag()
Here is a tutorial using it.
Hope it helps.
I have a problem with my code, I perform a search into a HashMap inside an Adapter. It works fine but when I delete quickly all letters in EditText so the Adapter show the list of the first entire string typed and not the list of all elements.
Example:
I type James, the view get all the James in the Map, but if I delete quickly the EditText (pressing back) so the method perform the search right back and show the correct list for any substring (jame, jam, ja, j) but at the end he shows again the list inherited "James" and not the full contact list
Thank you for any answers!
public class ContactsActivity extends ListActivity {
private HashMap<String, UserEntry> all_map_jid=new HashMap<String, UserEntry>();
private ArrayList<String> all_mkey=new ArrayList<String>();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_contacts);
getListView().setTextFilterEnabled(true);
final EditText searchText = (EditText) findViewById(R.id.searchbox);
TextWatcher textWatcher = new TextWatcher() {
#Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
//... your logic
adapter.getFilter().filter(s.toString());
}
#Override
public void afterTextChanged(Editable arg0) {
// ... your logic
}
#Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
// ... your logic
}
};
searchText.addTextChangedListener(textWatcher);}
public class RosterAdapter extends BaseAdapter implements Filterable{
//private ViewHolder holder;
private LayoutInflater inflater;
private HashMap<String, UserEntry> mappa_users=null;
private ArrayList<String> mKeys;
public RosterAdapter(){
this.mappa_users =new HashMap<String, UserEntry>();
this.inflater= (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);
this.mKeys=new ArrayList<String>();
}
#Override
public int getCount() {
return mappa_users.size();
}
#Override
public UserEntry getItem(int position) {
return mappa_users.get(mKeys.get(position));
}
#Override
public long getItemId(int arg0) {
return arg0;
}
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder;
if (convertView == null) {
convertView = inflater.inflate(R.layout.layout_row, null);
// Creates a ViewHolder and store references to the two children
// views we want to bind data to.
holder = new ViewHolder();
holder.username = (TextView) convertView.findViewById(R.id.user_info);
holder.availability = (ImageView) convertView.findViewById(R.id.user_availability);
holder.user_ic = (ImageView) convertView.findViewById(R.id.icon);
// Keep track of the view holder as a tag of the view
convertView.setTag(holder);
} else {
// Get the ViewHolder back to get fast access to the TextView
// and the ImageView.
holder = (ViewHolder) convertView.getTag();
}
String user = getItem(position).getUserName();
//Log.e("Nome","username "+user);
holder.username.setText(user);
if(!(getItem(position).getUserStatus())){
System.out.println("unavailable");
holder.availability.setImageResource(R.drawable.ic_not_available);
}else{
holder.availability.setImageResource(R.drawable.ic_available);
}
//do your view stuff here
return convertView;
}
#Override
public Filter getFilter() {
return new Filter() {
#SuppressWarnings("unchecked")
#Override
protected void publishResults(CharSequence constraint, FilterResults results) {
mappa_users = (HashMap<String,UserEntry>) results.values;
mKeys= new ArrayList<String>(Arrays.asList(mappa_users.keySet().toArray(new String[mappa_users.size()])));
Collections.sort(mKeys, new RosterEntryComparator(mappa_users));
notifyDataSetChanged();
}
#Override
protected FilterResults performFiltering(CharSequence constraint) {
HashMap<String,UserEntry> searched_user=new HashMap<String,UserEntry>();
FilterResults results = new FilterResults();
if (constraint!= null && constraint.toString().length() > 0) {
SmithWaterman metric = new SmithWaterman();
for(String element : all_mkey){
//La mappa dell'adapter è riempito con le sole entry simily all'occorrenza ricercata
if (metric.getSimilarity(constraint.toString().toLowerCase(), all_map_jid.get(element).getUserName().toLowerCase()) >= 0.8 ){
UserEntry rEntry=all_map_jid.get(element);
searched_user.put(element, rEntry );
}
}
results.values = searched_user;
results.count = searched_user.size();
}
else{
results.values = all_map_jid;
results.count = all_map_jid.size();
}
return results;
}
};
}
Solved
I solved the issue, the problem was that I created a new Filter object on any new typing, using the same Filter all works well, because as is written in the android documentation:
public final void filter (CharSequence constraint,
Filter.FilterListener listener)
Added in API level 1 Starts an asynchronous filtering operation.
Calling this method cancels all previous non-executed filtering
requests and posts a new filtering request that will be executed
later.
This is the correct code:
//My Adapter
public class RosterAdapter extends BaseAdapter implements Filterable{
//private ViewHolder holder;
private LayoutInflater inflater;
private ItemsFilter mFilter;
private HashMap<String, UserEntry> mappa_users=null;
private HashMap<String, UserEntry> all_map_jid=null;
private ArrayList<String> all_mkey=null;;
private ArrayList<String> mKeys;
public RosterAdapter(){
this.mappa_users =new HashMap<String, UserEntry>();
this.inflater= (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);
this.all_map_jid=new HashMap<String, UserEntry>();
this.all_mkey=new ArrayList<String>();
this.mKeys=new ArrayList<String>();
}
#Override
public int getCount() {
return mappa_users.size();
}
#Override
public UserEntry getItem(int position) {
return mappa_users.get(mKeys.get(position));
}
#Override
public long getItemId(int arg0) {
return arg0;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder;
if (convertView == null) {
convertView = inflater.inflate(R.layout.layout_row, null);
// Creates a ViewHolder and store references to the two children
// views we want to bind data to.
holder = new ViewHolder();
holder.username = (TextView) convertView.findViewById(R.id.user_info);
holder.availability = (ImageView) convertView.findViewById(R.id.user_availability);
holder.user_ic = (ImageView) convertView.findViewById(R.id.icon);
// Keep track of the view holder as a tag of the view
convertView.setTag(holder);
} else {
// Get the ViewHolder back to get fast access to the TextView
// and the ImageView.
holder = (ViewHolder) convertView.getTag();
}
String user = getItem(position).getUserName();
//Log.e("Nome","username "+user);
holder.username.setText(user);
if(!(getItem(position).getUserStatus())){
holder.availability.setImageResource(R.drawable.ic_not_available);
}else{
holder.availability.setImageResource(R.drawable.ic_available);
}
//do your view stuff here
return convertView;
}
/**
* Implementing the Filterable interface.
*/
#Override
public Filter getFilter() {
if (mFilter == null) {
mFilter = new ItemsFilter();
}
return mFilter;}
/**
* Custom Filter implementation for the items adapter.
*
*/
private class ItemsFilter extends Filter {
#SuppressWarnings("unchecked")
#Override
protected void publishResults(CharSequence constraint, FilterResults results) {
adapter.mappa_users = (HashMap<String,UserEntry>) results.values;
adapter.mKeys= new ArrayList<String>(Arrays.asList(adapter.mappa_users.keySet().toArray(new String[adapter.mappa_users.size()])));
Collections.sort(mKeys, new RosterEntryComparator(adapter.mappa_users));
notifyDataSetChanged();
Log.e("fine", "Terminato filtraggio "+constraint);
}
#Override
protected FilterResults performFiltering(CharSequence constraint) {
HashMap<String,UserEntry> searched_user=new HashMap<String,UserEntry>();
FilterResults results = new FilterResults();
if (constraint!= null && constraint.toString().length() > 0) {
SmithWaterman metric = new SmithWaterman();
for(String element : all_mkey){
//La mappa dell'adapter è riempito con le sole entry simily all'occorrenza ricercata
if (metric.getSimilarity(constraint.toString().toLowerCase(), all_map_jid.get(element).getUserName().toLowerCase()) >= 0.8 ){
UserEntry rEntry=all_map_jid.get(element);
searched_user.put(element, rEntry );
}
}
results.values = searched_user;
results.count = searched_user.size();
}
else{
results.values = all_map_jid;
results.count = all_map_jid.size();
}
return results;
}
};