Android - onAttach (Kontext) wird für API 23 nicht aufgerufen

73

Ich habe das SDK auf die neueste Version (API 23) aktualisiert und die onAttach(Activity)Methode für Fragment ist veraltet. Anstatt diese Methode zu verwenden, verwende ich jetzt, onAttach(Context)aber diese wird während des Lebenszyklus nicht aufgerufen. Die Aktivität ist eine Instanz AppCompatActivityvon v7 und das Fragment ist eine Instanz der Klasse Fragment ( android.app.Fragment).

Irgendwelche Ideen, wie man die onAttachArbeit in API 23 zum Laufen bringt?

Lösung

Ich habe einige Antworten gefunden, die Ihnen helfen können, dieses Problem zu verstehen und zu beheben:

  • Wie bereits erwähnt, verwende ich die Aktivität aus Support v7 (AppCompatActivity) und das Fragment aus android.app.

  • Zum Anzeigen von Fragmenten erhalte ich den Fragmentmanager mit der Methode getFragmentManager für die Aktivität. Der Fragmentmanager ist also eine Instanz von FragmentManager aus android.app -> und hier ist das Problem

  • Wenn Sie die Anwendung auf einem Gerät mit API 23 ausführen (ich habe sie auf dem AS-Emulator ausgeführt), wird die Methode onAttach (Context) aufgerufen. Während des Prozesses zum Anzeigen eines Fragments durch den FragmentManager wird zu einem bestimmten Zeitpunkt die Methode onAttach (..) aufgerufen. Mit getFragmentManager () erhalten Sie eine Instanz des Fragment-Managers, die für die Android-Version verfügbar ist, die auf diesem Gerät ausgeführt wird (z. B. API 22, 23). Wenn die Anwendung auf einem Gerät mit API <23 ausgeführt wird, ist die Methode onAttach (Context) nicht verfügbar. Der Fragmentmanager weiß nicht, dass es in API 23 eine Methode onAttach (Context) gibt. Daher wird sie nicht aufgerufen Für die API <23 -> besteht die Lösung für diese Art von Problemen in der Verwendung des FragmentManager aus Support-Bibliotheken.

  • Lösungen:

    1. Wenn Sie getSupportFragmentManager () verwenden, werden Sie gezwungen, ein Fragment aus der Support-Bibliothek zu verwenden. Die erste Lösung besteht also darin, alle Fragmente durch das Fragment aus support lib zu ersetzen und getSupportFragmentManager () zu verwenden.

    2. Die Lösung, die ich bereits implementiert habe, besteht darin, zwei Möglichkeiten zu behandeln (1. Die App wird auf einem Gerät mit API <23 ausgeführt, die App wird auf einem Gerät mit API> = 23 ausgeführt).

    Kurz gesagt, in meiner Implementierung habe ich eine Basisklasse für alle Fragmente aus dem Projekt und ich habe diesen Code dort hinzugefügt:

    /*
     * onAttach(Context) is not called on pre API 23 versions of Android and onAttach(Activity) is deprecated
     * Use onAttachToContext instead
     */
    @TargetApi(23)
    @Override
    public final void onAttach(Context context) {
        super.onAttach(context);
        onAttachToContext(context);
    }
    
    /*
     * Deprecated on API 23
     * Use onAttachToContext instead
     */
    @SuppressWarnings("deprecation")
    @Override
    public final void onAttach(Activity activity) {
        super.onAttach(activity);
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
            onAttachToContext(activity);
        }
    }
    
    /*
     * Called when the fragment attaches to the context
     */
    protected void onAttachToContext(Context context) {
    }
    

    Jetzt überschreibe ich einfach die onAttachToContext (Context) -Methode für alle Fragmente, bei denen ich dies benötige.

    David Rauca
    quelle
    1
    Hast du @Overrideauf deinem onAttach(Context)? Wenn nicht, fügen Sie es hinzu. Wenn Sie dann einen Compilerfehler erhalten, der sich darüber beschwert, dass dies nicht der onAttach(Context)Fall ist , stellen Sie sicher, dass Sie sich auf Version 23 von befinden appcompat-v7.
    CommonsWare
    1
    Ja. Ich habe @Override auf onAttach (Kontext). Auch die Version für v7 ist 23.0.0.
    David Rauca
    1
    Hab das gerade getestet. Meine Tätigkeit erstreckt sich AppCompatActivityauch. Ich habe überschrieben onAttach(Activity)und onAttach(Context)beide wurden für mich gerufen. Getestet mit Nexus 5 (MPA44G), minSdk = 16, targetSdk = 23.
    Mygod
    2
    Noch nicht. Ich habe es mit Support v4 versucht und es funktioniert. Sie können versuchen, Support v4 zu verwenden.
    David Rauca
    2
    @ WédneyYuri Gemäß dieser Antwort werden sowohl onAttach (Kontext) als auch onAttach (Aktivität) auf einem Gerät mit API-Level 23 aufgerufen. Daher müssen Sie die obige Überprüfung durchführen, um sicherzustellen, dass die Arbeit, die Sie als Teil von onAttach ausführen, nicht ausgeführt wird zweimal auf einem Gerät ausgeführt, auf dem API Level 23 ausgeführt wird.
    Janus Varmarken

    Antworten:

    28

    Ich habe das Problem folgendermaßen gelöst:

    @TargetApi(23)
    @Override public void onAttach(Context context) {
        //This method avoid to call super.onAttach(context) if I'm not using api 23 or more
        //if (Build.VERSION.SDK_INT >= 23) {
            super.onAttach(context);
            onAttachToContext(context);
        //}
    }
    
    /*
     * Deprecated on API 23
     * Use onAttachToContext instead
     */
    @SuppressWarnings("deprecation")
    @Override public void onAttach(Activity activity) {
        super.onAttach(activity);
        if (Build.VERSION.SDK_INT < 23) {
            onAttachToContext(activity);
        }
    }
    
    /*
     * This method will be called from one of the two previous method
     */
    protected void onAttachToContext(Context context) {}
    
    Francesco Florio
    quelle
    3
    In Bezug auf onAttach (Kontext) .. wird die Methode nicht für API <23 aufgerufen, sodass Sie die darin enthaltene Version nicht überprüfen müssen.
    David Rauca
    onDetach () wird auch nicht aufgerufen. Wie mache ich, wenn ich einstellen möchte this.context = null?
    Honghe.Wu
    E / AndroidRuntime: FATAL EXCEPTION: main, java.lang.ClassCastException:, unter com.fragment.fragment_home_new.onAttachToContext, unter com.fragment.fragment_home_new.onAttach, unter android.support.v4.app.FragmentManI einige notwendige Zeilen meines Fehlers. Bitte helfen Sie mir, dieses Problem zu beheben. Danke im Voraus.
    MohanRaj S
    18

    Sie sollten versuchen, die Support-Bibliotheksversion von Fragment zu verwenden.

    Sie müssen Schalter import android.support.v4.app.Fragment;statt import android.app.Fragment;. Sie müssen auch sicherstellen, dass Sie getSupportFragmentManager()anstelle von verwenden getFragmentManager().

    Jellibus Bellibean
    quelle
    Ich denke das ist die richtige Antwort. Ich nahm an, dass ich das integrierte Fragment verwenden könnte, da ich auf SDK Version 18 abziele, aber die Fragment-API weist Unterschiede zwischen verschiedenen SDK-Versionen auf. Das Fragment der Unterstützungsbibliothek ist versionübergreifend konsistent und ruft als solches onAttach (Aktivitätsaktivität) auf.
    Ben
    Angenommen, Sie möchten das PreferenceFragment verwenden, das nicht in der Support-Bibliothek enthalten ist, und Sie möchten hinzufügen, dass Ihre Lösung für den Wechsel zum Support-Fragment als eines der Fragmente in einer Navigationsschublade nicht funktioniert
    Jayshil Dave,
    6

    Bitte poste hier über diesen BUG

    AUSGABE AUF GOOGLE AOSP PROJECT HOMESITE ERÖFFNET:

    https://code.google.com/p/android/issues/detail?id=185465

    ps. Dies ist nicht Ihre Aufgabe, nach einer Lösung für dieses Problem zu suchen und irgendwelche Problemumgehungen zu finden. Aber Google zu zwingen, seine kaputte API zu reparieren! Um dies zu tun, musst du dich beschweren, wie ich sagte.

    verwandtes Problem - getContext () aus Fragment:

    https://code.google.com/p/android/issues/detail?id=185848

    ceph3us
    quelle
    5

    Ich habe mir das gleiche Problem ausgedacht. Ich habe eine minSdkVersion von 19 und eine targetSdkVersion von 23 und verwende fragmentManager in einer AppCompatActivity.

    onAttach(Activity activity)ist als veraltet markiert, aber ich habe App-Abstürze festgestellt, als ich es durch ersetzt habe onAttach(Context context).

    Stattdessen sind jetzt beide Versionen vorhanden, und wenn ich meine App auf API22 ausführe, onAttach(Activity activity) wird sie ausgelöst , obwohl sie als veraltet markiert ist.

    Ich habe es nicht auf einem Android Marshmallow-Gerät getestet, aber ich verstehe, dass es die onAttach(Context context)Version ausführen würde , wobei die andere ignoriert wird.

    Update , um die Beobachtung von @ skaar in den Kommentaren unten zu berücksichtigen: Ich konnte jetzt auf API23 testen und bestätigen, dass beim Ausführen auf Plattform 23 beide Methoden (mit Aktivität und Kontext) aufgerufen werden. Danke für die Warnung!

    0x4e84
    quelle
    kann das jemand bestätigen?
    Martin Mlostek
    Dieses Verhalten sehe ich mit Ausnahme der letzten Aussage. Angenommen, Sie verwenden android.app.Fragment und nicht die Support-Bibliotheksversion. Wenn Ihre Kompilierungs- / Zielversion 23 ist, ist die Methode Fragment.onAttach (Aktivität) veraltet. Sie müssen jedoch weiterhin onAttach (Aktivität) verwenden, wenn Sie auf Plattformen <23 abzielen, da diese nicht über die Methode onAttach (Kontext) verfügen. Außerdem werden beide Methoden aufgerufen, wenn Sie auf einem Gerät mit Plattformversion 23 ausgeführt werden.
    vman
    4

    Nachdem ich Ihre Antwort @ David Rauca gelesen habe, denke ich, dass die zweite mein Problem lösen kann. Aber wenn ich in den Quellcode schaue. Ich fand, dass eigentlich onAttach(Context context)nichts auf Android M zu tun, nur die alte Methode genannt.

    Als Lösung:

    @SuppressWarnings("deprecation")
    

    Fügen Sie es einfach in die alte Methode ein, um die beste Lösung zu finden.

    Tony Zhang
    quelle
    3

    Ich bin auf das gleiche Problem gestoßen. Was ich getan habe, um es zu lösen:

    1. Ändern Sie den Argumenttyp des onAttach-Rückrufs von Aktivität in Kontext . Aus unbekannten Gründen führt diese Änderung dazu, dass die Methode onAttach (Context) während des Fragmentlebenszyklus nicht mehr aufgerufen wird. Infolgedessen stürzte meine App ab, da der Code in der onAttach-Methode nie ausgeführt wurde.

    2. Verschieben Sie den Code in der onAttach-Methode in onCreate one, da er noch ausgeführt wird.

    Mit dieser Änderung funktioniert die App wie zuvor. Es importwaren keine zusätzlichen Aussagen erforderlich.

    Andrew
    quelle
    1
    @Override
    public void onAttach(Context context) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            super.onAttach(context);
            onAttachToContext(context);
        } else {
            Activity activity = getActivity();
            super.onAttach(activity);
            onAttachToContext(activity);
        }
    }
    
    Hayk Mkrtchyan
    quelle