loadercallbacks android android-fragments android-viewpager android-loadermanager android-loader

android - loadercallbacks



Android TabsAdapter con ActionbarSherlock (3)

Si todavía está utilizando el LoaderManager la LoaderManager para administrar los cargadores de su Fragment ... no lo haga. El LoaderManager la LoaderManager gestiona los cargadores a lo largo del ciclo de vida * de su Activity ... no de su Fragment . Es probable que su Fragment intente acceder a un Loader que todavía no ha iniciado la Activity .

Estoy utilizando ActionbarSherlock con un SherlockListFragment que implementa LoaderManager.LoaderCallbacks .

En mi método ApplicationActivity onCreate que estoy usando

setContentView(R.layout.application);

para establecer el diseño - funciona muy bien.

Estoy inicializando la barra de acciones como tal

ActionBar bar = getSupportActionBar(); bar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS); bar.setDisplayOptions(0, ActionBar.DISPLAY_SHOW_TITLE); bar.setDisplayHomeAsUpEnabled(false); bar.setDisplayShowTitleEnabled(true); // users event list bar.addTab(bar.newTab() .setTag("event_list") .setText(getString(R.string.list_events_header)) .setTabListener(new TabListener<EventListFragment>( this, getString(R.string.list_events_header), EventListFragment.class, null)));

Dentro de ApplicationActivity, tengo una AsyncTask que tarda unos segundos en cargarse en la apertura inicial, y cuando se actualiza manualmente en la API, lo que significa que necesito asegurarme de actualizar ListView en el fragmento instanciado arriba, lo cual hago en el método onPostExecute, aquí es cómo lo hago:

// update the events fragment EventListFragment fragment = (EventListFragment) getSupportFragmentManager().findFragmentById(R.string.list_events_header); if(fragment != null) { // restart the loader for this fragment, refreshing the listview getSupportLoaderManager().restartLoader(0, null, fragment); }

ESTO TODO FUNCIONA

Ahora, quería poner un TabsAdapter para obtener las elegantes pestañas, lo que hice, y funciona, pero la última parte que mencioné sobre el onPostExecute, no funciona :(

Este es mi TabsAdapter:

package com.lateral.app.ui; import java.util.ArrayList; import android.content.Context; import android.os.Bundle; import android.support.v4.app.Fragment; import android.support.v4.app.FragmentPagerAdapter; import android.support.v4.app.FragmentTransaction; import android.support.v4.view.ViewPager; import com.actionbarsherlock.app.ActionBar; import com.actionbarsherlock.app.ActionBar.Tab; public class APPTabsAdapter extends FragmentPagerAdapter implements ActionBar.TabListener, ViewPager.OnPageChangeListener { private final Context mContext; private final ActionBar mActionBar; private final ViewPager mViewPager; private final ArrayList<TabInfo> mTabs = new ArrayList<TabInfo>(); static final class TabInfo { private final Class<?> clss; private final Bundle args; TabInfo(Class<?> _class, Bundle _args) { clss = _class; args = _args; } } public APPTabsAdapter(ApplicationActivity activity, ViewPager pager) { super(activity.getSupportFragmentManager()); mContext = activity; mActionBar = activity.getSupportActionBar(); mViewPager = pager; mViewPager.setAdapter(this); mViewPager.setOnPageChangeListener(this); } public APPTabsAdapter(EventActivity activity, ViewPager pager) { super(activity.getSupportFragmentManager()); mContext = activity; mActionBar = activity.getSupportActionBar(); mViewPager = pager; mViewPager.setAdapter(this); mViewPager.setOnPageChangeListener(this); } public void addTab(ActionBar.Tab tab, Class<?> clss, Bundle args) { TabInfo info = new TabInfo(clss, args); tab.setTag(info); tab.setTabListener(this); mTabs.add(info); mActionBar.addTab(tab); notifyDataSetChanged(); } @Override public int getCount() { return mTabs.size(); } @Override public Fragment getItem(int position) { TabInfo info = mTabs.get(position); return Fragment.instantiate(mContext, info.clss.getName(), info.args); } public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { } public void onPageSelected(int position) { mActionBar.setSelectedNavigationItem(position); } public void onPageScrollStateChanged(int state) { } public void onTabSelected(Tab tab, FragmentTransaction ft) { Object tag = tab.getTag(); for (int i = 0; i < mTabs.size(); i++) { if (mTabs.get(i) == tag) { mViewPager.setCurrentItem(i); } } } public void onTabUnselected(Tab tab, FragmentTransaction ft) { } public void onTabReselected(Tab tab, FragmentTransaction ft) { } }

Este es mi método onCreate actualizado de ApplicationActivity

mViewPager = new ViewPager(this); mViewPager.setId(R.id.pager); setContentView(mViewPager); ActionBar bar = getSupportActionBar(); bar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS); bar.setDisplayOptions(0, ActionBar.DISPLAY_SHOW_TITLE); bar.setDisplayHomeAsUpEnabled(false); bar.setDisplayShowTitleEnabled(true); mTabsAdapter = new APPTabsAdapter(this, mViewPager); // users event list mTabsAdapter.addTab(bar.newTab() .setTag("event_list") .setText(getString(R.string.list_events_header)) .setTabListener(new TabListener<EventListFragment>( this, getString(R.string.list_events_header), EventListFragment.class, null)), EventListFragment.class, null);

Y esta es la actualización que realicé en mi método onPostExecute en ApplicationActivity

// update the events fragment EventListFragment fragment = (EventListFragment) mTabsAdapter.getItem(0); if(fragment != null) { // restart the loader for this fragment, refreshing the listview getSupportLoaderManager().restartLoader(0, null, fragment); }

Básicamente, cuando intenta ejecutar mi código onPostExecute

Obtengo una NullPointerException de mi cursorAdapter dentro del fragmento ... pero encontró el fragmento ...

EDITAR - Código solicitado

public Loader<Cursor> onCreateLoader(int loaderId, Bundle args) { Log.d(TAG, "onCreateLoader"); return new EventCursorLoader(getActivity()); } public static final class EventCursorLoader extends SimpleCursorLoader { Context mContext; public EventCursorLoader(Context context) { super(context); Log.d("EventCursorLoader", "Constructor"); mContext = context; } @Override public Cursor loadInBackground() { Log.d("EventCursorLoader", "loadInBackground"); EventsDataSource datasource = new EventsDataSource(mContext, ((ApplicationActivity)mContext).getDbHelper()); SharedPreferences app_preferences = PreferenceManager.getDefaultSharedPreferences(mContext); long userId = app_preferences.getLong("authenticated_user_id", 0); return datasource.getAllEvents(userId); } }


Tuve el mismo problema hace un par de días, durante un hackaton :-)

Resulta que getItem () no devuelve el fragmento que ha creado, sino que crea una instancia nueva. Básicamente ese es el método que se llama para crear inicialmente los fragmentos. Es por eso que encuentras que su miembro está vacío.

Tenía un poco de prisa, pero creo que con esa solución no hay forma de acceder a los fragmentos de la actividad.

Sin embargo, la solución que funcionó para mí fue establecer una referencia a los fragmentos en la actividad cuando se crearon.

Algo como

@Override public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); ((ApplicationActivity)getActivity()).setEventListFragment(this); }

dentro de tu fragmento y

EventListFragment getEventListFragment(){ return mEventListFragment; } public void setEventListFragment(EventListFragment m){ mEventListFragment = m; }

dentro de tu actividad.

Luego debe usar getEventListFragment () en lugar de usar el método getItem () del adaptador.

Si quieres ver todo el código que escribí (y especialmente la parte que necesitas), puedes consultarlo aquí

https://github.com/moodeque/moodeque-android/tree/master/src/main/java/com/whiterabbit/hackitaly/Activities

La actividad del contenedor es InVenueActivity , mientras que los dos fragmentos son los que figuran en las pestañas.


Intentar recuperar el cargador aquí es simplemente la idea equivocada, ya que el propósito es actualizar los datos. Después de investigar, descubrí que puedo notificar más de 1 juego de carga de contenido en mi proveedor usando

getContext().getContentResolver().notifyChange(uri, null);

que notifica cambios y actualizaciones, todo este código se puede eliminar y reemplazar con una sola línea.