如何从 ListView 中的视图访问适配器对象

How to access an Adapter object from a View in the ListView

很长一段时间后我要回到 Android,但我遇到了一些问题。
该应用程序包含一个布局列表,每个布局都通过适配器由一个模型支持。
每个布局都有几个视图,其中一个是 Spinner。
想在改变Spinner的值时修改Adapter中的数据,但不知道如何引用Adapter中的对象

public class MainActivity extends AppCompatActivity {
    ArrayList<Troop> values = new ArrayList<Troop>();
    MySimpleArrayAdapter adapter;

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

        values.add(new Troop());

        final ListView listView =(ListView) findViewById(R.id.listview);

        adapter = new MySimpleArrayAdapter(
                this,
                values);
        listView.setAdapter(adapter);
    }

    public class Troop {
        private String weapon;
        private int bs;
        private int total_modifier;

        public Troop() {

        }

        public int getBs() {
            return bs;
        }

        public void setBs(int bs) {
            this.bs = bs;
        }
    }

    public class MySimpleArrayAdapter extends ArrayAdapter {
        private final Context context;
        private ArrayList<Troop> troopers;
        private String[] possible_bs = new String[] {"10", "11", "12", "13", "15", "16"};

        public MySimpleArrayAdapter(Context context, ArrayList<Troop> values) {
            super(context, -1, values);
            this.context = context;
            this.troopers = values;
        }

        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
                LayoutInflater inflater = (LayoutInflater) context
                        .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
                View rowView = inflater.inflate(R.layout.rowlayout, parent, false);

                Spinner bs_spinner = rowView.findViewById(R.id.bs_spinner);
                ArrayAdapter<String> bs_adapter = new ArrayAdapter<String>(
                        context,
                        android.R.layout.simple_spinner_dropdown_item,
                        possible_bs);
                bs_spinner.setOnItemSelectedListener(new CustomOnItemSelectedListener());
                bs_spinner.setAdapter(bs_adapter);
            return rowView;
        }

    }

    public class CustomOnItemSelectedListener implements AdapterView.OnItemSelectedListener {

        public void onItemSelected(AdapterView<?> parent, View view, int pos,long id) {
        // I want to call getBs on the Trooper correspoding to this view here
        }

        @Override
        public void onNothingSelected(AdapterView<?> arg0) {
            // TODO Auto-generated method stub
        }

    }
}

这里有很多我要解决的问题。首先,让我们谈谈您的 ArrayAdapter 子类。

如您问题的评论中所述,您应该将其更改为 extends ArrayAdapter<Troop>。这将导致 getItem() 变为 return Troop 而不是 Object.

您无需存储自己的 contexttroopers 字段。基本 ArrayAdapter 实现在 mContext 字段中存储了一个上下文,您可以通过 getContext() 访问它。此外,它将支持数据存储在 mObjects 字段中,您可以通过 getItem().

访问它

最后,如果您的适配器中的所有项目都将共享相同的 possible_bs 值,您应该将其设为常量。

接下来说说AdapterView.OnItemSelectedListener.

您需要一种方法来了解您的 Spinner 所在的位置(从您的 MySimpleArrayAdapter)(相对于项目 内部 [=49= 的位置) ] Spinner 用户已选择)。我建议将此位置传递给构造函数并将其保存为私有最终字段。

要从 Spinner 内部获取适配器,您可以通过调用 parent.getAdapter() 访问支持 AdapterView 参数的 Adapter,然后将其转换为您的想要的类型。

总的来说,你还剩下这个:

public static class MySimpleArrayAdapter extends ArrayAdapter {

    private static final String[] POSSIBLE_BS = new String[] {"10", "11", "12", "13", "15", "16"};

    public MySimpleArrayAdapter(Context context, ArrayList<Troop> values) {
        super(context, -1, values);
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        LayoutInflater inflater = (LayoutInflater) getContext()
                .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        View rowView = inflater.inflate(R.layout.rowlayout, parent, false);

        Spinner bs_spinner = rowView.findViewById(R.id.bs_spinner);
        ArrayAdapter<String> bs_adapter = new ArrayAdapter<>(
                getContext(),
                android.R.layout.simple_spinner_dropdown_item,
                POSSIBLE_BS);
        bs_spinner.setOnItemSelectedListener(new CustomOnItemSelectedListener(position));
        bs_spinner.setAdapter(bs_adapter);
        return rowView;
    }

}

private static class CustomOnItemSelectedListener implements AdapterView.OnItemSelectedListener {

    private final int troopPosition;

    private CustomOnItemSelectedListener(int troopPosition) {
        this.troopPosition = troopPosition;
    }

    @Override
    public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
        MySimpleArrayAdapter adapter = (MySimpleArrayAdapter) parent.getAdapter();
        int bs = adapter.getItem(troopPosition).getBs();
    }

    @Override
    public void onNothingSelected(AdapterView<?> parent) {

    }
}

您可以匿名移动class。

如果您想要当前 ListView 元素以及内部适配器位置,则需要同时获取两个位置元素。

可能有更简洁的方法来做到这一点,但这是我的第一个想法

public class MySimpleArrayAdapter extends ArrayAdapter<Troop>  {
    private final Context context;
    private ArrayList<Troop> troopers;
    private String[] possible_bs = new String[] {"10", "11", "12", "13", "15", "16"};

    @Override
    public View getView(final int position, View convertView, ViewGroup parent) {
            LayoutInflater inflater = (LayoutInflater) context
                    .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            View rowView = inflater.inflate(R.layout.rowlayout, parent, false);
            Spinner bs_spinner = rowView.findViewById(R.id.bs_spinner);

            final ArrayAdapter<String> bs_adapter = new ArrayAdapter<String>(
                    context,
                    android.R.layout.simple_spinner_dropdown_item,
                    possible_bs);
            bs_spinner.setAdapter(bs_adapter);

            bs_spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() { 

                @Override
                public void onItemSelected(AdapterView<?> parent, View view, int pos, long id) {
                    // You can access MySimpleArrayAdapter.this or bs_adapter
                    Troop t = troopers.get(position); // or getItem(position);
                    String bs = possible_bs[pos];
                }

                @Override
                public void onNothingSelected(AdapterView<?> arg0) {
                    // TODO Auto-generated method stub
                }

            });

        return rowView;
    }