An Android ActionBar + ListFragment example

The source code below corresponds to an article I wrote titled, Android ActionBar example: How to create an options menu item.

package com.valleyprogramming.justbe;

import android.app.ListFragment;
import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
import android.graphics.Color;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.CursorAdapter;
import android.widget.ListView;
import android.widget.TextView;
import com.valleyprogramming.justbe.QuotesDatabaseHelper.QuoteCursor;
import com.example.android.swipedismiss.SwipeDismissListViewTouchListener;

public class QuotesListFragment extends ListFragment {

    private static final String TAG = "VPQuotesListFragment";
    private QuoteCursor quoteCursor;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setHasOptionsMenu(true);
        getActivity().setTitle(R.string.title_quotes_screen);

        // config the database and adapter
        quoteCursor = DatabaseManager.get(getActivity()).queryQuotes();

        // create an adapter to point at this cursor
        QuoteCursorAdapter adapter = new QuoteCursorAdapter(getActivity(), quoteCursor);
        setListAdapter(adapter);
    }

    @Override
    public void onDestroy() {
        quoteCursor.close();

        //TODO working on possible memory leaks
        quoteCursor = null;
        setListAdapter(null);
        
        super.onDestroy();
    }

    @Override
    public void onActivityCreated(Bundle bundle) {
        super.onActivityCreated(bundle);
        // get a handle to our list view to implement 'swipe to delete'
        ListView listView = getListView();
        // Create a ListView-specific touch listener. ListViews are given special treatment because
        // by default they handle touches for their list items... i.e. they're in charge of drawing
        // the pressed state (the list selector), handling list item clicks, etc.
        SwipeDismissListViewTouchListener touchListener =
            new SwipeDismissListViewTouchListener(
                listView,
                new SwipeDismissListViewTouchListener.DismissCallbacks() {
                    @Override
                    public boolean canDismiss(int position) {
                        return true;
                    }
                    @Override
                    public void onDismiss(ListView listView, int[] reverseSortedPositions) {
                        for (int position : reverseSortedPositions) {
                            String quoteToDelete = ((QuoteCursor)(getListAdapter()).getItem(position)).getQuote().getQuote();
                            DatabaseManager.get(getActivity()).deleteQuote(quoteToDelete);

                            // need the next two lines to update the list after the delete
                            refreshQuoteCursorDataSet();

                            handleCasesWhereThisQuoteWasTheCurrentlyDisplayedQuote(quoteToDelete);
                        }
                    }
                });
        listView.setOnTouchListener(touchListener);
        // setting this scroll listener is required to ensure that during ListView scrolling,
        // we don't look for swipes.
        listView.setOnScrollListener(touchListener.makeScrollListener());

    }
    
    private void handleCasesWhereThisQuoteWasTheCurrentlyDisplayedQuote(String quoteThatWasDeleted) {
        if (GlobalState.currentlyDisplayedQuote.equals(quoteThatWasDeleted)) {
            if (GlobalState.pinnedStateEnabled) {
                // the quote that was deleted was the current quote and it was pinned
                PreferencesUtils.handleUserUnpinsQuoteAction(getActivity().getBaseContext());
                GlobalState.currentlyDisplayedQuote = "";
            } else {
                // the quote that was deleted was the current quote but it was not pinned
                GlobalState.currentlyDisplayedQuote = "";
            }
        }
    }

    /**
     * When a list item is clicked, perform the 'Edit' action.
     */
    @Override
    public void onListItemClick(ListView l, View v, int position, long id) {
        String quote = ((QuoteCursor)(getListAdapter()).getItem(position)).getQuote().getQuote();
        Log.d(TAG, quote + " was clicked");

        // i'm doing this in the long form just for my own knowledge
        Context context = getActivity();
        Class destination = EditQuoteActivity.class;
        Intent intent = new Intent(context, destination);
        intent.putExtra(EditQuoteFragment.KEY_QUOTE_EXTRA, quote);
        startActivityForResult(intent, 0);
    }

    /**
     * update the list of quotes when the user returns, presumably after
     * using the 'edit' screen. p. 197.
     * 
     * the book's code example actually uses onActivityResult instead of
     * onResume. i just tested it, and they both get called, so either one
     * will work.
     */
    @Override
    public void onResume() {
        super.onResume();
        refreshQuoteCursorDataSet();
    }

    /**
     * as the code shows, the cursor needs to be refreshed before
     * notifyDataSetChanged is called
     */
    private void refreshQuoteCursorDataSet() {
        quoteCursor.requery();
        ((QuoteCursorAdapter)getListAdapter()).notifyDataSetChanged();
    }

    /**
     * the menu layout has the 'add/new' menu item
     */
    @Override
    public void onCreateOptionsMenu(Menu menu, MenuInflater menuInflater) {
        menuInflater.inflate(R.menu.menu_quotes_list, menu);
        super.onCreateOptionsMenu(menu, menuInflater);
    }

    /**
     * react to the user tapping/selecting an options menu item
     */
    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
            case R.id.menu_item_new_quote:
                Intent addQuoteIntent = new Intent(getActivity(), NewQuoteActivity.class);
                startActivityForResult(addQuoteIntent, 0);
                return true;
            default:
                return super.onOptionsItemSelected(item);
        }
    }

    /**
     * The adapter class that will work with the ListView.
     */
    private static class QuoteCursorAdapter extends CursorAdapter {

        private QuoteCursor mRunCursor;

        public QuoteCursorAdapter(Context context, QuoteCursor cursor) {
            super(context, cursor, 0);
            mRunCursor = cursor;
        }

        @Override
        public View newView(Context context, Cursor cursor, ViewGroup parent) {
            LayoutInflater inflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            return inflater.inflate(R.layout.quote_item_view, parent, false);
        }

        @Override
        public void bindView(View view, Context context, Cursor cursor) {
            // get the quote for the current row
            Quote quote = mRunCursor.getQuote();

            // this works with my custom view (quote_item_view.xml)
            TextView textView = (TextView)view.findViewById(R.id.the_quote);
            textView.setText(quote.getQuote());

            // set the text size
            textView.setTextAppearance(context, R.style.listViewText);

            // confirmed: this works. can also specify alpha as '00-ff' before the rgb
            // component, but that won't do anything in this case
            textView.setBackgroundColor(Color.parseColor("#ffffff"));
        }

    }

}

The reason I show the code here is because it shows how to enable the Android ActionBar, in this case from a Fragment, and more specifically a ListFragment.

Share it!

There’s just one person behind this website; if this article was helpful (or interesting), I’d appreciate it if you’d share it. Thanks, Al.

Add new comment

The content of this field is kept private and will not be shown publicly.

Anonymous format

  • Allowed HTML tags: <em> <strong> <cite> <code> <ul type> <ol start type> <li> <pre>
  • Lines and paragraphs break automatically.
By submitting this form, you accept the Mollom privacy policy.