Viktor Apoyan
Viktor Apoyan

Reputation: 10755

Good practice to use Fragments and ViewPager

Problem Description

I am writing application which use fragments and ViewPager below you can see my FragmentPagerAdapter. I just want to know is it right way to write FragmentPagerAdapter? because in some cases when I call getActivity() in fragment it return null.

public class FragmentAdapter extends FragmentPagerAdapter {

/* Fragments */
private Fragments[] mFragments;

/**
 * Constructor.
 * @param fm
 */
public FragmentAdapter(FragmentManager fm) {
    super(fm);

    /* Initialize Fragments. */
    mFragments = Fragments.values();
}

public enum Fragments {

    Favorites(App.getStringByResId(R.string.favorites), new FragmentFavorites()),
    Categories(App.getStringByResId(R.string.categories), new FragmentCategories()),
    YellowPages(App.getStringByResId(R.string.yellow_pages), new FragmentYellowPages());


    /**
     * Constructor.
     * @param title Fragment title.
     * @param fragment Fragment object.
     */
    Fragments(String title, BaseListFragment fragment) {
        this.mTitle = title;
        this.mFragment = fragment;
    }

    /* Fragment Title Text. */
    private String mTitle;
    /* Fragment */
    private BaseListFragment mFragment;

    /**
     * Get Fragment Title.
     * @return Title.
     */
    public String getTitle() {
        return mTitle;
    }

    /**
     * Get Fragment 
     * @return Fragment.
     */
    public BaseListFragment getFragment() {
        return mFragment;
    }
};

@Override
public CharSequence getPageTitle(int position) {
    return mFragments[position].getTitle();
}

@Override
public Fragment getItem(int position) {
    return mFragments[position].getFragment();
}

@Override
public int getCount() {
    return mFragments.length;
};

};

Edited

from main activity I call this code. is it correct ? In most cases in this case getActivity() return null.

/* Call Search function for the given fragment. */
Fragments.values()[tabControl.getCurrentItem()].getFragment().search(tv.getText().toString());

Fragment

public class FragmentFavorites extends BaseListFragment {

    final static String TAG = FragmentFavorites.class.getSimpleName();

    /* Controllers. */
    ListView lvFavorites;
    TextView tvInfo;

    /* Simple Cursor Adapter. */
    SimpleCursorAdapter scAdapter;

    /* This member keep current database language, every time then onResume method called
     * application must check if database language was changed, if language changed application 
     * must update list view by creating new adapter. */
    String language;

    /* This flag shows that new favorite was added and list need to be updated. */
    boolean newFavoriteAdded = false;

    boolean canUpdateOnSearch = false;

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {

        View favoritesPagesView = inflater.inflate(R.layout.fragment_favorites, container, false);

        Log.i(TAG, "onCreateView( )");

        /* Initialize Controllers. */
        tvInfo = (TextView) favoritesPagesView.findViewById(R.id.tvNoFavoritesText);
        lvFavorites = (ListView) favoritesPagesView.findViewById(android.R.id.list);

        return favoritesPagesView;

    } /* onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) */


    @Override
    public void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        Log.i(TAG, "onCreate( )");

        /* Tell the framework to try to keep this fragment around
           during a configuration change. */
        setRetainInstance(true);

        /* Get context, if context is null set default language "English". */
        final Context context = getActivity();
        if (context != null) {

            Log.wtf(TAG, "onCreate(Context is null, set default language \"en\".)");

            /* Set language when fragment first created, default language is "English". */
            SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context);
            language = preferences.getString(Preferences.LANGUAGE, Preferences.EN);
        }
        else language = Preferences.EN;

    } /* onCreate(Bundle savedInstanceState) */


    @Override
    public void onActivityCreated(Bundle savedInstanceState) {

        super.onActivityCreated(savedInstanceState);

        Log.i(TAG, "onActivityCreated( )");

        ListView listView = getListView();
        /* Set on item click listener */ 
        listView.setOnItemClickListener(new OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> adapterView, View v, int position, long id) {
                Cursor cursor = (Cursor)adapterView.getAdapter().getItem(position);
                final String _id = cursor.getString(cursor.getColumnIndex("_id"));
                Log.i(TAG, "onItemClick(_id = " + _id + ")");

                /* Get current selected language. */
                final SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(getActivity());
                final String lang = preferences.getString(Preferences.LANGUAGE, "en");

                ActionDialog dialog = new ActionDialog(getActivity());

                dialog.setFavoriteRemovedListener(new OnActionDialogListeners() {

                    @Override
                    public void onFavoriteRemoved() {
                        /* Get Saved favorites from the preferences, if there are no favorites return form onResume. */
                        final String favorites = preferences.getString(Preferences.FAVORITE, null);

                        /* Update favorites adapter with new favorite contacts. */
                        updateAdapterIfNeeded(lang, favorites, true);
                    }

                    @Override
                    public void onFavoriteAdded() { /* Not used... */ }

                });

                dialog.setID(_id);
                dialog.setDeleteFavorite(true);
                dialog.setTitle(cursor.getString(cursor.getColumnIndex(String.format("name_%s", language))));
                dialog.setPhone(cursor.getString(cursor.getColumnIndex("telephones")));
                dialog.show();
            }
        });

    } /* onActivityCreated(Bundle savedInstanceState) */


    @Override
    public void onResume() {

        super.onResume();

        Log.i(TAG, "onResume( )");

        /* Check if database current language was changed. */
        SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(getActivity());
        final String currentLanguage = preferences.getString(Preferences.LANGUAGE, Preferences.EN);

        /* Get Saved favorites from the preferences, if there are no favorites return form onResume. */
        final String favorites = preferences.getString(Preferences.FAVORITE, null);
        if (favorites == null || favorites.length() == 0) {
            /* Hide List View and show Text View. */
            Log.i(TAG, "There are no saved favorites in the preferences.");
            lvFavorites.setVisibility(View.GONE);
            tvInfo.setVisibility(View.VISIBLE);
            tvInfo.setText(getActivity().getString(R.string.no_selected_favorites));
            return;
        }


        if (!currentLanguage.equalsIgnoreCase(language)) {

            Log.i(TAG, "onResume(Database language was changed.)");

            /* Update language with changed one. */
            language = currentLanguage;

            /* Update Adapter, do not pay attention if it is already created or no. */
            updateAdapterIfNeeded(currentLanguage, favorites, true);
        } 
        else if (newFavoriteAdded) {

            Log.i(TAG, "onResume(New favorite was added to the list, update needed");

            /* Update adapter as new favorite was added. */
            updateAdapterIfNeeded(currentLanguage, favorites, true);

            newFavoriteAdded = false;
        }
        else {
            /* Update Adapter only in the case if no adapter is created (This will create new adapter) */
            updateAdapterIfNeeded(currentLanguage, favorites, false);
        }

    } /* void onResume() */


    /**
     * This function update Simple Cursor Adapter in the case if it is needed or
     * cursor adapter is not created yet.
     * 
     * @param currentLanguage Current language of database.
     * @param forceUpdate if true adapter will be updated in any case; otherwise it will
     *        not be updated.
     */
    void updateAdapterIfNeeded(final String lang, final String favs, final boolean forceUpdate) {

        Log.i(TAG, String.format("updateAdapterIfNeeded(%s, %b)", lang, forceUpdate));

        /* Show "Favorites" list view and hide Info text view. */
        lvFavorites.setVisibility(View.VISIBLE);
        tvInfo.setVisibility(View.GONE);

        if (forceUpdate || scAdapter == null) {

            /* Preparing Adapter Settings. */
            final int[] to = new int[]{ R.id.tvContactTitle, R.id.tvContactTelephone };
            final String[] from = new String[] { String.format("name_%s", lang), "telephones" };

            /* Get Contacts from the SQLite Database. */
            final Cursor cursor = DataBaseManager.instance().getAllFavorites(favs, lang);

            Log.i(TAG, "updateAdapterIfNeeded(Creating new Adapter ...)");
            /* Create New Simple Cursor Adapter, even if it is already exists. */
            scAdapter = new  FragmentCursorAdapter(getActivity(), R.layout.contact_row, cursor, from, to, 0);
            Log.i(TAG, "updateAdapterIfNeeded(Adapter was successfully created ...)");

            /* Set Adapter to the list. */
            this.setListAdapter(scAdapter);
        }

    } /* updateAdapterIfNeeded(final String currentLanguage, boolean forceUpdate) */


    void updateAdapterOnSearch(final String tts, final String lang, final String favs) {

        Log.i(TAG, String.format("updateAdapterOnSearch(%s, %s)", tts, lang));

        /* Show "Favorites" list view and hide Info text view. */
        lvFavorites.setVisibility(View.VISIBLE);
        tvInfo.setVisibility(View.GONE);

        /* Preparing Adapter Settings. */
        final int[] to = new int[]{ R.id.tvContactTitle, R.id.tvContactTelephone };
        final String[] from = new String[] { String.format("name_%s", lang), "telephones" };

        /* Get Contacts from the SQLite Database. */
        final Cursor cursor = DataBaseManager.instance().getSearchedFavorites(favs, lang, tts);
        if (cursor.getCount() == 0) {
            lvFavorites.setVisibility(View.GONE);
            tvInfo.setVisibility(View.VISIBLE);
            tvInfo.setText(String.format(getActivity().getString(R.string.no_companies_were_found), tts));
        }

        Log.i(TAG, "updateAdapterOnSearch(Creating new Adapter ...)");
        /* Create New Simple Cursor Adapter, even if it is already exists. */
        scAdapter = new  FragmentCursorAdapter(getActivity(), R.layout.contact_row, cursor, from, to, 0);
        Log.i(TAG, "updateAdapterOnSearch(Adapter was successfully created ...)");

        /* Set Adapter to the list. */
        this.setListAdapter(scAdapter);

    } /* updateAdapterOnSearch(final String tts, final String lang) */


    @Override
    public void search(final String tts) {

            final Context context = getActivity();

        Log.i(TAG, String.format("search(%s)", tts));

        /* Get application context. */
        if (context == null) {
            Log.wtf(TAG, "search(Search can't be completed as context is null)");
            return;
        }

        /* Get Database current language. */
        SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context);
        if (preferences == null) {
            Log.w(TAG, "search(Search can't be completed as preferences object is null)");
            return;
        }


        /* Get language from the preferences */
        final String lang = preferences.getString(Preferences.LANGUAGE, Preferences.EN);

        /* Get Saved favorites from the preferences, if there are no favorites return form onResume. */
        final String favorites = preferences.getString(Preferences.FAVORITE, null);

        /* If user search for the text. */
        if (tts != null && tts.length() != 0) {
            updateAdapterOnSearch(tts, lang, favorites);

            canUpdateOnSearch = true; 
        }

        if ((tts == null || tts.length() == 0) && canUpdateOnSearch) {
            /* In this case all contacts will be shown in the list view. */
             updateAdapterIfNeeded(lang, favorites, true);

            canUpdateOnSearch = false;
        }

    } /* search(final String tts) */


    public void newFavoriteAdded(final boolean value) {

        Log.i(TAG, String.format("newFavoriteAdded(%b)", value));

        newFavoriteAdded = value;
    }



};

Upvotes: 1

Views: 1888

Answers (1)

Dmytro Danylyk
Dmytro Danylyk

Reputation: 19788

You should call getActivity() only inside or after Fragment.onActivityCreated() is called, in this way activity will never be null, as in example.

Also here is another case of where null activity may occurs, when you start thread inside fragment, and call getActivity() while user already closed fragment.

new Thread() {
    @Override
    public void run() {
        // long operations goes here
        // user decided to close fragment
        Activity activity = getActivity();
        // here 'activity' is null because fragment is destroyed
        }
}.start();  

Upvotes: 4

Related Questions