title: Recycler View Adapter: Best practice to notify that data set has updated
body: <p>I am trying to make a volley request to api's url. The problem is that data is fetched appropriately, but every time data set updates, the whole recycler view refreshes again and begins from the start; in the docs it is mentioned that use <code>notifyDataSetChanged()</code> as the last resort. How can it be avoided and what are the best practices for such tasks? Any design pattern that should be followed?</p>
  
  <p>Here is the Fragment Code :- </p>
  
  <pre><code>public class PageFragment extends Fragment implements SortDialogCallback {
  
      private static final String TAG = PageFragment.class.getSimpleName();
      /**
       * Unsplash API, By Default=10
       */
      private static final String per_page = "10";
      public static String order_By;
      /**
       * Unsplash API call parameter, By Default=latest
       * Change it in Pager Fragment, based on Tab tapped
       */
      RecyclerView recyclerView;
      ImageAdapter imageAdapter;
      GridLayoutManager layoutManager;
      EndlessRecyclerViewScrollListener scrollListener;
      FloatingActionButton actionButton;
      FrameLayout no_internet_container;
      Bundle savedInstanceState;
      // Attaching Handler to the main thread
      Handler handler = new Handler();
      boolean shouldHandlerRunAgain = true;
      private ArrayList&lt;DataModel&gt; model;
      /**
       * Handler is attached to the Main Thread and it's message queue, because it is the one who created it.
       * &lt;p&gt;
       * Handler is responsible for checking every second that are we connected to internet, and if we are, then :-
       * 1. Then we remove empty view
       * 2. Make the network call
       * 3. Stop handler from posting the code again using shouldHandlerRunAgain variable
       * 3.1 This is a kill switch otherwise handler will post the runnable again and again to the message queue, which will be executed as soon as it reaches the looper
       * &lt;p&gt;
       * Handler removeCallbacks is used to remove all the pending runnables  in the Message Queue
       */
      Runnable job = new Runnable() {
          @Override
          public void run() {
              Log.d(TAG, "Thread run " + job.hashCode());
              swapViews();
              if (shouldHandlerRunAgain)
                  handler.postDelayed(job, HANDLER_DELAY_TIME);
          }
      };
  
      @Override
      public void onSaveInstanceState(Bundle outState) {
          super.onSaveInstanceState(outState);
          outState.putString("ORDER_BY", order_By);
      }
  
      @Override
      public void onResume() {
          super.onResume();
          if (handler != null)
          handler.post(job);
      }
  
      @Override
      public void onCreate(@Nullable Bundle savedInstanceState) {
          super.onCreate(savedInstanceState);
          Log.d(TAG, "Starting Handler");
          layoutManager = new GridLayoutManager(getContext(), 2);
          scrollListener = new EndlessRecyclerViewScrollListener(layoutManager) {
  
              public void onLoadMore(int page, int totalItemsCount, RecyclerView view) {
                  Log.w(TAG, "On load More Called with page number " + page);
                  loadDataUsingVolley(page, order_By);
              }
          };
  
      }
  
      @Override
      public boolean onOptionsItemSelected(MenuItem item) {
          switch (item.getItemId()) {
              case R.id.search:
                  Toast.makeText(getContext(), "Async task", Toast.LENGTH_SHORT).show();
                  break;
              default:
                  Toast.makeText(getContext(), "Invalid Options", Toast.LENGTH_SHORT).show();
          }
          return true;
      }
  
      @Override
      public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
          inflater.inflate(R.menu.menu_page_fragment, menu);
      }
  
  
      private void swapViews() {
          if (detectConnection(getContext()) == false) {
              recyclerView.setVisibility(View.INVISIBLE);
              actionButton.setVisibility(View.INVISIBLE);
              no_internet_container.setVisibility(View.VISIBLE);
          } else {
              Log.d(TAG, "Removing callbacks from handler and stopping it from posting");
              shouldHandlerRunAgain = false;
              handler.removeCallbacks(job, null);
              handler = null;
              recyclerView.setVisibility(View.VISIBLE);
              actionButton.setVisibility(View.VISIBLE);
              no_internet_container.setVisibility(View.INVISIBLE);
              if (savedInstanceState != null) {
                  loadDataUsingVolley(1, savedInstanceState.getString("ORDER_BY"));
              } else {
                  order_By = "latest";
                  loadDataUsingVolley(1, order_By);
              }
          }
      }
  
      @Nullable
      @Override
      public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, final Bundle savedInstanceState) {
  
          this.savedInstanceState = savedInstanceState;
          View view = inflater.inflate(R.layout.fragment_page, container, false);
  
          actionButton = (FloatingActionButton) view.findViewById(R.id.sort_button);
          actionButton.setOnClickListener(new View.OnClickListener() {
              @Override
              public void onClick(View view) {
                  SortDialog sortDialog = new SortDialog();
                  sortDialog.setTargetFragment(PageFragment.this, 911);
                  sortDialog.show(getChildFragmentManager(), "sortfragment");
              }
          });
  
          recyclerView = (RecyclerView) view.findViewById(R.id.recyclerview);
          recyclerView.setHasFixedSize(true);
          no_internet_container = (FrameLayout) view.findViewById(R.id.no_internet_container);
  
          return view;
      }
  
      void setUpRecyclerView() {
          if (imageAdapter == null)
              imageAdapter = new ImageAdapter(getContext(), (model==null)?new ArrayList&lt;DataModel&gt;():model);
          recyclerView.setAdapter(imageAdapter);
          recyclerView.setLayoutManager(layoutManager);
          recyclerView.addOnScrollListener(scrollListener);
      }
  
      void loadDataUsingVolley(int page, String order_by) {
          final ProgressDialog dialog = ProgressDialog.show(getContext(), "Wallser", "Loading");
          RequestQueue requestQueue = Volley.newRequestQueue(getContext());
          String URL = "https://api.unsplash.com/photos/?page=" + page + "&amp;client_id=" + api_key + "&amp;per_page=" + per_page + "&amp;order_by=" + order_by;
          Log.d(TAG, URL);
          JsonArrayRequest objectRequest = new JsonArrayRequest(Request.Method.GET, URL, null, new Response.Listener&lt;JSONArray&gt;() {
              @Override
              public void onResponse(JSONArray array) {
                  int len = array.length();
                  if (model == null)
                  model = new ArrayList&lt;&gt;();
                  for (int i = 0; i &lt; len; i++) {
                      try {
                          JSONObject object = array.getJSONObject(i);
                          String id = object.getString("id");
                          JSONObject object1 = object.getJSONObject("urls");
                          String imageURL = object1.getString("regular");
                          JSONObject object2 = object.getJSONObject("links");
                          String downloadURL = object2.getString("download");
                          model.add(new DataModel(imageURL, downloadURL, id));
                          Log.d(TAG, downloadURL);
                      } catch (JSONException e) {
                          e.printStackTrace();
                      }
                  }
  
                  if (dialog != null) {
                      dialog.dismiss();
                  }
                  Log.d(TAG, model.size() + "");
                  setUpRecyclerView();
  
              }
          }, new Response.ErrorListener() {
  
              @Override
              public void onErrorResponse(VolleyError error) {
                  dialog.dismiss();
                  Toast.makeText(getContext(), "" + error.getMessage(), Toast.LENGTH_SHORT).show();
              }
          });
          requestQueue.add(objectRequest);
      }
  
      /**
       * marks a new network call to Unsplash API
       * Thus, set model array list to null, to start fresh.
       * as model is reset, ImageAdapter also needs to start fresh.
       *
       * @param order_by
       */
      @Override
      public void onDialogFinish(String order_by) {
          model = null;
          imageAdapter=null;
          order_By = order_by;
          loadDataUsingVolley(1, order_By);
      }
  }
  </code></pre>