2017-01-08 1 views
4

Introduction

Huh, ist dies eine harte ein. WenigstensIch denke, so ... Dinge zu klären:OnClickListener nicht (korrekt) nach ConfigurationChange in Fragmente Arbeits

ich keine Antworten auf meine Frage nach der Suche im Internet (mit Google) gefunden wurde.

Alles, was ich wollte Menschen gefunden, die onClickListener 's für ihre View ist falsch einrichten. Ich denke, es ist das gleiche Problem in meinem Fall, aber keines der anderen Probleme entsprach meinem.

This scheint das gleiche Problem zu sein ... Es hat keine Antworten.

Setup-

ich mit einem ViewPager in meinem AppCompatActivity zusammen drei Fragment ‚s eingerichtet haben.

viewPager = (ViewPager) findViewById(R.id.main_view_pager); 
viewPager.setAdapter(new SectionsPagerAdapter(getSupportFragmentManager())); 

Behandelt von der SectionsPagerAdapter.

public class SectionsPagerAdapter extends FragmentPagerAdapter { 

    SectionsPagerAdapter(FragmentManager fm) { 
     super(fm); 
    } 

    @Override 
    public Fragment getItem(int position) { 
     switch (position) { 
      case 0: 
       return MainTextHolder.newInstance(tabIndicatorOnClick); 
      case 1: 
       return PostWriter.newInstance(tabIndicatorOnClick); 
      case 2: 
       return TopPage.newInstance(tabIndicatorOnClick); 
      default: 
       return Error.newInstance(); 
     } 
    } 

    @Override 
    public int getCount() { 
     return 3; 
    } 

    // ... more methods 
} 

In jedem der Fragment ‚s ich einige Inhalte sowie eine benutzerdefinierte haben TabIndicator.

(die folgende xml Datei ist mein View 's für den Indikator)

<?xml version="1.0" encoding="utf-8"?> 
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 
    android:layout_width="match_parent" 
    android:layout_height="wrap_content" > 

    <View 
     android:id="@+id/fragment_divider_one" 
     android:layout_width="0dp" 
     android:layout_height="match_parent" 
     android:layout_weight="1" 
     android:tag="one" /> 

    <View 
     android:id="@+id/fragment_divider_two" 
     android:layout_width="0dp" 
     android:layout_height="match_parent" 
     android:layout_weight="1" 
     android:tag="two" /> 

    <View 
     android:id="@+id/fragment_divider_three" 
     android:layout_width="0dp" 
     android:layout_height="match_parent" 
     android:layout_weight="1" 
     android:tag="three" /> 

</LinearLayout> 

Und dann stelle ich eine OnClickListener für jede dieser View' s (Teiler) in der Fragment ‚s onCreateView(LayoutInflater inflater, ViewGroup Bundle savedInstanceState) Methode. Die OnClickListener ist bereits in meinem Activity vorbereitet, wo ich auch meine ViewPager instanziiere, so dass ich die aktuelle Item (Fragment/tab) ändern kann.

private final View.OnClickListener tabIndicatorOnClick = new View.OnClickListener() { 
    @Override 
    public void onClick(View view) { 
     if (view.getTag().toString().equals("one")) 
      viewPager.setCurrentItem(0, true); // second argument for smooth transition 
     else if (view.getTag().toString().equals("two")) 
      viewPager.setCurrentItem(1, true); 
     else if (view.getTag().toString().equals("three")) 
      viewPager.setCurrentItem(2, true); 
    } 
}; 

gebe ich, dass OnClickListener auf die Fragment ist, indem sie in meine newInstance(View.OnClickListener tabIndicatorOnClick) Methode setzen.

Dies ist für eines der Fragmente. Es ist identisch für die anderen!

public static MainTextHolder newInstance(View.OnClickListener tabIndicatorOnClick) { 
    MainTextHolder fragment = new MainTextHolder(); 
    Bundle args = new Bundle(); 
    fragment.putIndicatorTabIndicatorOnClick(tabIndicatorOnClick); 
    fragment.setArguments(args); 
    fragment.setRetainInstance(true); 
    return fragment; 
} 

Meine putIndicatorTabIndicatorOnClick(View.OnClickListener tabIndicatorOnClick) Methode ist ein Void in einem Interface. Es gilt nur die OnClickListener an die Class (Fragment).

@Override 
public void putIndicatorTabIndicatorOnClick(View.OnClickListener tabIndicatorOnClick) { 
    this.tabIndicatorOnClick = tabIndicatorOnClick; 
} 

Ist es

Ja, es funktioniert tut. Es funktioniert einwandfrei ... bis eine ConfigurationChange passiert.In meinem Fall habe ich es mit getestet und die Ausrichtung geändert.

Das Problem

Was nach diesen ConfigurationChange passiert ist, dass alles normal geht. Die OnClickListener wird an alle View 's in alleFragment' s angewendet, aber die tabIndicatorOnClickOnClickListener ist ein null Objektreferenz in der zweiten und dritten Fragment.

So in PostWriter und TopPage gibt es nicht einmal wirklich ein OnClickListener auf den View ist für welchen Gründen auch immer. Aber es wird besser: In MainTextHolderFragment ist das tabIndicatorOnClick kein null object reference, aber es ändert nicht die ViewPager 's Item mehr. Es führt den Code, aber es scrollt nicht Tab.

Wenn auf drehen „Do Aktivitäten nicht halten“ ind Entwickleroptionen des Gerätes und die App zu verlassen, alle OnClickListener ‚s sind null object references. Auch solche in MainTextHolder.

Zusammenfassung

Nach dem ConfigurationChange die OnClickListener wird in meine erste Fragment vergangen, aber es ist nicht ordnungsgemäß funktioniert und in die verbleibenden Fragment ‚s es ist nicht einmal vergangen/a null object reference.

Das Problem kann repliziert werden, indem die Activity repliziert und dann neu geladen wird.

Am Ende ...

... Ich habe keine Ahnung, was falsch läuft. Ich hoffe, dass ich meine Frage richtig strukturiert habe.

von Interesse sein

minSdkVersion:

targetSdkVersion:

ich bereits eine SpringIndicator auf meinem ViewPager haben. Dies hat keine OnClickListener, so fügte ich meine eigenen "überlagerte" Indikatoren, die die erforderliche Funktion haben. Ich mag auch das Aussehen, aber wenn Sie mir eine bessere Lösung für meine TabIndicator geben können, würde ich auch gerne als Antwort haben.

stieß ich auf die Lösung, die das Verfahren in setzen die xml:onClick mehrere Male zuschreiben, aber dafür würde ich die gleiche OnClickListener für jeden Fragment erstellen müssen, die nicht wirklich die nette Art und Weise ist, und es ist auch nicht Lösung mein Problem, aber ein Weg um es herum. - Ich müsste die ViewPager in meine Fragment und dann diese Methode von xml, die, wie ich schon sagte, nur eine andere Möglichkeit, es zu tun und nicht die Art, wie ich es lieber tun. Auch ich weiß nicht, ob es funktioniert. Ich werde es wahrscheinlich testen.

Andere OnClickListener 's in der Fragment funktionieren immer noch richtig. Also wie gesagt das Problem liegt in der OnClickListener selbst nicht richtig funktioniert/ein null object reference.

+0

haben Sie versucht, in Ihrem Manifest zu ändern android: configChanges = "orientation | screenSize"? –

+0

Das klingt wie ein Fragments-Lebenszyklusproblem. Können Sie bestätigen, dass Sie den Fehler replizieren können, indem Sie Entwickleroptionen aktivieren/Aktivitäten nicht beibehalten und dann die Home-Schaltfläche verwenden, um die Aktivität zu verlassen oder zu verlassen? –

+0

@MilosLulic ja – creativecreatorormaybenot

Antwort

2

Erstens, gut gemacht, um eine detaillierte Beschreibung des Problems zu schreiben. Viele Fragesteller von StackOverflow können aus der Fähigkeit dieser Frage lernen, das Problem zu artikulieren.

Dieser Fehler scheint von der Nichtberücksichtigung von Fragmentlebenszyklusänderungen zu stammen. Innerhalb eines ViewPagers durchlaufen Fragmente verschiedene Zustände, einschließlich ausgeblendet und angezeigt, wenn sie vorübergehend außerhalb des Bildschirms sind, und angehalten und fortgesetzt, wenn sie sich außerhalb des Bildschirms befinden und das System Speicher freigibt und schließlich erstellt und zerstört, wenn das Android-System den Instanzstatus speichert Ihrer Aktivität (z. B. von einer Konfigurationsänderung). Im letzteren Fall versucht Android, den Status Ihrer Fragmente aus dem Status der gespeicherten Instanz in Ihrem ViewPager wiederherzustellen. Da Ihre Fragmente keine Möglichkeit haben, die View.OnClickedListener zu speichern, die in den Argumenten übergeben wurden, enden sie mit einem Zeiger null, wenn sie wiederhergestellt werden, was Ihren Fehler verursacht.

Um den Fehler zu beheben, schlage ich vor, dass Sie die View.OnClickedListener nicht als Parameter an die Fragmente übergeben. Stelle die OnClickListener deinen Fragmenten stattdessen über eine öffentliche Methode in deiner Aktivität zur Verfügung und lasse die Fragmente sie selbst in ihrem onResume() erhalten. Auf diese Weise können Sie garantieren, dass die Fragmente einen Verweis auf die View.OnClickedListener haben, wenn sie sich in einem wiederaufgenommenen Zustand befinden. Also Ihr onResume() könnte wie folgt aussehen:

@Override 
public void onResume() { 
    OnClickListener onClickListener = ((MyActivity) getActivity).getOnClickListener(); 
    putIndicatorTabIndicatorOnClick(onClickListener); 

}

Da Sie es in onResume() gesetzt haben, sollten Sie es in onPause() entfernen:

@Override 
public void onPause() { 
    //set the onClickListener to null to free up the resource 
} 

Mit onResume() und onPause() wie diese Ressourcen freizugeben von Listenern ist der im Entwicklerleitfaden empfohlene Ansatz.

Natürlich müssen Sie sicherstellen, dass Ihre Aktivität auch ihren eigenen Lebenszyklus behandelt, indem Sie den gespeicherten Status in onCreate(Bundle savedInstanceState) überprüfen und ihn entsprechend wiederherstellen.

Bitte beachten Sie, dass Spar Instanz Zustand und die Wiederherstellung kann auf eine Anzahl von Arten ausgelöst werden:

  1. Konfigurationszustandsänderung (zB Drehen des Telefons und wodurch die Aktivität Landschaft angezeigt werden in eher als Porträt
  2. Das Gerät wird nicht mehr genügend Arbeitsspeicher (z. B. wenn eine große Anzahl von Aktivitäten in aktuellen Apps enthalten sind)
  3. Aktivieren von Entwickleroptionen/Keine Aktivitäten und Verwendung von zu Hause, um Ihre Anwendung in den letzten Anwendungen zu speichern und dann zu Ihrer ca.

Sie können eine dieser Methoden verwenden, um festzustellen, ob Sie die Lebenszyklen Ihrer Aktivitäten und Fragmente korrekt verarbeitet haben.

+0

Zunächst einmal, vielen Dank für Ihre Antwort. Sehr gute Information. Obwohl ich es nicht zur Arbeit gebracht habe. Ich habe herausgefunden, dass die 'onCreateView()' Methode im Lebenszyklus vor meiner 'onResume()' Methode aufgerufen wird, so dass mein tabIndicator immer Null ist, wenn er auf die 'View' angewendet wird. Ich weiß, wie man das umgeht, aber gibt es einen besseren Weg, als onClick in der Methode onResume() zu setzen, die Sie kennen? – creativecreatorormaybenot

+0

Einstellung in 'onResume()' ist die empfohlene Vorgehensweise. Sie können den Lebenszyklus der Aktivitäten und relevante Abschnitte des Entwicklerhandbuchs überprüfen. Fragmente/Aktivitäten sind nicht wie POJO, wo Sie immer Abhängigkeiten als Konstruktor Parameter übergeben können –

+0

Great! Danke für Ihre Hilfe. Dies hatte einige wirklich nette zusätzliche Informationen. – creativecreatorormaybenot

Verwandte Themen