Loader : CursorLoader - CursorAdapter - AsyncTask

Functionality Overview


Loader reads ContentProvider data into cursor & callbacks swap it into Adapter for display:
    cursor = getContentResolver().query("content://com.example.shreekant.sunshine.app/weather/<Pune>?date=<normalizedDate>");
    mForecastAdapter = CursorAdapter(cursor);


Reads Json, adds data to ContentProvider:


ContentProvider implements "content://" interface over SQLiteOpenHelper
    See Content Provider


DB table and field names referred by all
    See Query Projection & Contract

Loader - CursorLoader - CursorAdapter - AsyncTask [- Content Resolver/Provider - Database support]

Loader performs asynchronous loading of data. While Loaders are active they monitor the source of their data and deliver new results when the contents change.

// Creates CursorLoader to load Cursor with data fetched from Uri, and
// takes care of showing it in views (either directly or thru CursorAdapter)
public class ForecastFragment extends Fragment
        implements LoaderManager.LoaderCallbacks<Cursor> {

    private static final int FORECAST_LOADER_ID = 0;
    private ForecastAdapter mForecastAdapter;

    private static final String[] FORECAST_COLUMNS = {
            // ID needs to be fully qualified as a join is used
            WeatherContract.WeatherEntry.TABLE_NAME + "." + WeatherContract.WeatherEntry._ID,
    // These indices are tied to FORECAST_COLUMNS.  If FORECAST_COLUMNS changes, these must change.
    static final int COL_WEATHER_ID = 0;
    static final int COL_WEATHER_DATE = 1;
    static final int COL_WEATHER_DESC = 2;

    // LoaderManager.LoaderCallbacks
    public Loader<Cursor> onCreateLoader(int id, Bundle args) {
        // Create and return a CursorLoader that will take care of
        // creating a Cursor for the data being displayed.

        // CursorLoader implements the Loader protocol in a standard way for querying cursors, building
        // on AsyncTaskLoader to perform the cursor query on a background thread so that
        // it does not block the application's UI.

        Uri weatherForLocationStartDateUri = WeatherContract.WeatherEntry.buildWeatherLocationWithStartDate(
        return new CursorLoader(getActivity(),
                FORECAST_COLUMNS,   // projection
                null,               // selection
                null,               // selection params
                null);              // sort order
        // This takes care of bulk of work needed to fetch data thru Uri, load it into Cursor in background.

    // LoaderManager.LoaderCallbacks
    public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
        // This is called when a previously created loader has finished its load.
        // Swap the new cursor in the CursorAdapter.
        // For a simple view (that doesn't need Adapter):

    // LoaderManager.LoaderCallbacks
    public void onLoaderReset(Loader<Cursor> loader) {
        // This is called when the last Cursor provided to onLoadFinished() above is about to be closed.
        // We need to make sure we are no longer using it.

    public void onActivityCreated(Bundle savedInstanceState) {
        getLoaderManager().initLoader(FORECAST_LOADER_ID, null, this); // this class itself implements LoaderManager.LoaderCallbacks

    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        // The CursorAdapter will take data from our cursor and populate the ListView.
        mForecastAdapter = new ForecastAdapter(getActivity(), null, 0);
        ListView listView = (ListView) rootView.findViewById(R.id.listview_forecast);
        // For a simple view (that doesn't need Adapter):
        Nothing needs to be done!

    private void updateWeather() {
        FetchWeatherTask weatherTask = new FetchWeatherTask(getActivity());
        String location = Utility.getPreferredLocation(getActivity());

    public void onStart() {

    public void onLocationChanged() {
//        updateWeather();
        // Starts a new or restarts an existing Loader in this manager, registers the callbacks to it,
        // and (if the activity/fragment is currently started) starts loading it.
        getLoaderManager().restartLoader(FORECAST_LOADER_ID, null, this);

} // ForecastFragment

// Exposes a list (of weather forecasts) from Cursor ListView
public class ForecastAdapter extends CursorAdapter {

    public View newView(Context context, Cursor cursor, ViewGroup parent) {
        View view = LayoutInflater.from(context).inflate(R.layout.list_item_forecast, parent, false);
        return view;

    // fill-in the views with the contents of the cursor.
    public void bindView(View view, Context context, Cursor cursor) {

} // CursorAdapter

// Read, parse Json and add (bulkinsert) records into database
public class FetchWeatherTask extends AsyncTask<String, Void, Void> {

    protected Void doInBackground(String... params) {
        Uri builtUri = Uri.parse("http://api.openweathermap.org/data/2.5/forecast/daily?").buildUpon()
                .appendQueryParameter("q", params[0])
                .appendQueryParameter("mode", format)
                .appendQueryParameter("units", units)
                .appendQueryParameter("cnt", Integer.toString(numDays))
        URL url = new URL(builtUri.toString());
        urlConnection = (HttpURLConnection) url.openConnection();
        inserted = mContext.getContentResolver().bulkInsert(WeatherEntry.CONTENT_URI, cvArray);
} // FetchWeatherTask

No comments:

Post a Comment