voncox
voncox

Reputation: 1201

Android custom view button with custom attribute is referencing the same object

I have a custom button that extends View. In the constructor I am setting a member variable to hold a custom attribute set in the XML definition. At the moment there are 5 of these buttons defined in the XML each with a different int attached to represent a stage.

<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:custom="http://schemas.android.com/apk/res/com.mycompany.stagedApp"
android:layout_width="match_parent"
android:orientation="horizontal"
style="@style/stepFooter">

<com.mycompany.stagedApp.StepButtonView
    android:text="@string/step_one_icon"
    style="@style/numberedIcon"
    android:id="@+id/step_one_button"
    custom:stepNumber="1"
    android:background="@drawable/circle" />
<com.mycompany.stagedApp.StepButtonView
    android:text="@string/step_two_icon"
    style="@style/numberedIcon"
    android:id="@+id/step_two_button"
    custom:stepNumber="2"
    android:background="@drawable/circle" />
<com.mycompany.stagedApp.StepButtonView
    android:text="@string/step_three_icon"
    style="@style/numberedIcon"
    android:id="@+id/step_three_button"
    custom:stepNumber="3"
    android:background="@drawable/circle" />
<com.mycompany.stagedApp.StepButtonView
    android:text="@string/step_four_icon"
    style="@style/numberedIcon"
    android:id="@+id/step_four_button"
    custom:stepNumber="4"
    android:background="@drawable/circle" />
<com.mycompany.stagedApp.StepButtonView
    android:text="@string/step_five_icon"
    style="@style/numberedIcon"
    android:id="@+id/step_five_button"
    custom:stepNumber="5"
    android:background="@drawable/circle" />
</LinearLayout>

In the StepButtonView.java I have:

class StepButtonView extends View {

  private static int stepNumber;

  public StepButtonView(Context context, AttributeSet attrs) {
    super(context, attrs);

    TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.custom_values);
    stepNumber = ta.getInt(R.styleable.custom_values_stepNumber, 0);

    // This log correctly displays the numbers 1 - 5
    Log.d("StepFromCustom in constructor", String.format("%d",StepButtonView.stepNumber));

    this.setOnClickListener(new OnClickListener(){
        @Override
        public void onClick(View view) {
            Log.d("Step", String.format("%d", view.getId()));
            // This log only displays the last number 5
            Log.d("StepFromCustom", String.format("%d",StepButtonView.stepNumber));
        }
    });
  }
}

When the activity starts and each button is constructed the numbers 1 -5 are logged. However on click the number logged is always 5, the last stepNumber. In the onClick listener it lists a different ID value but the same stepNumber so my initial thought that it was referring to the same object must be incorrect.

Could anyone explain what's going on, and why, as I think this is a misunderstanding with the language which I obviously need to clear up.

Upvotes: 0

Views: 1347

Answers (1)

stealthjong
stealthjong

Reputation: 11093

That is because your stepNumber is static. That means it's a class variable, thus it will remain 5, as it is the last value which is set (constructor of you last Button). Removing it will solve the problem.

Let's run through the application:

  • First constructor: stepNumber is 1.
  • Second constructor: stepNumber is 2.
  • Third constructor: stepNumber is 3.
  • Fourth constructor: stepNumber is 4.
  • Fifth constructor: stepNumber is 5.

After this it is not set anymore, so it will remain 5. So:

  • every onClick after that: Log.d() will output 5

Edit: seeing your comment, you probably mean a final attribute, which cannot be modified and only be set in the constructor. Seeing that you already set it in your constructor, it's perfectly fine to add that to your attribute, making it:

private final int stepNumber;

Edit2: static members belong to the class instead of a specific instance.

It means that only one instance of a static field exists even if you create a million instances of the class or you don't create any. It will be shared by all instances.

Upvotes: 4

Related Questions