Android Open Source - GuildViewerApp2 News List Fragment






From Project

Back to project page GuildViewerApp2.

License

The source code is released under:

Apache License

If you think the Android project GuildViewerApp2 listed in this page is inappropriate, such as containing malicious code/tools or violating the copyright, please email info at java2s dot com, thanks.

Java Source Code

package com.skywomantechnology.app.guildviewer;
/*  www  .  j  a va 2s . c om*/
/*
 * Guild Viewer is an Android app that allows users to view news feeds and news feed details
 * on a mobile device and while not logged into the game servers.
 *
 * Copyright 2014 Sky Woman Technology LLC
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *        http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */

import android.app.Activity;
import android.app.ListFragment;
import android.app.LoaderManager;
import android.content.CursorLoader;
import android.content.Loader;
import android.database.Cursor;
import android.os.Bundle;
//import android.util.Log;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.widget.ListView;

import com.skywomantechnology.app.guildviewer.data.GuildViewerContract.NewsEntry;
import com.skywomantechnology.app.guildviewer.sync.GuildViewerSyncAdapter;

/**
 * A list fragment representing a list of News. This fragment also supports tablet devices by
 * allowing list items to be given an 'activated' state upon selection. This helps indicate which
 * item is currently being viewed in a {@link NewsDetailFragment}.
 * <p/>
 * Activities containing this fragment MUST implement the {@link Callbacks} interface.
 */
public class NewsListFragment extends ListFragment
        implements LoaderManager.LoaderCallbacks<Cursor> {

    // logging identifier is the class name
    //public final String LOG_TAG = NewsListFragment.class.getSimpleName();

    private NewsAdapter mNewsAdapter;

    // key for storing the currently selected news item to be used in detail fragment
    public static final String NEWS_ID_KEY = "news_id";

    // key for storing the currently selected position in the list to retain list state
    private static final String STATE_ACTIVATED_POSITION = "activated_position";

    // actual list item selected in the list
    private int mActivatedPosition = ListView.INVALID_POSITION;

    // cursor loader identifier
    private static final int NEWS_LIST_LOADER = 0;



    // For the news list view we're showing only a small subset of the stored data.
    // Specify the columns we need.
    private static final String[] NEWS_LIST_COLUMNS = {
            NewsEntry.TABLE_NAME + "." + NewsEntry._ID,
            NewsEntry.COLUMN_TYPE,
            NewsEntry.COLUMN_TIMESTAMP,
            NewsEntry.COLUMN_CHARACTER,
            NewsEntry.COLUMN_ITEM_NAME,
            NewsEntry.COLUMN_ACHIEVEMENT_TITLE
    };

    // These indices are tied to NEWS_LIST_COLUMNS.
    public static final int COL_NEWS_ID = 0;
    public static final int COL_TYPE = 1;
    public static final int COL_TIMESTAMP = 2;
    public static final int COL_CHARACTER = 3;
    public static final int COL_ITEM_NAME = 4;
    public static final int COL_ACHIEVEMENT_TITLE = 5;

    private Callbacks mCallbacks = sNewsListCallbacks; // dummy callbacks

    /**
     * Callback for any activity using this fragment to implement so that the when a list item is
     * selected it is correctly processed on UI
     */
    public interface Callbacks {
        public void onNewsListItemSelected(long id);
        public void onNoDataForGuild();
        public void onDataRefresh();
    }

    /**
     * dummy callback
     */
    private static Callbacks sNewsListCallbacks = new Callbacks() {
        @Override
        public void onNewsListItemSelected(long id) {
        }
        public void onNoDataForGuild() {
        }
        public void onDataRefresh() {
        }
    };

    /**
     * constructor
     */
    public NewsListFragment() {
    }

    /**
     * When this fragment is created lets it know that there is an options menu
     * create the news list adapter
     *
     * @param savedInstanceState
     *         Bundle with saved information to be used on creating a new fragment
     */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setHasOptionsMenu(true);

        //create & set cursor adapter for the news list items
        mNewsAdapter = new NewsAdapter(getActivity(), null, 0);
        setListAdapter(mNewsAdapter);
    }

    /**
     * Setup the options menu for this fragment
     *
     * @param menu Options Menu to be inflated
     * @param inflater Inflater to generate menu from xml
     */
    @Override
    public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
        inflater.inflate(R.menu.newslistfragment, menu);
    }

    /**
     * Process the options item selection Refresh - sends out a refresh message and syncs the data
     *
     * @param item MenuItem selected
     * @return true if processed OK
     */
    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
            // if you get tired of waiting for a refresh
            // or just need to refresh for testing purposes
            case R.id.action_refresh:
                // sync immediately
                ((Callbacks) getActivity()).onDataRefresh();
                GuildViewerSyncAdapter.syncImmediately(getActivity());
                return true;
            default:
                return super.onOptionsItemSelected(item);
        }
    }

    /**
     * Starts the set up for the cursor loader
     *
     * @param savedInstanceState Bundle with saved information to be used on creating a new fragment
     */
    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        getLoaderManager().initLoader(NEWS_LIST_LOADER, null, this);
        super.onActivityCreated(savedInstanceState);
        setEmptyText(getString(R.string.type_loading_data));
    }

    /**
     * Creates a cursor loader to obtain data from the content provider This cursor loader will get
     * ALL of the news list items from the content provider in descending order.  Since it only
     * stores data for one guild at a time right now it doesn't matter but in the future this could
     * be modified to get only the data for the prefered guild, realm and region.
     *
     * @param id  loader identifier
     * @param args  Bundle of data
     * @return Cursor Loader
     */
    @Override
    public Loader<Cursor> onCreateLoader(int id, Bundle args) {
        String sortOrder = NewsEntry.COLUMN_TIMESTAMP + " DESC";
        return new CursorLoader(
                getActivity(),
                NewsEntry.buildNewsListUri(),
                NEWS_LIST_COLUMNS,
                null,
                null,
                sortOrder
        );
    }

    /**
     * We loaded all the data from the content provider.
     *
     * @param loader  cursor loader
     * @param data    data loaded
     */
    @Override
    public void onLoadFinished(Loader<Cursor> loader, Cursor data) {

        // if it didn't find any guild news let the activity know so they can warn the user
        setEmptyText(getString(R.string.type_loading_data));
        if (data.getCount() == 0) {
            setActivatedPosition(ListView.INVALID_POSITION);
            setEmptyText(getString(R.string.type_no_data));
            ((Callbacks) getActivity()).onNoDataForGuild();
        }

        // some guilds will have zero data so only try to sync if the notification timestamp
        // is defaulted to zero otherwise we can get in a big loop here until data shows up
        if (data.getCount() == 0 &&
                Utility.getPreferenceForLastNotificationDate(getActivity()) == 0L) {
            GuildViewerSyncAdapter.syncImmediately(getActivity());
        }

        // put the newly loaded data into the adapter
        mNewsAdapter.swapCursor(data);
        // scroll to the current position in the list
        if (mActivatedPosition != ListView.INVALID_POSITION) {
            getListView().smoothScrollToPosition(mActivatedPosition);
        }
    }

    /**
     * Clear out the data cursor if the loader is reset
     *
     * @param loader  Cursor loader being reset
     */
    @Override
    public void onLoaderReset(Loader<Cursor> loader) {
        mNewsAdapter.swapCursor(null);
    }

    /**
     * Resets the activated position when the fragment view is created
     * and sets up the text to display if there is no data in the list
     *
     * @param view View being processed
     * @param savedInstanceState Bundle with saved information to be used on creating a new View
     */
    @Override
    public void onViewCreated(View view, Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        // Tell the listview what to say if there is no guild news data
        setEmptyText(getString(R.string.type_loading_data));
        // handle the activated position in the list
        // use the one in the bundle unless this is a brand new instance
        // and then use the one that was saved in the preferences
        if (savedInstanceState != null
                && savedInstanceState.containsKey(STATE_ACTIVATED_POSITION)) {
            setActivatedPosition(savedInstanceState.getInt(STATE_ACTIVATED_POSITION));
        }
    }

    /**
     * Ensure that the activity calling this fragment implements the required callbacks to handle
     * the item list processing
     *
     * @param activity Activity that is attaching this fragment
     */
    @Override
    public void onAttach(Activity activity) {
        super.onAttach(activity);
        if (!(activity instanceof Callbacks)) {
            throw new IllegalStateException("Activity must implement fragment's callbacks.");
        }
        mCallbacks = (Callbacks) activity;
    }

    /**
     * setup the dummy callbacks on detach
     */
    @Override
    public void onDetach() {
        super.onDetach();
        mCallbacks = sNewsListCallbacks;
    }

    /**
     * Match the data cursor to the selected item in the listview, then process the news item
     * selected in the calling activity.
     *
     * @param listView  ListView being processed
     * @param view      View being processed
     * @param position  new position for the list item selected
     * @param id  id of the item selected
     */
    @Override
    public void onListItemClick(ListView listView, View view, int position, long id) {
        Cursor cursor = mNewsAdapter.getCursor();
        if (cursor != null && cursor.moveToPosition(position)) {
            ((Callbacks) getActivity()).onNewsListItemSelected(cursor.getLong(COL_NEWS_ID));
        }
        setActivatedPosition(position);
    }

    /**
     * Save the currently store list position so it can be reactivated later
     *
     * @param outState Bundle to hold the save data
     */
    @Override
    public void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        if (mActivatedPosition != ListView.INVALID_POSITION) {
            outState.putInt(STATE_ACTIVATED_POSITION, mActivatedPosition);
        }
    }

    /**
     * Setup so that we can change the background of the listview when selected
     *
     * @param activateOnItemClick  true for CHOICE_MODE_SINGLE else CHOICE_MODE_NONE
     */
    public void setActivateOnItemClick(boolean activateOnItemClick) {
        getListView().setChoiceMode(activateOnItemClick
                ? ListView.CHOICE_MODE_SINGLE
                : ListView.CHOICE_MODE_NONE);
    }

    /**
     * Update the selected item background activation
     *
     * @param position new position for the list viewer to activate
     */
    private void setActivatedPosition(int position) {
        // only process if the listview has been created
        if (getListView() == null) return;
        mActivatedPosition = position;
        if (position == ListView.INVALID_POSITION) {
            getListView().setItemChecked(mActivatedPosition, false);
        } else {
            getListView().setItemChecked(position, true);
        }
    }
}




Java Source Code List

com.skywomantechnology.app.guildviewer.Constants.java
com.skywomantechnology.app.guildviewer.NewsAdapter.java
com.skywomantechnology.app.guildviewer.NewsDetailActivity.java
com.skywomantechnology.app.guildviewer.NewsDetailFragment.java
com.skywomantechnology.app.guildviewer.NewsListActivity.java
com.skywomantechnology.app.guildviewer.NewsListFragment.java
com.skywomantechnology.app.guildviewer.SetPreferenceActivity.java
com.skywomantechnology.app.guildviewer.SettingsFragment.java
com.skywomantechnology.app.guildviewer.Utility.java
com.skywomantechnology.app.guildviewer.data.GuildViewerAchievement.java
com.skywomantechnology.app.guildviewer.data.GuildViewerContract.java
com.skywomantechnology.app.guildviewer.data.GuildViewerDbHelper.java
com.skywomantechnology.app.guildviewer.data.GuildViewerGuild.java
com.skywomantechnology.app.guildviewer.data.GuildViewerItem.java
com.skywomantechnology.app.guildviewer.data.GuildViewerMember.java
com.skywomantechnology.app.guildviewer.data.GuildViewerNewsItem.java
com.skywomantechnology.app.guildviewer.data.NewsProvider.java
com.skywomantechnology.app.guildviewer.sync.GuildViewerAuthenticatorService.java
com.skywomantechnology.app.guildviewer.sync.GuildViewerAuthenticator.java
com.skywomantechnology.app.guildviewer.sync.GuildViewerSyncAdapter.java
com.skywomantechnology.app.guildviewer.sync.GuildViewerSyncService.java