11

Po aktualizacji do najnowszej repozytorium wsparcia,Fragment musi być publiczny klasa statyczna być prawidłowo odtworzone z instancji stanu

compile 'com.android.support:appcompat-v7:24.2.0' 
compile 'com.android.support:design:24.2.0' 
compile 'com.android.support:percent:24.2.0' 
compile 'com.android.support:recyclerview-v7:24.2.0' 

Otrzymuję dziwny wyjątek.

java.lang.IllegalStateException: Fragment null must be a public static class to be properly recreated from instance state. 
at android.support.v4.app.BackStackRecord.doAddOp(BackStackRecord.java:435) 
at android.support.v4.app.BackStackRecord.add(BackStackRecord.java:414) 
at android.support.v4.app.DialogFragment.show(DialogFragment.java:154) 
at com.androidapp.base.BaseActivity.showDialogFragment(BaseActivity.java:78) 
at com.androidapp.MainActivity.showNewDialog(MainActivity.java:304) 
at com.androidapp.MainActivity$6.onClick(MainActivity.java:228) 

W moim BaseActivity klasy I utworzeniu fragmentu wielokrotnego użytku, które mogą być wykorzystane w klasie aktywności, który rozszerza BaseActivty

public void showDialogFragment(DialogFragment newFragment) { 
     FragmentTransaction ft = getSupportFragmentManager().beginTransaction(); 
     Fragment prev = getSupportFragmentManager().findFragmentByTag("dialog"); 
     if (prev != null) { 
      ft.remove(prev); 
     } 
     ft.addToBackStack("dialog"); 
     newFragment.show(ft, "dialog"); 
    } 

Powrót do MainActivty I użyłem tego fragmentu,

DialogNew klasa jest poniżej

public abstract class DialogNew extends DialogFragment { 

    private View rootView; 

    private String title; 
    private String message; 

    public void setArgs(String title, String message) { 
     Bundle args = new Bundle(); 
     args.putString("title", title); 
     args.putString("message", message); 
     setArguments(args); 
    } 

    @Override 
    public void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     setStyle(STYLE_NO_TITLE, 0); 
    } 

    @Override 
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { 

     rootView = inflater.inflate(R.layout.fragment_new_dialog, container, false); 

     init(); 
     setListeners(); 

     return rootView; 
    } 

    public abstract void success(boolean isLandscape); 

    public abstract void cancel(); 
} 

PS: Ten sam kod działa ze starszymi repozytorium wsparcia.

+0

Dlaczego skrót 'DialogNew' jest abstrakcyjny? Nie można utworzyć instancji klasy abstrakcyjnej. – Vucko

+0

@ Vucko, w porządku. Robiąc takie rzeczy tak masz rację, że nie możesz * utworzyć abstrakcji * zamiast tego zainicjować anonimową klasę, która rozszerza tę klasę abstrakcji. W skrócie nie ma z tym problemu. – Enzokie

+0

z tym samym błędem w wersji biblioteki wsparcia 24.2.1 – Meet

Odpowiedz

10

Błąd nie jest szczególnie dziwny. Jeśli nie dostałeś tego błędu przed, , że było dziwne.

Android niszczy i odtwarza fragmenty w ramach zmiany konfiguracji (np. Rotacja ekranu) i jako część przebudowy zadania w razie potrzeby (np. Użytkownik przełącza się do innej aplikacji, proces aplikacji zostaje przerwany, gdy znajduje się w tle , następnie użytkownik próbuje wrócić do aplikacji, wszystko w ciągu 30 minut lub coś koło tego). Android nie ma możliwości odtworzenia anonimowej podklasy DialogNew.

więc uczynić regularny public klasy Java (lub publicstatic zagnieżdżonych klasa), który rozciąga się DialogNew i ma swoją logikę biznesową, zastępując anonimowe podklasy DialogNew że używasz obecnie.

+0

Dzięki za odpowiedź! Zgodziłem się z twoją logiką.Obecnie mój DialogNew już rozszerza DialogFragment, więc nie mogę go rozszerzyć w MainActivity, ponieważ sama MainActivity rozszerza działanie. Nie wiem jak, ale ten sam kod działał poprawnie ze starszym repo wsparciem. Chcę tylko zachować oddzielne okno dialogowe i klasę aktywności. –

0

Edytuj: Prawdopodobnie nie chcesz tego robić ... Zobacz komentarze.

Próbka kodu wygląda podobnie do tego, co zasugerowałem powyżej here, a ostatnio odkryłem, że rozwiązanie, które tam miałem, już nie działa. Zaktualizowałem moją odpowiedź tam Java7, ale jeśli masz Java8 rozwiązanie jest bardzo proste:

(nie testowałem tego jeszcze)

public class DialogNew extends DialogFragment { 
    private View rootView; 
    private String title; 
    private String message; 

    // Do nothing by default 
    private Consumer mSuccess = (boolean b) -> {}; 
    private Runnable mCancel =() -> {}; 

    public void setArgs(String title, String message) { 
     Bundle args = new Bundle(); 
     args.putString("title", title); 
     args.putString("message", message); 
     setArguments(args); 
    } 

    @Override 
    public void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     setStyle(STYLE_NO_TITLE, 0); 
    } 

    @Override 
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { 
     rootView = inflater.inflate(R.layout.fragment_new_dialog, container, false); 
     // use mSuccess.accept(boolean) when needed 
     init(); 
     setListeners(); 
     return rootView; 
    } 

    public void setSuccess(Consumer success) { 
     mSuccess = success; 
    } 

    public void setCancel(Runnable cancel) { 
     mCancel = cancel; 
    } 
} 

Następnie w głównej działalności:

public class MainActivity extends BaseActivity { 
     public void showNewDialog(int type, String title, String message) { 
      final DialogNew dialog = new DialogNew(); 
      dialog.setArgs(title, message); 
      dialog.setSuccess((boolean isLandscape) -> { 
       //.... 
      }); 
      super.showDialogFragment(dialog); 
     } 
} 
+1

To nie zadziała z kilku powodów. Po pierwsze, 'mSuccess' i' mCancel' nie przetrwają Fragmentu, który jest paczkowany. Jeśli utworzyłeś ten Fragment, masz gorszy problem: Kiedy wywołujesz dialog.setSuccess i przekazujesz mu wyrażenie lambda, stworzyłeś wewnętrzną klasę MainActivity. Gdy działanie zostanie odtworzone po zmianie konfiguracji, wystąpi przeciek pamięci, a wywołania zwrotne będą próbowały wywoływać metody na zniszczonej aktywności. –

Powiązane problemy