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.
答案 0 :(得分:2)
我认为这种行为是可预测的,因为适配器利用视图用新数据替换其内容。由于您没有在 getView()方法中将新文本值设置为EditText,因此您将获得具有旧值的EditText,这是您输入的值。 因此,尝试将TextWatcher添加到EditText,并将输入的值保存在TrainingPass对象的相应实例中。在getView()方法中,您必须添加 holder.exerciseSearchField.setText()。如果相应的TrainingPass对象包含先前输入的值,则必须将其设置为EditText,否则必须设置空字符串。
答案 1 :(得分:1)
@Oleg Osipenko说它是因为重复使用/回收listview ..一个样本
class Items {
String name;
String searchField=""; //to stored edit text values , init with empty string
//create getter and setter
}
适配器&#39; 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;
}
获取有关此次访问的简要说明: Creating ListView with EditText and TextWatcher in Android