问题
I have come accross a bit of a weird problem (i think) with my listview and its customadapter.
The problem is that I have some different view elements for every item in my listview, such as EditText fields among others. Whenever I have more than 2 items in the listview, entries to these elements are now in every other item.
Let me give an example: - I am adding 8 items to the listview. - I enter a value in the first textfield - Now the same value repeats in the textfields: 3, 5 and 7 - If I enter a value in the second item's textfield, this value is repeated in textfield of item number: 4, 6 and 8
I hope that you can see the problem now.
Here is some of the relevant code for this problem:
First, the code for my customadapter (CreateProgramAdapter):
public class CreateProgramAdapter extends BaseAdapter {
private LayoutInflater inflater;
private ArrayList<TrainingPass> trainingPasses;
private List<TrainingPass> items;
private int layoutResourceId;
private Context context;
public CreateProgramAdapter(Context context, List<TrainingPass> items) {
this.context = context;
this.items = items;
this.inflater = LayoutInflater.from(this.context);
}
@Override
public int getCount() {
return items.size();
}
@Override
public TrainingPass 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;
TrainingPassHolder holder;
if(convertView == null) {
view = inflater.inflate(R.layout.adapter_createprogram_trainingpasses_item, parent, false);
holder = new TrainingPassHolder();
view.setTag(holder);
} else {
view = convertView;
holder = (TrainingPassHolder)view.getTag();
}
holder.trainingPass = this.getItem(position);
holder.trainingPass.trainingPassID = position + 1;
holder.trainingPassContainer = (RelativeLayout) view.findViewById(R.id.trainingPassContainer);
holder.trainingPassHeadlineShowHide = (TextView) view.findViewById(R.id.trainingpass_headline);
holder.noExercisesYet = (TextView) view.findViewById(R.id.txt_no_exercises_yet);
holder.exerciseSearchField = (EditText) view.findViewById(R.id.trainingpass_exercise_searchfield);
holder.trainingPassSetsListView = (ListView) view.findViewById(R.id.trainingpass_sets_listview);
holder.exercisesListView = (ListView) view.findViewById(R.id.exercises_listview);
holder.addSetButton = (Button) view.findViewById(R.id.add_set_button);
holder.addExerciseButton = (Button) view.findViewById(R.id.add_exercise_button);
holder.deleteTrainingpass = (Button) view.findViewById(R.id.delete_trainingpass_button);
holder.doneTrainingpass = (Button) view.findViewById(R.id.done_trainingpass_button);
setupItems(holder);
return view;
}
private void setupItems(TrainingPassHolder trainingPassHolder) {
final TrainingPassHolder holder = trainingPassHolder;
int trainingPassID = trainingPassHolder.trainingPass.trainingPassID;
TextView showHide = holder.trainingPassHeadlineShowHide;
Button addSet = holder.addSetButton;
Button deleteTrainingPass = holder.deleteTrainingpass;
final EditText exerciseNameField = holder.exerciseSearchField;
// Set title of the trainingpass
showHide.setText("Trainingpass " + trainingPassID);
// Set name of exercise
if (trainingPassHolder.trainingPass.tempExerciseName != null) {
System.out.println(holder.trainingPass.tempExerciseName);
exerciseNameField.setText(holder.trainingPass.tempExerciseName);
} else {
exerciseNameField.setText("");
}
// Add 1 default set to exercise
if (holder.sets.size() == 0) {
holder.sets.add(1);
}
/*
Set adapter for sets of the listview for the trainingpass
*/
final TrainingPassSetsAdapter createProgramAdapter = new TrainingPassSetsAdapter(context, holder.sets);
holder.trainingPassSetsListView.setAdapter(createProgramAdapter);
exerciseNameField.setOnKeyListener(new View.OnKeyListener() {
@Override
public boolean onKey(View v, int keyCode, KeyEvent event) {
holder.trainingPass.tempExerciseName = exerciseNameField.getText().toString();
return false;
}
});
/*
Show / hide the trainingpass
*/
showHide.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (holder.trainingPass.visible) {
holder.trainingPass.visible = false;
holder.trainingPassContainer.setVisibility(View.GONE);
} else {
holder.trainingPass.visible = true;
holder.trainingPassContainer.setVisibility(View.VISIBLE);
}
}
});
/*
Add set to the listview
*/
addSet.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
holder.sets.add(1);
createProgramAdapter.notifyDataSetChanged();
}
});
/*
Delete training pass
*/
deleteTrainingPass.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
items.remove(holder.trainingPass);
notifyDataSetChanged();
}
});
}
private static class TrainingPassHolder {
ArrayList<Integer> sets = new ArrayList<Integer>();
TrainingPass trainingPass;
RelativeLayout trainingPassContainer;
TextView trainingPassHeadlineShowHide;
TextView noExercisesYet;
EditText exerciseSearchField;
ListView trainingPassSetsListView;
ListView exercisesListView;
Button addSetButton;
Button addExerciseButton;
Button deleteTrainingpass;
Button doneTrainingpass;
}
}
And here is the code for the class TrainingPass:
public class TrainingPass {
public String trainingPassName;
public ArrayList<Exercise> exercises;
public int trainingPassID;
public boolean visible = false;
public String tempExerciseName;
public TrainingPass() {
exercises = new ArrayList<Exercise>();
}
public void addExercise(Exercise exercise ) {
exercises.add(exercise);
}
}
An the code for the activity class CreateProgramActivity:
public class CreateProgramActivity extends CustomActivity {
private ArrayList<TrainingPass> trainingPasses;
private CreateProgramAdapter createProgramAdapter;
private ListView trainingPassesListView;
@Override
protected void onCreate(Bundle savedInstanceState) {
setTheme(R.style.AppTheme);
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_create_program);
trainingPasses = new ArrayList<TrainingPass>();
trainingPassesListView = (ListView)findViewById(R.id.listView_trainingpasses);
createProgramAdapter = new CreateProgramAdapter(CreateProgramActivity.this, trainingPasses);
trainingPassesListView.setAdapter(createProgramAdapter);
}
public void addTrainingPass(View v) {
TrainingPass trainingPass = new TrainingPass();
trainingPasses.add(trainingPass);
createProgramAdapter.notifyDataSetChanged();
}
public void addTrainingPassHelp(View v) {
Toast.makeText(this, "Add training pass HELP!", Toast.LENGTH_SHORT).show();
}
public void createProgram(View v) {
Toast.makeText(this, "Create program", Toast.LENGTH_SHORT).show();
}
}
Here is the xml layout for the CreateProgramActivity, containing the parent listview:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.mobileplatformexam.activities.CreateProgramActivity"
android:id="@+id/relativeLayoutCreateProgram">
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Add training pass"
android:id="@+id/btn_add_trainingpass"
android:layout_alignParentTop="true"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_toLeftOf="@+id/btn_add_trainingpass_help"
android:layout_toStartOf="@+id/btn_add_trainingpass_help"
android:onClick="addTrainingPass"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="\?"
android:id="@+id/btn_add_trainingpass_help"
android:layout_alignParentTop="true"
android:layout_alignParentRight="true"
android:layout_alignParentEnd="true"
android:onClick="addTrainingPassHelp"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Create program"
android:id="@+id/btn_create_program"
android:layout_alignParentBottom="true"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_alignRight="@+id/btn_add_trainingpass_help"
android:layout_alignEnd="@+id/btn_add_trainingpass_help"
android:onClick="createProgram"/>
<ListView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/listView_trainingpasses"
android:layout_above="@+id/btn_create_program"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_below="@+id/btn_add_trainingpass" />
</RelativeLayout>
And lastly, here is my xml layout for the item of the parent listview:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_gravity="center_horizontal"
android:orientation="horizontal"
android:padding="10dp">
<TextView
android:id="@+id/trainingpass_headline"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="false"
android:layout_alignParentTop="true"
android:text="Trainingpass"
android:textSize="16dp"
android:textColor="@android:color/white"
android:background="@android:color/holo_blue_dark"
android:height="35dp"
android:gravity="center_vertical"
android:paddingLeft="10dp"
android:textIsSelectable="true"
android:textStyle="bold"
android:layout_alignParentRight="true"
android:layout_alignParentEnd="true" />
<ImageView
android:id="@+id/trainingpass_showhide_imageview"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@android:color/holo_blue_dark"
android:height="25dp"
android:minWidth="50dp"
android:layout_alignParentRight="true"
android:layout_alignParentEnd="true"
android:padding="7dp"
android:layout_alignBottom="@+id/trainingpass_headline"
android:src="@mipmap/arrows_up_down"
android:layout_alignParentTop="true" />
<RelativeLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_below="@+id/trainingpass_headline"
android:layout_alignLeft="@+id/trainingpass_headline"
android:layout_alignStart="@+id/trainingpass_headline"
android:id="@+id/trainingPassContainer"
android:background="@color/blue_bg_neutral"
android:visibility="visible"
android:paddingBottom="10dp">
<EditText
android:id="@+id/trainingpass_exercise_searchfield"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:hint="Name of exercise"
android:padding="6dp"
android:layout_alignParentTop="true"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_alignParentRight="true"
android:layout_alignParentEnd="true"
android:background="@color/blue_bg_inputField"
android:layout_margin="10dp" />
<RelativeLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_below="@+id/trainingpass_exercise_searchfield"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:id="@+id/sets_container"
android:background="@color/blue_bg_inputField"
android:padding="10dp"
android:layout_marginLeft="10dp"
android:layout_marginRight="10dp"
android:layout_marginTop="10dp">
<TextView
android:id="@+id/txt_sets_for_exercise"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Sets for exercise"
android:textSize="14dp"
android:textColor="@android:color/black"
android:paddingRight="30dp"
android:paddingLeft="0dp"
android:paddingTop="0dp"
android:paddingBottom="10dp"
android:textStyle="bold"
android:layout_alignParentTop="true"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_alignRight="@+id/add_set_button"
android:layout_alignEnd="@+id/add_set_button" />
<ListView
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:id="@+id/trainingpass_sets_listview"
android:nestedScrollingEnabled="true"
android:layout_alignParentRight="true"
android:layout_alignParentEnd="true"
android:layout_alignTop="@+id/txt_no_sets"
android:layout_alignBottom="@+id/txt_no_sets" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Add set"
android:id="@+id/add_set_button"
android:layout_below="@+id/trainingpass_sets_listview"
android:layout_alignParentRight="true"
android:layout_alignParentEnd="true" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Add exercise"
android:id="@+id/add_exercise_button"
android:layout_below="@+id/add_set_button"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_alignParentRight="true"
android:layout_alignParentEnd="true" />
<TextView
android:id="@+id/txt_no_sets"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="No sets yet"
android:textSize="14dp"
android:textColor="@android:color/black"
android:paddingRight="30dp"
android:paddingLeft="10dp"
android:paddingTop="20dp"
android:paddingBottom="10dp"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_alignParentRight="true"
android:layout_alignParentEnd="true"
android:layout_below="@+id/txt_sets_for_exercise"
android:visibility="invisible" />
</RelativeLayout>
<RelativeLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_alignParentEnd="true"
android:layout_below="@+id/sets_container"
android:id="@+id/exercises_container"
android:background="@color/blue_bg_inputField"
android:padding="10dp"
android:layout_marginLeft="10dp"
android:layout_marginRight="10dp"
android:layout_marginTop="10dp">
<TextView
android:id="@+id/txt_exercises"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Exercises"
android:textSize="14dp"
android:textColor="@android:color/black"
android:paddingRight="30dp"
android:paddingLeft="0dp"
android:paddingTop="0dp"
android:paddingBottom="10dp"
android:textStyle="bold"
android:layout_alignParentTop="true"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_alignRight="@+id/txt_no_exercises_yet"
android:layout_alignEnd="@+id/txt_no_exercises_yet" />
<TextView
android:id="@+id/txt_no_exercises_yet"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="No exercises yet"
android:textSize="14dp"
android:textColor="@android:color/black"
android:paddingRight="30dp"
android:paddingLeft="10dp"
android:paddingTop="20dp"
android:paddingBottom="10dp"
android:layout_below="@+id/txt_exercises"
android:layout_alignParentRight="true"
android:layout_alignParentEnd="true"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true" />
<ListView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:id="@+id/exercises_listview"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_below="@+id/txt_exercises"
android:layout_alignBottom="@+id/txt_no_exercises_yet" />
</RelativeLayout>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Delete"
android:id="@+id/delete_trainingpass_button"
android:layout_alignRight="@+id/exercises_container"
android:layout_alignEnd="@+id/exercises_container"
android:layout_below="@+id/exercises_container"
android:background="@color/btn_red"
android:layout_marginLeft="10dp" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Done"
android:id="@+id/done_trainingpass_button"
android:layout_below="@+id/exercises_container"
android:layout_alignLeft="@+id/exercises_container"
android:layout_alignStart="@+id/exercises_container"
android:layout_toStartOf="@+id/delete_trainingpass_button"
android:background="@color/btn_green"
android:layout_marginRight="10dp" />
</RelativeLayout>
</RelativeLayout>
I really hope that someone can see what the problem is.
Any help will be greatly appreciated.
回答1:
I think this behavior is predictable as adapter utilizes views replacing its content with new data. As you didn't set new text value to EditText in the getView() method you get EditText with old value, which is that you entered. So try to add TextWatcher to your EditText and save entered value in the corresponding instance of TrainingPass object. And in the getView() method you have to add of holder.exerciseSearchField.setText(). If corresponding TrainingPass object contains previously entered value you have to set it to EditText, otherwise you have to set empty string.
回答2:
@Oleg Osipenko said its because reuse/recycle of listview.. A Sample
class Items {
String name;
String searchField=""; //to stored edit text values , init with empty string
//create getter and setter
}
Adapter's getView()
@Override
public View getView(int position, View convertView, ViewGroup parent) {
final ViewHolder holder;
if (convertView == null) {
holder = new ViewHolder();
convertView = inflater.inflate(R.layout.your_adapter_layout, null);
holder.textView1 = (TextView) convertView.findViewById(R.id.textView1);
holder.editText1 = (EditText) convertView.findViewById(R.id.editText1);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
//holder.position to store view position
holder.position= position;
item=items.get(position);
holder.textView1.setText(item.getName());
holder.editText1.setText(item.getSearchField());
holder.editText1.addTextChangedListener(new TextWatcher() {
@Override
public void onTextChanged(CharSequence arg0, int arg1, int arg2, int arg3) {
}
@Override
public void beforeTextChanged(CharSequence arg0, int arg1, int arg2,
int arg3) {
}
@Override
public void afterTextChanged(Editable arg0) {
//set more conditions if needed - like arg0=null, or empty
items.get(holder.position).setSearchField(arg0.toString());
}
});
return convertView;
}
private class ViewHolder {
TextView textView1;
EditText editText1;
int position;
}
Get brief explanation about this Visit : Creating ListView with EditText and TextWatcher in Android
来源:https://stackoverflow.com/questions/29814620/listview-with-a-custom-adapter-every-other-item-element-are-duplicates