OnPause, onStop ve onDestroy yöntemlerinde süper sınıf yöntemlerini çağırmanın doğru sırası nedir? ve neden?


92

Aktivite Yaşam döngüsünü tazeleyen Android Geliştirici Sitesi'nden geçiyordum ve her kod örneğinde süper sınıf yöntemlerinin yanında "Her zaman önce süper sınıf yöntemini çağırın" yazan bir yorum var.

Yaratma yarı döngüsünde bu mantıklı olsa da: onCreate, onStart ve onResume, yarım imha döngüsünde doğru prosedürün ne olduğu konusunda biraz kafam karıştı: onPause, onStop, onDestroy.

Örneğe özgü kaynakların bağlı olabileceği süper sınıf kaynaklarını yok etmeden önce ilk önce örneğe özgü kaynakları yok etmek mantıklı, tersi değil, ancak yorumlar aksini gösteriyor. Neyi kaçırıyorum?

Düzenleme : İnsanlar sorudaki amaç konusunda kafaları karışmış göründüğüne göre, bilmek istediğim şey aşağıdakilerden hangisinin doğru olduğu? VE NEDEN ?

1. Google öneriyor

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

      //my implementation here
    }

2. diğer yol

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

       super.onStop();  
    }

1
Kapatma yöntemleri için ikinci kamptayım. Başlangıç ​​yöntemleri için birinci kamptayım.
danny117

1
Esas nokta bu. Kapatma yöntemleri için yöntem 1'i kullanmanın nasıl mantıklı olduğunu anlayamadım.
Anudeep Bulla

Yanıtlar:


109

Örneğe özgü kaynakların bağlı olabileceği süper sınıf kaynaklarını yok etmeden önce ilk önce örneğe özgü kaynakları yok etmek mantıklıdır, tersi değil. Ancak yorumlar aksini gösteriyor. Neyi kaçırıyorum?

Bence: tek bir şey değil.

Mark'ın verdiği bu yanıt (SO'da CommonsWare olarak da bilinir) konuya ışık tutuyor: Bağlantı - Üst sınıf yöntemine yapılan çağrı ilk ifade mi olmalı? . Ancak cevabında kalan şu yorumu görebilirsiniz:

Ama neden resmi doktor onPause () 'da "Her zaman önce süper sınıf yöntemini çağırın" diyor?

Silbaştan. Tamam, buna başka bir açıdan bakalım. Java Dil Spesifikasyonunun , çağrının yapılması gereken bir sırayı (veya çağrının yapılması gerekip gerekmediğini) belirtmediğini biliyoruz super.overridenMethod().

Sınıf Aktivitesi durumunda, super.overridenMethod()çağrılar gereklidir ve zorunludur :

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

mCallediçinde true olarak ayarlandı Activity.onStop().

Şimdi, üzerinde tartışılacak tek detay sıralama.

I also know that both work

Elbette. Activity.onPause () için yöntem gövdesine bakın:

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;
}

Aramayı hangi şekilde yaparsanız yapın super.onPause(), iyi olacaksınız. Activity.onStop () benzer bir yöntem gövdesine sahiptir. Ancak Activity.onDestroy () 'a bir göz atın:

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);
}

Burada, sipariş verebilir belki olsun faaliyettir nasıl kurulum bağlı olarak ve arama olmadığını super.onDestroy()aşağıdaki kodu ile müdahale ederim.

Son söz olarak, ifadenin Always call the superclass method firstonu destekleyecek çok fazla kanıtı yok gibi görünüyor. Daha kötüsü (ifade için) aşağıdaki kodun şuradan alınmış olmasıdır android.app.ListActivity:

public class ListActivity extends Activity {

    ....

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

Ve android sdk'ye dahil edilen LunarLander örnek uygulamasından:

public class LunarLander extends Activity {

    ....

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

Özet ve değerli sözler:

Kullanıcı Philip Sheard : Kullanılmaya super.onPause()başlanan bir Aktivite durumunda çağrının ertelenmesi gereken bir senaryo sağlar startActivityForResult(Intent). Sonucu setResult(...) after kullanarak ayarlamak super.onPause()işe yaramayacaktır. Daha sonra cevabına yapılan yorumlarda bunu açıklığa kavuşturur.

Kullanıcı Sherif elKhatib : Süper sınıfın neden önce kaynaklarını başlatmasına ve kaynaklarını en son olarak yok etmesine izin vermenin mantıktan sonra nedenini açıklar:

İndirdiğiniz, konumu sağlayan bir getLocation () işlevi içeren bir LocationActivity'ye sahip bir kitaplığı düşünelim. Büyük olasılıkla, bu etkinliğin onCreate () içindeki öğelerini başlatması gerekecek ve bu da sizi önce super.onCreate'i çağırmaya zorlayacaktır . Bunu zaten yapıyorsun çünkü mantıklı olduğunu hissediyorsun. Şimdi, onDestroy'unuzda, Konumu Paylaşılan Tercihler'de bir yere kaydetmeye karar veriyorsunuz. Önce super.onDestroy'u çağırırsanız, belirli bir dereceye kadar getLocation'ın bu çağrıdan sonra boş bir değer döndürmesi mümkündür, çünkü LocationActivity uygulaması onDestroy'daki konum değerini geçersiz kılar. Buradaki fikir, bu olursa onu suçlamamanızdır.Bu nedenle, kendi onDestroy ile işiniz bittikten sonra super.onDestroy'u çağırırsınız.

Şöyle devam ediyor: Eğer bir çocuk sınıf, ebeveyn sınıftan uygun şekilde izole edilmişse (kaynak bağımlılığı açısından), super.X()çağrıların herhangi bir sipariş spesifikasyonuna uyması gerekmez.

Yerleştirilmesi nerede bir senaryo okumak için bu sayfadaki onun cevabını Bkz super.onDestroy()çağrı gelmez programı mantığı etkiler.

Mark'ın bir cevabından :

Bileşen oluşturmanın parçası olan geçersiz kıldığınız yöntemler (onCreate (), onStart (), onResume (), vb.), Android'in işini sizden önce yapma şansına sahip olmasını sağlamak için ilk ifade olarak üst sınıfa zincirlemelisiniz. yapılmış olan işe dayanan bir şey yapmaya çalışın.

Bileşen yok etmenin parçası olan geçersiz kıldığınız yöntemler (onPause (), onStop (), onDestroy (), vb.), Önce işinizi yapmalı ve son şey olarak üst sınıfa zincirlemelisiniz . Bu şekilde, Android'in çalışmanızın bağlı olduğu bir şeyi temizlemesi durumunda, önce işinizi yapmış olursunuz.

Void (onCreateOptionsMenu (), vb.) Dışında bir şey döndüren yöntemler, bazen özellikle belirli bir dönüş değerini zorlamak için gereken bir şey yapmadığınızı varsayarak, dönüş ifadesinde üst sınıfa zincirlenirsiniz.

Diğer her şey - örneğin onActivityResult () - genel olarak size bağlıdır. İlk şey olarak süper sınıfa zincirleme eğilimindeyim, ancak sorun yaşamıyorsanız, daha sonra zincirleme iyi olacaktır.

Bob Kerns gelen bu konuya :

Bu iyi bir model [(Mark'ın yukarıda önerdiği model)], ancak bazı istisnalar buldum. Örneğin, PreferenceActivity'ye uygulamak istediğim tema, süper sınıfın onCreate () öğesinin önüne koymadığım sürece etkili olmayacak.

Kullanıcı Steve Benett de şuna dikkat çekiyor:

Süper aramanın zamanlamasının gerekli olduğu tek bir durum biliyorum. OnCreate'de temanın veya ekranın standart davranışını değiştirmek isterseniz, bir efekt görmek için süper'i aramadan önce bunu yapmanız gerekir . Aksi takdirde, AFAIK'i hangi saatte aradığınızın bir farkı yoktur.

Kullanıcı Sunil Mishra , Activity sınıfının yöntemlerini çağırırken düzenin (büyük olasılıkla) bir rol oynamadığını onaylar. Ayrıca, önce süper sınıf yöntemlerini çağırmanın en iyi uygulama olarak kabul edildiğini iddia ediyor . Ancak bunu doğrulayamadım.

LOG_TAG Kullanıcısı : Neden bir üst sınıf kurucusuna yapılan çağrının her şeyden önce olması gerektiğini açıklar . Kanımca bu açıklama sorulan soruya katkı sağlamaz.

Son not : Güven, ama doğrula. Bu sayfadaki yanıtların çoğu, ifadenin Always call the superclass method firstmantıksal bir dayanağı olup olmadığını görmek için bu yaklaşımı izler . Görünüşe göre öyle değil; en azından, faaliyet sınıfı durumunda değil. Genel olarak, süper sınıfın kaynak kodunu, süperin yöntemlerine çağrı siparişi vermenin bir gereklilik olup olmadığını belirlemek için okunması gerekir.


2
Vay. Öneriler için teşekkürler. Hem bu hem de @ Şerif'in yanıtları önemli bir bağlam sağlar. Eğer ikinizden biri bu sayfadaki cevapları özetleyebilirse, onu kabul edildi olarak işaretlerim. Lütfen şunları ekleyin: 1. Bu sayfadaki cevaplar. 2. @ Philip'in bu sayfadaki cevabı 3. @ CommonsWare'in bu sayfadaki cevabı 4. Bu tartışma isterdim, ama harika cevaplarınız için krediyi istemiyorum. Cheers & Thanks
Anudeep Bulla

Selam. @Sherif'in istemediğini görerek özetleyebilir misiniz?
Anudeep Bulla

@AnudeepBulla Merhaba Anudeep, bana yarına kadar ver. İlgili materyali cevabıma ekleyeceğim ve size burada bir yorum bırakacağım.
Vikram

@AnudeepBulla Yukarıya bir özet ekledim. Bir şeyi kaçırmışsam diye lütfen bana haber verin.
Vikram

@Vikram TL'dir; DR. onDestroyve onStopson arama daha güvenli bir varsayılandır ve bu, onPausebirkaç durumda bazı şeyler için daha yanıltıcı olabilir? Önce ekleyebilir misin? Cevabı kendim düzenlemek istedim ama bu özetin doğru olduğundan emin değilim.
Blaisorblade

13

Süper onCreate'i aramak mantıklı olduğundan (söylediğinizden): Bir düşünün.

Yaratmak istediğimde süperim kaynaklarını yaratır> Kaynaklarımı ben yaratırım.

Tersine: (bir yığın türü)

Yok etmek istediğimde kaynaklarımı yok ederim> Süperim kaynaklarını yok eder.


Bu anlamda, herhangi bir çift işlev için geçerlidir (onCreate / onDestroy, onResume / onPause, onStart / onStop). Doğal olarak, onCreate kaynaklar yaratacak ve onDestroy bu kaynakları serbest bırakacaktır. Bu arada, aynı kanıt diğer çiftler için de geçerli.

İndirdiğiniz, konumu sağlayan bir getLocation () işlevi içeren bir LocationActivity'ye sahip bir kitaplığı düşünelim. Büyük olasılıkla, bu etkinliğin onCreate () içindeki öğelerini başlatması gerekecek ve bu da sizi önce super.onCreate'i çağırmaya zorlayacaktır. Bunu zaten yapıyorsun çünkü mantıklı olduğunu hissediyorsun. Şimdi, onDestroy'unuzda, Konumu Paylaşılan Tercihler'de bir yere kaydetmeye karar veriyorsunuz. Önce super.onDestroy'u çağırırsanız, belirli bir dereceye kadar getLocation'ın bu çağrıdan sonra boş bir değer döndürmesi mümkündür, çünkü LocationActivity uygulaması onDestroy'daki konum değerini geçersiz kılar. Buradaki fikir, bu olursa onu suçlamamanızdır. Bu nedenle, kendi onDestroy ile işiniz bittikten sonra super.onDestroy'u çağırırsınız. Umarım bu biraz mantıklıdır.

Yukarıdakiler mantıklıysa, her an yukarıdaki konsepte uyan bir faaliyetimiz olduğunu düşünün. Bu aktiviteyi genişletmek istersem, muhtemelen aynı şekilde hissedeceğim ve aynı argüman nedeniyle aynı sıralamayı izleyeceğim.

Tümevarım yoluyla, herhangi bir aktivite aynı şeyi yapmalıdır. İşte bu kurallara uymaya zorlanan bir aktivite için iyi bir soyut sınıf:

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);
    }
}

Son olarak, adındaki etkinliğiniz AnudeepBullaActivityBaseActivity'yi genişletirse ve daha sonra, SherifElKhatibActivityetkinliğinizi genişleten bir etkinlik oluşturmak istersem ? super.doFonksiyonları hangi sırayla çağırmalıyım ? Sonuçta aynı şey.


Sorunuza gelince:

Sanırım Google'ın niyetinin bize şunu söylemek olduğunu düşünüyorum: Lütfen nerede olursa olsun kapıcıyı arayın. Tabii ki genel bir uygulama olarak başlangıçta deyin. Google elbette en parlak mühendislere ve geliştiricilere sahiptir, bu yüzden muhtemelen süper çağrılarını izole ederek ve çocuk çağrılarına müdahale etmeden iyi bir iş çıkardılar.

Biraz denedim ve muhtemelen (Google olduğu için yanlış olduğunu kanıtlamaya çalışıyoruz), When is super denildiği için basit bir şekilde çökecek bir aktivite oluşturmak kolay değil.

Neden?

Bu işlevlerde yapılan her şey, Activity sınıfına gerçekten özeldir ve alt sınıfınızla hiçbir zaman çatışmaya neden olmaz. Örneğin (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 ve mManagedDialogs ve mSearchManager özel alanlardır. Ve herkese açık / korunan api'lerin hiçbiri burada yapılanlardan etkilenmeyecektir.

Ancak API 14'te, uygulamanıza kayıtlı ActivityLifecycleCallbacks'e onActivityDestroyed göndermek için dispatchActivityDestroyed eklenmiştir. Bu nedenle, ActivityLifecycleCallback'lerinizdeki bazı mantığa bağlı olan herhangi bir kod, süper kişiyi ne zaman aradığınıza bağlı olarak farklı bir sonuca sahip olacaktır. Örneğin:

Halihazırda çalışan etkinliklerin sayısını sayan bir Uygulama Sınıfı oluşturun:

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) {}
}

Aşağıdakiler bir anlam ifade etmeyebilir veya iyi bir uygulama olmayabilir, ancak sadece bir noktayı kanıtlamak içindir (Kişi daha gerçek bir durum bulabilir). Bittiğinde ve son etkinlik olduğunda GoodBye etkinliğine gittiği varsayılan MainActivity'yi oluşturun:

@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'unuzun başlangıcında super.onDestroy'u çağırırsanız, GoodBye etkinliği başlatılır. OnDestroy'unuzun sonunda super.onDestroy'u çağırırsanız, GoodBye etkinliği başlatılmaz.

Tabii ki yine, bu optimal örnek değil. Ancak bu, Google'ın burada biraz karışıklık yaptığını gösteriyor. Diğer değişkenlerden herhangi biri uygulamanızın davranışını etkilemezdi. Ancak bu gönderiyi onDestroy'a eklemek süperin alt sınıfınıza bir şekilde müdahale etmesine neden oldu.

Farklı bir sebepten dolayı da berbat ettiklerini söylüyorum. Sadece (api 14'ten önce) süper aramalarda nihai ve / veya özel olana dokunmakla kalmadılar, aynı zamanda onPause ... işlevlerini gerçekten gönderen farklı dahili işlevler (özel) olarak da adlandırdılar.

Örneğin, performStopişlev, sırayla onStop işlevini çağıran işlevdir:

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;
}

Bu işlevde bir yerde Activity's onStop olarak adlandırdıklarına dikkat edin. Bu nedenle, tüm kodu (super.onStop içinde bulunan) onStop çağrısından önce veya sonra koymuş olabilirler ve ardından boş onStop süper işlevlerini kullanarak ve hatta SuperNotCalledException eklemeden veya çağrıyı kontrol etmeden onStop hakkında alt sınıfları bilgilendirebilirler.

Bunun için bu gönderiyi super.onDestroy'un sonunda çağırmak yerine performDestroy'daki ActivityLifeCycle'a çağırsalar, süper'i ne zaman çağırdığımıza bakılmaksızın etkinliğimizin davranışı aynı olurdu.

Her neyse, yaptıkları ilk şey bu (biraz yanlış) ve sadece API 14'te.


Soru hiçbir zaman super.onDestroy () 'u son olarak çağırmanın neden mantıklı olduğu olmadı. Kütüphane örneğinizi seviyorum. Ben de tam olarak iletmek istediğim şey. Kazara veri kaybını önlemek için, tıpkı bir yığındaki gibi, en son imha yarım döngülerinde süper yöntemleri çağırmak konusunda daha fazla anlaşamadım. Sorun, yukarıdaki öncül göz önüne alındığında, Google'ın neden önce süper yöntemleri çağırmakta ısrar etmesidir? Soruyu sordum çünkü belki ben ve görünüşe göre sen de tamamen farklı bir şekilde yaklaşabileceğimi düşündüm. Şerefe
Anudeep Bulla

Oh, Google'ın önerdiği ve Diğer yolu görmedim: p! Dinle, önce onDestroy'u ararsan çökecek bir aktivite oluşturmaya çalışacağım. Bunu da denemelisin. Şerefe
Sherif elKhatib

@AnudeepBulla düzenlemelerimi kontrol edebilirsiniz. Ve btw denemeyi bırakabilirsiniz. super.onmuhtemelen aktivitenizi asla bozmayacaktır.
Sherif elKhatib

Vay. Öneriler için teşekkürler. Hem bu hem de @ Kullanıcının yanıtları önemli bağlam sağlar. Eğer ikinizden biri bu sayfadaki cevapları özetleyebilirse, onu kabul edildi olarak işaretlerim. Lütfen şunları ekleyin: 1. Bu sayfadaki cevaplar. 2. @ Philip'in bu sayfadaki cevabı 3. @ CommonsWare'in bu sayfadaki cevabı 4. Bu tartışma isterdim, ama harika cevaplarınız için krediyi istemiyorum. Cheers & Thanks
Anudeep Bulla

@AnudeepBulla Rica ederim. Son yazıyı kimin göndereceğine nasıl karar vereceğimizden emin değilim.
Vikram

2

Google'ın 1. yöntemi önerdiğini söylüyorsunuz, ancak iyi bilinen bir Android çerçeve mühendisi olan Dianne Hackborn, aksi takdirde Google Forum Bağlantısına bakın .

Süper sınıf aramak için sezgisel mantıklı son ne zaman tahrip içinde bir örneğini OnPause, OnStop ve OnDestroy yöntemleri ve ilk ne zaman yaratma yöntemleri ile bir örneğini onCreate, onResume ve onStart .


Dianne Hackborn'un gönderisine bağlantı önemlidir ve düzeni doğrulamaktadır.
Nick Westgate

1

Java perspektifinden bakıldığında, işte bu karışıklık için bir çözüm:

This () ve super () neden bir yapıcıdaki ilk ifade olmak zorunda?

Üst sınıf 'yapıcısının' alt sınıf 'yapıcısından önce çağrılması gerekir. Bu, kurucunuzdaki üst sınıfta herhangi bir yöntemi çağırırsanız, üst sınıfın zaten doğru şekilde ayarlandığından emin olmanızı sağlayacaktır.

Yapmaya çalıştığınız şey, süper kurucuya argümanlar iletmek tamamen yasaldır, yalnızca bu bağımsız değişkenleri yaptığınız gibi satır içi olarak oluşturmanız veya kurucunuza iletmeniz ve ardından onları süper kurucuya iletmeniz gerekir:

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

Derleyici bunu zorlamadıysa, bunu yapabilirsiniz:

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

Aslında, alt alanların üst sınıftan önce inilialize edilmesi gerektiğini gösteriyor! Bu arada, java gereksinimi, süper yapıcı argümanını uzmanlaştırarak sınıfı uzmanlaşmaktan bizi "korur"

Bir üst sınıfın varsayılan bir kurucuya sahip olduğu durumlarda, super çağrısı sizin için derleyici tarafından otomatik olarak eklenir. Java'daki her sınıf Object'ten miras aldığından, nesne yapıcısı bir şekilde çağrılmalı ve önce çalıştırılmalıdır. Derleyici tarafından super () 'in otomatik olarak eklenmesi buna izin verir. Super'i ilk olarak görünmeye zorlamak, yapıcı gövdelerinin doğru sırada yürütülmesini zorunlu kılar: Nesne -> Üst -> Çocuk -> ChildOfChild -> SoOnSoForth

(1) Super'in ilk ifade olduğunu kontrol etmek, bu sorunu önlemek için yeterli değildir. Örneğin, "super (someMethodInSuper ());" kurucunuzda. Bu, ilk ifade süper olsa bile, oluşturulmadan önce üst sınıftaki bir yönteme erişmeye çalışır.

(2) Derleyici, bu sorunu önlemek için kendi başına yeterli olan farklı bir denetim uyguluyor gibi görünüyor. Mesaj "süper tip yapıcısı çağrılmadan önce xxx'e başvurulamaz" şeklindedir. Bu nedenle, süper'in ilk ifade olduğunu kontrol etmek gerekli değildir

Lütfen bu http://valjok.blogspot.in/2012/09/super-constructor-must-be-first.html sayfasını inceleyin


Oraya ne koyduğunuzu çok iyi anlıyorum. Önce süper sınıf kurucuları çağırırsınız, çünkü çocuğun ihtiyaç duyabileceği kaynakları başlatabilirler; ve yıkıcılar son olarak, çünkü muhtemelen tüm ebeveynleri yerel kaynaklardan silmek istemiyorsunuz, bu da onları anlamsız hale getiriyor. Benim amacım tam olarak bu. Ve onPause, onStop ve onDestroy, durum bilgilerini kaydetme ve az çok kaynakları GC için kullanılabilir hale getirme (yani bir anlamda onları yok etme) işine sahip olduğundan, onları yıkıcılara benzer görüyorum ve bu nedenle onları son olarak adlandırmanın mantıklı olduğunu düşünüyorum. Hayır?
Anudeep Bulla

Yukarıda söylediğin her şey, "süper metotları çağırmak ilk olarak yaradılış yarı döngüsünde anlamlıdır" dediğimde tam olarak kastettiğim şeydi. Yıkıcılara daha benzer görünen yarım döngü yöntemlerinin imha edilmesi durumunda endişeliyim ve kafam karıştı. Şerefe
Anudeep Bulla

1

Akılda tutulması gereken en önemli şey, super.onPause()örtük olarak çağırmasıdır setResult(Activity.RESULT_CANCELED). Ancak setResultyalnızca bir kez çağrılabilir ve sonraki tüm çağrılar dikkate alınmaz. Üst etkinliğe sonuç arkasında her türlü zorlamaya istiyorsanız, aramak zorunda setResult, kendini önce çağrı super.onPause(). Bildiğim kadarıyla en büyük sorun bu.


Vay canına, bu önemli görünüyor. Yani süper metotlara yapılan çağrıyı kesinlikle geciktirmeniz gereken bir durum var. Teşekkür ederim.
Anudeep Bulla

super.onPause() implicitly calls setResult(Activity.RESULT_CANCELED). Bunu nereden aldığını söyleyebilir misin?
Vikram

Kafam karışmıştı. Aslında setResult'u çağıran finish () 'dir ve super.onBackPressed (), finish ()' yi çağırır. Yani setResult kesinlikle super.onBackPressed () 'den önce çağrılmalıdır. Super.onPause () işlevinin setResult'un çağrılmasına neden olabileceği herhangi bir koşul olup olmadığından emin değilim, ancak riske atmamayı tercih ediyorum.
Philip Sheard

1

HER İKİSİ de doğru IMO

Dokümanlara göre

Türetilmiş sınıflar, süper sınıfın bu yöntemin uygulamasını çağırmalıdır. Aksi takdirde, bir istisna atılır.

Super yöntem her zaman dokümantasyon açıkça söylediğinde çağrılmalıdır.

Bununla birlikte, süper yöntemi ne zaman çağıracağınızı seçebilirsiniz.

Kaynağına bakıyorum onPause

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

Bu nedenle, çağrılmadan önce veya sonra olursa olsun. İyi olmalısın.

Ancak en iyi uygulama için önce onu aramalısınız.

Çoğunlukla bir koruma mekanizması olarak tavsiye ederim: bir istisna varsa, o zaman superörnek yöntemi zaten çağrılmış olacaktır.

Ayrıca bu çağrıları ilk satıra koymak, gelecekte yöntemdeki kodu silmek ve kazara süper sınıfa yapılan çağrıyı silmek gibi hatalardan kaçınmanıza yardımcı olacaktır.


İlk seferinde soru tam olarak anlaşılmadıysa özür dilerim, ama lütfen şimdi bir göz atın.
Anudeep Bulla

@AnudeepBulla Size bunu açıkladım. İkisini de kullanabilirsiniz. İkisi de geçerlidir.
Sunil Mishra

Anladığıma göre, onPause, onStop ve onDestroy yöntemlerinin özel olarak uygulanması kesinlikle gerekli değildir. Bunlar olmadan çok sayıda uygulama yaptım. Peki, Süper yöntemler her zaman çağrılmalıdır derken neyi kastediyorsunuz? Geçersiz kılınmadan bile dolaylı olarak çağrılırlar. İkisinin de işe yaradığını da biliyorum. Doktorların neden önce süper çağrılması gerektiğini söylediğini bilmek istiyorum. Ve soru hala açık değilse, lütfen "Ama en iyi uygulama için önce onu aramalısın" derken NEDEN açıklar mısınız?
Anudeep Bulla

Geçersiz kılmıyorsanız, yöntemler çağrılır, Base Classancak geçersiz kılarsanız, supersahip olacağınız android.app.SuperNotCalledException
diğerini

1
Yanlış anlıyorsun. Soru, arayıp aramamak değil. Sizin de belirttiğiniz gibi, onları geçersiz kılarsanız, YAPMANIZ GEREKİR. Soru şu ki, ne zaman?
Anudeep Bulla

0

Geri aramaların en üst düzeyine, Aktiviteyi sistem için dahili olarak doğru duruma getirmek için gereklidir.

Diyelim ki Aktivitenizi başlattınız ve onCreate sistem tarafından çağrıldı. Şimdi onu geçersiz kılabilir ve örneğin düzeninizi yükleyebilirsiniz. Ancak sistem akışı adına, sistemin standart prosedüre devam edebilmesi için süper çağırmanız gerekir. Bu yüzden onu çağırmazsan bir istisna atılacak.

Bu, onCreate'deki uygulamanızdan bağımsız olarak gerçekleşir. Sadece sistem için önemli. ANR yoksa, herhangi bir geri aramada sonsuz bir döngünüz olabilir ve Etkinlik bu döngüye yakalanır. Böylece, sistem geri aramanın ne zaman sonlandırıldığını bilir ve bir sonrakini arar.

Süper aramanın zamanlamasının gerekli olduğu tek bir durum biliyorum. OnCreate'de temanın veya ekranın standart davranışını değiştirmek isterseniz, bir efekt görmek için süper'i aramadan önce bunu yapmanız gerekir. Aksi takdirde AFAIK'i hangi saatte aradığınızın bir farkı yoktur.

Ancak sistemin, süper kişiyi geri aramanın ilk satırına en iyi şekilde yerleştirmesine ve ardından onu bozmak için iyi bir nedeniniz yoksa kodunuza bırakmasına izin verin.


OnCreate'deki sıra oldukça anlaşılır görünüyor. İmha yöntemlerinde neler oluyor? OnStop deyin. Benim onStop uygulamamın, çağrılırsa süper yöntemin yayınladığı bazı kaynakları kullandığını varsayalım.
Anudeep Bulla

İdeal olarak, durum bu olmalıdır, doğru. Aktivitemiz her zaman süper sınıfın sahip olduğu kaynaklara ve daha fazlasına sahip olacaktır ve benim aktivitemden bağımsız olanlar, çoğu durumda ortak olan süper sınıf kaynaklarına bağlı olabilir. Önce kaynaklarımla uğraşmak, sonra da ortak olanlarla ilgilenmek için süper sınıfı aramak daha mantıklı geliyor. O halde Google neden önce üst sınıf yöntemlerini "ÇAĞIRMALIYIZ" diyor?
Anudeep Bulla

OnCreate'te erişebileceğiniz ancak onDestroy'da erişemeyeceğiniz hangi kaynaktan bahsediyorsunuz?
Steve Benett

Kullanım alanım yok. Sadece merak ediyorum, OOP tarzına göre nasıl değişiyor. Uygulamanızdan önce süper sınıf kurucuları, son olarak ise süper sınıf yıkıcıları çağrılır, doğru mu? onPause, onStop ve onDestroy kesinlikle yıkıcı değildir, ancak aynı şeyleri yapma eğilimindedirler, değil mi? En azından imha sırasında ve çoğunlukla da durdurulduğunda .. hayır?
Anudeep Bulla

Yapıcı / yıkıcı olarak değil, durumdaki geri aramaların değiştiğini görün. Her geri aramanın ihtiyacı vardır, örneğin bir Aktivite yaratma (kullanıma hazır olma) / yok etme (etkileşim için son şansınız) veya onu ön plana / arka plana koyma. Geri aramalar, kaynaklarınızı sistem akışında kontrol edebileceğiniz oradadır. Sistem sadece hangi durumda olduğunu kontrol eder ve buna göre işlem yapar. Kullandığınız kaynaklar ve sistemin kontrol ettiği kaynaklar birbirinden bağımsızdır ve kesişme olmayacaktır.
Steve Benett
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.