onPause, onStop 및 onDestroy 메서드에서 슈퍼 클래스 메서드를 호출하는 올바른 순서는 무엇입니까? 그리고 왜?


89

방금 Android 개발자 사이트를 살펴보고 활동 수명주기를 새로 고쳤습니다. 각 코드 예제에는 "항상 수퍼 클래스 메서드를 먼저 호출하십시오"라는 주석이 수퍼 클래스 메서드 옆에 있습니다.

생성 반주기 onCreate, onStart 및 onResume에서는 이것이 의미가 있지만 파괴 반주기의 올바른 절차 인 onPause, onStop, onDestroy에 대해 약간 혼란 스럽습니다.

인스턴스 특정 리소스가 의존 할 수있는 슈퍼 클래스 리소스를 파괴하기 전에 먼저 인스턴스 특정 리소스를 파괴하는 것이 합리적이며 그 반대가 아닙니다. 내가 무엇을 놓치고 있습니까?

편집 : 사람들이 질문의 의도에 대해 혼란스러워하는 것 같아서 내가 알고 싶은 것은 다음 중 올바른 것은 무엇입니까? 그리고 왜 ?

1. Google 제안

    @Override
    protected void onStop() {
      super.onStop();  // Always call the superclass method first

      //my implementation here
    }

2. 다른 방법

    @Override
    protected void onStop() {
       //my implementation here

       super.onStop();  
    }

1
나는 종료 방법을 위해 캠프 2에 있습니다. 나는 시작 방법을 위해 캠프 1에 있습니다.
danny117 2013 년

1
그게 요점입니다. 종료 방법에 방법 1을 사용하는 것이 어떻게 합리적인지 이해할 수 없었습니다.
Anudeep Bulla 2013

답변:


107

인스턴스 특정 리소스가 의존 할 수있는 수퍼 클래스 리소스를 파괴하기 전에 먼저 인스턴스 특정 리소스를 파괴하는 것이 합리적입니다. 그러나 의견은 그렇지 않다는 것을 암시합니다. 내가 무엇을 놓치고 있습니까?

제 생각에는 하나도 아닙니다.

Mark (일명 CommonsWare on SO)의이 답변은 문제에 대해 밝힙니다. Link- 수퍼 클래스 메서드에 대한 호출이 첫 번째 문이어야합니까? . 그러나 그의 답변에 다음과 같은 댓글이 남았습니다.

그러나 왜 공식 문서에서 onPause ()에서 "항상 수퍼 클래스 메서드를 먼저 호출"이라고 말하는가?

원점으로 돌아가다. 좋아요, 이것을 다른 각도에서 봅시다. Java 언어 사양 호출을 super.overridenMethod()해야하는 순서 (또는 호출을 수행 해야하는 경우) 를 지정 하지 않습니다 .

클래스 Activity의 경우 super.overridenMethod()호출이 필요하고 적용됩니다 .

if (!mCalled) {
    throw new SuperNotCalledException(
        "Activity " + mComponent.toShortString() +
            " did not call through to super.onStop()");
}

mCalled에서 true로 설정됩니다 Activity.onStop().

이제 토론해야 할 유일한 세부 사항은 주문입니다.

I also know that both work

확실한. Activity.onPause ()에 대한 메서드 본문을 살펴보십시오.

protected void onPause() {
    if (DEBUG_LIFECYCLE) Slog.v(TAG, "onPause " + this);

    // This is to invoke 
    // Application.ActivityLifecyleCallbacks.onActivityPaused(Activity)
    getApplication().dispatchActivityPaused(this);

    // The flag to enforce calling of this method
    mCalled = true;
}

어떤 식으로 전화를 super.onPause()걸어도 괜찮을 것입니다. Activity.onStop ()에는 유사한 메서드 본문이 있습니다. 그러나 Activity.onDestroy ()를 살펴보십시오.

protected void onDestroy() {
    if (DEBUG_LIFECYCLE) Slog.v(TAG, "onDestroy " + this);
    mCalled = true;

    // dismiss any dialogs we are managing.
    if (mManagedDialogs != null) {
        final int numDialogs = mManagedDialogs.size();
        for (int i = 0; i < numDialogs; i++) {
            final ManagedDialog md = mManagedDialogs.valueAt(i);
            if (md.mDialog.isShowing()) {
                md.mDialog.dismiss();
            }
        }
        mManagedDialogs = null;
    }

    // close any cursors we are managing.
    synchronized (mManagedCursors) {
        int numCursors = mManagedCursors.size();
        for (int i = 0; i < numCursors; i++) {
            ManagedCursor c = mManagedCursors.get(i);
            if (c != null) {
                c.mCursor.close();
            }
        }
        mManagedCursors.clear();
    }

    // Close any open search dialog
    if (mSearchManager != null) {
        mSearchManager.stopSearch();
    }

    getApplication().dispatchActivityDestroyed(this);
}

여기서 순서는 활동이 설정되는 방법과 호출 이 다음 코드를 방해 하는지 여부에 따라 중요 할 수 있습니다super.onDestroy() .

마지막으로, 진술 Always call the superclass method first은 그것을 뒷받침 할 증거가 많지 않은 것 같습니다. 더 나쁜 것은 (문의 경우) 다음 코드가 다음에서 가져온 것입니다 android.app.ListActivity.

public class ListActivity extends Activity {

    ....

    @Override
    protected void onDestroy() {
        mHandler.removeCallbacks(mRequestFocus);
        super.onDestroy();
    }
    ....    
}

그리고 Android SDK에 포함 된 LunarLander 샘플 애플리케이션에서 :

public class LunarLander extends Activity {

    ....

    @Override
    protected void onPause() {
        mLunarView.getThread().pause(); // pause game when Activity pauses
        super.onPause();
    }
    ....
}

요약 및 가치있는 언급 :

사용자 Philip Sheard : super.onPause()활동이을 (를) 사용하여 시작한 경우 호출을 지연해야하는 시나리오를 제공합니다 startActivityForResult(Intent). 사용하여 결과 설정 setResult(...) super.onPause() 작동하지 않습니다를. 그는 나중에 그의 답변에 대한 의견에서 이에 대해 명확히 설명합니다.

사용자 Sherif elKhatib : 수퍼 클래스가 먼저 리소스를 초기화하고 마지막에 논리에서 리소스를 파괴하도록하는 이유를 설명합니다.

위치를 제공하는 getLocation () 함수가 포함 된 LocationActivity가있는 다운로드 한 라이브러리를 고려해 보겠습니다. 대부분의 경우이 액티비티는 onCreate ()에서 항목을 초기화해야하므로 super.onCreate를 먼저 호출해야합니다 . 당신은 그것이 의미가 있다고 느끼기 때문에 이미 그렇게하고 있습니다. 이제 onDestroy에서 SharedPreferences 어딘가에 위치를 저장하기로 결정했습니다. super.onDestroy를 먼저 호출하면 LocationActivity의 구현이 onDestroy의 위치 값을 무효화하기 때문에 getLocation이이 호출 후에 null 값을 반환 할 가능성이 어느 정도 있습니다. 아이디어는 이런 일이 발생하더라도 당신이 그것을 비난하지 않을 것이라는 것입니다.따라서 자신의 onDestroy를 완료 한 후 마지막에 super.onDestroy를 호출합니다.

그는 계속해서 지적합니다. 만약 자식 클래스가 부모 클래스로부터 적절하게 분리되어 있다면 (자원 의존성 측면에서), super.X()호출은 어떤 주문 사양을 따를 필요가 없습니다.

배치 어디 시나리오를 읽고이 페이지에 자신의 답변을 참조 super.onDestroy()호출 않는 프로그램 로직에 영향을 미칩니다.

Mark의 답변에서 :

구성 요소 생성의 일부인 재정의하는 메서드 (onCreate (), onStart (), onResume () 등), 첫 번째 문으로 수퍼 클래스에 연결하여 Android가 먼저 작업을 수행 할 수 있도록해야합니다. 수행 된 작업에 의존하는 작업을 시도합니다.

컴포넌트 파괴 (onPause (), onStop (), onDestroy () 등)의 일부인 메서드를 재정의하면 먼저 작업을 수행하고 마지막으로 수퍼 클래스에 연결해야합니다 . 이렇게하면 Android가 작업에 의존하는 항목을 정리하는 경우 먼저 작업을 수행 한 것입니다.

void (onCreateOptionsMenu () 등) 이외의 것을 반환하는 메서드는 특정 반환 값을 강제하는 데 필요한 작업을 특별히 수행하지 않는다고 가정하여 때때로 return 문에서 수퍼 클래스에 연결합니다.

onActivityResult ()와 같은 다른 모든 것은 전체적으로 귀하에게 달려 있습니다. 우선 수퍼 클래스에 연결하는 경향이 있지만 문제가 발생하지 않는 한 나중에 연결하는 것이 좋습니다.

밥 컨스 에서 이 스레드 :

좋은 패턴 [(마크가 위에서 제안한 패턴)]이지만 몇 가지 예외를 발견했습니다. 예를 들어, PreferenceActivity에 적용하고 싶은 테마는 수퍼 클래스의 onCreate () 앞에 놓지 않으면 효과가 없습니다.

사용자 Steve Benett 도 이에 대해주의를 기울입니다.

나는 슈퍼 콜의 타이밍이 필요한 한 가지 상황만을 알고 있습니다. onCreate에서 테마 또는 디스플레이 등의 표준 동작을 변경하려면 super를 호출하여 효과를 확인하기 전에 변경해야합니다 . 그렇지 않으면 AFAIK를 호출하는 시간에 차이가 없습니다.

사용자 Sunil Mishra 는 Activity 클래스의 메서드를 호출 할 때 순서 (거의 가능성이 높음)가 역할을하지 않는다는 것을 확인합니다. 그는 또한 슈퍼 클래스 메서드를 먼저 호출하는 것이 모범 사례라고 주장합니다 . 그러나 나는 이것을 확증 할 수 없었다.

사용자 LOG_TAG : 슈퍼 클래스 생성자 호출이 다른 모든 것보다 우선해야하는 이유를 설명합니다 . 제 생각에는이 설명이 질문에 추가되지 않습니다.

끝 메모 : 신뢰 하지만 확인하십시오. 이 페이지에있는 대부분의 답변은이 접근 방식을 따라 문 Always call the superclass method first에 논리적 근거가 있는지 확인합니다 . 밝혀진대로 그렇지 않습니다. 적어도 Activity 클래스의 경우는 아닙니다. 일반적으로 super의 메서드에 대한 호출 순서가 요구 사항인지 확인하려면 수퍼 클래스의 소스 코드를 읽어야합니다.


2
와. 포인터 주셔서 감사합니다. 이것과 @Sherif의 답변 모두 중요한 컨텍스트를 제공합니다. 이 페이지의 답변을 요약 해 주시면 수락 한 것으로 표시하겠습니다. 친절하게 포함 : 1.이 페이지의 답변. 2. @에 CommonsWare의 대답 @이 3 페이지에 필립의 대답 이 페이지 4. 이 논의 나는 것,하지만 난 당신의 훌륭한 답변에 대한 크레딧을 싶지 않아요. Cheers & Thanks
Anudeep Bulla 2013

안녕하세요. @Sherif가 원하지 않는 것처럼 요약 해 주시겠습니까?
Anudeep Bulla 2013

@AnudeepBulla 안녕하세요 Anudeep, 내일까지 줘. 내 답변에 관련 자료를 추가하고 여기에 의견을 남길 것입니다.
Vikram 2013 년

@AnudeepBulla 위의 요약을 추가했습니다. 내가 놓친 것이 있으면 알려주십시오.
Vikram 2013 년

@Vikram은 TL; DR입니다. 그 부름 onDestroyonStop마지막이 더 안전한 기본값이며, onPause몇 가지 경우에 더 까다로울 수 있습니까? 먼저 추가해 주 시겠어요? 답변을 직접 수정하고 싶었지만이 요약이 정확한지 확신 할 수 없습니다.
Blaisorblade

13

(당신이 말했듯이) super onCreate를 먼저 호출하는 것이 합리적이므로 생각해보십시오.

내가 만들고 싶을 때, 내 수퍼가 리소스를 생성하고> 내 리소스를 생성합니다.

반대로 : (일종의 스택)

내가 파괴하고 싶을 때, 나는 내 자원을 파괴합니다.> 나의 수퍼가 그의 자원을 파괴합니다.


이러한 의미에서 두 가지 함수 (onCreate / onDestroy, onResume / onPause, onStart / onStop)에 적용됩니다. 당연히 onCreate는 리소스를 생성하고 onDestroy는 이러한 리소스를 해제합니다. 그건 그렇고, 다른 커플에게도 같은 증거가 적용됩니다.

위치를 제공하는 getLocation () 함수를 포함하는 LocationActivity가있는 다운로드 한 라이브러리를 고려해 보겠습니다. 아마도이 액티비티는 onCreate ()에서 항목을 초기화해야 할 것입니다. 그러면 super.onCreate를 먼저 호출해야합니다. 당신은 그것이 의미가 있다고 느끼기 때문에 이미 그렇게하고 있습니다. 이제 onDestroy에서 SharedPreferences 어딘가에 위치를 저장하기로 결정했습니다. super.onDestroy를 먼저 호출하면 LocationActivity의 구현이 onDestroy의 위치 값을 무효화하기 때문에 getLocation이이 호출 후에 null 값을 반환 할 가능성이 어느 정도 있습니다. 아이디어는 이런 일이 발생해도 당신이 그것을 비난하지 않을 것이라는 것입니다. 따라서 자신의 onDestroy를 완료 한 후 마지막에 super.onDestroy를 호출합니다. 나는 이것이 약간 의미가 있기를 바랍니다.

위의 내용이 타당하다면 언제든지 위의 개념을 준수하는 활동이 있다는 것을 고려하십시오. 이 활동을 확장하고 싶다면, 똑같은 주장 때문에 같은 방식으로 느끼고 같은 순서를 따를 것입니다.

귀납법으로 모든 활동은 똑같은 일을해야합니다. 다음은 이러한 규칙을 따라야하는 활동에 대한 좋은 추상 클래스입니다.

package mobi.sherif.base;

import android.app.Activity;
import android.os.Bundle;

public abstract class BaseActivity extends Activity {
    protected abstract void doCreate(Bundle savedInstanceState);
    protected abstract void doDestroy();
    protected abstract void doResume();
    protected abstract void doPause();
    protected abstract void doStart();
    protected abstract void doStop();
    protected abstract void doSaveInstanceState(Bundle outState);
    @Override
    protected final void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        doCreate(savedInstanceState);
    }
    @Override
    protected final void onDestroy() {
        doDestroy();
        super.onDestroy();
    }
    @Override
    protected final void onResume() {
        super.onResume();
        doResume();
    }
    @Override
    protected final void onPause() {
        doPause();
        super.onPause();
    }
    @Override
    protected final void onStop() {
        doStop();
        super.onStop();
    }
    @Override
    protected final void onStart() {
        super.onStart();
        doStart();
    }
    @Override
    protected final void onSaveInstanceState(Bundle outState) {
        doSaveInstanceState(outState);
        super.onSaveInstanceState(outState);
    }
}

마지막으로,라는 활동이 AnudeepBullaActivityBaseActivity를 확장하고 나중에 SherifElKhatibActivity활동을 확장하는 것을 만들고 싶습니다 . super.do함수를 어떤 순서로 호출해야 합니까? 궁극적으로 같은 것입니다.


질문 :

Google의 의도는 다음과 같이 말하는 것 같습니다. 어디에 있든 상관없이 수퍼에 전화하십시오. 물론 일반적인 관행으로 처음에는 호출하십시오. 물론 Google에는 가장 뛰어난 엔지니어와 개발자가 있으므로 그들은 아마도 슈퍼 통화를 분리하고 어린이 통화를 방해하지 않는 좋은 작업을 수행했을 것입니다.

나는 조금 시도했지만 When is super가 호출되기 때문에 간단하게 충돌하는 활동을 만드는 것이 (Google이기 때문에 우리가 잘못 증명하고 있기 때문에) 쉽지 않을 것입니다.

왜?

이 함수에서 수행되는 모든 작업은 실제로 Activity 클래스에만 적용되며 하위 클래스와 충돌을 일으키지 않습니다. 예 : (onDestroy)

protected void onDestroy() {
    if (DEBUG_LIFECYCLE) Slog.v(TAG, "onDestroy " + this);
    mCalled = true;

    // dismiss any dialogs we are managing.
    if (mManagedDialogs != null) {
        final int numDialogs = mManagedDialogs.size();
        for (int i = 0; i < numDialogs; i++) {
            final ManagedDialog md = mManagedDialogs.valueAt(i);
            if (md.mDialog.isShowing()) {
                md.mDialog.dismiss();
            }
        }
        mManagedDialogs = null;
    }

    // close any cursors we are managing.
    synchronized (mManagedCursors) {
        int numCursors = mManagedCursors.size();
        for (int i = 0; i < numCursors; i++) {
            ManagedCursor c = mManagedCursors.get(i);
            if (c != null) {
                c.mCursor.close();
            }
        }
        mManagedCursors.clear();
    }

    // Close any open search dialog
    if (mSearchManager != null) {
        mSearchManager.stopSearch();
    }

    getApplication().dispatchActivityDestroyed(this);
}

mManagedCursors 및 mManagedDialogs 및 mSearchManager는 모두 개인 필드입니다. 그리고 공개 / 보호 된 API는 여기서 수행되는 작업에 영향을받지 않습니다.

그러나 API 14에서는 애플리케이션에 등록 된 ActivityLifecycleCallbacks에 onActivityDestroyed를 디스패치하기 위해 dispatchActivityDestroyed가 추가되었습니다. 따라서 ActivityLifecycleCallbacks의 일부 논리에 의존하는 코드는 super를 호출하는시기에 따라 다른 결과를 갖습니다. 예를 들면 :

현재 실행중인 활동의 수를 계산하는 애플리케이션 클래스를 만듭니다.

package mobi.shush;

import android.app.Activity;
import android.app.Application;
import android.app.Application.ActivityLifecycleCallbacks;
import android.os.Bundle;

public class SherifApplication extends Application implements ActivityLifecycleCallbacks {
    @Override
    public void onCreate() {
        super.onCreate();
        registerActivityLifecycleCallbacks(this);
    }
    public int getCount() {
        return count;
    }
    int count = 0;
    @Override
    public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
        count++;
    }
    @Override
    public void onActivityDestroyed(Activity activity) {
        count--;
    }
    @Override
    public void onActivityPaused(Activity activity) {}
    @Override
    public void onActivityResumed(Activity activity) {}
    @Override
    public void onActivitySaveInstanceState(Activity activity, Bundle outState)           {}
    @Override
    public void onActivityStarted(Activity activity) {}
    @Override
    public void onActivityStopped(Activity activity) {}
}

다음은 말이되지 않거나 좋은 관행이 아닐 수도 있지만 단지 요점을 증명하기위한 것입니다 (더 실제 상황을 찾을 수 있음). GoodBye 활동이 완료되고 마지막 활동 일 때 이동하는 MainActivity를 만듭니다.

@Override
protected void onDestroy() {
    super.onDestroy();
    if(((SherifApplication) getApplication()).getCount() == 0) {
        //i want to go to a certain activity when there are no other activities
        startActivity(new Intent(this, GoodBye.class));
    }
}

onDestroy를 시작할 때 super.onDestroy를 호출하면 GoodBye 활동이 시작됩니다. onDestroy가 끝날 때 super.onDestroy를 호출하면 GoodBye 활동이 시작되지 않습니다.

물론 이것은 최적의 예가 아닙니다. 그러나 이것은 Google이 여기서 약간 엉망임을 보여줍니다. 다른 변수는 앱의 동작에 영향을주지 않았습니다. 그러나 이러한 디스패치를 ​​onDestroy에 추가하면 수퍼가 어떻게 든 하위 클래스를 방해합니다.

나는 그들이 다른 이유로도 엉망이라고 말합니다. 그들은 (api 14 이전에) 최종 및 / 또는 비공개 인 슈퍼 호출 만 터치했을뿐만 아니라 실제로 onPause ... 함수를 전달하는 다른 내부 함수 (비공개)를 호출했습니다.

예를 들어 performStopfunction은 onStop 함수를 차례로 호출하는 호출 된 함수입니다.

final void performStop() {
    if (mLoadersStarted) {
        mLoadersStarted = false;
        if (mLoaderManager != null) {
            if (!mChangingConfigurations) {
                mLoaderManager.doStop();
            } else {
                mLoaderManager.doRetain();
            }
        }
    }

    if (!mStopped) {
        if (mWindow != null) {
            mWindow.closeAllPanels();
        }

        if (mToken != null && mParent == null) {
            WindowManagerGlobal.getInstance().setStoppedState(mToken, true);
        }

        mFragments.dispatchStop();

        mCalled = false;
        mInstrumentation.callActivityOnStop(this);
        if (!mCalled) {
            throw new SuperNotCalledException(
                    "Activity " + mComponent.toShortString() +
                    " did not call through to super.onStop()");
        }

        synchronized (mManagedCursors) {
            final int N = mManagedCursors.size();
            for (int i=0; i<N; i++) {
                ManagedCursor mc = mManagedCursors.get(i);
                if (!mc.mReleased) {
                    mc.mCursor.deactivate();
                    mc.mReleased = true;
                }
            }
        }

        mStopped = true;
    }
    mResumed = false;
}

이 함수에서 Activity의 onStop을 호출합니다. 따라서 그들은 onStop에 대한 호출 전후에 모든 코드 (super.onStop에 포함됨)를 넣은 다음 빈 onStop 슈퍼 함수를 ​​사용하고 SuperNotCalledException을 추가하거나이 호출을 확인하지 않고도 onStop에 대해 하위 클래스에 알릴 수 있습니다.

이를 위해 super.onDestroy의 끝에서 호출하는 대신 performDestroy의 ActivityLifeCycle에이 디스패치를 ​​호출하면 super를 호출 한시기에 관계없이 활동의 ​​동작이 동일했을 것입니다.

어쨌든 이것은 그들이하는 첫 번째 일이며 (약간 잘못되었습니다) API 14에만 있습니다.


왜 super.onDestroy ()를 마지막으로 호출하는 것이 타당한 지에 대한 질문은 결코 없었습니다. 나는 당신의 도서관 예를 좋아합니다. 정확히 내가 전달하고 싶었던 것. 우발적 인 데이터 손실을 방지하기 위해 스택에서와 똑같이 파괴 반주기 마지막에 super 메서드를 마지막으로 호출하는 것에 더 동의 할 수 없습니다. 문제는 위의 전제를 감안할 때 Google이 먼저 슈퍼 메서드를 호출하도록 고집하는 이유입니다. 나는 아마도 내가 그리고 겉보기에 당신도 아마 완전히 다르게 접근 할 것이라고 생각했기 때문에 질문을했습니다. 건배
Anudeep Bulla 2013

오, Google 제안과 다른 방법을 보지 못했습니다 : p! 먼저 onDestroy를 호출하면 충돌 할 활동을 만들려고합니다. 당신도 그것을 시도해야합니다. 건배
보안관 elKhatib

@AnudeepBulla 당신은 내 편집을 확인할 수 있습니다. 그리고 btw 당신은 시도를 멈출 수 있습니다. super.on아마도 당신의 활동을 결코 충돌시키지 않을 것입니다.
보안관 elKhatib

와. 포인터 주셔서 감사합니다. 이 답변과 @User의 답변은 모두 중요한 컨텍스트를 제공합니다. 둘 중 한 사람이이 페이지의 답변을 요약 할 수 있다면 수락 한 것으로 표시하겠습니다. 친절하게 포함 : 1.이 페이지의 답변. 2. @에 CommonsWare의 대답 @이 3 페이지에 필립의 대답 이 페이지 4. 이 논의 나는 것,하지만 난 당신의 훌륭한 답변에 대한 크레딧을 싶지 않아요. Cheers & Thanks
Anudeep Bulla 2013

@AnudeepBulla 천만에요. 최종 글을 올릴 사람을 어떻게 결정할지 모르겠습니다.
Vikram

2

Google이 방법 1을 제안한다고 말하지만, 잘 알려진 Android 프레임 워크 엔지니어 인 Dianne Hackborn은 그렇지 않으면 Google Forum Link를 참조 할 것을 제안합니다 .

onPause, onStoponDestroy 메서드 에서 인스턴스를 삭제할마지막에 슈퍼 클래스를 호출하고 onCreate, onResumeonStart 메서드를 사용하여 인스턴스를 만들먼저 슈퍼 클래스를 호출하는 것이 직관적 입니다.


Dianne Hackborn의 게시물에 대한 링크는 중요하며 패턴을 확인합니다.
Nick Westgate 2015 년

1

Java 관점에서 다음은 이러한 혼란에 대한 몇 가지 해결책입니다.

왜 this ()와 super ()가 생성자의 첫 번째 문장이어야합니까?

상위 클래스의 생성자는 하위 클래스의 생성자보다 먼저 호출되어야합니다. 이렇게하면 생성자의 부모 클래스에서 메서드를 호출하는 경우 부모 클래스가 이미 올바르게 설정되었는지 확인할 수 있습니다.

당신이하려는 것은 슈퍼 생성자에 args를 전달하는 것은 완벽하게 합법적입니다. 당신이하는 것처럼 그 args를 인라인으로 생성하거나 생성자에 전달한 다음 super에 전달하기 만하면됩니다.

public MySubClassB extends MyClass {
        public MySubClassB(Object[] myArray) {
                super(myArray);
        }
}

컴파일러가 이것을 강제하지 않았다면 다음과 같이 할 수 있습니다.

public MySubClassB extends MyClass {
        public MySubClassB(Object[] myArray) {
                someMethodOnSuper(); //ERROR super not yet constructed
                super(myArray);
        }
}

실제로 서브 필드가 상위 클래스보다 먼저 비 실리 화되어야 함을 보여줍니다! 한편, 자바 요구 사항은 슈퍼 생성자 인수를 전문화하여 클래스를 전문화하는 것을 "방어"합니다.

부모 클래스에 기본 생성자가있는 경우 super에 대한 호출이 컴파일러에 의해 자동으로 삽입됩니다. Java의 모든 클래스는 Object에서 상속되기 때문에 객체 생성자는 어떻게 든 호출되어야하며 먼저 실행되어야합니다. 컴파일러에 의한 super () 자동 삽입이이를 허용합니다. super가 먼저 나타나도록 강제하면 생성자 본문이 다음과 같은 올바른 순서로 실행됩니다. Object-> Parent-> Child-> ChildOfChild-> SoOnSoForth

(1) super가 첫 번째 문장인지 확인하는 것만으로는 문제를 방지 할 수 없습니다. 예를 들어 "super (someMethodInSuper ());"를 입력 할 수 있습니다. 생성자에서. super가 첫 번째 명령문이더라도 생성되기 전에 수퍼 클래스의 메소드에 액세스하려고 시도합니다.

(2) 컴파일러는 자체적으로이 문제를 방지하기에 충분한 다른 검사를 구현하는 것으로 보입니다. 메시지는 "supertype 생성자가 호출되기 전에 xxx를 참조 할 수 없습니다"입니다. 따라서 super가 첫 번째 명령문인지 확인할 필요가 없습니다.

http://valjok.blogspot.in/2012/09/super-constructor-must-be-first.html을 살펴보십시오.


나는 당신이 거기에 무엇을 내놓고 있는지 완벽하게 이해합니다. 먼저 슈퍼 클래스 생성자를 호출합니다. '그들은 자식에게 필요할 수있는 리소스를 초기화 할 수 있습니다. 소멸자는 마지막으로, '지역 자원에 대한 모든 부모를 지우고 싶지 않아서 무의미하게 만듭니다. 그것이 바로 제 요점입니다. 그리고 onPause, onStop 및 onDestroy는 상태 정보를 저장하고 GC에서 리소스를 어느 정도 사용할 수 있도록하는 작업을 수행하기 때문에 (따라서 어떤 의미에서는이를 파괴) 소멸자와 유사하므로 마지막으로 호출하는 것이 합리적이라고 생각합니다. 아니?
Anudeep Bulla 2013

위에서 말한 모든 것은 내가 "초기 생성 반주기에서 슈퍼 메소드를 먼저 호출하는 것이 합리적"이라고 말했을 때의 의미입니다. 소멸자와 더 유사 해 보이는 파괴 반주기 방법의 경우에는 걱정이됩니다. 건배
Anudeep Bulla 2013

1

명심해야 할 가장 중요한 것은 super.onPause()암시 적으로 setResult(Activity.RESULT_CANCELED). 그러나 setResult한 번만 호출 할 수 있으며 모든 후속 호출은 무시됩니다. 따라서 모든 종류의 결과를 부모 활동으로 다시 푸시하려면를 호출 하기 전에setResult 자신 에게 전화 해야 합니다 super.onPause(). 내가 아는 한 가장 큰 문제입니다.


와, 이건 중요해 보입니다. 따라서 슈퍼 메서드에 대한 호출을 확실히 지연해야하는 상황이 있습니다. 감사합니다.
Anudeep Bulla 2013

super.onPause() implicitly calls setResult(Activity.RESULT_CANCELED). 이걸 어디서 구했는지 말씀해 주 시겠어요?
Vikram

나는 혼란 스러웠다. 실제로는 setResult를 호출하는 finish ()이고 super.onBackPressed ()는 finish ()를 호출합니다. 따라서 setResult는 반드시 super.onBackPressed () 전에 호출되어야합니다. super.onPause ()로 인해 setResult가 호출 될 수있는 상황이 있는지 확실하지 않지만 위험을 감수하고 싶지는 않습니다.
Philip Sheard

1

둘 다 올바른 IMO입니다.

문서에 따르면

파생 클래스는이 메서드의 슈퍼 클래스 구현을 통해 호출해야합니다. 그렇지 않으면 예외가 발생합니다.

Super 메서드는 문서에서 명시 적으로 언급 할 때 항상 호출되어야합니다.

그러나 super 메서드를 호출 할시기를 선택할 수 있습니다.

소스를 보면 onPause

protected void onPause() {
    getApplication().dispatchActivityPaused(this);
    mCalled = true;
}

따라서 호출 전후에 관계없이. 당신은 잘해야합니다.

그러나 모범 사례를 위해서는 먼저 호출해야합니다.

대부분 보호 메커니즘으로 권장합니다. 예외가 있으면 super인스턴스 메서드가 이미 호출되었을 것입니다.

또한 이러한 호출을 첫 번째 줄에 배치하면 메서드에서 코드를 삭제하고 실수로 수퍼 클래스에 대한 호출을 삭제하는 등의 실수를 방지 할 수 있습니다.


처음에 질문이 완전히 명확하지 않은 경우 죄송합니다. 지금부터 친절하게 살펴보세요.
Anudeep Bulla 2013 년

@AnudeepBulla 그것이 내가 당신에게 설명했던 것입니다. 둘 중 하나를 사용할 수 있습니다. 둘 다 유효합니다.
Sunil Mishra 2013 년

onPause, onStop 및 onDestroy 메소드의 사용자 정의 구현이 엄격하게 필요하지 않다는 것을 이해합니다. 나는 그것들없이 충분한 앱을 만들었다. 그렇다면 Super 메서드가 항상 호출되어야한다는 것은 무엇을 의미합니까? 재정의하지 않아도 암시 적으로 호출됩니다. 둘 다 작동한다는 것도 알고 있습니다. 문서에서 super를 먼저 호출해야한다고 말하는 이유를 알고 싶습니다. 그래도 질문이 명확하지 않은 경우 "하지만 모범 사례를 위해 먼저 전화를 걸어야합니다"라고 말할 때 그 이유를 설명해 주시겠습니까?
Anudeep Bulla 2013 년

재정의하지 않으면 메서드는에서 호출 Base Class되지만 재정의하는 경우 super다른 사람을 호출 해야합니다android.app.SuperNotCalledException
Sunil Mishra

1
당신은 오해하는 것 같습니다. 문제는 전화 할 것인지 말 것인지가 아닙니다. 당신이 지적한 것처럼, 당신이 그것을 무시한다면 당신은해야합니다. 문제는 언제?
Anudeep Bulla 2013 년

0

콜백의 수퍼는 활동을 시스템 내부적으로 올바른 상태로 만드는 데 필요합니다.

활동을 시작하고 시스템에서 onCreate를 호출한다고 가정 해 보겠습니다. 이제이를 재정의하고 레이아웃을로드 할 수 있습니다. 그러나 시스템 흐름을 위해 super를 호출해야 시스템이 표준 절차를 계속할 수 있습니다. 이것이 호출하지 않으면 예외가 발생하는 이유입니다.

이것은 onCreate의 구현과는 별개로 발생합니다. 시스템에 대한 유일한 수입원입니다. ANR이 없으면 모든 콜백에 무한 루프가있을 수 있으며 해당 콜백에서 활동이 포착됩니다. 따라서 시스템은 콜백이 종료 된시기를 알고 다음 콜백을 호출합니다.

나는 슈퍼 콜의 타이밍이 필요한 한 가지 상황만을 알고 있습니다. onCreate에서 테마 또는 디스플레이 등의 표준 동작을 변경하려면 super를 호출하기 전에 변경해야 효과를 볼 수 있습니다. 그렇지 않으면 AFAIK를 호출하는 시간에 차이가 없습니다.

그러나 시스템이 가장 잘 할 수있는 작업을 수행 할 수 있도록하기 위해 코드가 뒤 따르는 콜백의 첫 번째 줄에 수퍼를 넣을 수 있습니다.


onCreate의 순서는 꽤 이해하기 쉽습니다. 파기 방법은 어떻게 되나요? onStop이라고 말합니다. 내 onStop 구현이 호출되면 super 메서드가 릴리스하는 리소스 중 일부를 사용한다고 가정하면 구현 후 super 메서드를 호출하는 것이 합리적입니다.
Anudeep Bulla 2013 년

이상적으로는 이것이 사실이어야합니다. 우리의 활동은 항상 수퍼 클래스가 가지고있는 자원과 그 이상을 가질 것이며, 내 활동과 독립적 인 자원은 대부분의 경우 공통된 수퍼 클래스 자원에 의존 할 수 있습니다. 내 리소스를 먼저 처리 한 다음 수퍼 클래스를 호출하여 일반적인 리소스를 처리하는 것이 더 합리적입니다. Google은 왜 슈퍼 클래스 메서드를 먼저 호출해야한다고 말하는가?
Anudeep Bulla 2013 년

onCreate에서는 액세스 할 수 있지만 onDestroy에서는 액세스 할 수없는 리소스에 대해 이야기하고 있습니까?
Steve Benett 2013 년

사용 사례가 없습니다. OOP 스타일에 따라 어떻게 달라지는 지 궁금합니다. 슈퍼 클래스 생성자는 구현 전에 먼저 호출되고 슈퍼 클래스 소멸자는 구현 후에 마지막으로 호출됩니다. onPause, onStop 및 onDestroy는 엄격하게 소멸자는 아니지만 동일한 작업을 수행하는 경향이 있습니다. Atleast onDestroy와 대부분 onStop도 .. 아니?
Anudeep Bulla 2013 년

생성자 / 소멸자가 아닌 상태 변경 방식의 콜백을 참조하십시오. 모든 콜백에는 액티비티 생성 (사용 준비) / 파괴 (마지막 상호 작용 기회) 또는 포 그라운드 / 백그라운드에 배치하는 것이 필요합니다. 콜백은 시스템 흐름에서 리소스를 제어 할 수있는 곳입니다. 시스템은 상태를 확인하고 그에 따라 처리합니다. 사용하는 리소스와 시스템에서 제어하는 ​​리소스는 서로 독립적이며 교차점이 없습니다.
Steve Benett 2013 년
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.