replacing the AsyncTask with an AsyncTaskLoader.

github: Done S05.01: with AsyncTaskLoader

  • Have MainActivity implement the loader callbacks
  • Create a loader ID
  • Fill out the loader callbacks using the code from FetchWeatherQuery
  • Call initLoader in onCreate (whether or not the loader already exists)
  • Restart the loader if refresh is triggered from the menu

1. Implement the proper LoaderCallbacks interface and the methods of that interface

public class MainActivity extends AppCompatActivity implements
        ForecastAdapterOnClickHandler,
        LoaderManager.LoaderCallbacks<String[]> {

2. Within onCreateLoader, return a new AsyncTaskLoader

@Override
public Loader<String[]> onCreateLoader(int id, final Bundle args) {
    return new AsyncTaskLoader<String[]>(this) {

        String[] mWeatherData = null;

        /**
         * Subclasses of AsyncTaskLoader must implement this to take care of loading their data.
         */
        @Override
        protected void onStartLoading() {
            if(mWeatherData != null){
                deliverResult(mWeatherData);
            }else{
                mLoadingIndicator.setVisibility(View.VISIBLE);
                forceLoad();
            }
        }

3. Cache the weather data in a member variable and deliver it in onStartLoading.

   /**
         * This is the method of the AsyncTaskLoader that will load and parse the JSON data
         * from OpenWeatherMap in the background.
         *
         * @return Weather data from OpenWeatherMap as an array of Strings.
         *         null if an error occurs
         */
        @Override
        public String[] loadInBackground() {

            String locationQuery = SunshinePreferences
                    .getPreferredWeatherLocation(MainActivity.this);

            URL weatherRequestUrl = NetworkUtils.buildUrl(locationQuery);

            try{
                String jsonWeatherResponse = NetworkUtils
                        .getResponseFromHttpUrl(weatherRequestUrl);

                String[] simpleJsonWeatherData = OpenWeatherJsonUtils
                        .getSimpleWeatherStringsFromJson(MainActivity.this, jsonWeatherResponse);

                return simpleJsonWeatherData;

            }catch (Exception e){
                e.printStackTrace();
                return null;
            }
        }


        /**
         * Sends the result of the load to the registered listener.
         *
         * @param data The result of the load
         */
        public void deliverResult(String [] data){
            mWeatherData = data;
            super.deliverResult(data);
        }

    };
}

4. When the load is finished, show either the data or an error message if there is no data

/**
 * Called when a previously created loader has finished its load.
 *
 * @param loader The Loader that has finished.
 * @param data The data generated by the Loader.
 */
@Override
public void onLoadFinished(Loader<String[]> loader, String[] data) {
    mLoadingIndicator.setVisibility(View.INVISIBLE);
    mForecastAdapter.setWeatherData(data);

    if(data == null){
        showErrorMessage();
    }else{
        showWeatherDataView();
    }
}

@Override
public void onLoaderReset(Loader<String[]> loader) {
    /*
     * We aren't using this method in our example application, but we are required to Override
     * it to implement the LoaderCallbacks<String> interface
     */
}

5.Refactor the refresh functionality to work with our AsyncTaskLoader

/**
 * This method is used when we are resetting data, so that at one point in time during a
 * refresh of our data, you can see that there is no data showing.
 */
public void invailidataData(){
    mForecastAdapter.setWeatherData(null);
}
@Override
    public boolean onOptionsItemSelected(MenuItem item) {
        int id = item.getItemId();
            invailidataData();
            getSupportLoaderManager().restartLoader(FORECAST_LOADER_ID, null, this);
            return true;
        }

        if (id == R.id.action_map) {
            openLocationInMap();
            return true;
        }

        return super.onOptionsItemSelected(item);
    }

6. Remove any and all code from MainActivity that references FetchWeatherTask7

7. Remove the code for the AsyncTask and initialize the AsyncTaskLoader.

/*
 * This ID will uniquely identify the Loader. We can use it, for example, to get a handle
 * on our Loader at a later point in time through the support LoaderManager.
 */
int loaderId = FORECAST_LOADER_ID;

/*
 * From MainActivity, we have implemented the LoaderCallbacks interface with the type of
 * String array. (implements LoaderCallbacks<String[]>) The variable callback is passed
 * to the call to initLoader below. This means that whenever the loaderManager has
 * something to notify us of, it will do so through this callback.
 */
LoaderManager.LoaderCallbacks<String[]> callbacks = MainActivity.this;

/*
 * The second parameter of the initLoader method below is a Bundle. Optionally, you can
 * pass a Bundle to initLoader that you can then access from within the onCreateLoader
 * callback. In our case, we don't actually use the Bundle, but it's here in case we wanted
 * to.
 */
Bundle bundleForLoader = null;

/*
 * Ensures a loader is initialized and active. If the loader doesn't already exist, one is
 * created and (if the activity/fragment is currently started) starts the loader. Otherwise
 * the last created loader is re-used.
 */
getSupportLoaderManager().initLoader(loaderId, bundleForLoader, callbacks);
Resource: Udacity- Associate Android Developer Fast Track

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s