I'm developing for Android and I have an app (called Forget-Me-Not) that uses a ListView as the Tasks screen (Its a ToDo list app). And I have set the items to be grayed out when they are completed.
When the list is bigger than the screen, scrolling occur as usual. But the problem is when scrolled upwards/downwards and come back again, the uncompleted items too have been grayed out. I have checked this many times and the graying-out seems to be random. The items are clickable and they are functioning as expected (i.e. long-clicking, etc). The only problem is the graying-out. (This confuses the users as this app is ToDo list managing app and graying-out is "completing" a task).
I don't know what code to post, so if anyone can tell me what code I should post or could give an answer straightaway, I would be really thankful.
PS: I've got a custom ListAdapter class. It mainly reads the items from SQLite database and sets them to the adapter. You can see the bug in my app- its in the Android Market (Forget-Me-Not).
EDIT:
Here is my custom TaskAdapter class:
public class TasksAdapter extends BaseAdapter {
private String[] items;
private int[] priorities;
private Vector<String> completed;
private Context context;
public TasksAdapter(TasksActivity context, int textViewResourceId, String[] items) {
if(items != null)
this.items = items;
else
this.items = new String[0];
this.priorities = new int[this.items.length];
for(int i = 0; i < this.priorities.length; i++) {
this.priorities[i] = FMN.PRIORITY_LOW;
}
this.completed = new Vector<String>(0);
this.context = context;
}
public TasksAdapter(TasksActivity context, int textViewResourceId, String[] items, int[] priorities, Vector<String> completed) {
if(items != null)
this.items = items;
else
this.items = new String[0];
if(priorities != null)
this.priorities = priorities;
else {
this.priorities = new int[this.items.length];
for(int i = 0; i < this.priorities.length; i++) {
this.priorities[i] = FMN.PRIORITY_LOW;
}
}
if(completed != null)
this.completed = completed;
else
this.completed = new Vector<String>(0);
this.context = context;
}
public View getView(int position, View convertView, ViewGroup parent) {
View v = convertView;
if (v == null) {
LayoutInflater vi = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
v = vi.inflate(R.layout.task_item, null);
}
TextView task = (TextView) v.findViewById(R.id.tv_task);
task.setText(items[position]);
ImageView prio = (ImageView) v.findViewById(R.id.im_task_priority);
switch(priorities[position]) {
case FMN.PRIORITY_HIGH:
prio.setImageResource(R.drawable.fmn_priority_high);
break;
case FMN.PRIORITY_MEDIUM:
prio.setImageResource(R.drawable.fmn_priority_low);
break;
case FMN.PRIORITY_LOW:
prio.setImageResource(R.drawable.fmn_priority_medium);
break;
default:
prio.setImageResource(R.drawable.fmn_priority_medium);
break;
}
if((completed.size() != 0) && (completed.contains(task.getText()))) {
task.setTextColor(Color.rgb(155, 175, 155));
}
return v;
}
public int getCount() {
return items.length;
}
public Object getItem(int position) {
return position;
}
public long getItemId(int position) {
return position;
}
}
And a screenshot BEFORE scrolling:
And AFTER scrolling:
It is probably a bug in your ListAdapter getView. Do you recycle your list objects/items? The properties for colors and so on will remain on the object when recycled. Make sure you set the properties correct depending on in which state the task is in.
In the getView function you probably check if the view-item allready is set and then you just change the text for the task on the item (recycling)? At the same place in the code change the color settings for background to the correct task state.
EDIT
Now that I see your code it looks like you have got the priorities mixed up, default and priority low set the background to prio.setImageResource(R.drawable.fmn_priority_medium);
and medium sets the background to prio.setImageResource(R.drawable.fmn_priority_low);
Ok I found the problem:
if((completed.size() != 0) && (completed.contains(task.getText()))) {
task.setTextColor(Color.rgb(155, 175, 155));
}
You need an else statement here to set the text color to the original color if it is not completed. Like:
if((completed.size() != 0) && (completed.contains(task.getText()))) {
task.setTextColor(Color.rgb(155, 175, 155));
} else {
task.setTextColor(Color.rgb(0, 0, 0));
}
Related
I, am new to android. and I created one view pager which fetching image from firebase. and It's working fine. but there are some loopholes in that view pager which I failed to solve.
1) My View-pager not getting update on real-time basis. Means when ever I modify image in firebase. it's does't effect on real-time basis. I have to close my app and then have to start it again for seeing those updates.
2) When I am removing item from my list in firebase. My app getting crashed and in Logcat this exception is thrown.
java.lang.IndexOutOfBoundsException: Index: -1, Size: 5
at java.util.ArrayList.add(ArrayList.java:483)
at com.release.pack.lootbox.Fragments.HomeFragment$7.onEvent(HomeFragment.java:294)
at com.release.pack.lootbox.Fragments.HomeFragment$7.onEvent(HomeFragment.java:281)
Here is my code:
Slider Image Adapter:
public class SliderImageAdapter extends SliderViewAdapter<SliderImageAdapter.SliderAdapterVH> {
public List<Banner> bannerList;
public Context context;
public SliderImageAdapter(Context context, List<Banner> bannerList) {
this.bannerList = bannerList;
this.context = context;
}
#Override
public SliderAdapterVH onCreateViewHolder(ViewGroup parent) {
View inflate = LayoutInflater.from(parent.getContext()).inflate(R.layout.image_slider_myshop, parent, false);
return new SliderAdapterVH(inflate);
}
#Override
public void onBindViewHolder(final SliderAdapterVH viewHolder, final int position) {
Glide.with(viewHolder.itemView)
.load(bannerList.get(position).getmSliderImage())
.fitCenter()
.into(viewHolder.imageViewBackground);
}
#Override
public int getCount() {
return bannerList.size();
}
class SliderAdapterVH extends SliderViewAdapter.ViewHolder {
View itemView;
ImageView imageViewBackground;
ImageView imageGifContainer;
TextView textViewDescription;
public ProgressBar progressBar;
public ImageView imageViewFailed;
public SliderAdapterVH(View itemView) {
super(itemView);
imageViewBackground = itemView.findViewById(R.id.iv_auto_image_slider);
imageGifContainer = itemView.findViewById(R.id.iv_gif_container);
textViewDescription = itemView.findViewById(R.id.tv_auto_image_slider);
progressBar = itemView.findViewById(R.id.featured_deal_progress);
imageViewFailed = itemView.findViewById(R.id.featured_deal_img_failed_to_load);
this.itemView = itemView;
}
}
}
Home Fragment :
private SliderImageAdapter sliderImageAdapter;
private List<Banner> bannerList;
bannerList = new ArrayList<>();
sliderImageAdapter = new SliderImageAdapter(getActivity(),bannerList);
sliderMyshop = view.findViewById(R.id.imageSlider);
sliderMyshop.setSliderAdapter(sliderImageAdapter);
sliderMyshop.setIndicatorAnimation(IndicatorAnimations.WORM); //set indicator animation by using SliderLayout.IndicatorAnimations. :WORM or THIN_WORM or COLOR or DROP or FILL or NONE or SCALE or SCALE_DOWN or SLIDE and SWAP!!
sliderMyshop.setSliderTransformAnimation(SliderAnimations.SIMPLETRANSFORMATION);
sliderMyshop.setIndicatorSelectedColor(Color.WHITE);
sliderMyshop.setIndicatorUnselectedColor(Color.GRAY);
sliderMyshop.startAutoCycle();
mFirestore.collection("Banner").orderBy("priority", Query.Direction.DESCENDING).addSnapshotListener(new EventListener<QuerySnapshot>() {
#Override
public void onEvent(#javax.annotation.Nullable QuerySnapshot documentSnapshots, #javax.annotation.Nullable FirebaseFirestoreException e) {
if (e != null) {
Log.d(TAG, "Error : " + e.getMessage());
}
assert documentSnapshots != null;
for (DocumentChange doc : documentSnapshots.getDocumentChanges()) {
if (doc.getType() == DocumentChange.Type.ADDED) {
String doc_id = doc.getDocument().getId();
Banner banner = doc.getDocument().toObject(Banner.class).withDocId(doc_id);
bannerList.add(doc.getNewIndex(), banner);
sliderImageAdapter.notifyDataSetChanged();
} else if (doc.getType() == DocumentChange.Type.MODIFIED) {
String docID = doc.getDocument().getId();
Banner changedModel = doc.getDocument().toObject(Banner.class).withDocId(docID);
if (doc.getOldIndex() == doc.getNewIndex()) {
// Item changed but remained in same position
bannerList.set(doc.getOldIndex(), changedModel);
// sliderImageAdapter.notifyItemChanged(doc.getOldIndex());
} else {
// Item changed and changed position
bannerList.remove(doc.getOldIndex());
bannerList.add(doc.getNewIndex(), changedModel);
// sliderImageAdapter.notifyItemMoved(doc.getOldIndex(), doc.getNewIndex());
}
} else if (doc.getType() == DocumentChange.Type.REMOVED) {
// remove
bannerList.remove(doc.getOldIndex());
// sliderImageAdapter.notifyItemRemoved(doc.getOldIndex());
}
}
}
});
When I am adding a new image in firebase it's getting update on real-time basis. but not when I am doing modification in my image. or removing the item from my list.
Getting crashed
bannerList.add(doc.getNewIndex(), banner);
This line is the reason for the IndexOutOfBoundsException.
(java.lang.IndexOutOfBoundsException: Index: -1, Size: 5)
doc.getNewIndex() is returning -1. and list can not accept -1 as an index. so please check your doc.getNewIndex().
For realtime update
bannerList.clear();
add this code before your for loop, otherwise redundant data will be added and you can not update the new changes.
See this: The snapshot handler will receive a new query snapshot every time the query results change (that is, when a document is added, removed, or modified).
for every changes whole collection will be fetched
UPDATE: I tried to create 3 different layouts, one with a green card, other with red, and other yellow. It still not working. All color remain the same. :(
I have a RFID device. When I read tags, it would populate a listview with cardviews which has the tag's code.
I have just 3 rules: If the tag read exists in a text file loaded into the device, the card will become green. If the tag read does not exists in the text file, it becomes yellow. And if I don't read a tag which code exists in the text file (in other words, if the tag is missing) the cardview will become red.
Everything is working. The RFID reader, the app, ok.
But I simply cannot change the colors correctly.
Does anyone know how to do it? Looks simple, but I really can't figure it out.
I did a switch case, I tried if/else, but nothing worked. It simply changes all cards colors to the same one.
It does not changing the color individually.
Actually, the information inside the cardviews are correct! But I cannot understand why the colors does not change individually. All cards become with the same color, does not matter if they were read or not.
This is my adapter class. Please ignore the commented lines, they were all my tries...
public class NewAdapter extends BaseAdapter {
private Context context;
private List<PropsCard> cardProps1;
//private RecyclerView.Recycler<PropsCard> cardProps2;
public NewAdapter(Context context, List<PropsCard> cardProps) {
this.context = context;
this.cardProps1 = cardProps;
}
#Override
public int getCount() {
return cardProps1.size();
}
#Override
public Object getItem(int position) {
return cardProps1.get(position);
}
#Override
public long getItemId(int position) {
return position;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
PropsCard cardProps = cardProps1.get(position);
if (convertView == null) {
for(com.example.compexrf.PropsCard card: cardProps1) {
switch (card.cor) {
case 0:
//Red
//cd.setBackgroundColor(Color.parseColor("#F4BABA"));
//cdview_red.setCardBackgroundColor(Color.RED);
//bt.setBackgroundColor(Color.RED);
//CardView cdview_red = (CardView) convertView.findViewById(R.id.cdviewred);
//convertView.setBackgroundColor(Color.parseColor("#F4BABA"));
//convertView = View.inflate(context, R.layout.card_itens, null);
convertView = LayoutInflater.from(context).inflate(R.layout.card_itens, null);
//convertView.setBackgroundColor(Color.RED);
break;
case 1:
//Yellow
//cd.setBackgroundColor(Color.parseColor("#FCECA4"));
//cdview_yellow.setBackgroundColor(Color.YELLOW);
//CardView cdview_yellow = (CardView) convertView.findViewById(R.id.cdviewyellow);
//convertView.setBackgroundColor(Color.parseColor("#FCECA4"));
//convertView = View.inflate(context, R.layout.card_itens2, null);
convertView = LayoutInflater.from(context).inflate(R.layout.card_itens2, null);
//convertView.setBackgroundColor(Color.YELLOW);
break;
case 2:
//Green
//cd.setBackgroundColor(Color.parseColor("#5FDDC1"));
//cdview_green.setBackgroundColor(Color.GREEN);
//CardView cdview_green = (CardView) convertView.findViewById(R.id.cdviewgreen);
//convertView.setBackgroundColor(Color.parseColor("#5FDDC1"));
//convertView = View.inflate(context, R.layout.card_itens3, null);
convertView = LayoutInflater.from(context).inflate(R.layout.card_itens3, null);
//convertView.setBackgroundColor(Color.GREEN);
break;
default:
break;
}
}
}
TextView desc_txt = (TextView) convertView.findViewById(R.id.descricao);
TextView cod_txt = (TextView) convertView.findViewById(R.id.codigoRFID);
ImageView imageView = (ImageView) convertView.findViewById(R.id.image);
//RelativeLayout relativeLayout = (RelativeLayout) convertView.findViewById(R.id.relative);
CardView cd = (CardView) convertView.findViewById(R.id.cdviewred);
CardView cd2 = (CardView) convertView.findViewById(R.id.cdviewyellow);
CardView cd3 = (CardView) convertView.findViewById(R.id.cdviewgreen);
//Button bt = (Button) convertView.findViewById(R.id.botao);
desc_txt.setText(cardProps.desc);
cod_txt.setText(cardProps.id);
if (cardProps.desc.contains("Controlador")) {
imageView.setImageResource(R.drawable.quadro);
//relativeLayout.setBackgroundColor(Color.parseColor("F4BABA"));
}
else if (cardProps.desc.contains("Quadro")) {
imageView.setImageResource(R.drawable.quadro);
//relativeLayout.setBackgroundColor(Color.parseColor("FCECA4"));
}
else if (cardProps.desc.contains("Quadro")) {
imageView.setImageResource(R.drawable.quadro);
}
else if (cardProps.desc.contains("Câmera de Validação Esteira")) {
imageView.setImageResource(R.drawable.quadro);
}
else if (cardProps.desc.contains("Medicamentos")) {
imageView.setImageResource(R.drawable.med);
//relativeLayout.setBackgroundColor(Color.parseColor("5FDDC1"));
}
else if (cardProps.desc.contains("Impressora")) {
imageView.setImageResource(R.drawable.printer01);
}
else {
imageView.setImageResource(R.drawable.cpx);
}
return convertView;
}
This is another class to help to what I need:
public class PropsCard implements Comparable<PropsCard> {
String id;
String desc;
int cor;
public PropsCard(String id, String desc, int cor){
this.id = id;
this.desc = desc;
this.cor = cor;
}
public PropsCard(String id, int cor){
this.id = id;
this.desc = "";
this.cor = cor;
}
#Override
public boolean equals (Object object){
if(object != null && object instanceof PropsCard){
PropsCard obj = (PropsCard) object;
return id.equals(obj.id);
}
return false;
}
#Override
public int compareTo(PropsCard cdProp){
if(cor > cdProp.cor)
return 1;
else if(cor == cdProp.cor)
return 0;
else
return -1;
}
}
Ans this is my method of RFID reading:
public void onScanCompleted(String code, String rssi, int type) {
PropsCard rdCard = new PropsCard(code, 0);
if(!cardList.contains(rdCard)){
rdCard.cor = 1;
cardList.add(rdCard);
}
else {
int idx = cardList.indexOf(rdCard);
rdCard = cardList.get(idx);
if(rdCard.cor == 0) {
rdCard.cor = 2;
cardList.set(idx, rdCard);
}
}
if(!ScanAndUhf.getHasData())
makeCards(cardList);
}
}
To change CardView background colour, you should use card.setCardBackgroundColor(color); instead of cd.setBackgroundColor(Color.parseColor("#FCECA4"));
I would recommend you to use a custom adapter and use a drawable.
You can see something like that in this Example
Although it changes on click, you just have to implement your logic, but it's going to be something like this:
public void onBindViewHolder(MyViewHolder holder, int position) {
if(youritem==somevalue)
holder.view.setBackgroundColor(Color.GREEN);
else if(youritem==anothervalue)
holder.view.setBackgroundColor(Color.parseColor("#somecolor"));
}
I use something like this to change text colors all the time:
#Override
public void onBindViewHolder(OSCardAdapter.MyViewHolder holder, int position) {
OSActivity OS = OSListFiltered.get(position);
if(holder.status.getText().toString().equals("CLOSED"))
{
holder.status.setTextColor(Color.RED);
}
}
You can use it to change the text color according to your background changes.
I'm trying to implement a listview that has fast scrolling with header previews. It looks like it's almost working correct, but I'm encountering some weird, bug-like behaviour. When I scroll down without using the fast scroll bar, the fast scroll bar disappears, and reappears only almost at the end. So there seems to be a gap or something like that.
My ListView's ArrayAdapter implements SectionIndexer and it's methods getSections(), getPositionForSection(int sectionIndex) and getSectionForPosition(int position). The getPositionForSection method is in my belief, the one causing trouble. When I log the value given by sectionIndex and I scroll down the list, this value exceeds the length of the actual sections (which is 20). This value comes from the SectionIndexer, not from myself. The Android refererence states:
If the section's starting position is outside of the adapter bounds,
the position must be clipped to fall within the size of the adapter.
But when I clip the value to either 0 or section_size -1 (=19), the weird behaviour keeps appearing. Below is my ListView's ArrayAdapter implementing SectionIndexer. One note: the updateSections method is called from outside the adapter when the data changes in an AsyncTask. I hope someone knows what the problem is! Thanks in advance.
public class SoortArrayAdapter extends ArrayAdapter<Soort> implements SectionIndexer {
List<Soort> data;
private HashMap<String, Integer> alphaIndexer;
private ArrayList<String> sections;
public SoortArrayAdapter(#NonNull Context context, int resource, int textViewResourceId, List<Soort> data) {
super(context, resource, textViewResourceId, data);
this.data = data;
sections = new ArrayList<>();
alphaIndexer = new HashMap<String, Integer>();
}
private void updateSections() {
alphaIndexer.clear();
sections = new ArrayList<String>();
for (int i = 0; i < data.size(); i++) {
String s = data.get(i).getNaam().substring(0, 1).toUpperCase();
if (!alphaIndexer.containsKey(s)) {
alphaIndexer.put(s, i);
sections.add(s);
}
}
}
#NonNull
#Override
public View getView(int position, #Nullable View convertView, #NonNull ViewGroup parent) {
if (convertView == null) {
convertView = getLayoutInflater().inflate(android.R.layout.simple_list_item_1, parent, false);
}
TextView textView = convertView.findViewById(android.R.id.text1);
textView.setText(data.get(position).getNaam());
return convertView;
}
#Override
public Object[] getSections() {
return sections.toArray(new String[0]);
}
#Override
public int getPositionForSection(int sectionIndex) {
System.out.println(sectionIndex);
if (sectionIndex >= sections.size()) {
return 0;
}
System.out.println("position for section=" + sections.get(sectionIndex));
return alphaIndexer.get(sections.get(sectionIndex));
}
#Override
public int getSectionForPosition(int position) {
String section = data.get(position).getNaam().substring(0, 1).toUpperCase();
System.out.println("section for position=" + section);
return alphaIndexer.get(section);
}
}
Looks like I misread the documentation for the above stated methods getSectionForPosition() and getPositionForSection(), especially for getSectionForPosition(). This made getPositionForSection() act strangely. I corrected my implementation, so the final implementation of the two methods is as follows:
#Override
public int getPositionForSection(int sectionIndex) {
if (sectionIndex >= sections.size()) {
return data.size() - 1;
}
if (sectionIndex < 0) {
return 0;
}
return alphaIndexer.get(sections.get(sectionIndex));
}
#Override
public int getSectionForPosition(int position) {
String section = data.get(position).getNaam().substring(0, 1).toUpperCase();
for (int i = 0; i < sections.size(); i++) {
if (section.equals(sections.get(i))) {
return i;
}
}
return 0;
}
In my LinearLayout, there's a variable number of CheckBoxes. In a question I had a month ago someone said it´s better to add checkboxes dynamicly instead of make them not visible.
Integer[] count = new Integer[]{1,2,3,4,5,6,7,8,9,10};
size = mFrageList.get(position).getAuswahlList().size();
for (int i = 0; i < size; i++) {
cBox = new CheckBox(this);
cBox.setText(mFrageList.get(position).getAuswahlList().get(i));
cBox.setId(count[i]);
cBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if(isChecked){
antwortencode[position] += "" + buttonView.getId();
frageBeantworten.setText("Antwort :"+antwortencode[position]+" abgeben");
} else {
String id = Integer.toString(buttonView.getId());
antwortencode[position] = antwortencode[position].replaceAll(id,"");
if(!antwortencode[position].isEmpty() || antwortencode[position]!= "") {
frageBeantworten.setText("Antwort :" + antwortencode[position] + " abgeben");
} else {
frageBeantworten.setText("Keine Checkbox(en) gewählt");
}
}
}
});
antworten.addView(cBox);
Currently, I'm able to save a string with the checked checkboxes, if I un-check a checkbox, it deletes it's value out of the string.
If I update the activity, the string is saved, and the checkboxes get a new List from the mFrageList.get(position)getAuswahlList(); and fill a new string in the "antwortencode" List with their values.
If I go back to the last position, I have the string which was generated but the checkboxes aren't checked anymore. But they have the Strings from the old position. that means everything is saved except the state of the checkboxes. I cant set a cBox.setChecked(isChecked) or buttonView.setChecked(isChecked) or buttonView.setChecked(buttonView.isChecked()) or something which is nearly the same in syntax.
I don't know what I can do besides declaring 10 Checkboxes in a xml file to talk to them one by one and set the VISIBLE.false if the auswahlList.get(position).isEmpty().
IMPORTANT: My XML is a Scrollable Activity because the size of the content overextended the screen. Thats why i didn´t and can´t use a Listview. So i need a solution that uses a LinearLayout
The truth is, you should actually use a ListView. As long as you reuse a layout multiple times - do it.
There are 2 options:
ListView as root - add other contents of your layout as different types of view
ListView inside a scrollable layout - there are many lightweight implementations of ListView that allow it to wrap content, e.g. https://github.com/paolorotolo/ExpandableHeightListView
The other thing is how to maintain the state of Checkboxes - use model classes. It's extremely easy with a ListView as it forces you to use an Adapter which provides methods to iterate over all positions.
Example of an adapter:
public class CheckableItemAdapter extends BaseAdapter {
private List<Pair<Integer, Boolean>> items = new ArrayList<>();
public void setItems(List<Pair<Integer, Boolean>> items) {
this.items = items;
}
#Override
public int getCount() {
return items.size();
}
#Override
public Object getItem(int position) {
return items.get(position);
}
#Override
public long getItemId(int position) {
return position;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View view;
ViewHolder holder;
if (convertView == null) {
view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_checkable, parent, false);
holder = new ViewHolder(view);
view.setTag(holder);
} else {
view = convertView;
holder = (ViewHolder) view.getTag();
}
Pair<Integer, Boolean> item = items.get(position);
holder.itemCheck.setChecked(item.second);
return view;
}
static class ViewHolder {
CheckBox itemCheck;
public ViewHolder(View itemView) {
itemCheck = (CheckBox) itemView.findViewById(R.id.check);
}
}
}
I´ve managed to solve my problem alone, and now i want to share it, even if it isn´t the best example of programming.
Integer[] count = new Integer[]{1,2,3,4,5,6,7,8,9,10}; //maximum of 10 Checkboxes
size = mFrageList.get(position).getAuswahlList().size();
for (int i = 0; i < size; i++) {
cBox = new CheckBox(this);
cBox.setText(mFrageList.get(position).getAuswahlList().get(i));
cBox.setId(count[i]);
try{ //this is where the magic happens
if(antwortencode[position] != ""){ //cause i won´t want null in my db i´ve set "" as standard string in my activity for the List<String>
String code = antwortencode[position];
char[] c = code.toCharArray();
for(int j=0;j<=c.length;j++){
int x = c[j] -'0'; // 'char 1' - 'char 0' = Integer 1 , lol
if(cBox.getId()== x){ //compare them
cBox.toggle(); //if it fits, toggle
}
}
}
} catch (Exception e){
e.printStackTrace();
} //and here it ends
cBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
#Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if(isChecked){
antwortencode[position] += "" + buttonView.getId();
frageBeantworten.setText("Antwort :"+antwortencode[position]+" abgeben");
} else {
String id = Integer.toString(buttonView.getId());
antwortencode[position] = antwortencode[position].replaceAll(id,"");
if(!antwortencode[position].isEmpty() || antwortencode[position]!= "") {
frageBeantworten.setText("Antwort :" + antwortencode[position] + " abgeben");
} else {
frageBeantworten.setText("Keine Checkbox(en) gewählt");
}
}
}
});
antworten.addView(cBox);
Ty for the answers and for the correction of my question.
Nostramärus
I have this question related the AutocompleteTextView. Basically I have implemented a custom adapter with a custom Filter which filters a list of custom objects and all is working fine except that when I type in a fast way in the autocompleteTextView seems like a queue of worker filter threads starts and the typing and filtering itself becomes really slow. How can I set only ONE filter at a time based on the latest input of the user (thus cancel the previous filter thread if it actually runs) and set a small delay before starting the filtering so when the user types fast the autocomplete doesn't slow???
Thanks!
EDIT: I have this custom adapter with a Filter implementation:
public class MunicipalitySearchAdapter extends ArrayAdapter<Municipality> {
private ArrayList<Municipality> municipalities;
private ArrayList<Municipality> allMunicipalities;
private ArrayList<Municipality> suggestedMunicipalities;
private List<Trieable> triableList;
private Trie municipalityTrie;
private int viewResourceId;
#SuppressWarnings("unchecked")
public MunicipalitySearchAdapter(Context context, int viewResourceId, ArrayList<Municipality> municipalities) {
super(context, viewResourceId, municipalities);
this.municipalities = municipalities;
this.allMunicipalities = (ArrayList<Municipality>) this.municipalities.clone();
this.suggestedMunicipalities = new ArrayList<Municipality>();
this.viewResourceId = viewResourceId;
this.triableList = new ArrayList<Trieable>();
for (Municipality mun : allMunicipalities) {
triableList.add(mun);
}
municipalityTrie = new Trie(triableList, Locale.ITALY);
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View v = convertView;
if (v == null) {
LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
v = inflater.inflate(this.viewResourceId, null);
}
Municipality municipality = municipalities.get(position);
if (municipality != null) {
TextView munNameTxtView = (TextView) v.findViewById(R.id.name);
TextView proSignTxtView = (TextView) v.findViewById(R.id.sign);
TextView regNameTxtView = (TextView) v.findViewById(R.id.regionName);
if (munNameTxtView != null) {
munNameTxtView.setText(municipality.getName());
}
if (proSignTxtView != null) {
proSignTxtView.setText(municipality.getProvinceSign());
}
if (regNameTxtView != null) {
regNameTxtView.setText(municipality.getRegionName());
}
}
return v;
}
#Override
public Filter getFilter() {
return municipalityFilter;
}
Filter municipalityFilter = new Filter() {
CharSequence filterConstraint;
#Override
public String convertResultToString(Object resultValue) {
String str = ((Municipality) (resultValue)).getName();
return str;
}
#Override
protected FilterResults performFiltering(CharSequence constraint) {
FilterResults filterRes = new FilterResults();
synchronized (filterRes) {
if (this.filterConstraint == null) {
this.filterConstraint = constraint;
}
if (constraint == null || constraint.length() == 0) {
filterRes.values = allMunicipalities;
filterRes.count = allMunicipalities.size();
}
else {
String constraintString = constraint.toString().trim().toLowerCase(Locale.ITALY);
suggestedMunicipalities.clear();
List<Integer> wordsIndexesList = municipalityTrie.getWordsIndexes(municipalityTrie.getRootVertex(), constraintString);
for (int index : wordsIndexesList) {
suggestedMunicipalities.add(allMunicipalities.get(index));
}
List<Integer> prefixesIndexesList = municipalityTrie.getPrefixesIndexes(municipalityTrie.getRootVertex(), constraintString);
for (int index : prefixesIndexesList) {
suggestedMunicipalities.add(allMunicipalities.get(index));
}
filterRes.values = suggestedMunicipalities;
filterRes.count = suggestedMunicipalities.size();
}
}
return filterRes;
}
#Override
protected void publishResults(CharSequence constraint, FilterResults results) {
if (results != null && results.count > 0) {
synchronized (results) {
#SuppressWarnings("unchecked")
ArrayList<Municipality> filteredMunicipalities = (ArrayList<Municipality>) results.values;
ArrayList<Municipality> supportMunicipalitiesList = new ArrayList<Municipality>();
clear();
for (Municipality mun : filteredMunicipalities) {
supportMunicipalitiesList.add(mun);
}
Iterator<Municipality> municipalityIterator = supportMunicipalitiesList.iterator();
while (municipalityIterator.hasNext()) {
Municipality municipality = municipalityIterator.next();
add(municipality);
}
notifyDataSetChanged();
}
}
}
};
}
How can I make a Loader manage this filter worker thread?
Best approach is to use Loader. On textinput change restart the loader to search for the current text. So if there is a loder with same Id is already running it will be restarted. This will make sure you will get the result of last input . I am using this approach in one of my app in play store.
getLoaderManager().restartLoader(0, bundle, callback);
// 0 - I'd
// pass the input text through bundle
// callback - loader callback
Note : you can call restart for the first search itself, it will be created if not exist.
Check this link if your not aware of loader
http://developer.android.com/guide/components/loaders.html