Reputation: 80
My app has a listView containing several items, and an editText with a customAdapter. Filtering my items for the given text goes completely fine, but when I try to "open" an item (by passing it to a new Intent) from an already filtered ist, getItemAtPosition(position)
returns the item at the given position from the original list, but not from the filtered one. How can I change my code for it to return the item at at the exact position from the filtered list?
MainActivity.java
package fasde.android.distanceapp.View;
import android.content.Intent;
import android.os.Bundle;
import android.text.Editable;
import android.text.TextWatcher;
import android.view.View;
import android.widget.AdapterView;
import android.widget.EditText;
import android.widget.ListView;
import androidx.appcompat.app.AppCompatActivity;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.Map;
import java.util.TreeMap;
import fasde.android.distanceapp.Controller.SpielortAdapter;
import fasde.android.distanceapp.DataBase.SaveData;
import fasde.android.distanceapp.Model.Spielort;
import fasde.android.distanceapp.R;
import lombok.NonNull;
/**
* Creates a Activity about a ListView of Spielorts.
*/
public class MainActivity extends AppCompatActivity {
ListView listView;
SpielortAdapter spielortAdapter;
EditText editText;
/**
* Gets the whole app running. Creates a listView, an editText and a spielortAdapter and gets
* all of them running.
*
* @param savedInstanceState
*/
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Intent intent = getIntent();
@NotNull
String variante = intent.getStringExtra("variante");
listView = findViewById(R.id.list);
editText = findViewById(R.id.inputSearch);
ArrayList<Spielort> spielorts = new ArrayList<>();
Map<String, Spielort> vereine = new TreeMap<>();
vereine.putAll(SaveData.fillVereine(variante));
for (Map.Entry<String, Spielort> entry : vereine.entrySet()) {
spielorts.add(entry.getValue());
}
spielortAdapter = new SpielortAdapter(this, spielorts);
listView.setAdapter(spielortAdapter);
editText.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
// Nothing
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
MainActivity.this.spielortAdapter.getFilter().filter(s);
}
@Override
public void afterTextChanged(Editable s) {
// Nothing
}
});
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
Intent openDetail = new Intent(MainActivity.this, SpielortDetailActivity.class)
.putExtra("spielort", ((Spielort) listView.getItemAtPosition(position)).toStringArray());
startActivity(openDetail);
}
});
}
}
SpielortAdapter.java
package fasde.android.distanceapp.Controller;
import android.annotation.SuppressLint;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.Filter;
import android.widget.TextView;
import androidx.annotation.LayoutRes;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.List;
import fasde.android.distanceapp.Model.Spielort;
import fasde.android.distanceapp.R;
/**
* Custom Adapter for a ListView of Spielorts.
*/
public class SpielortAdapter extends ArrayAdapter<Spielort> {
private Context context;
private List<Spielort> spielortList;
private List<Spielort> filteredList;
private List<Spielort> allDataList;
private SpielortFilter filter;
/**
* Constructor for SpielortAdapter, that creates an instance of this class while giving a
* context and an ArrayList<Spielort>, that is used to initalize two beforehandly declared
* Lists.
*
* @param context
* @param spielortList
*/
public SpielortAdapter(@NonNull Context context, @SuppressLint("SupportAnnotationUsage") @LayoutRes ArrayList<Spielort> spielortList) {
super(context, 0, spielortList);
this.context = context;
this.spielortList = spielortList;
this.allDataList = spielortList;
}
/**
* Returns the size of the spielortList used at the moment.
*
* @return int
*/
@Override
public int getCount() {
return spielortList.size();
}
/**
* Returns an View-element which is used in the ListView. This element contains a Spielort.
*
* @param position
* @param convertView
* @param parent
* @return View
*/
@NonNull
@Override
public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) {
View listItem = convertView;
if (listItem == null) {
listItem = LayoutInflater.from(context).inflate(R.layout.list_item, parent, false);
}
Spielort ort = spielortList.get(position);
TextView spielort = listItem.findViewById(R.id.textView_ort);
spielort.setText("\t" + ort.getSpielort());
TextView km = listItem.findViewById(R.id.textView_km);
km.setText(ort.getDistanz() + "km");
TextView kosten = listItem.findViewById(R.id.textView_kosten);
kosten.setText(ort.getKosten().toString() + "€");
TextView kreis = listItem.findViewById(R.id.textView_kreis);
kreis.setText(ort.getKreis().getName());
return listItem;
}
/**
* Returns the current Filter. If it is null, a new one is initialized.
*
* @return Filter
*/
@Override
public Filter getFilter() {
if (filter == null) {
filter = new SpielortFilter();
}
return filter;
}
private class SpielortFilter extends Filter {
/**
* Filters the Spielorts in the spielortList. Every Spielort, which name contains the
* constraint, is returned.
*
* @param constraint
* @return FilterResults
*/
@Override
protected FilterResults performFiltering(CharSequence constraint) {
FilterResults results = new FilterResults();
filteredList = new ArrayList<>();
for (Spielort ort : allDataList) {
if (ort.getSpielort().toLowerCase().contains(constraint.toString().toLowerCase())) {
filteredList.add(ort);
}
}
results.count = filteredList.size();
results.values = filteredList;
return results;
}
/**
* Publishes the results of the filtering to the listView.
*
* @param constraint
* @param results
*/
@SuppressWarnings("unchecked")
@Override
protected void publishResults(CharSequence constraint, @NotNull FilterResults results) {
spielortList = (ArrayList<Spielort>) results.values;
notifyDataSetChanged();
}
}
}
Upvotes: 1
Views: 274
Reputation: 141
You should get the item directly from your adapter. Add the following method to your SpielortAdapter :
public Model getItemAtPosition(int position)
{
return spielortList.get(position);
}
and call that from your OnItemClickListener implementation:
spielortAdapter.getItemAtPosition(position)
Upvotes: 1
Reputation: 19
Create getter method for spielortList in SpielortAdapter class and use that in this way
//in adapter class
public List<Spielort> getList(){
return spielortList;
}
//in activity class
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
Intent openDetail = new Intent(MainActivity.this, SpielortDetailActivity.class)
.putExtra("spielort", (spielortAdapter .getList().get(position)).toStringArray());
startActivity(openDetail);
}
});
Upvotes: 1
Reputation: 2857
When you call ListView.getItemAtPosition()
method, it calls Adapter.getItem()
methods and return the result. The easiest way to solve the problem is overriding Adapter.getItem()
method in SpielortAdapter
class like bellow:
@Override
public Spielort getItem(int position) {
return spielortList.get(position);
}
Upvotes: 1