这是关于回收问题。我正在使用自定义适配器来填充列表视图。在自定义行中,有一个图像视图,两个文本框和一个复选框。填充了所有元素,但未正确填充复选框。
在getView()
内部执行条件,如果条件为真,我将复选框设置为启用状态。这工作正常,但勾选了正确的复选框,还有一些其他复选框也被勾选。我经历了许多堆栈溢出类似的问题,但无法找到答案。非常感谢任何帮助。
以下是我的适配器类:
public class LocationsListAdapter extends BaseAdapter {
List<Locations> data;
Context context;
Locations userSelectedLocation;
private SharedPreferences locationPreferences;
private SharedPreferences.Editor locationPrefsEditor;
public LocationsListAdapter(List<Locations> data, Context c) {
this.data = data;
this.context = c;
}
@Override
public int getCount() {
return data.size();
}
@Override
public Object getItem(int position) {
// TODO Auto-generated method stub
return data.get(position);
}
@Override
public long getItemId(int position) {
// TODO Auto-generated method stub
return position;
}
@SuppressWarnings("static-access")
@Override
public View getView(final int position, View convertView, ViewGroup parent) {
ViewHolder holder = null;
Log.v("ConvertView", String.valueOf(position));
if (convertView == null) {
LayoutInflater vi = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = vi.inflate(R.layout.find_your_location_row, null);
holder = new ViewHolder();
holder.LocationImage = (SmartImageView) convertView.findViewById(R.id.loca_row_image);
holder.locationName = (TextView) convertView.findViewById(R.id.txt_loca_name);
holder.LocationDescription = (TextView) convertView.findViewById(R.id.txt_loca_desc);
holder.locationCheckText = (TextView) convertView.findViewById(R.id.txt_check);
holder.locationCheck = (CheckBox) convertView.findViewById(R.id.location_check);
holder.locationCheck.setOnCheckedChangeListener(myCheckChangList);
convertView.setTag(holder);
locationPreferences = context.getSharedPreferences("locationPrefs", context.MODE_PRIVATE);
locationPrefsEditor = locationPreferences.edit();
String locationID = locationPreferences.getString("locationID", "");
try {
if(locationID.contains(String.valueOf(data.get(position).getLocationID()))){
holder.locationCheck.setChecked(true);
}
} catch (Exception e) {
Log.e("Fatal", " Exception");
}
holder.locationCheck.setOnClickListener( new OnClickListener() {
@Override
public void onClick(View v) {
userSelectedLocation = data.get(position);
locationPreferences = context.getSharedPreferences("locationPrefs", context.MODE_PRIVATE);
locationPrefsEditor = locationPreferences.edit();
String userSelectedLocationID = userSelectedLocation.getLocationID();
locationPrefsEditor.clear();
locationPrefsEditor.putString("locationID", userSelectedLocationID);
locationPrefsEditor.commit();
Intent intent = new Intent(context, HomeScreen.class);
context.startActivity(intent);
Log.e("Check Box ", "Clicked");
}
});
}else {
holder = (ViewHolder) convertView.getTag();
}
final Locations location = data.get(position);
holder.LocationImage.setImageUrl(location.getImagePath());
holder.locationName.setText(location.getLocationName());
holder.LocationDescription.setText(location.getLocationDescription());
return convertView;
}
@Override
public void unregisterDataSetObserver(DataSetObserver observer) {
if (observer != null) {
super.unregisterDataSetObserver(observer);
}
}
protected class ViewHolder {
protected SmartImageView LocationImage;
protected TextView locationName;
protected TextView LocationDescription;
protected TextView locationCheckText;
protected CheckBox locationCheck ;
}
OnCheckedChangeListener myCheckChangList = new OnCheckedChangeListener() {
public void onCheckedChanged(CompoundButton buttonView,
boolean isChecked) {
Log.e("checked", "");
}
};
}
答案 0 :(得分:1)
您需要在CheckBox
或类似的东西中保存Array
状态,以便在检查/取消选中时记住状态,并在getView(...)
方法结束时,需要根据数组值设置CheckBox的状态。
查看Checkbox not working properly with ListView链接了解更多详情。
答案 1 :(得分:1)
你必须在开始创建一个数组列表并将状态存储为false
时执行类似的操作 private ArrayList<Boolean> itemChecked = new ArrayList<Boolean>();
for (int i = 0; i < this.getCount(); i++) {
itemChecked.add(i, false); // initializes all items value with false
}
每当您点击时只需更改状态并每次都使用更新的值填充列表。
答案 2 :(得分:1)
OnClickListener()仅针对前几个列表项进行声明,并使用相同的&#34;位置&#34;对于所有其他项目。
可以使用的一个选项是,您可以在列表中的每个复选框的标记中设置位置,并从v param中的OnClickListener中获取
答案 3 :(得分:1)
locationPreferences = context.getSharedPreferences("locationPrefs", context.MODE_PRIVATE);
locationPrefsEditor = locationPreferences.edit();
String locationID = locationPreferences.getString("locationID", "");
try {
if(locationID.contains(String.valueOf(data.get(position).getLocationID()))){
holder.locationCheck.setChecked(true);
}
} catch (Exception e) {
Log.e("Fatal", " Exception");
}
只有convertView == null
,才能执行此部分代码。您convertView != null
时没有进行setChecked,这意味着当您重复使用视图时,它将无法正确检查
答案 4 :(得分:1)
我相信你的问题在于你的if / else语句。
如果convertView为null,那么您创建一个新视图并使用所有正确的数据填充它,但如果它不是null(即它是一个循环视图),您只需从标记返回完全相同的视图。您没有对有关设置其属性的视图执行任何操作,因此它保持已有的状态(其中一些已被检查)
拥有有效的viewHolder后设置属性。
您目前拥有此模型。
if (convertView == null) {
//Your code to create the view
// Your code to set the view properties
}else {
holder = (ViewHolder) convertView.getTag();
}
将其更改为此(移动将视图属性设置在if / else之外的代码,以便可以为所有视图设置视图属性,无论它们是否被回收。
if (convertView == null) {
LayoutInflater vi = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = vi.inflate(R.layout.find_your_location_row, null);
holder = new ViewHolder();
holder.LocationImage = (SmartImageView) convertView.findViewById(R.id.loca_row_image);
holder.locationName = (TextView) convertView.findViewById(R.id.txt_loca_name);
holder.LocationDescription = (TextView) convertView.findViewById(R.id.txt_loca_desc);
holder.locationCheckText = (TextView) convertView.findViewById(R.id.txt_check);
holder.locationCheck = (CheckBox) convertView.findViewById(R.id.location_check);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
Locations location = data.get(position);
holder.LocationImage.setImageUrl(location.getImagePath());
holder.locationName.setText(location.getLocationName());
holder.LocationDescription.setText(location.getLocationDescription());
boolean ShouldBoxBeChecked = //Insert check for the current box here
holder.locationCheck.setChecked(ShouldBoxBeChecked);
答案 5 :(得分:1)
在这里,我有一个解决方案。
基本上我已经创建了两个类型字符串的数组列表。当您选中一个复选框时,相应的textview值(或您可以存储到该列表视图项目的任何值)将存储在列表 CHECKEDLIST 中。在另一个列表 ALLVALUES 中,将存储所有值。
在按钮上单击我匹配两个列表,如果匹配发生,那么我从 ALLVALUES 中删除该值并调用notifydatasetchanged
package com.example.test;
import java.io.File;
import java.util.ArrayList;
import android.app.Activity;
import android.content.Context;
import android.os.Bundle;
import android.os.Environment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.View.OnClickListener;
import android.widget.BaseAdapter;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.CompoundButton.OnCheckedChangeListener;
public class MainActivity extends Activity implements OnClickListener {
private ArrayList<String> checkedIndices = new ArrayList<String>();
ArrayList<String> list = new ArrayList<String>();
AScustomadapter adapter;
int count = 0;
private String[] vidNames = {"a","b","c","d","e","f","g","h","i"};
private ListView myList;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button b1 = (Button) findViewById(R.id.button1);
b1.setOnClickListener(this);
for (int i = 0; i < vidNames.length; i++) {
list.add(vidNames[i]);
}
myList = (ListView)findViewById(R.id.list);
adapter = new AScustomadapter(getApplicationContext(), list);
myList.setAdapter(adapter);
}
@Override
public void onClick(View v) {
if(v.getId() == R.id.button1) {
for (int i = 0; i < checkedIndices.size(); i++) {
for(int j = 0; j <list.size();j++){
if(list.get(j).contains(checkedIndices.get(i))){
list.remove(j);
}
}
}
adapter.notifyDataSetChanged();
}
}
public class AScustomadapter extends BaseAdapter {
private ArrayList<String> mListItems;
private LayoutInflater mLayoutInflater;
int i = 0;
public AScustomadapter(Context context, ArrayList<String> arrayList) {
mListItems = arrayList;
//get the layout inflater
mLayoutInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
@Override
public int getCount() {
return mListItems.size();
}
@Override
public Object getItem(int i) {
return list.get(i);
}
@Override
public long getItemId(int i) {
return 0;
}
public int getTotalCheckedCount() {
return checkedIndices.size();
}
@Override
public View getView(final int position, View view, ViewGroup viewGroup) {
ViewHolder holder;
if (view == null) {
holder = new ViewHolder();
view = mLayoutInflater.inflate(R.layout.list_item, null);
holder.itemName = (TextView) view.findViewById(R.id.list_item_text_view);
holder.cb1 = (CheckBox) view.findViewById(R.id.checkBox1);
view.setTag(holder);
} else {
holder = (ViewHolder)view.getTag();
}
final String stringItem = mListItems.get(position);
if (stringItem != null) {
if (holder.itemName != null) {
holder.itemName.setText(stringItem);
}
}
holder.cb1.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
//is chkIos checked?
if (((CheckBox) v).isChecked()) {
if(!checkedIndices.contains(getItem(index).toString()))
checkedIndices.add(getItem(index).toString()); }
else {
checkedIndices.remove(getItem(index).toString());
}
//case 2
}
});
if(checkedIndices.contains((Integer)position)) {
holder.cb1.setChecked(true);
} else {
holder.cb1.setChecked(false);
}
//this method must return the view corresponding to the data at the specified position.
return view;
}
private class ViewHolder {
protected TextView itemName;
protected CheckBox cb1;
}
}
}