【问题标题】:Pass String variables by reference to setOnItemSelectedListener of multiple Spinners通过引用多个 Spinner 的 setOnItemSelectedListener 传递字符串变量
【发布时间】:2012-01-18 04:47:45
【问题描述】:

好的,我 read around 看到 Java 只通过值传递,而不是通过引用传递,所以我不知道如何实现。

  • 我在一个 Android Activity 中有 6 个 Spinner,它们填充了不同的 SQLite 查询。
  • 填充每个 Spinner 和设置 OnItemSelectedListener 的代码非常相似,因此我希望重构为一种方法,并使用每个 Spinner ID 和 Sqlite 查询调用 6 次。
  • 如何让 Spinner onItemSelectedListener 更改每个不同 Spinner 上的正确实例成员?

    public void fillSpinner(String spinner_name, final String field_name) {
    // This finds the Spinner ID passed into the method with spinner_name
    // from the Resources file. e.g. spinner1
    int resID = getResources().getIdentifier(spinner_name, "id",
            getPackageName());
    Spinner s = (Spinner) findViewById(resID);
    final Cursor cMonth;
    // This gets the data to populate the spinner, e.g. if field_name was
    // strength = SELECT _id, strength FROM cigars GROUP BY strength
    cMonth = dbHelper.fetchSpinnerFilters(field_name);
    startManagingCursor(cMonth);
    String[] from = new String[] { field_name };
    int[] to = new int[] { android.R.id.text1 };
    SimpleCursorAdapter months = new SimpleCursorAdapter(this,
            android.R.layout.simple_spinner_item, cMonth, from, to);
    months.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
    s.setAdapter(months);
    // This is setting the Spinner Item Selected Listener Callback, where
    // all the problems happen
    s.setOnItemSelectedListener(new OnItemSelectedListener() {
        public void onItemSelected(AdapterView<?> parent, View view,
                int position, long id) {
            Cursor theCursor = (Cursor) parent.getSelectedItem();
            // This is the problem area.
            object_reference_to_clas_member_of_field_name = theCursor
                    .getString(theCursor.getColumnIndex(field_name));
        }
    
        public void onNothingSelected(AdapterView<?> parent) {
            // showToast("Spinner1: unselected");
        }
    });
    

    }

您像这样调用此方法fillSpinner("spinner1","strength");

它找到 id 为 spinner1 的微调器,并在数据库中查询 strength 字段。 field_name,在此示例中是强度必须声明为要在 onItemSelectedListener 中使用的最终变量,否则我会收到错误 Cannot refer to a non-final variable field_name inside an inner class defined in a different method

但是当使用每个不同的 Spinner 时,如何让 onItemSelectedListener 更改不同实例成员的值?这是最重要的代码行: object_reference_to_clas_member_of_field_name = theCursor .getString(theCursor.getColumnIndex(field_name));

我不能使用最终字符串,因为当用户选择不同的值时,变量显然会发生变化。我已经阅读了很多内容,并且很难找到解决方案。我可以复制并粘贴此代码 6 次而忘记重构,但我真的很想知道优雅的解决方案。如果您不理解我的问题,请发表评论,我不确定我是否解释得很好。

【问题讨论】:

  • 其实,在onItemSelected 中你想要什么以及你面临什么问题并不清楚。请详细说明。
  • Cannot refer to a non-final variable field_name inside an inner class defined in a different method.,为什么不在主类中全局声明field_name

标签: java android pass-by-reference android-spinner


【解决方案1】:

您可以通过传递附加类作为fillSpinner 方法的参数来做到这一点:

A.创建interface

public interface OnSpinnerValueSelected {
    void onValueSelected(String selectedValue);
}

B.稍微改变一下你的方法:

public void fillSpinner(String spinner_name, final String field_name,
                    final OnSpinnerValueSelected valueChangeListener) {

    // Prepare spinner

    s.setOnItemSelectedListener(new OnItemSelectedListener() {

        public void onItemSelected(AdapterView<?> parent, View view,
                     int position, long id) {
            Cursor theCursor = (Cursor) parent.getSelectedItem();

            valueChangeListener.onValueSelected(theCursor
                           .getString(theCursor.getColumnIndex(field_name)));
        }

        public void onNothingSelected(AdapterView<?> parent) {

        }
    });
}

C.提供监听器:

fillSpinner("spinner1","strength", new OnSpinnerValueSelected() {
    public void onValueSelected(String selectedValue) {
        yourObject.setField(selectedValue);
    }
});

【讨论】:

  • 很好,这很有效,而且似乎比在重构函数本身中硬编码变量名更好。所以在 Java 中你不能通过引用传递一个 String 对象,但是你可以传递一个 final 对象,它有一个方法来设置 String 对象的值。
【解决方案2】:

将你的监听器重构为一个新的“类”。根据需要使用正确的参数/实例进行初始化,以便重复的“代码”可重用。

【讨论】:

  • 是的,听起来不错。我会尝试并报告,干杯
【解决方案3】:

是的,这就是我管理它的方式,但我仍然愿意接受新的建议以获得可接受的答案,并且我还创建了一个赏金。

我没有像panzerschreck 建议的那样创建一个新课程,所以我将其发布为我自己问题的新答案。有点小技巧,但我只是在侦听器中创建了一个 if..then..else 语句来检查选择了哪个微调器,然后设置了一个不同的实例成员。

s.setOnItemSelectedListener(new OnItemSelectedListener() {
        public void onItemSelected(AdapterView<?> parent, View view,
                int position, long id) {
            Cursor theCursor = (Cursor) parent.getSelectedItem();
            if (field_name.equalsIgnoreCase("strength")) {
                strength=theCursor.getString(theCursor.getColumnIndex(field_name));
            } else if (field_name.equalsIgnoreCase("ring")) {
                ring_gauge=theCursor.getString(theCursor.getColumnIndex(field_name));
            } else if (field_name.equalsIgnoreCase("country")) {
                country=theCursor.getString(theCursor.getColumnIndex(field_name));
            } else if (field_name.equalsIgnoreCase("wrapper")) {
                wrapper=theCursor.getString(theCursor.getColumnIndex(field_name));
            } else if (field_name.equalsIgnoreCase("length")) {
                length=theCursor.getString(theCursor.getColumnIndex(field_name));
            } else if (field_name.equalsIgnoreCase("price")) {
                price=theCursor.getString(theCursor.getColumnIndex(field_name));
            } 
            // showToast(category);
        }

        public void onNothingSelected(AdapterView<?> parent) {
            // showToast("Spinner2: unselected");
        }
    });

这是班级成员

private String strength,ring_gauge,country,wrapper,length,price;

有点 hack 但没有 Java 允许真正通过引用传递对象,这就是我所能做的。

【讨论】:

  • 我必须说放置“if”语句不是一个好习惯。尽可能避免硬编码值,这是维护的噩梦!
  • 如果这就是你的意思,我不能在字符串上使用 switch 语句。我知道,我也不想使用硬编码值,但还有其他选择。我很想知道这个优雅的解决方案。我尝试按照您的建议创建一个新类作为侦听器,但问题仍然是我如何通过引用而不是值将实例成员传递给这个新侦听器类的构造函数。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-08-11
  • 2017-07-25
  • 2016-07-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多