Android Fragment onAttach () veraltet

326

Ich habe meine App aktualisiert, um die neueste Support-Bibliothek (Version 23.0.0) zu verwenden. Ich habe festgestellt, dass die Funktion onAttach () der Fragment-Klasse nicht mehr unterstützt wird.

Anstatt:

onAttach (Activity activity)

Es schneit:

onAttach (Context context)

Da meine App die vor der Verwerfung übergebenen Aktivitäten verwendet, ist eine mögliche Lösung meiner Meinung nach:

@Override
public void onAttach(Context context) {
    super.onAttach(context);
    activity = getActivity();
}

Wäre das der richtige Weg?

AKTUALISIEREN:

Wenn ich ein Gerät mit einer API unter 23 ausführe, wird das neue onAttach () nicht einmal aufgerufen. Ich hoffe, dass dies nicht das ist, was sie vorhatten!

UPDATE 2:

Das Problem wurde mit den neuesten Updates für das SDK behoben.

Ich habe auf meinem API 22-Gerät getestet und onAttach (Context) wird aufgerufen.

Klicken Sie hier , um dem Fehlerbericht zu folgen, den ich vor ein paar Wochen geöffnet habe, und den Antworten der Jungs von Google.

TareK Khoury
quelle
Wenn Sie dann bestimmte Aktivitätsmethoden aus Ihrer übergebenen Instanz verwenden, haben Sie versucht, den Kontext in die Ihrer Aktivität umzuwandeln? Denken Sie daran, Aktivität ist eine Unterklasse des Kontexts. Vielleicht würde ein Casting funktionieren.
MarkSkayff
Aus irgendeinem Grund wird onAttach () nicht einmal aufgerufen! irgendwelche Ideen? Haben Sie versucht, auf die neueste Support-Bibliothek zu aktualisieren?
TareK Khoury
2
Warum wurde die API verschoben Context? ActivityBenötigen Sie keine , um ein Fragment anzuhängen und anzuzeigen? Wie werden Sie den ContextParameter sonst noch verwenden ?
Kenny Worden
1
Ich habe es als Fehler gepostet, siehe Link code.google.com/p/android/issues/detail?id=183358
TareK Khoury
6
Damit das neue onAttach(Context context)Gerät aufgerufen werden kann, müssen Sie entweder ein Gerät mit mindestens API 23 verwenden oder android.support.v4.app.Fragment verwenden. Siehe hier
Nevzo

Antworten:

337

Aktivität ist ein Kontext. Wenn Sie also einfach überprüfen können, ob es sich bei dem Kontext um eine Aktivität handelt, können Sie sie bei Bedarf umwandeln.

@Override
public void onAttach(Context context) {
    super.onAttach(context);

    Activity a;

    if (context instanceof Activity){
        a=(Activity) context;
    }

}

Update: Einige behaupten, dass die neue ContextÜberschreibung niemals aufgerufen wird. Ich habe einige Tests durchgeführt und kann kein Szenario finden, in dem dies wahr ist, und laut Quellcode sollte es niemals wahr sein. In allen Fällen habe ich sowohl vor als auch nach SDK23 getestet, sowohl dieActivity als auch die ContextVersionen von onAttachaufgerufen. Wenn Sie ein Szenario finden, in dem dies nicht der Fall ist, empfehlen wir Ihnen, ein Beispielprojekt zu erstellen, das das Problem veranschaulicht, und es dem Android-Team zu melden .

Update 2: Ich verwende immer nur die Fragmente der Android Support Library, da Fehler dort schneller behoben werden. Es scheint, dass das obige Problem, bei dem die Überschreibungen nicht korrekt aufgerufen werden, nur dann auftritt, wenn Sie die Framework-Fragmente verwenden.

Kuffs
quelle
5
Keine wirkliche Lösung, da onAttach mit Kontext nicht wie onAttach mit Aktivität aufgerufen wird. Wenn Sie in onAttach einen Initialisierungscode mit einer Aktivität als Parameter haben, funktioniert diese Änderung nicht.
Buddy
2
Nein, es funktioniert nicht gleich, zumindest in meinem Fall. Ich verwende weder Aktivität noch Kontext in onAttach, ich initialisiere. Ich habe versucht, onAttach durch Aktivität durch Aktivität mit Kontext zu ersetzen, und es wird nicht auf die gleiche Weise aufgerufen. Sie sind also nicht so leicht austauschbar.
Buddy
7
Dieselben Probleme, die Buddy hat ... onAttach(Context)scheinen nicht einmal genannt zu werden.
Stéphane
2
Ich habe meinen Code durchgearbeitet und kann überprüfen, ob es möglich ist onAttach(context), nicht aufgerufen zu werden.
Chad Bingham
2
In meinem Fall wird onAttach () nicht aufgerufen, wenn wir die Aktivität neu starten, die zuvor vom System gelöscht wurde. Aber das ist nicht immer so. Ich habe eine Initialisierung einer WeakReference in den onAttach (Kontextkontext) eingefügt, refActivity = new WeakReference <> ((AppCompatActivity) -Kontext). Und es löst gelegentlich NullPointerException in onCreateView () aus.
Kimi Chiu
45

Dies ist eine weitere große Veränderung von Google ... Die vorgeschlagene Änderung: ersetzen onAttach(Activity activity)mit onAttach(Context context)abgestürzt meinen apps auf ältere APIs seitonAttach(Context context) nicht auf nativen Fragmente bezeichnet werden.

Ich verwende die nativen Fragmente (android.app.Fragment), daher musste ich Folgendes tun, damit es auf älteren APIs wieder funktioniert (<23).

Folgendes habe ich getan:

@Override
public void onAttach(Context context) {
    super.onAttach(context);

    // Code here
}

@SuppressWarnings("deprecation")
@Override
public void onAttach(Activity activity) {
    super.onAttach(activity);

    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
        // Code here
    }
}
Yoann Hercouet
quelle
Mr.Yoann Hercouet, können Sie mir erklären, wie es über API 23 gemacht wird? Bitte helfen Sie mir im Voraus. E / AndroidRuntime: FATAL EXCEPTION: main, java.lang.ClassCastException: com.ual.SMS_Activity@afd5683, at android. support.v4.app.FragmentManagerImpl.moveToState unter android.support.v4.app.FragmentManagerImpl.execSingleAction. Hier habe ich die notwendigen Zeilen gepostet, um meinen Fehler zu erkennen.
MohanRaj S
@MohanRajS Auf API 24 (der von mir verwendeten) ist es dasselbe. Laut Ihrem Code scheint Ihr Problem damit nichts zu tun zu haben.
Yoann Hercouet
@ YoannHercouet, Vielen Dank für Ihre Antwort, lassen Sie mich überprüfen und aktualisieren.
MohanRaj S
1
Sie sind mit Google nicht zufrieden, da es schwierig ist, auf ältere APIs abzuzielen. Betrachten Sie den Segen, dass Sie auf ältere APIs abzielen KÖNNEN, während Apple Sie beispielsweise nur enorm verkrüppeln und Sie zwingen würde, nur die neuesten zu unterstützen.
Stan
39

Wenn Sie die Framework-Fragmente verwenden und die SDK-Version des Geräts niedriger als 23 ist, OnAttach(Context context) dies nicht aufgerufen.

Ich verwende stattdessen Unterstützungsfragmente, daher ist die Ablehnung behoben und wird onAttach(Context context)immer aufgerufen.

Kikermo
quelle
11

Derzeit ist aus dem onAttachFragmentcode nicht ersichtlich, ob Contextes sich um die aktuelle Aktivität handelt: Quellcode

public void onAttach(Context context) {
    mCalled = true;
    final Activity hostActivity = mHost == null ? null : mHost.getActivity();
    if (hostActivity != null) {
        mCalled = false;
        onAttach(hostActivity);
    }
}

Wenn Sie einen Blick darauf werfen, sehen getActivitySie den gleichen Anruf

/**
 * Return the Activity this fragment is currently associated with.
 */
final public Activity getActivity() {
    return mHost == null ? null : mHost.getActivity();
}

Also , wenn Sie wollen sicher sein , dass Sie die Aktivität verwenden Sie dann bekommen getActivity()(in onAttachIhrer Fragment) , aber vergessen Sie nicht , zu überprüfen , nulldenn wenn mHostist nullIhre Aktivität wirdnull

royB
quelle
6
@Override
public void onAttach(Context context) {
    super.onAttach(context);

    Activity activity = context instanceof Activity ? (Activity) context : null;
}
hat funktioniert
quelle
5

Obwohl es in den meisten Fällen ausreicht onAttach(Context), gibt es einige Telefone (z. B. Xiaomi Redme Note 2), auf denen es nicht aufgerufen wird, sodass NullPointerExceptions verursacht werden. Um auf der sicheren Seite zu sein, schlage ich vor, auch die veraltete Methode beizubehalten:

// onAttach(Activity) is necessary in some Xiaomi phones
@SuppressWarnings("deprecation")
@Override
public void onAttach(Activity activity) {
    super.onAttach(activity);
    _onAttach(activity);
}

@Override
public void onAttach(Context context) {
    super.onAttach(context);
    _onAttach(context);
}

private void _onAttach(Context context) {
    // do your real stuff here
}
Gavriel
quelle
3

Laden Sie die neueste Support-Bibliothek mit dem SDK-Manager herunter und fügen Sie sie hinzu

compile 'com.android.support:appcompat-v7:23.1.1'

in gradle.app und setze die Kompilierungsversion auf api 23

Essah
quelle
1

Die folgende Antwort bezieht sich auf diese Verfallswarnung, die im Fragment-Tutorial auf der Android-Entwickler-Website angezeigt wird, und möglicherweise nicht auf die obigen Beiträge.

Ich habe diesen Code in der Tutorial-Lektion verwendet und es hat funktioniert.

public void onAttach(Context context){
    super.onAttach(context);

    Activity activity = getActivity();

Ich war besorgt, dass die Aktivität möglicherweise null ist, wie in der Dokumentation angegeben.

getActivity

FragmentActivity getActivity () Gibt die FragmentActivity zurück, der dieses Fragment derzeit zugeordnet ist. Kann null zurückgeben, wenn das Fragment stattdessen einem Kontext zugeordnet ist.

Das onCreate für die main_activity zeigt jedoch deutlich, dass das Fragment geladen wurde. Nach dieser Methode gibt der Aufruf von get activity aus dem Fragment die main_activity-Klasse zurück.

getSupportFragmentManager (). beginTransaction () .add (R.id.fragment_container, firstFragment) .commit ();

Ich hoffe ich bin damit richtig. Ich bin ein absoluter Neuling.

Roy Selim
quelle
1

Sie verwenden wahrscheinlich android.support.v4.app.Fragment. onAttachVerwenden Sie dazu anstelle der Methode nur getActivity()die, FragmentActivitymit der das Fragment verknüpft ist. Andernfalls könnten Sie die onAttach(Context context)Methode verwenden.

LeoCoder
quelle
0

Dies funktionierte für mich, wenn ich die benutzerdefinierte Schnittstelle 'TopSectionListener' habe, deren Objektaktivitätsbefehl:

  //This method gets called whenever we attach fragment to the activity
@Override
public void onAttach(Context context) {
    super.onAttach(context);
    Activity a=getActivity();
    try {
        if(context instanceof Activity)
           this.activitycommander=(TopSectionListener)a;
    }catch (ClassCastException e){
        throw new ClassCastException(a.toString());}

}
Muskan Agarwal
quelle