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

Rve
  • 107
  • 2
  • 9

4 Answers4

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;

Community
  • 1
  • 1
Loop
  • 233
  • 1
  • 3
  • 13
  • hints and tips (if they're not actual solutions) should be posted as comments – Stultuske Aug 10 '18 at 07:39
  • 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) – Loop Aug 10 '18 at 07:39
  • @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. – Loop Aug 10 '18 at 07:41
  • 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. – Stultuske Aug 10 '18 at 07:43
  • I do that intentionally, is educational insight frowned upon on SO? I am mostly used to askreddit threads where these types of comments are really valuable to all. – Loop Aug 10 '18 at 07:44
  • I'm not saying it is frowned upon, I'm merely saying an answer should (at the very least) contain an answer. – Stultuske Aug 10 '18 at 07:51
  • Fair enough, it does contain now. – Loop Aug 10 '18 at 07:52
  • After 5 edits my initial answers reaches this point. It's how I work, since I like to commit to a discussion early. Any feedback on the final result? Is it worth continuing like this, since it's mostly a habit to me to start fast and re-edit massively. – Loop Aug 10 '18 at 07:54
  • I'm guessing its an inputMap? – Rve Aug 10 '18 at 07:56
  • 1
    The naming is ambiguous, and that needs to be clarified. Assumptions are the bane of my existence. – Loop Aug 10 '18 at 07:58
  • Sorry, it's a list – Rve Aug 10 '18 at 08:12
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();
}
JohanLarsson
  • 195
  • 1
  • 7
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();
}
Th2mas
  • 11
  • 1
  • 2
0

The answer lied in Android Manifest:

android:windowSoftInputMode="stateHidden"

... had to be replaced with:

android:windowSoftInputMode="adjustPan"
Rve
  • 107
  • 2
  • 9