java.lang.IllegalStateException: Fragment, Activity'e eklenmemiş


153

Bir API çağrısı yaparken nadiren bu hatayı alıyorum.

java.lang.IllegalStateException: Fragment  not attached to Activity

isAdded()Parçanın şu anda etkinliğine eklenip eklenmediğini kontrol etmek için kodu yöntemin içine koymayı denedim, ancak yine de nadiren bu hatayı alıyorum. Neden hala bu hatayı aldığımı anlayamıyorum. Nasıl önleyebilirim?

Satırda hata gösteriyor

cameraInfo.setId(getResources().getString(R.string.camera_id));

Aşağıda yaptığım örnek api çağrısı var.

SAPI.getInfo(getActivity(),
                new APIResponseListener() {
                    @Override
                    public void onResponse(Object response) {


                        cameraInfo = new SInfo();
                        if(isAdded()) {
                            cameraInfo.setId(getResources().getString(R.string.camera_id));
                            cameraInfo.setName(getResources().getString(R.string.camera_name));
                            cameraInfo.setColor(getResources().getString(R.string.camera_color));
                            cameraInfo.setEnabled(true);
                        }


                    }

                    @Override
                    public void onError(VolleyError error) {
                        mProgressDialog.setVisibility(View.GONE);
                        if (error instanceof NoConnectionError) {
                            String errormsg = getResources().getString(R.string.no_internet_error_msg);
                            Toast.makeText(getActivity(), errormsg, Toast.LENGTH_LONG).show();
                        }
                    }
                });

cameraInfo.setId (getActivity (). getResources (). getString (R.string.camera_id));
Ashwin H

Yanıtlar:


208

Bu hata, iki faktörün birleşik etkisinden kaynaklanır:

  • HTTP isteği, tamamlandığında, ön planda olup olmadığını bilmeden onResponse()veya onError()(ana iş parçacığı üzerinde çalışan) birini çağırır Activity. Eğer Activity(kullanıcı başka bir yere navigasyon) gitti, getActivity()döner boş.
  • Voleybol Response, dış Activitysınıfa güçlü bir gönderme yapan anonim bir iç sınıf olarak ifade edilir . Bu, klasik bir bellek sızıntısına neden olur.

Bu sorunu çözmek için her zaman şunları yapmalısınız:

Activity activity = getActivity();
if(activity != null){

    // etc ...

}

ve ayrıca kullan isAdded() de onError()bir yöntem olarak da var olmaktadır:

@Override
public void onError(VolleyError error) {

    Activity activity = getActivity(); 
    if(activity != null && isAdded())
        mProgressDialog.setVisibility(View.GONE);
        if (error instanceof NoConnectionError) {
           String errormsg = getResources().getString(R.string.no_internet_error_msg);
           Toast.makeText(activity, errormsg, Toast.LENGTH_LONG).show();
        }
    }
}

2
Volley isteklerini ve AsyncTasklerini bir içinden kullanırken Activity, NPE'lerden kaçınmanın kusursuz bir yolu yoktur. İş Activityparçacıklarından biri arka planda bir şeyler yaparken kullanıcının her zaman mevcut durumdan uzaklaşması şansı vardır ve iş parçacığı tamamlandığında ve onPostExecute()veya onResponse()çağrıldığında, hayır yoktur Activity. Yapabileceğiniz tek şey, kodunuzun çeşitli noktalarında boş referansları kontrol etmek ve bu kurşun geçirmez değil :)
YS

2
Android maymun testi (adb kabuk maymunu), bunu genel / küresel bir şekilde daha önce açıklamadıysanız, bu hatayı kökten çözmede gerçekten iyidir.
Groovee60

6
Eklendi () yeterli, son genel boole eklendi () {dönüş mActivity! = null && m added; }
lannyf

2
@ruselli: addedBoole bayrağını ve mevcut Activityörneğin olup olmadığını kontrol eder null.
YS

1
@gauravjain Eşzamansız istekler (HTTP çağrıları gibi) doğrudan Fragments'tan yapmaktan kaçının. Aktiviteden yapın ve iyi olmalı. Ayrıca FragmentManager'daki Fragment referanslarını temizleyin, bu iyi bir uygulamadır ve bellek sızıntılarını önlemenin en iyi yoludur.
YS

56

Parça yaşam döngüsü çok karmaşık ve hatalarla dolu, eklemeye çalışın:

Activity activity = getActivity(); 
if (isAdded() && activity != null) {
...
}

2
Nereye koymalıyım?
Vaclovas Rekašius Jr.

1
@Kafadergisi Aktiviteye parçanın içinden erişmek istediğiniz hemen hemen her yer gibi görünüyor. Eğlence!
TylerJames

2
Activity == null ise ne yapmalıyım. başvurumu canlı tutmak için @Miroslav
pavel

Eklendi () bölümüne bakın , "etkinlik! = Boş"
ifadesinin

@BertKing return mHost != null && mAdded;- fragment.isAdded () yönteminin içinde budur. Eğer izlerseniz mHost'un bir Etkinlik olduğunu düşünmüştüm, ancak mHost FragmentActivity'nin içinde gibi görünüyor. Yani, muhtemelen haklısın. Herhangi bir ekleme var mı?
Johnny Five

17

Çok Basit Bir Çözüm Buldum Bu mevcut parçanın Aktivitesine eklenip eklenmediğini belirlemeye yönelik fragman yöntemlerinden biri olan Eklendi () yöntemi.

bunu fragment sınıfında her yerde olduğu gibi kullanabiliriz:

if(isAdded())
{

// using this method, we can do whatever we want which will prevent   **java.lang.IllegalStateException: Fragment not attached to Activity** exception.

}

13

İstisna: java.lang.IllegalStateException: Parça

DeadlineListFragment {ad2ef970} Etkinliğe eklenmemiş

Kategori: Yaşam Döngüsü

Açıklama : Arka plan iş parçacığında (örneğin, AsyncTask) zaman alıcı işlem yaparken, bu arada yeni bir Fragment oluşturuldu ve arka plan iş parçacığı tamamlanmadan önce Activity'den ayrıldı. UI iş parçacığındaki kod (örn. OnPostExecute), böyle bir istisna atarak ayrılmış bir Fragmenti çağırır.

Düzeltme çözümü:

  1. Parçayı duraklatırken veya durdururken arka plan iş parçacığını iptal edin

  2. Parçanın eklenip eklenmediğini kontrol etmek için eklenmiş () öğesini kullanın ve ardından etkinlikten getResources () öğesini kullanın.


11

Geç kalmış olabilirim ama birine yardımcı olabilirim ..... Bunun için en iyi çözüm, global bir uygulama sınıfı örneği oluşturmak ve onu faaliyetinizin eklenmediği belirli bir bölümde çağırmaktır

aşağıdaki gibi

icon = MyApplication.getInstance().getString(R.string.weather_thunder);

İşte uygulama sınıfı

public class MyApplication extends Application {

    private static MyApplication mInstance;
    private RequestQueue mRequestQueue;

    @Override
    public void onCreate() {
        super.onCreate();
        mInstance = this;
    }

    public static synchronized MyApplication getInstance() {
        return mInstance;
    }
}

1
Evet, bu yöntem de yaygın olarak kullanılmaktadır.
CoolMind

1
Bu akıllıca bir seçenek değil. FragmentContext ve ApplicationContext'in farklı stilleri vardır. Fragment Context karanlık temaya, özel stile, Locale vb. Olabilir. Bu, farklı dosyalardan rengi, dizgi kaynaklarını çeker. ApplicationContext doğru kaynağı çekemeyebilir. Bağlamınız yoksa, o kaynağı oluşturmaya çalışmamalısınız.
Jemshit İskenderov

2

Bu hata, bir şekilde somutlaştırılamayan bir parçayı örneklediğinizde ortaya çıkabilir:

Fragment myFragment = MyFragment.NewInstance();


public classs MyFragment extends Fragment {
  public void onCreate() {
   // Some error here, or anywhere inside the class is preventing it from being instantiated
  }
}

Benim durumumda, kullanmaya çalıştığımda bununla tanıştım:

private String loading = getString(R.string.loading);

2

Parça kullanımında isAdded() şu anda Aktiviteye eklenmişse doğru geri dönecektir.

Faaliyetin içini kontrol etmek isterseniz

 Fragment fragment = new MyFragment();
   if(fragment.getActivity()!=null)
      { // your code here}
      else{
       //do something
       }

Umarım birine yardım eder


1

Bu konuyu ele almak için aşağıdaki yaklaşımı benimsedim. Bunun gibi etkinlik yöntemleri için sarmalayıcı görevi gören yeni bir sınıf oluşturuldu

public class ContextWrapper {
    public static String getString(Activity activity, int resourceId, String defaultValue) {
        if (activity != null) {
            return activity.getString(resourceId);
        } else {
            return defaultValue;
        }
    }

    //similar methods like getDrawable(), getResources() etc

}

Artık, kaynaklara parçalardan veya etkinliklerden erişmem gereken her yerde, yöntemi doğrudan çağırmak yerine, bu sınıfı kullanıyorum. Aktivitenin contextolmaması durumunda, nullvarlığın değerini döndürür ve contextboş olması durumunda, varsayılan bir değer geçirir (bu aynı zamanda işlevin çağırıcısı tarafından da belirtilir).

Önemli Bu bir çözüm değildir, bu, bu çökmeyi incelikle halledebileceğiniz etkili bir yoldur. Aktivite örneğini boş olarak aldığınız durumlarda bazı günlükler eklemek ve mümkünse bunu düzeltmeye çalışmak istersiniz.


0

bu, parçanın bir bağlamı olmadığında gerçekleşir, bu nedenle getActivity () yöntemi null döndürür. bağlamı anlamadan önce kullanıp kullanmadığınızı kontrol edin , veya Aktivite artık mevcut değilse. fragment.onCreate içinde bağlam kullanın ve api yanıtından sonra genellikle bu sorunu ortaya çıkarın


0

Bazen bu istisna, destek kitaplığı uygulamasındaki bir hatadan kaynaklanır. Son zamanlarda ondan kurtulmak için 26.1.0'dan 25.4.0'a geçmek zorunda kaldım.


Hayır yok, ama belki bir tane yaratmalıyım.
Bord81

0

Bu sorun, çağrıldığında kullanılamayan veya boş olan bir bağlamı aradığınızda ortaya çıkar. Bu, bir arka plan iş parçacığındaki ana etkinlik iş parçacığının bağlamını veya ana etkinlik dizisindeki arka plan iş parçacığının bağlamını çağırdığınızda bir durum olabilir.

Örneğin, paylaşılan tercih dizimi aşağıdaki gibi güncelledim.

editor.putString("penname",penNameEditeText.getText().toString());
editor.commit();
finish();

Ve hemen ardından finish () çağırdı. Şimdi yaptığı şey, commit ana iş parçacığı üzerinde çalışır ve bitene kadar gelirse diğer Async commit'leri durdurur. Dolayısıyla, yazım tamamlanana kadar içeriği canlıdır. Dolayısıyla önceki bağlam canlıdır ve hatanın oluşmasına neden olur.

Bu nedenle, bu bağlam sorununa sahip bazı kodlar varsa, kodunuzun yeniden kontrol edildiğinden emin olun.


bu sorunu nasıl çözdünüz? Onu bir asenkron iş parçacığı içinde arıyorum ve şimdi bu sorunu yaşıyorum.
Simon

Sadece yazma işleminin bittiğinden emin olun, ardından yazma işlemi tamamlanmadan önce yalnızca bağlam öldürülür.
Prashant Paliwal

0

Yani temel fikir, onDetach yaşam döngüsüne giren bir parça üzerinde bir UI işlemi çalıştırmanızdır .

Bu gerçekleştiğinde, parça yığından çıkıyor ve Faaliyet bağlamını kaybediyor .

Dolayısıyla, UI ile ilgili işlevleri çağırdığınızda, örneğin ilerleme çarkını çağırdığınızda ve parçanın yığına eklenip eklenmediğini kontrol etmek istediğinizde, aşağıdaki gibi:

if(isAdded){ progressBar.visibility=View.VISIBLE }

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.