Android 사용자 정의보기를 위해 세 생성자가 모두 필요합니까?


143

사용자 정의보기를 만들 때 많은 사람들이 다음과 같이하는 것으로 나타났습니다.

public MyView(Context context) {
  super(context);
  // this constructor used when programmatically creating view
  doAdditionalConstructorWork();
}

public MyView(Context context, AttributeSet attrs) {
  super(context, attrs);
  // this constructor used when creating view through XML
  doAdditionalConstructorWork();
}

private void doAdditionalConstructorWork() {

  // init variables etc.
}

내 첫 번째 질문은 생성자는 MyView(Context context, AttributeSet attrs, int defStyle)어떻습니까? 어디에 사용되는지 잘 모르겠지만 수퍼 클래스에서 볼 수 있습니다. 필요합니까, 어디에 사용됩니까?

이 질문 에는 또 다른 부분이 있습니다.

답변:


145

다음 과 같이 사용자 정의 View를 추가하는 경우 xml:

 <com.mypack.MyView
      ...
      />

당신은 생성자가 필요합니다 public MyView(Context context, AttributeSet attrs). 그렇지 않으면 Exception안드로이드가 당신을 팽창 시키려고 할 때 얻을 것 View입니다.

Viewfrom 을 추가하고 다음 xmlandroid:style같은 속성을 지정하면 :

 <com.mypack.MyView
      style="@styles/MyCustomStyle"
      ...
      />

MyCustomStyle명시적인 XML 속성을 적용 하기 전에 두 번째 생성자가 호출되고 스타일의 기본값이 설정 됩니다.

세 번째 생성자는 일반적으로 응용 프로그램의 모든 뷰가 동일한 스타일을 갖기를 원할 때 사용됩니다.


3
첫 번째 생성자를 언제 사용합니까?
안드로이드 킬러

@OvidiuLatcu 세 번째 CTOR (3 개의 매개 변수 포함)의 예를 보여 주시겠습니까?
안드로이드 개발자

생성자에 추가 매개 변수를 추가하고 어떻게 사용할 수 있습니까?
Mohammed Subhi Sheikh Quroush

24
세 번째 생성자와 관련하여 이것은 실제로 완전히 잘못되었습니다 . XML은 항상 두 개의 인수 생성자를 호출합니다. 3 개의 인수 (및 4 개의 인수 ) 생성자는 기본 스타일을 포함하는 속성을 지정하거나 기본 스타일을 직접 지정하려면 ( 4 개의 인수 생성자의 경우) 서브 클래스에 의해 호출됩니다.
imgx64

방금 답변을 수정하기 위해 수정 사항을 제출했습니다. 나는 또한 아래의 다른 대답을 제안했다.
mbonnin

118

세 생성자를 모두 재정의하는 경우 CASCADE this(...)CALLS를 호출 하지 마십시오 . 대신이 작업을 수행해야합니다.

public MyView(Context context) {
    super(context);
    init(context, null, 0);
}

public MyView(Context context, AttributeSet attrs) {
    super(context,attrs);
    init(context, attrs, 0);
}

public MyView(Context context, AttributeSet attrs, int defStyle) {
    super(context, attrs, defStyle);
    init(context, attrs, defStyle);
}

private void init(Context context, AttributeSet attrs, int defStyle) {
    // do additional work
}

그 이유는 부모 클래스가 실수로 재정의 할 수있는 자체 생성자에 기본 속성을 포함 할 수 있기 때문입니다. 예를 들어, 이것은 다음의 생성자입니다 TextView.

public TextView(Context context) {
    this(context, null);
}

public TextView(Context context, @Nullable AttributeSet attrs) {
    this(context, attrs, com.android.internal.R.attr.textViewStyle);
}

public TextView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
    this(context, attrs, defStyleAttr, 0);
}

에 전화하지 않으면 스타일 속성으로 super(context)올바르게 설정되지 않은 것 R.attr.textViewStyle입니다.


12
이것은 ListView를 확장 할 때 필수적인 조언입니다. 위의 계단식의 (이전) 팬으로서, 나는 각 생성자에 대해 올바른 슈퍼 메소드를 호출했을 때 사라지는 미묘한 버그를 추적하는 데 시간을 소비하는 것을 회상합니다.
Groovee60

BTW @Jin 나는이 답변에 코드를 사용했습니다 : stackoverflow.com/a/22780035/294884 이것은 귀하의 답변을 기반으로하는 것처럼 보이지만 작가는 Inflator?
Fattie

1
모든 생성자에서 init를 호출 할 필요는 없다고 생각합니다. 호출 계층 구조를 따를 때 어쨌든 프로그래밍 방식의 뷰 생성을위한 기본 생성자가됩니다. View (Context context) {}
Marian Klühspies

메신저 동일한 작업을 수행하지만 내 사용자 정의보기에서 사용할 수있는 textview에서 값을 설정하지 못했습니다. 활동에서 값을 설정하고 싶습니다.
Erum

1
나는 이것을 어떻게 알지 못했습니까?
Suragch

49

MyView (컨텍스트 컨텍스트)

프로그래밍 방식으로 뷰를 구성 할 때 사용됩니다.

MyView (컨텍스트 컨텍스트, AttributeSet 속성)

LayoutInflaterxml 속성을 적용 하기 위해 사용 합니다. 이 속성 중 하나의 이름이 style이면 레이아웃 xml 파일에서 명시 적 값을 찾기 전에 속성이 스타일을 찾습니다.

MyView (컨텍스트 컨텍스트, AttributeSet 속성, int defStyleAttr)

style각 레이아웃 파일에서 지정할 필요없이 모든 위젯에 기본 스타일을 적용한다고 가정 하십시오. 예를 들어 기본적으로 모든 확인란을 분홍색으로 만듭니다. defStyleAttr을 사용하여이 작업을 수행 할 수 있으며 프레임 워크는 테마에서 기본 스타일을 조회합니다.

참고 defStyleAttr잘못 선정되었습니다 defStyle몇 시간 전에이 생성자가 정말 필요 여부에 대한 논의가있다. https://code.google.com/p/android/issues/detail?id=12683을 참조 하십시오.

MyView (컨텍스트 컨텍스트, AttributeSet 속성, int defStyleAttr, int defStyleRes)

응용 프로그램의 기본 테마를 제어 할 수 있으면 세 번째 생성자가 잘 작동합니다. 기본 테마와 함께 위젯을 제공하기 때문에 Google에서 작동합니다. 그러나 위젯 라이브러리를 작성 중이고 사용자가 테마를 조정할 필요없이 기본 스타일을 설정하려고한다고 가정하십시오. defStyleRes두 개의 첫 생성자에서 기본값으로 설정 하여이 작업을 수행 할 수 있습니다 .

public MyView(Context context) {
  super(context, null, 0, R.style.MyViewStyle);
  init();
}

public MyView(Context context, AttributeSet attrs) {
  super(context, attrs, 0, R.style.MyViewStyle);
  init();
}

전부

자체 뷰를 구현하는 경우 두 개의 첫 번째 생성자 만 필요하며 프레임 워크에서 호출 할 수 있습니다.

뷰를 확장 가능하게하려면 클래스의 하위 항목에 전역 스타일을 사용할 수 있도록 네 번째 생성자를 구현할 수 있습니다.

세 번째 생성자에 대한 실제 사용 사례는 보이지 않습니다. 위젯에 기본 스타일을 제공하지 않지만 사용자가 여전히 그렇게 할 수있게하려면 바로 가기 일 수 있습니다. 그렇게 많이 일어나서는 안됩니다.


7

코 틀린은이 고통을 많이 없애는 것 같습니다.

class MyView
@JvmOverloads constructor(context: Context, attrs: AttributeSet? = null, defStyle: Int = 0)
    : View(context, attrs, defStyle)

@JvmOverloads는 필요한 생성자를 모두 생성합니다 (주석의 설명서 참조 ). 각각은 아마도 super ()를 호출합니다. 그런 다음 초기화 방법을 Kotlin init {} 블록으로 바꾸십시오. 상용구 코드가 사라졌습니다!


1

세 번째 생성자는 훨씬 더 복잡합니다. 예를 들어 보겠습니다.

Support-v7 SwitchCompact패키지는 24 버전부터 지원 thumbTinttrackTint속성을 제공하지만 23 버전은 지원하지 않습니다. 이제 23 버전에서 지원하려면 어떻게해야합니까?

우리는 custom View SupportedSwitchCompactextends 를 사용한다고 가정합니다 SwitchCompact.

public SupportedSwitchCompat(Context context) {
    this(context, null);
}

public SupportedSwitchCompat(Context context, AttributeSet attrs) {
    this(context, attrs, 0);
}

public SupportedSwitchCompat(Context context, AttributeSet attrs, int defStyleAttr) {
    super(context, attrs, defStyleAttr);
    init();
}

private void init(){
    mThumbDrawable = getThumbDrawable();
    mTrackDrawable = getTrackDrawable();
    applyTint();
}

전통적인 코드 스타일입니다. 여기서 우리는 세 번째 매개 변수에 0을 전달합니다 . 코드를 실행할 때 getThumbDrawable()메소드 getThumbDrawable()가 수퍼 클래스 의 메소드이기 때문에 얼마나 이상한지 항상 null을 리턴합니다 SwitchCompact.

R.attr.switchStyle세 번째 매개 변수에 합격 하면 모든 것이 잘 진행됩니다.

세 번째 매개 변수는 간단한 속성입니다. 이 속성은 스타일 리소스를 가리 킵니다. 위의 경우, 시스템은 switchStyle현재 테마에서 속성을 찾게됩니다.

에서가 frameworks/base/core/res/res/values/themes.xml, 당신은 볼 것이다 :

<style name="Theme">
    <item name="switchStyle">@style/Widget.CompoundButton.Switch</item>
</style>

-2

지금 논의중인 것과 같은 세 개의 생성자를 포함해야하는 경우에도이를 수행 할 수 있습니다.

public MyView(Context context) {
  this(context,null,0);
}

public MyView(Context context, AttributeSet attrs) {
  this(context,attrs,0);
}

public MyView(Context context, AttributeSet attrs, int defStyle) {
  super(context, attrs, defStyle);
  doAdditionalConstructorWork();

}

2
@Jin 많은 경우에 좋은 생각이지만 많은 경우에도 안전합니다 (예 : RelativeLayout, FrameLayout, RecyclerView 등). 따라서 이것은 사례별로 요구되는 사항이므로 계단식으로 결정하기 전에 기본 클래스를 확인해야합니다. 기본적으로 기본 클래스의 2 매개 변수 생성자가 this (context, attrs, 0)를 호출하는 경우 사용자 지정 뷰 클래스에서도 그렇게하는 것이 안전합니다.
ejw

@IanWong은 물론 첫 번째 메소드와 두 번째 메소드가 세 번째를 호출하기 때문에 호출됩니다.
CoolMind
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.