Kurzversion:onResume() nicht aufgerufen ViewPager Fragment, wenn benutzerdefinierte Loader
ich ein Fragment haben, die für die Anzeige von zwei anderen Fragmenten eine ViewPager
hält, nennen wir sie FragmentOne
und FragmentTwo
. Beim Start der App ist FragmentOne
sichtbar und FragmentTwo
ist off-screen, wird nur sichtbar, wenn man die Ansicht nach links wischt.
Normalerweise werden onStart()
und onResume()
sofort für beide Fragmente aufgerufen, sobald die App gestartet wird.
Das Problem, das ich habe, ist, wenn FragmentOne
eine benutzerdefinierte beginnt Loader
dann ist onResume()
nicht auf FragmentTwo
aufgerufen, bis es vollständig sichtbar wird.
Fragen:
Ist das ein Problem mit meinem Code oder einen Fehler in der Bibliothek Android-Support? (Das Problem trat bei Revision 12 der Bibliothek nicht auf. Es begann mit Revision 13.)
Wenn es sich um einen Fehler in den Revisionen 13 und 18 handelt, gibt es einen Workaround?
Ist etwas falsch mit meiner benutzerdefinierten Loader
?
Lange Version:
ich eine Beispielanwendung erstellt haben, die das Problem veranschaulicht. Ich habe versucht, den Code auf das Nötigste zu reduzieren, aber es ist immer noch sehr viel, bitte ertragen Sie mit mir.
Ich habe eine MainActivity
, die eine MainFragment
lädt, die eine ViewPager
erstellt. Für meine App ist es wichtig, dass der ViewPager von einem Fragment statt einer Aktivität verwaltet wird.
MainFragment
schafft eine FragmentPagerAdapter
dass die Fragmente wiederum FragmentOne
und FragmentTwo
schafft.
die mit dem interessanten Bit Lassen Sie beginnen, die beiden Fragmente:
FragmentOne
ist ein ListFragment
, die eine benutzerdefinierte verwendet Loader
den Inhalt zu laden:
public class FragmentOne extends ListFragment implements LoaderCallbacks<List<String>> {
private ArrayAdapter<String> adapter;
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
adapter = new ArrayAdapter<String>(getActivity(), android.R.layout.simple_list_item_1);
setListAdapter(adapter);
setEmptyText("Empty");
}
@Override
public void onResume() {
super.onResume();
// initializing the loader seems to cause the problem!
getLoaderManager().initLoader(0, null, this);
}
@Override
public Loader<List<String>> onCreateLoader(int id, Bundle args) {
return new MyLoader(getActivity());
}
@Override
public void onLoadFinished(Loader<List<String>> loader, List<String> data) {
adapter.clear();
adapter.addAll(data);
}
@Override
public void onLoaderReset(Loader<List<String>> loader) {
adapter.clear();
}
public static class MyLoader extends AsyncTaskLoader<List<String>> {
public MyLoader(Context context) {
super(context);
}
@Override
protected void onStartLoading() {
forceLoad();
}
@Override
public List<String> loadInBackground() {
return Arrays.asList("- - - - - - - - - - - - - - - - - - - foo",
"- - - - - - - - - - - - - - - - - - - bar",
"- - - - - - - - - - - - - - - - - - - baz");
}
}
}
Es ist das Loader
, die das Problem zu verursachen scheint . Wenn Sie die Zeile initLoader auskommentieren, funktioniert der Fragmentlebenszyklus wie erwartet.
FragmentTwo
ändert seinen Inhalt basierend darauf, ob onResume()
angerufen worden ist oder nicht:
public class FragmentTwo extends Fragment {
private TextView text;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
text = new TextView(container.getContext());
text.setText("onCreateView() called");
return text;
}
@Override
public void onResume() {
super.onResume();
Log.i("Fragment2", "onResume() called");
text.setText("onResume() called");
}
}
Und hier ist der langweilige Rest des Codes.
MainActivity
:
public class MainActivity extends FragmentActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Fragment fragment = new MainFragment();
getSupportFragmentManager().beginTransaction().add(R.id.container, fragment).commit();
}
}
Layout-activity_main
:
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent" />
MainFragment
:
public class MainFragment extends Fragment {
private ViewPager viewPager;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View layout = inflater.inflate(R.layout.frag_master, container, false);
viewPager = (ViewPager) layout.findViewById(R.id.view_pager);
return layout;
}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
viewPager.setAdapter(new MyPagerAdapter(getChildFragmentManager()));
}
private static final class MyPagerAdapter extends FragmentPagerAdapter {
public MyPagerAdapter(FragmentManager fragmentManager) {
super(fragmentManager);
}
@Override
public int getCount() {
return 2;
}
@Override
public Fragment getItem(int position) {
if (position == 0)
return new FragmentOne();
else
return new FragmentTwo();
}
}
}
Layout-frag_master
:
<android.support.v4.view.ViewPager xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/view_pager"
android:layout_width="match_parent"
android:layout_height="match_parent" />
Ich habe genau das gleiche Problem wie du bist, du Lösung funktioniert, aber mit Leistung - Verzögerung Preis. Wie haben Sie eine Lösung gefunden? –
warum postest du es in den Handler? – Xenione
@Xenione Dies ist nur ein Workaround, aber es ist sicher zu verwenden. Hier sind meine Gedanken. Wir sehen, dass das Aufrufen von initLoader() im ersten Fragment verhindert, dass onResume() auf anderen Fragmenten aufgerufen wird (höchstwahrscheinlich aufgrund eines Fehlers in der Bibliothek). Wenn es keinen solchen Aufruf gibt, werden alle onResume() -Methoden in einem einzigen Ausführungsrahmen aufgerufen. Wenn wir möchten, dass das Framework onResume() -Methoden in allen Fragmenten aufruft, müssen wir logischerweise vermeiden, initLoader() aufzurufen. Um loader unmittelbar nach onResume() zu initialisieren, müssen wir es logischerweise im nächsten Ausführungsrahmen tun. Hier hilft handler.post() sehr. –