Android: Spinner 和 ListView 具有相同的 ArrayList

Android: Spinner and ListView with the same ArrayList

我正在尝试为给定的项目列表实施选择 activity。每个项目都是可检查的,所以我有一个带有 TextView 和 CheckBox 的项目。我实现了一个用于显示所有选项的 ListView 和一个用于仅显示 "Top Ten" 选择的微调器,作为同一列表的子集。现在我在 ListView 和 Spinner 中显示所有项目。

我希望当用户在 Spinner 中选择一个项目时更新 ListView 中的项目(注意:反向路径工作正常,因为 Spinner 获取更新的 ArrayList每次它下降)。 我试图为我的 Spinner 实现 setOnItemSelectedListener,并在 Listener 中为我的 ListViewAdapter 调用 notifyOnDataSetChanged()。但是 Listener 仅在崩溃时调用,我收到一条奇怪的(可能不相关的)警告消息。

当 Spinner 折叠时,Spinner 的 onItemSelectedListener 仅 运行s。但是 notifyOnDataSetChanged() 似乎忽略了项目的检查状态作为更改。每次检查项目并让 ListAdapter 正确接收更改时,我如何才能做出第一个选项 运行?

这是 Activity.java 代码:

public class TriageReasonActivity extends BaseActivity {

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_triage_reason);

    final String[] select_qualification = {
            "Select Qualification", "10th / Below", "12th", "Diploma", "UG",
            "PG", "Phd"};
    Spinner spinner = (Spinner) findViewById(R.id.top_reasons_spinner);
    ListView symptoms_list  = (ListView) findViewById(R.id.view_list_symptoms);
    ArrayList<Symptoms> listVOs = new ArrayList<>();

    for (int i = 0; i < select_qualification.length; i++) {
        Symptoms reason = new Symptoms();
        reason.setTitle(select_qualification[i]);
        reason.setSelected(false);
        listVOs.add(reason);
    }
    SymptomsListAdapter mListAdapter = new SymptomsListAdapter(this, 0,
            listVOs);
    SymptomsSpinnerAdapter mSpinnerAdapter = new SymptomsSpinnerAdapter(this, 0,
            listVOs);

    symptoms_list.setAdapter(mListAdapter);
    spinner.setAdapter(mSpinnerAdapter);

    spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
        @Override
        public void onItemSelected(AdapterView<?> parentView, View selectedItemView, int position, long id) {
            Log.i("Item selected", "but not cahnged");
            symptoms_list.invalidateViews();
            mListAdapter.notifyDataSetInvalidated();
        }

        @Override
        public void onNothingSelected(AdapterView<?> parentView) {
            Log.i("Not item selected", "but actually it did");
        }

    });
}

SpinnerCustom 适配器代码:

public class SymptomsSpinnerAdapter extends ArrayAdapter<Symptoms>{
private Context mContext;
private ArrayList<Symptoms> listState;
private SymptomsSpinnerAdapter myAdapter;
private boolean isFromView = false;

/*@Override
public void notifyDataSetChanged() {
    super.notifyDataSetChanged();
    //mNotifyOnChange = true;
}*/

public SymptomsSpinnerAdapter(Context context, int resource, List<Symptoms> objects) {
    super(context, resource, objects);
    this.mContext = context;
    this.listState = (ArrayList<Symptoms>) objects;
    this.myAdapter = this;
}

@Override
public View getDropDownView(int position, View convertView,
                            ViewGroup parent) {
    return getCustomView(position, convertView, parent);
}

@Override
public View getView(int position, View convertView, ViewGroup parent) {
    return getCustomView(position, convertView, parent);
}

public View getCustomView(final int position, View convertView,
                          ViewGroup parent) {

    final ViewHolder holder;
    if (convertView == null) {
        LayoutInflater layoutInflator = LayoutInflater.from(mContext);
        convertView = layoutInflator.inflate(R.layout.item_reasons, null);
        holder = new ViewHolder();
        holder.mTextView = (TextView) convertView.findViewById(R.id.text);
        holder.mCheckBox = (CheckBox) convertView.findViewById(R.id.checkbox);
        convertView.setTag(holder);
    } else {
        holder = (ViewHolder) convertView.getTag();
    }

    holder.mTextView.setText(listState.get(position).getTitle());

    // To check weather checked event fire from getview() or user input
    isFromView = true;
    holder.mCheckBox.setChecked(listState.get(position).isSelected());
    isFromView = false;

    if ((position == 0)) {
        holder.mCheckBox.setVisibility(View.INVISIBLE);
    } else {
        holder.mCheckBox.setVisibility(View.VISIBLE);
    }
    holder.mCheckBox.setTag(position);
    holder.mCheckBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {

        @Override
        public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
            int getPosition = (Integer) buttonView.getTag();

            if (!isFromView) {
                listState.get(position).setSelected(isChecked);
            }
        }
    });
    return convertView;
}

@Override
public int getCount() {
    return listState.size();
}

@Override
public Symptoms getItem(int position) {
    if( position < 1 ) {
        return null;
    }
    else {
        return listState.get(position-1);
    }
}

@Override
public long getItemId(int position) {
    return 0;
}

private class ViewHolder {
    private TextView mTextView;
    private CheckBox mCheckBox;
}
}

这是(几乎相同的)ListAdapter:

public class SymptomsListAdapter extends BaseAdapter implements ListAdapter {
private Context mContext;
private ArrayList<Symptoms> listState;
private boolean isFromView = false;


public SymptomsListAdapter(Context context, int resource, List<Symptoms> objects) {
    this.mContext = context;
    this.listState = (ArrayList<Symptoms>) objects;
}

@Override
public View getView(int position, View convertView, ViewGroup parent) {
    return getCustomView(position, convertView, parent);
}

public View getCustomView(final int position, View convertView,
                          ViewGroup parent) {

    ViewHolder holder;
    if (convertView == null) {
        LayoutInflater layoutInflator = LayoutInflater.from(mContext);
        convertView = layoutInflator.inflate(R.layout.item_reasons, null);
        holder = new SymptomsListAdapter.ViewHolder();
        holder.mTextView = (TextView) convertView.findViewById(R.id.text);
        holder.mCheckBox = (CheckBox) convertView.findViewById(R.id.checkbox);
        convertView.setTag(holder);
    } else {
        holder = (SymptomsListAdapter.ViewHolder) convertView.getTag();
    }


    holder.mTextView.setText(listState.get(position).getTitle());

    // To check weather checked event fire from getview() or user input
    isFromView = true;
    holder.mCheckBox.setChecked(listState.get(position).isSelected());
    isFromView = false;

    if ((position == 0)) {
        holder.mCheckBox.setVisibility(View.INVISIBLE);
    } else {
        holder.mCheckBox.setVisibility(View.VISIBLE);
    }
    holder.mCheckBox.setTag(position);
    holder.mCheckBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {

        @Override
        public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
            int getPosition = (Integer) buttonView.getTag();

            if (!isFromView) {
                listState.get(position).setSelected(isChecked);
            }
        }
    });
    return convertView;
}

@Override
public int getCount() {
    return listState.size();
}

@Override
public Symptoms getItem(int position) {
    if( position < 1 ) {
        return null;
    }
    else {
        return listState.get(position-1);
    }
}

@Override
public long getItemId(int position) {
    return 0;
}

private class ViewHolder {
    public TextView mTextView;
    public CheckBox mCheckBox;
}
}

这是我收到的警告:

W/art: Before Android 4.1, method int android.support.v7.widget.DropDownListView.lookForSelectablePosition(int, boolean) would have incorrectly overridden the package-private method in android.widget.ListView

编辑:添加布局和模型 class 以防它们可能导致问题: Activity布局:

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="demo.hb.activity.visit.TriageReasonActivity">

<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textFontWeight="6dp"
        android:textSize="30sp"
        android:layout_margin="20dp"
        android:textAlignment="center"
        android:textColor="#000000"
        android:text="What is the reason for your visit?" />

    <Spinner
        android:id="@+id/top_reasons_spinner"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="@android:drawable/btn_dropdown"
        android:spinnerMode="dropdown"/>



    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        android:layout_gravity="end">

        <ListView
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:id="@+id/view_list_symptoms"
            android:layout_above="@+id/next_btn"
            android:layout_alignParentTop="true"/>

    </RelativeLayout>
</LinearLayout>

</FrameLayout>

项目布局:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content">

<TextView
    android:id="@+id/text"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_marginStart="20dp"
    android:text="text"
    android:textAlignment="gravity" />

<CheckBox
    android:id="@+id/checkbox"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_alignParentEnd="true" />
</RelativeLayout>

型号Class:

public class Symptoms {
private String title;
private boolean selected;

public String getTitle() {
    return title;
}

public void setTitle(String title) {
    this.title = title;
}

public boolean isSelected() {
    return selected;
}

public void setSelected(boolean selected) {
    this.selected = selected;
}
}

没有任何变化的原因是您还没有实现处理数据集变化的方法。您需要处理数据在适配器中的重新加载方式:

public class SymptomsListAdapter extends BaseAdapter implements ListAdapter {
  ...
  public void refreshData(ArrayList<Symptoms> objects){
    this.listState = (ArrayList<Symptoms>) objects;
    notifyDataSetChanged();
  }
  ...
}

这个 link 很好地解释了 notifyDataSetInvalidated() 的工作原理(或者在您的情况下,为什么它不起作用)。