title: How do I load data in RecyclerView asynchronously?
body: <p>I have a blank recycler view inside a fragment. Upon receiving a GCM notification, I like to call a webservice. That webservice will store data into a blank database. When this is all done, how do I notify the recycler view to update itself with the new database content?</p>
  
  <p>I am only stuck at the portion where I need to notify recycler view somehow to update itself. I implemented this <a href="https://gist.github.com/skyfishjy/443b7448f59be978bc59" rel="nofollow noreferrer">https://gist.github.com/skyfishjy/443b7448f59be978bc59</a>, but it works only when there is data already in database. It does not work in my scenario.</p>
  
  <p>I am providing the code I have currently for better understanding of the problem:</p>
  
  <pre><code>package mypackage;
  
  import android.app.Activity;
  import android.app.LoaderManager;
  import android.content.ContentResolver;
  import android.content.ContentValues;
  import android.content.CursorLoader;
  import android.content.Loader;
  import android.database.Cursor;
  import android.net.Uri;
  import android.os.AsyncTask;
  import android.os.Bundle;
  import android.os.Handler;
  import android.support.v4.app.Fragment;
  import android.support.v4.view.ViewCompat;
  import android.support.v7.widget.LinearLayoutManager;
  import android.support.v7.widget.RecyclerView;
  import android.view.LayoutInflater;
  import android.view.View;
  import android.view.ViewGroup;
  import android.view.animation.OvershootInterpolator;
  
  import com.squareup.picasso.Picasso;
  
  import mypackage.R;
  import mypackage.adapters.NewsRecyclerViewAdapter;
  import mypackage.database.NewsProvider;
  import mypackage.models.News;
  import mypackage.utils.SaveImageTask;
  
  import java.text.SimpleDateFormat;
  import java.util.ArrayList;
  import java.util.Arrays;
  import java.util.Calendar;
  import java.util.Date;
  import java.util.List;
  import java.util.Locale;
  import java.util.Random;
  
  import butterknife.ButterKnife;
  import jp.wasabeef.recyclerview.animators.FlipInRightYAnimator;
  import jp.wasabeef.recyclerview.animators.adapters.AlphaInAnimationAdapter;
  import jp.wasabeef.recyclerview.animators.adapters.ScaleInAnimationAdapter;
  
  import static mypackage.MyDbOpenHelper.*;
  
  
  public class NewsListFragment extends Fragment implements LoaderManager.LoaderCallbacks&lt;Cursor&gt; {
  
      private NewsRecyclerViewAdapter mAdapter;
      private SaveImageTask saveImageTask;
      private NewsType newsType;
      private Activity parent;
  
      public static NewsListFragment newInstance(NewsType newsType, Activity container) {
          NewsListFragment fragment = new NewsListFragment();
          fragment.saveImageTask = new SaveImageTask(container);
          fragment.newsType = newsType;
          fragment.parent = container;
          return fragment;
      }
  
      @Override
      public View onCreateView(LayoutInflater inflater, ViewGroup container,
                               final Bundle savedInstanceState) {
          View view = inflater.inflate(R.layout.recycler_view, container, false);
          ButterKnife.bind(this, view);
  
          final RecyclerView mRecyclerView = (RecyclerView) view.findViewById(R.id.my_recycler_view);
          mRecyclerView.setHasFixedSize(true);
          RecyclerView.LayoutManager mLayoutManager = new LinearLayoutManager(view.getContext());
          mRecyclerView.setLayoutManager(mLayoutManager);
  
          Picasso picasso = new Picasso.Builder(parent).build();
          ContentResolver contentResolver = parent.getContentResolver();
          Cursor newsCursor;
          if (newsType == NewsType.ALL) {
              newsCursor = contentResolver.query(NewsProvider.CONTENT_URI, null, null, null, null);
          } else {
              newsCursor = contentResolver.query(SavedNewsProvider.CONTENT_URI, null, null, null, null);
          }
  
          mAdapter = new NewsRecyclerViewAdapter(newsCursor);
          mAdapter.setPicasso(picasso);
  
          AlphaInAnimationAdapter alphaAdapter = new AlphaInAnimationAdapter(mAdapter);
          ScaleInAnimationAdapter scaleAdapter = new ScaleInAnimationAdapter(alphaAdapter);
          scaleAdapter.setFirstOnly(false);
          scaleAdapter.setInterpolator(new OvershootInterpolator());
          mRecyclerView.setItemAnimator(new FlipInRightYAnimator());
          mRecyclerView.getItemAnimator().setAddDuration(300);
  
          mRecyclerView.setAdapter(scaleAdapter);
  
          ViewCompat.setElevation(view, 50);
          parent.getLoaderManager().initLoader(0, null, this);
  
          new AsyncTask&lt;Void, Void, Void&gt;() {
              @Override
              protected Void doInBackground(Void... params) {
                  Cursor news = parent.getContentResolver().query(NewsProvider.CONTENT_URI,
                          null, null, null, null);
                  if (news == null || news.getCount() == 0) {
                      insertNewsList();
                  } else {
                      news.close();
                  }
                  return null;
              }
  
              @Override
              protected void onPostExecute(Void aVoid) {
                  parent.getLoaderManager().restartLoader(0, null, NewsListFragment.this);
                  mAdapter.notifyDataSetChanged();
                  ContentResolver.requestSync(null, NewsProvider.AUTHORITY, new Bundle());
                  mRecyclerView.refreshDrawableState();
                  mRecyclerView.postInvalidate();
              }
          }.execute(null, null, null);
  
  
          return view;
      }
  
      private void insertNewsList() {
          String[] titles = {"Web", "Java", "Android"};
          Random random = new Random(Calendar.getInstance().getTimeInMillis());
          for (String title : titles) {
              int count = random.nextInt(20);
              List&lt;News&gt; newsList = generateDataSet(title, count);
              for (News dataObject : newsList) {
                  ContentValues initialValues = new ContentValues();
                  initialValues.put(NEWS_IMAGE_LINK, dataObject.getTopImageLink());
                  initialValues.put(NEWS_IMAGE_PATH, dataObject.getTopImagePath());
                  initialValues.put(NEWS_LINK, dataObject.getLink());
                  initialValues.put(NEWS_SOURCE, dataObject.getSourceText());
                  initialValues.put(NEWS_SOURCE_IMG_LINK, dataObject.getSourceImageLink());
                  initialValues.put(NEWS_SOURCE_IMG_PATH, dataObject.getSourceImagePath());
                  initialValues.put(NEWS_TAGS, Arrays.toString(dataObject.getTag()));
                  initialValues.put(NEWS_TEXT, dataObject.getText());
                  initialValues.put(NEWS_TIME, getDateTime());
                  initialValues.put(NEWS_TITLE, dataObject.getTitle());
                  parent.getContentResolver().insert(NewsProvider.CONTENT_URI, initialValues);
              }
          }
      }
  
      @Override
      public void onDestroy() {
          super.onDestroy();
      }
  
      @Override
      public Loader&lt;Cursor&gt; onCreateLoader(int id, Bundle args) {
          return new CursorLoader(parent, NewsProvider.CONTENT_URI, null, null, null, null);
      }
  
      @Override
      public void onLoadFinished(Loader&lt;Cursor&gt; loader, Cursor data) {
          mAdapter.swapCursor(data);
      }
  
      @Override
      public void onLoaderReset(Loader&lt;Cursor&gt; loader) {
          mAdapter.swapCursor(null);
      }
  
  
  
      private List&lt;News&gt; generateDataSet(String subject, int count) {
          String title = "Neque porro quisquam est qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit...";
          String text = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque porttitor nulla nec nulla fermentum, " +
                  "quis imperdiet ipsum aliquet. Phasellus quis odio sit amet nulla rutrum porta. Quisque in ultrices metus." +
                  " Aliquam gravida et lacus ac vestibulum.";
  
          String topImageLink = "http://lorempixel.com/1024/768/";
          String[] categories = {"abstract", "city", "people", "transport", "animals",
                  "food", "nature", "business", "nightlife", "sports", "cats", "fashion", "technics"};
          String sourceImageLink = "http://thegg.net/wp-content/themes/Orizon/css/blue_css/images/rss-icon.png";
          String sourceText = "Random Blog";
          String link = "http://www.google.com";
  
          List&lt;News&gt; results = new ArrayList&lt;&gt;();
          for (int index = 0; index &lt; count; index++) {
  
              int imgIndex = index % 12;
  
              String imgText = subject + "-card-" + index;
              String newTitle = imgText + " " + title;
  
              News obj = new News(newTitle);
              if (index % 2 == 0) {
                  obj.setText(text);
              } else {
                  obj.setTopImageLink(topImageLink + categories[imgIndex] + "/" + imgText);
              }
  
              if (index % 5 != 0) {
                  obj.setSourceImageLink(sourceImageLink);
                  obj.setSourceText(sourceText);
              }
  
              if (index % 7 == 0) {
                  obj.setText(text);
                  obj.setTopImageLink(topImageLink + categories[imgIndex] + "/" + imgText);
                  obj.setSourceImageLink(sourceImageLink);
                  obj.setSourceText(sourceText);
              }
  
              if (obj.getTopImageLink() != null &amp;&amp; !"".equalsIgnoreCase(obj.getTopImageLink())) {
                  Uri topImageUri = saveImageTask.saveImageFile(obj.getTopImageLink());
                  obj.setTopImagePath(topImageUri.getPath());
              }
  
              if (obj.getSourceImageLink() != null &amp;&amp; !"".equalsIgnoreCase(obj.getSourceImageLink())) {
                  Uri sourceImageUri = saveImageTask.saveImageFile(obj.getSourceImageLink());
                  obj.setSourceImagePath(sourceImageUri.getPath());
              }
  
              obj.setLink(link);
              obj.setTag(new String[] {subject});
              results.add(index, obj);
          }
          return results;
      }
  
      private String getDateTime() {
          SimpleDateFormat dateFormat = new SimpleDateFormat(
                  "yyyy-MM-dd HH:mm:ss", Locale.getDefault());
          Date date = new Date();
          return dateFormat.format(date);
      }
  
      public enum NewsType {
          ALL,
          FAVORITE
      }
  }
  </code></pre>
  
  <p>My ContentProvider</p>
  
  <pre><code>package mypackage.database;
  
  import android.content.ContentProvider;
  import android.content.ContentValues;
  import android.database.sqlite.SQLiteDatabase;
  import android.net.Uri;
  
  public abstract class NewsProvider extends ContentProvider {
  
      public static final String AUTHORITY = "myapp.data.newsprovider";
      private static final String BASE_PATH = "news";
      public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/" + BASE_PATH );
  
      // Constant to identify the requested operation
      private static final int NEWS = 1;
      private static final int NEWS_ID = 2;
      private static final int NEWS_TAG = 3;
      private static final UriMatcher uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
  
      static {
          uriMatcher.addURI(AUTHORITY, BASE_PATH, NEWS);
          uriMatcher.addURI(AUTHORITY, BASE_PATH + "/#", NEWS_ID);
          uriMatcher.addURI(AUTHORITY, BASE_PATH + "/tag/*", NEWS_TAG);
      }
  
      private String tableName;
      private String basePath;
      protected SQLiteDatabase database;
  
      public NewsProvider() {
          this.tableName = TABLE_NEWS;
          this.basePath = BASE_PATH;
      }
  
      @Override
      public boolean onCreate() {
          MyDbOpenHelper helper = new MyDbOpenHelper(getContext());
          database = helper.getWritableDatabase();
          return true;
      }
  
      @Override
      public String getType(Uri uri) {
          return null;
      }
  
      @Override
      public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
          if (uriMatcher.match(uri) == NEWS_ID) {
              selection = NEWS_ID + "=" + uri.getLastPathSegment();
          }
  
          if (uriMatcher.match(uri) == NEWS_TAG) {
              selection = NEWS_TAGS + " like %'" + uri.getLastPathSegment() + "'%";
          }
  
          return database.query(TABLE_NEWS, NEWS_ALL_COLUMNS,
                  selection, null, null, null, NEWS_TIME + " DESC");
      }
  
      @Override
      public Uri insert(Uri uri, ContentValues values) {
          long id = database.insert(tableName, null, values);
          Uri newUri = Uri.parse(basePath + "/" + id);
          getContext().getContentResolver().notifyChange(newUri, null);
          return newUri;
      }
  
      @Override
      public int delete(Uri uri, String selection, String[] selectionArgs) {
          return database.delete(tableName, selection, selectionArgs);
      }
  
      @Override
      public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
          return database.update(tableName, values, selection, selectionArgs);
      }
  }
  </code></pre>