Android
Fragmente
Suche…
Einführung
Einführung in Fragmente und deren Interkommunikationsmechanismus
Syntax
void onActivityCreated (Bundle savedInstanceState) // Wird aufgerufen, wenn die Aktivität des Fragments erstellt und die Ansichtshierarchie dieses Fragments instanziiert wurde.
void onActivityResult (int requestCode, int resultCode, Intent data) // Empfangen Sie das Ergebnis eines vorherigen Aufrufs an startActivityForResult (Intent, int).
void onAttach (Activity activity) // Diese Methode wurde auf API-Ebene 23 nicht mehr unterstützt. Verwenden Sie stattdessen onAttach (Context).
void onAttach (Kontextkontext) // Wird aufgerufen, wenn ein Fragment zum ersten Mal mit seinem Kontext verbunden wird.
void onAttachFragment (Fragment childFragment) // Wird aufgerufen, wenn ein Fragment als untergeordnetes Element dieses Fragments angehängt ist.
void onConfigurationChanged (Configuration newConfig) // Wird vom System aufgerufen, wenn sich die Gerätekonfiguration ändert, während Ihre Komponente ausgeführt wird.
void onCreate (Bundle savedInstanceState) // Wird aufgerufen, um ein Fragment zu erstellen.
View onCreateView (LayoutInflater-Inflater, ViewGroup-Container, Bundle savedInstanceState) // Wird aufgerufen, damit das Fragment seine Benutzeroberflächenansicht instanziiert.
void onDestroy () // Wird aufgerufen, wenn das Fragment nicht mehr verwendet wird.
void onDestroyView () // Wird aufgerufen, wenn die zuvor von onCreateView (LayoutInflater, ViewGroup, Bundle) erstellte Ansicht vom Fragment getrennt wurde.
void onDetach () // Wird aufgerufen, wenn das Fragment nicht mehr an seine Aktivität angehängt ist.
void onInflate (Aktivitätsaktivität, AttributeSet-Attribute, Bundle savedInstanceState) // Diese Methode wurde in API-Ebene 23 nicht mehr unterstützt. Verwenden Sie stattdessen onInflate (Context, AttributeSet, Bundle).
void onInflate (Context-Kontext, AttributeSet-Attribute, Bundle savedInstanceState) // Wird aufgerufen, wenn ein Fragment als Teil einer Inflation des Ansichtslayouts erstellt wird, normalerweise durch Festlegen der Inhaltsansicht einer Aktivität.
void onPause () // Wird aufgerufen, wenn das Fragment nicht mehr fortgesetzt wird.
void onResume () // Wird aufgerufen, wenn das Fragment für den Benutzer sichtbar ist und aktiv ausgeführt wird.
void onSaveInstanceState (Bundle outState) // Wird aufgerufen, um das Fragment zu bitten, seinen aktuellen dynamischen Status zu speichern, damit es später wiederhergestellt werden kann, wenn eine neue Instanz seines Prozesses neu gestartet wird.
void onStart () // Wird aufgerufen, wenn das Fragment für den Benutzer sichtbar ist.
void onStop () // Wird aufgerufen, wenn das Fragment nicht mehr gestartet wird.
void onViewStateRestored (Bundle savedInstanceState) // Wird aufgerufen, wenn der gesamte gespeicherte Status in der Ansichtshierarchie des Fragments wiederhergestellt wurde.
Bemerkungen
Ein Fragment repräsentiert ein Verhalten oder einen Teil einer Benutzeroberfläche in einer Aktivität. Sie können mehrere Fragmente in einer einzigen Aktivität kombinieren, um eine Benutzeroberfläche mit mehreren Bereichen zu erstellen und ein Fragment in mehreren Aktivitäten wiederzuverwenden. Sie können sich ein Fragment als modularen Abschnitt einer Aktivität vorstellen, der seinen eigenen Lebenszyklus hat, seine eigenen Eingabeereignisse empfängt und die Sie hinzufügen oder entfernen können, während die Aktivität ausgeführt wird (eine Art "Unteraktivität", die Sie können Wiederverwendung in verschiedenen Aktivitäten).
Konstrukteur
Jedes Fragment muss über einen leeren Konstruktor verfügen, sodass es beim Wiederherstellen des Aktivitätszustands instanziiert werden kann. Es wird dringend empfohlen, dass Unterklassen keine anderen Konstruktoren mit Parametern haben, da diese Konstruktoren nicht aufgerufen werden, wenn das Fragment erneut instanziiert wird. Stattdessen können Argumente vom Aufrufer mit setArguments (Bundle) bereitgestellt und später vom Fragment mit getArguments () abgerufen werden.Das newInstance () -Muster
Obwohl es möglich ist, einen Fragmentkonstruktor mit Parametern zu erstellen, ruft Android intern den Zero-Argument-Konstruktor auf, wenn Fragmente neu erstellt werden (z. B. wenn sie wiederhergestellt werden, nachdem sie aus eigenen Gründen von Android beendet wurden). Aus diesem Grund ist es nicht ratsam, sich auf einen Konstruktor mit Parametern zu verlassen.
Um sicherzustellen, dass die erwarteten Fragmentargumente immer vorhanden sind, können Sie das Fragment mit einer statischen newInstance()
Methode erstellen und die gewünschten Parameter in ein Bundle newInstance()
, das beim Erstellen einer neuen Instanz verfügbar ist.
import android.os.Bundle;
import android.support.v4.app.Fragment;
public class MyFragment extends Fragment
{
// Our identifier for obtaining the name from arguments
private static final String NAME_ARG = "name";
private String mName;
// Required
public MyFragment(){}
// The static constructor. This is the only way that you should instantiate
// the fragment yourself
public static MyFragment newInstance(final String name) {
final MyFragment myFragment = new MyFragment();
// The 1 below is an optimization, being the number of arguments that will
// be added to this bundle. If you know the number of arguments you will add
// to the bundle it stops additional allocations of the backing map. If
// unsure, you can construct Bundle without any arguments
final Bundle args = new Bundle(1);
// This stores the argument as an argument in the bundle. Note that even if
// the 'name' parameter is NULL then this will work, so you should consider
// at this point if the parameter is mandatory and if so check for NULL and
// throw an appropriate error if so
args.putString(NAME_ARG, name);
myFragment.setArguments(args);
return myFragment;
}
@Override
public void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
final Bundle arguments = getArguments();
if (arguments == null || !arguments.containsKey(NAME_ARG)) {
// Set a default or error as you see fit
} else {
mName = arguments.getString(NAME_ARG);
}
}
}
Jetzt in der Aktivität:
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
MyFragment mFragment = MyFragment.newInstance("my name");
ft.replace(R.id.placeholder, mFragment);
//R.id.placeholder is where we want to load our fragment
ft.commit();
Dieses Muster ist eine bewährte Methode, um sicherzustellen, dass alle erforderlichen Argumente bei der Erstellung an Fragmente übergeben werden. Wenn das System das Fragment zerstört und es später erneut erstellt, wird der Status automatisch wiederhergestellt. Sie müssen es jedoch mit einer onSaveInstanceState(Bundle)
Implementierung onSaveInstanceState(Bundle)
.
Navigation zwischen Fragmenten mit Backstack und statischem Gewebemuster
Zuallererst müssen wir unser erstes Fragment
am Anfang hinzufügen, wir sollten es in der onCreate()
-Methode unserer Activity tun:
if (null == savedInstanceState) {
getSupportFragmentManager().beginTransaction()
.addToBackStack("fragmentA")
.replace(R.id.container, FragmentA.newInstance(), "fragmentA")
.commit();
}
Als Nächstes müssen wir unseren Backstack verwalten. Am einfachsten verwenden Sie eine in unserer Aktivität hinzugefügte Funktion, die für alle FragmentTransactions verwendet wird.
public void replaceFragment(Fragment fragment, String tag) {
//Get current fragment placed in container
Fragment currentFragment = getSupportFragmentManager().findFragmentById(R.id.container);
//Prevent adding same fragment on top
if (currentFragment.getClass() == fragment.getClass()) {
return;
}
//If fragment is already on stack, we can pop back stack to prevent stack infinite growth
if (getSupportFragmentManager().findFragmentByTag(tag) != null) {
getSupportFragmentManager().popBackStack(tag, FragmentManager.POP_BACK_STACK_INCLUSIVE);
}
//Otherwise, just replace fragment
getSupportFragmentManager()
.beginTransaction()
.addToBackStack(tag)
.replace(R.id.container, fragment, tag)
.commit();
}
Schließlich sollten wir onBackPressed()
überschreiben, um die Anwendung zu onBackPressed()
wenn Sie vom letzten im Backstack verfügbaren Fragment zurückkehren.
@Override
public void onBackPressed() {
int fragmentsInStack = getSupportFragmentManager().getBackStackEntryCount();
if (fragmentsInStack > 1) { // If we have more than one fragment, pop back stack
getSupportFragmentManager().popBackStack();
} else if (fragmentsInStack == 1) { // Finish activity, if only one fragment left, to prevent leaving empty screen
finish();
} else {
super.onBackPressed();
}
}
Ausführung in Tätigkeit:
replaceFragment(FragmentB.newInstance(), "fragmentB");
Ausführung außerhalb der Aktivität (unter der Annahme, dass MainActivity
unsere Aktivität ist):
((MainActivity) getActivity()).replaceFragment(FragmentB.newInstance(), "fragmentB");
Übergeben Sie Daten mithilfe von Bundle von Activity an Fragment
Alle Fragmente sollten einen leeren Konstruktor haben (dh eine Konstruktormethode ohne Eingabeargumente). Um Ihre Daten an das erstellte Fragment zu übergeben, sollten Sie daher die Methode setArguments()
verwenden. Diese Methode erhält ein Bündel, in dem Sie Ihre Daten speichern, und speichert das Bündel in den Argumenten. Anschließend kann dieses Bundle in onCreate()
und onCreateView()
Rückrufen des Fragments abgerufen werden.
Aktivität:
Bundle bundle = new Bundle();
String myMessage = "Stack Overflow is cool!";
bundle.putString("message", myMessage );
FragmentClass fragInfo = new FragmentClass();
fragInfo.setArguments(bundle);
transaction.replace(R.id.fragment_single, fragInfo);
transaction.commit();
Fragment:
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
String myValue = this.getArguments().getString("message");
...
}
Ereignisse zurück an eine Aktivität mit Callback-Schnittstelle senden
Wenn Sie Ereignisse vom Fragment an die Aktivität senden müssen, besteht eine der möglichen Lösungen darin, die Callback-Schnittstelle zu definieren und von der Hostaktivität zu implementieren.
Beispiel
Senden Sie einen Rückruf an eine Aktivität, wenn Sie auf die Schaltfläche des Fragments klicken
Definieren Sie zunächst die Callback-Schnittstelle:public interface SampleCallback {
void onButtonClicked();
}
Der nächste Schritt besteht darin, diesen Rückruf in Fragment zuzuweisen:
public final class SampleFragment extends Fragment {
private SampleCallback callback;
@Override
public void onAttach(Context context) {
super.onAttach(context);
if (context instanceof SampleCallback) {
callback = (SampleCallback) context;
} else {
throw new RuntimeException(context.toString()
+ " must implement SampleCallback");
}
}
@Override
public void onDetach() {
super.onDetach();
callback = null;
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
final View view = inflater.inflate(R.layout.sample, container, false);
// Add button's click listener
view.findViewById(R.id.actionButton).setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
callback.onButtonClicked(); // Invoke callback here
}
});
return view;
}
}
Und schließlich implementiere Rückruf in Aktivität:
public final class SampleActivity extends Activity implements SampleCallback {
// ... Skipped code with settings content view and presenting the fragment
@Override
public void onButtonClicked() {
// Invoked when fragment's button has been clicked
}
}
Animieren Sie den Übergang zwischen Fragmenten
Um den Übergang zwischen Fragmenten oder das Anzeigen oder Ausblenden eines Fragments zu animieren, verwenden Sie den FragmentManager
, um eine FragmentTransaction
zu erstellen.
Für eine einzelne FragmentTransaction
gibt es zwei verschiedene Arten, Animationen auszuführen: Sie können eine Standardanimation verwenden oder eigene benutzerdefinierte Animationen bereitstellen.
Standardanimationen werden durch Aufrufen von FragmentTransaction.setTransition(int transit)
und Verwenden einer der vordefinierten Konstanten in der FragmentTransaction
Klasse angegeben. Zum Zeitpunkt des Schreibens sind diese Konstanten:
FragmentTransaction.TRANSIT_NONE
FragmentTransaction.TRANSIT_FRAGMENT_OPEN
FragmentTransaction.TRANSIT_FRAGMENT_CLOSE
FragmentTransaction.TRANSIT_FRAGMENT_FADE
Die vollständige Transaktion könnte ungefähr so aussehen:
getSupportFragmentManager()
.beginTransaction()
.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE)
.replace(R.id.contents, new MyFragment(), "MyFragmentTag")
.commit();
Benutzerdefinierte Animationen werden durch Aufrufen von FragmentTransaction.setCustomAnimations(int enter, int exit)
oder FragmentTransaction.setCustomAnimations(int enter, int exit, int popEnter, int popExit)
.
Die enter
und exit
Animationen für abgespielt FragmentTransaction
s, die nicht mit Fragmenten aus den hinteren Stapeln knallen. Die popEnter
und popExit
Animationen werden abgespielt, wenn Sie ein Fragment aus dem Back-Stack ziehen.
Der folgende Code zeigt, wie Sie ein Fragment ersetzen, indem Sie ein Fragment herausschieben und das andere an seiner Stelle verschieben.
getSupportFragmentManager()
.beginTransaction()
.setCustomAnimations(R.anim.slide_in_left, R.anim.slide_out_right)
.replace(R.id.contents, new MyFragment(), "MyFragmentTag")
.commit();
Die XML-Animationsdefinitionen verwenden das objectAnimator
Tag. Ein Beispiel für slide_in_left.xml könnte ungefähr so aussehen:
<?xml version="1.0" encoding="utf-8"?>
<set>
<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
android:propertyName="x"
android:valueType="floatType"
android:valueFrom="-1280"
android:valueTo="0"
android:duration="500"/>
</set>
Kommunikation zwischen Fragmenten
Alle Kommunikationen zwischen Fragmenten müssen über eine Aktivität erfolgen. Fragmente können NICHT ohne Aktivität miteinander kommunizieren.
Zusätzliche Ressourcen
In diesem Beispiel haben wir eine MainActivity
, die zwei Fragmente, SenderFragment
und ReceiverFragment
, zum Senden und Empfangen einer message
(in diesem Fall ein einfacher String) hostet.
Ein Button in SenderFragment
initiiert das Senden der Nachricht. Eine TextView im ReceiverFragment
wird aktualisiert, wenn die Nachricht von ihr empfangen wird.
Es folgt ein Ausschnitt für die MainActivity mit Kommentaren zu den wichtigen Codezeilen:
// Our MainActivity implements the interface defined by the SenderFragment. This enables
// communication from the fragment to the activity
public class MainActivity extends AppCompatActivity implements SenderFragment.SendMessageListener {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
/**
* This method is called when we click on the button in the SenderFragment
* @param message The message sent by the SenderFragment
*/
@Override
public void onSendMessage(String message) {
// Find our ReceiverFragment using the SupportFragmentManager and the fragment's id
ReceiverFragment receiverFragment = (ReceiverFragment)
getSupportFragmentManager().findFragmentById(R.id.fragment_receiver);
// Make sure that such a fragment exists
if (receiverFragment != null) {
// Send this message to the ReceiverFragment by calling its public method
receiverFragment.showMessage(message);
}
}
}
Die Layoutdatei für MainActivity
zwei Fragmente in einem LinearLayout:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="com.naru.fragmentcommunication.MainActivity">
<fragment
android:id="@+id/fragment_sender"
android:name="com.naru.fragmentcommunication.SenderFragment"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
tools:layout="@layout/fragment_sender" />
<fragment
android:id="@+id/fragment_receiver"
android:name="com.naru.fragmentcommunication.ReceiverFragment"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
tools:layout="@layout/fragment_receiver" />
</LinearLayout>
Das SenderFragment
macht eine Schnittstelle SendMessageListener
, mit der die MainActivity
, wann auf die SenderFragment
im SenderFragment
geklickt wurde.
Das folgende Codefragment für SenderFragment
die wichtigsten Codezeilen:
public class SenderFragment extends Fragment {
private SendMessageListener commander;
/**
* This interface is created to communicate between the activity and the fragment. Any activity
* which implements this interface will be able to receive the message that is sent by this
* fragment.
*/
public interface SendMessageListener {
void onSendMessage(String message);
}
/**
* API LEVEL >= 23
* <p>
* This method is called when the fragment is attached to the activity. This method here will
* help us to initialize our reference variable, 'commander' , for our interface
* 'SendMessageListener'
*
* @param context
*/
@Override
public void onAttach(Context context) {
super.onAttach(context);
// Try to cast the context to our interface SendMessageListener i.e. check whether the
// activity implements the SendMessageListener. If not a ClassCastException is thrown.
try {
commander = (SendMessageListener) context;
} catch (ClassCastException e) {
throw new ClassCastException(context.toString()
+ "must implement the SendMessageListener interface");
}
}
/**
* API LEVEL < 23
* <p>
* This method is called when the fragment is attached to the activity. This method here will
* help us to initialize our reference variable, 'commander' , for our interface
* 'SendMessageListener'
*
* @param activity
*/
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
// Try to cast the context to our interface SendMessageListener i.e. check whether the
// activity implements the SendMessageListener. If not a ClassCastException is thrown.
try {
commander = (SendMessageListener) activity;
} catch (ClassCastException e) {
throw new ClassCastException(activity.toString()
+ "must implement the SendMessageListener interface");
}
}
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container,
@Nullable Bundle savedInstanceState) {
// Inflate view for the sender fragment.
View view = inflater.inflate(R.layout.fragment_receiver, container, false);
// Initialize button and a click listener on it
Button send = (Button) view.findViewById(R.id.bSend);
send.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// Sanity check whether we were able to properly initialize our interface reference
if (commander != null) {
// Call our interface method. This enables us to call the implemented method
// in the activity, from where we can send the message to the ReceiverFragment.
commander.onSendMessage("HELLO FROM SENDER FRAGMENT!");
}
}
});
return view;
}
}
Die Layoutdatei für das SenderFragment
:
<?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="match_parent"
android:gravity="center"
android:orientation="vertical">
<Button
android:id="@+id/bSend"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="SEND"
android:layout_gravity="center_horizontal" />
</LinearLayout>
ReceiverFragment
ist einfach und stellt eine einfache öffentliche Methode zum Aktualisieren seiner TextView bereit. Wenn die MainActivity
die Nachricht von dem erhält SenderFragment
es nennt diese öffentliche Methode des ReceiverFragment
Im Folgenden finden Sie das Code-Snippet für das ReceiverFragment
mit Kommentaren zu den wichtigen Codezeilen:
public class ReceiverFragment extends Fragment {
TextView tvMessage;
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container,
@Nullable Bundle savedInstanceState) {
// Inflate view for the sender fragment.
View view = inflater.inflate(R.layout.fragment_receiver, container, false);
// Initialize the TextView
tvMessage = (TextView) view.findViewById(R.id.tvReceivedMessage);
return view;
}
/**
* Method that is called by the MainActivity when it receives a message from the SenderFragment.
* This method helps update the text in the TextView to the message sent by the SenderFragment.
* @param message Message sent by the SenderFragment via the MainActivity.
*/
public void showMessage(String message) {
tvMessage.setText(message);
}
}
Die Layoutdatei für das ReceiverFragment
:
<?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="match_parent"
android:gravity="center"
android:orientation="vertical">
<TextView
android:id="@+id/tvReceivedMessage"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Waiting for message!" />
</LinearLayout>