1

I'm using Java to build an Android application, and I'm trying to build a search function to find a result from a listview. So far, I've managed to get my search function to work, but it doesn't work properly - it only manages to find certain criteria. For example, it finds TC Product name, JC Product name but doesn't find Product name. And if I try to find certain string values, it doesn't seem to find all values either.

Here's my code:

package com.example.user.sortiment;

import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.Filter;
import android.widget.Filterable;
import android.widget.TextView;

import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

/**
 * Created by user on 11.05.2018
 */

public class SortimentAdapter extends BaseAdapter {

LayoutInflater mInflator;
List<Sortiment> map;
List<Sortiment> filterMap;

    public void performFiltering(CharSequence constraint) {

        String filterString = constraint.toString().toLowerCase();
        if (Objects.equals(filterString, "")) {
            filterMap = map;
            notifyDataSetChanged();
            return;
        }

        int count = map.size();
        filterMap = new ArrayList<Sortiment>(count);

        Sortiment filterableSortiment ;

        for (int i = 0; i < count; i++) {
            filterableSortiment = map.get(i);
            if 
(filterableSortiment.name.toLowerCase().contains(filterString)) {
                filterMap.add(filterableSortiment);
            }
        }

        notifyDataSetChanged();

    }

public SortimentAdapter(Context c, List<Sortiment> inputMap) {
    mInflator = (LayoutInflater) 
c.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    map = inputMap;
    filterMap = inputMap;
}

@Override
public int getCount() {
    return filterMap.size();
}

@Override
public Object getItem(int position) {
    return filterMap.get(position);
}

@Override
public long getItemId(int position) {
    return position;
}

@Override
public View getView(int position, View convertView, ViewGroup parent) {

    View v = mInflator.inflate(R.layout.item_layout,null);
    TextView nameTextView = (TextView) v.findViewById(R.id.nameTextView);
    TextView priceTextView = (TextView) v.findViewById(R.id.priceTextView);

    Sortiment viewObject = filterMap.get(position);
    nameTextView.setText(viewObject.name);
    //priceTextView.setText(String.format("%.0f", prices.get(position)));
    priceTextView.setText(viewObject.ean.toString());

    return v;
}

}

I'm suspecting an issue in: if (filterableSortiment.name.toLowerCase().contains(filterString)) { , but im not entirely sure.

Any ideas? Thanks

4
  • 3
    here is possibly/probably part of your problem: filterString == "". use equals to compare Objects' values, not == Commented Aug 10, 2018 at 7:33
  • Thanks for the answer, tried it, but didn't work. Commented Aug 10, 2018 at 7:38
  • Or even better use filterString.length == 0 for faster computation Commented Aug 10, 2018 at 7:38
  • @Rve I didn't say it solves everything, but it does fix one problem in your code Commented Aug 10, 2018 at 7:40

4 Answers 4

1

Edit:

Now that the full code has been posted, the map seems to be a list. My below explanations shouldn't apply to your example, apart from some general info on how maps work.

 

Maps, how do they work?

You are doing a for over a map, where the keys might not be in order necessarily.

Here is an explanation of how a map works.

A map is a key-value pair dictionary, not a simple list/array as you mentioned in your title.

This is my assumption, and I might be wrong, but something that looks weird to me is this line:

filterableSortiment = map.get(i);

This one gets via the key i, and not by the i'th position in the list, because a map is not a list.

A map in the mathematical sense is defined as: "A mapping of elements from one set to another."

Pay attention if the mapping is linear like an array, if not you might not reach all your elements.

 

The core issue:

The map you are using probably doesn't have linear keys and cannot be accessed by a simple increasing i for loop.

Check the structure of your map, by inspecting it at debug.

If your key-value pairs don't look like an array:

0 1 2 3 4 5

| | | | | |

A B C D E F

Then your algorithm will miss elements.

For example if in the map some elements have been added with the key 2324, when your count is just 30 elements, you will miss that since your map is sparsely populated through its keys.

If your map looks like

1 5 7 8 9 23

| | | | | |

A B C D E F

If you do a for 0 > map.count

You will go

map.get(0) - returns nothing

map.get(1) - returns A

map.get(2) - returns nothing

map.get(3) - returns nothing

map.get(4) - returns nothing

map.get(5) - returns B

The C, D, E and F elements are missed out with this approach, if the keys are not in order like in an array "map".

 

The solution:

I would suggest using an appropriate iterator (for each loop) on your map, instead of using a for loop that has a linearly increasing index i since you might miss the gaps in the map.

Refer to this answer or this answer

 

Follow-up questions:

  • Can you mention what data type the map is in your example?

filterMap = map;

Sign up to request clarification or add additional context in comments.

11 Comments

hints and tips (if they're not actual solutions) should be posted as comments
Basically, an array is a specific case of a map, where the mapping is one to one via a growing key (i a consecutive number index)
@Stultuske I am new on SO, is that an enforced rule, or just the common wisdom? What I was doing the past days was building on my solution through edits. This is the first thoughts and draft on the solution, but I was intending to expand on it while I think.
answers are meant to be clear and (short as possible) responses the OP can use to fix his specific problem. Sure, it can contain some additional information providing more insight, but it seems to me you are providing quite a bit insight, but no solution to what the OP did wrong in his code.
The naming is ambiguous, and that needs to be clarified. Assumptions are the bane of my existence.
|
1

Now you have updated your answer and it is clear that your "maps" are not maps at all. Hence this is invalidated now. In the future, supply enough information so that your questions can be answered.

public void performFiltering(CharSequence constraint) {

    String filterString = constraint.toString().toLowerCase();
    if (filterString.equals("")) {
        filterMap = map;
        notifyDataSetChanged();
        return;
    }

    int count = map.size();
    filterMap = new ArrayList<Sortiment>(count);

    Sortiment filterableSortiment ;

    for (filterMap.Entry<String, String> entry : filterMap.entrySet())
    {
        filterableSortiment = entry.getValue();
        if (filterableSortiment.name.toLowerCase().contains(filterString)) {
            filterMap.add(filterableSortiment);
        }
    }
    notifyDataSetChanged();
}

3 Comments

Why are you calling them "maps" when they are lists?! Well, now my answer will not work, but it would have worked if they were maps.
did you ask that question to yourself?
@Stultuske No, I made a mistake by adding it here to my answer after Rve updated his question. I'll update my answer with my frustration.
1

If you just want to filter your entries in your Sortiment list, I would recommend the Java 8 Stream API. This will filter all your entries in 'map' and save the result in 'filterMap'.

import java.util.List;
import java.util.stream.Collectors;

public void performFiltering(CharSequence constraint) {
    String filterString = constraint.toString().toLowerCase();

    // Define what to do, if filterString is an empty String
    if(filterString.isEmpty()){
        filterMap = map;
        notifyDataSetChanged();
        return;
    }

    // Filter through the sortiment list
    filterMap = map.stream()
        .filter(s -> s.name.toLowerCase().contains(filterString))
        .collect(Collectors.toList());

    notifyDataSetChanged();
}

Comments

0

The answer lied in Android Manifest:

android:windowSoftInputMode="stateHidden"

... had to be replaced with:

android:windowSoftInputMode="adjustPan"

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.