12

I'm implementing an endless data loading for a RecyclerView. When software detects that last item is going to be shown, it downloads new items and call to the loadMoreData() function but new dataset is not showing.

When I called notifyDataSetChanged() so nothing to be happened.

I have only one solution that is refresh the view is to set again the adapter but problem is that the recyclerview returns to the first position then again recyclerview scrolled up from the first position to last position.

RecyclerViewActivity.java

    RecyclerView rv;

    DatabaseHelpr databaseHelpr;

    RVAdapter adapter;

    LocationFinder locationfinder;

    Location currentLocation;

    ArrayList<ServiceModel> childList, list;

    private int MainService_ID, city_id;

    String url2;

    ActionBar actionBar;

    JSONArray items = null;

    Utility utility;

    Double lat, longi;

    LinearLayoutManager llm;

    int counter=0;

    ProgressBar progressBar;

    private static final String TAG_ITEMS = "items";

    private static final String TAG_LOCALITY = "Locality";

    private static final String TAG_BUSINESS_ID = "Business_Id";

    private static final String TAG_LONGITUDE = "Longitude";

    private static final String TAG_BUSINESS_NAME = "Business_Name";

    private static final String TAG_LATITUDE = "Latitude";


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.recyclerview_activity);

        list = new ArrayList<>();
        utility = new Utility(this);
        llm = new LinearLayoutManager(this);

        Bundle bundle=getIntent().getExtras();
        MainService_ID=bundle.getInt("service_id");
        String mainService_Name = bundle.getString("service_name");
        city_id = bundle.getInt("city_id");
        lat= bundle.getDouble("lat");
        longi=bundle.getDouble("longi");

        rv=(RecyclerView)findViewById(R.id.rv);
        rv.setLayoutManager(llm);

        actionBar = getSupportActionBar();
        assert actionBar != null;
        actionBar.setDisplayHomeAsUpEnabled(true);
        actionBar.setTitle(mainService_Name);

           //Here city_id = 8, lat = 18.552954, longi = 73.897200, counter=0, MainService_ID = 5
           String url="https://servicedata2-dot-indiacomapi.appspot.com/_ah/api/servicedata/v1/ServiceData?city_id=";
           url2 =url+city_id+"&lat="+lat+"&lng="+longi+"&roll="+counter+"&service_id="+MainService_ID;

           AsyncHttpClient client = new AsyncHttpClient();

           progressBar=(ProgressBar) findViewById(R.id.progressBar1);
           progressBar.setVisibility(View.VISIBLE);

           client.get(url2, new AsyncHttpResponseHandler() {

               @Override
               public void onSuccess(int statusCode, Header[] headers, byte[] response) {
                   // called when response HTTP status is "200 OK"
                   String s = new String(response);

                   try {
                       JSONObject jsonObj = new JSONObject(s);

                       // Getting JSON Array node
                       items = jsonObj.getJSONArray(TAG_ITEMS);

                       // looping through All Contacts
                       for (int i = 0; i < items.length(); i++) {

                           JSONObject c = items.getJSONObject(i);
                           String locality = c.getString(TAG_LOCALITY);
                           String business_Id = c.getString(TAG_BUSINESS_ID);
                           String longitude = c.getString(TAG_LONGITUDE);
                           String latitude = c.getString(TAG_LATITUDE);
                           String business_Name = c.getString(TAG_BUSINESS_NAME);
                           locationfinder = new LocationFinder(RecyclerViewActivity.this);
                           // check if GPS enabled
                           if (locationfinder.canGetLocation()) {
                               double lat = locationfinder.getLatitude();
                               double longi = locationfinder.getLongitude();
                               currentLocation = new Location("");
                               currentLocation.setLatitude(lat);
                               currentLocation.setLongitude(longi);
                           } else {
                               locationfinder.showSettingsAlert();
                           }
                           Location savedLocation = new Location("databaseLocation");
                           savedLocation.setLatitude(Double.parseDouble(latitude));
                           savedLocation.setLongitude(Double.parseDouble(longitude));
                           Double difference = currentLocation.distanceTo(savedLocation) * (0.001);
                           difference = Double.parseDouble(new DecimalFormat("##.##").format(difference));
                           String newDifference = String.valueOf(difference) + " km";
                           ServiceModel serviceModel = new ServiceModel(business_Id, business_Name, newDifference, locality);

                           list.add(serviceModel);
                       }
                   } catch (JSONException e) {
                       e.printStackTrace();
                   }

                   progressBar.setVisibility(View.GONE);
                   adapter = new RVAdapter(RecyclerViewActivity.this, list);
                   rv.setAdapter(adapter);
                   rv.addOnScrollListener(new EndlessRecyclerOnScrollListener(llm) {

                       @Override
                       public void onLoadMore(int current_page) {
                           //  counter= counter+1;
                           loadMoreData();
                       }
                   });
               }

               @Override
               public void onFailure(int statusCode, Header[] headers, byte[] errorResponse, Throwable e) {
                   // called when response HTTP status is "4XX" (eg. 401, 403, 404)
                   //Toast.makeText(getApplicationContext(),""+statusCode,Toast.LENGTH_LONG).show();
               }

           });

    }

    private void loadMoreData() {

        counter= counter+1;

        //Here city_id = 8, lat = 18.552954, longi = 73.897200, counter=1, MainService_ID = 5
        String url="https://servicedata2-dot-indiacomapi.appspot.com/_ah/api/servicedata/v1/ServiceData?city_id=";
        url2 =url+city_id+"&lat="+lat+"&lng="+longi+"&roll="+counter+"&service_id="+MainService_ID;

        AsyncHttpClient client = new AsyncHttpClient();

        progressBar=(ProgressBar) findViewById(R.id.progressBar1);
        progressBar.setVisibility(View.VISIBLE);

        client.get(url2, new AsyncHttpResponseHandler() {

            @Override
            public void onSuccess(int statusCode, Header[] headers, byte[] response) {
                // called when response HTTP status is "200 OK"
                String s = new String(response);

                try {
                    JSONObject jsonObj = new JSONObject(s);

                    // Getting JSON Array node
                    items = jsonObj.getJSONArray(TAG_ITEMS);
                    // looping through All Contacts
                    for (int i = 0; i < items.length(); i++) {
                        JSONObject c = items.getJSONObject(i);
                        String locality = c.getString(TAG_LOCALITY);
                        String business_Id = c.getString(TAG_BUSINESS_ID);
                        String longitude = c.getString(TAG_LONGITUDE);
                        String latitude = c.getString(TAG_LATITUDE);
                        String business_Name = c.getString(TAG_BUSINESS_NAME);
                        locationfinder = new LocationFinder(RecyclerViewActivity.this);
                        // check if GPS enabled
                        if (locationfinder.canGetLocation()) {
                            double lat = locationfinder.getLatitude();
                            double longi = locationfinder.getLongitude();
                            currentLocation = new Location("");
                            currentLocation.setLatitude(lat);
                            currentLocation.setLongitude(longi);
                        } else {
                            locationfinder.showSettingsAlert();
                        }
                        Location savedLocation = new Location("databaseLocation");
                        savedLocation.setLatitude(Double.parseDouble(latitude));
                        savedLocation.setLongitude(Double.parseDouble(longitude));
                        Double difference = currentLocation.distanceTo(savedLocation) * (0.001);
                        difference = Double.parseDouble(new DecimalFormat("##.##").format(difference));
                        String newDifference = String.valueOf(difference) + " km";
                        ServiceModel serviceModel = new ServiceModel(business_Id, business_Name, newDifference, locality);

                        list.add(serviceModel);
                    }
                } catch (JSONException e) {
                    e.printStackTrace();
                }
                progressBar.setVisibility(View.GONE);
                //adapter = new RVAdapter(RecyclerViewActivity.this, list);
                //rv.setAdapter(adapter);
                adapter.notifyDataSetChanged();
            }

            @Override
            public void onFailure(int statusCode, Header[] headers, byte[] errorResponse, Throwable e) {
            }
        });

        Toast.makeText(this, "Net is present", Toast.LENGTH_SHORT).show();
    }
}  

RVAdapter.java

public class RVAdapter extends RecyclerView.Adapter<RVAdapter.PersonViewHolder>{
    private final LayoutInflater mInflater;
    List<ServiceModel> persons ;
    private Context mContext;


    public RVAdapter(Context context,List<ServiceModel> persons){

       this.mInflater = LayoutInflater.from(context);
        this.persons = new ArrayList<>(persons);
       this.mContext = context;
    }

    @Override
    public void onAttachedToRecyclerView(RecyclerView recyclerView) {
        super.onAttachedToRecyclerView(recyclerView);
    }

    @Override
    public PersonViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
        View v = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.item, viewGroup, false);
        PersonViewHolder pvh = new PersonViewHolder(v);
        return pvh;
    }

    @Override
    public void onBindViewHolder(PersonViewHolder personViewHolder, int i) {
        ServiceModel person = persons.get(i);

        personViewHolder.businessName.setOnClickListener(clickListener);
        personViewHolder.image_url.setOnClickListener(clickListenerImage);

        personViewHolder.businessName.setTag(personViewHolder);
        personViewHolder.difference.setTag(personViewHolder);
        personViewHolder.business_id.setTag(personViewHolder);
        personViewHolder.image_url.setTag(personViewHolder);
        personViewHolder.locality.setTag(personViewHolder);

        personViewHolder.businessName.setText(Html.fromHtml(person.getBusinessname()));
        String firstLetter = String.valueOf(person.getBusinessname().charAt(0));
        ColorGenerators generator = ColorGenerators.MATERIAL; // or use DEFAULT
        int color = generator.getColor(person.getBusinessname());
        TextDrawable drawable = TextDrawable.builder().buildRound(firstLetter, color); // radius in px
        personViewHolder.image_url.setImageDrawable(drawable);
        personViewHolder.difference.setText(Html.fromHtml(person.getNewDiffer()));
        personViewHolder.locality.setText(Html.fromHtml(person.getLocality()));
        personViewHolder.bind(person);
    }

    View.OnClickListener clickListener = new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            PersonViewHolder holder = (PersonViewHolder) view.getTag();
            int position = holder.getPosition();
            ServiceModel person = persons.get(position);
            String businessids = person.getBusinessid();
            Intent intent = new Intent(mContext, BusinessInfoActivity.class);
            intent.putExtra("businessids", businessids);
            mContext.startActivity(intent);
        }
    };

    View.OnClickListener clickListenerImage = new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            PersonViewHolder holder = (PersonViewHolder) view.getTag();
            int position = holder.getPosition();

            ServiceModel person = persons.get(position);
            String businessids = person.getBusinessid();
            Intent intent = new Intent(mContext, BusinessInfoActivity.class);
            intent.putExtra("businessids", businessids);
            mContext.startActivity(intent);
        }
    };

    @Override
    public int getItemCount() {
        return persons.size();
    }

    public void animateTo(List<ServiceModel> models) {
        applyAndAnimateRemovals(models);
        applyAndAnimateAdditions(models);
        applyAndAnimateMovedItems(models);
    }

    private void applyAndAnimateRemovals(List<ServiceModel> newModels) {
        for (int i = persons.size() - 1; i >= 0; i--) {
            final ServiceModel model = persons.get(i);
            if (!newModels.contains(model)) {
                removeItem(i);
            }
        }
    }

    private void applyAndAnimateAdditions(List<ServiceModel> newModels) {
        for (int i = 0, count = newModels.size(); i < count; i++) {
            final ServiceModel model = newModels.get(i);
            if (!persons.contains(model)) {
                addItem(i, model);
            }
        }
    }

    private void applyAndAnimateMovedItems(List<ServiceModel> newModels) {
        for (int toPosition = newModels.size() - 1; toPosition >= 0; toPosition--) {
            final ServiceModel model = newModels.get(toPosition);
            final int fromPosition = persons.indexOf(model);
            if (fromPosition >= 0 && fromPosition != toPosition) {
                moveItem(fromPosition, toPosition);
            }
        }
    }

    public ServiceModel removeItem(int position) {
        final ServiceModel model = persons.remove(position);
        notifyItemRemoved(position);
        return model;
    }

    public void addItem(int position, ServiceModel model) {
        persons.add(position, model);
        notifyItemInserted(position);
    }

    public void moveItem(int fromPosition, int toPosition) {
        final ServiceModel model = persons.remove(fromPosition);
        persons.add(toPosition, model);
        notifyItemMoved(fromPosition, toPosition);
    }

    public static class PersonViewHolder extends RecyclerView.ViewHolder {

        protected CardView cv;

        protected TextView businessName, difference, business_id, locality;

        protected ImageView image_url;

        public PersonViewHolder(View itemView) {
            super(itemView);
            cv = (CardView)itemView.findViewById(R.id.cv);
            businessName = (TextView)itemView.findViewById(R.id.business_name);
            difference = (TextView)itemView.findViewById(R.id.txtDifferenece);
            business_id = (TextView)itemView.findViewById(R.id.business_id);
            image_url = (ImageView)itemView.findViewById(R.id.thumbnail);
            locality= (TextView)itemView.findViewById(R.id.txtLocality);
        }

        public void bind(ServiceModel model) {
            businessName.setText(model.getBusinessname());
        }
    }
}  

Please help me, How to set notifyDataSetChanged() to the adapter. it is not working in my code. I already checked all answers which is posted on the stackoverflow.

Jaiprakash Soni
  • 4,023
  • 4
  • 35
  • 66
A.R.
  • 635
  • 1
  • 10
  • 27

5 Answers5

28

you are setting the new list to the RecyclerView Adapter , set the list in the Adapter:

make a method setItems(list) in adapter and call it before notifyDataSetChanged() and in adapter do

this.persons = new ArrayList<>(persons);

in setItems

add this method in adapter:

public void setItems(List<ServiceModel> persons) {
    this.persons = persons;
}

and call it before notifyDataSetChanged() like this:

adapter.setItems(list);
adapter.notifyDataSetChanged();
JAAD
  • 12,171
  • 6
  • 34
  • 56
  • Could you explain in deatil? I am not getting what you saying. @ankitagrawal – A.R. Feb 02 '16 at 08:55
  • It is also good practice to use adapter.notifyItemInserted(mItems.size() - 1); insted of adapter.notifyDataSetChanged(); – emir Jan 06 '17 at 23:47
  • @emir here we are replacing the list and not inserting items , you are assuming that the list is empty which is not the case always – JAAD Jan 07 '17 at 07:34
  • I am doing the same in my project, when I want to replace list I just clear "list" before adding and it is working – emir Jan 07 '17 at 10:25
  • @ColdFire can you help with this one please https://stackoverflow.com/questions/58849910/how-to-stop-refreshing-recyclerview-data-scroll-to-top-position-android – AAA Nov 14 '19 at 07:10
0

Issue is in these lines..

     adapter = new RVAdapter(RecyclerViewActivity.this, list);
        rv.setAdapter(adapter);
        adapter.notifyDataSetChanged();

You are initialising your adapter every time. No need to reinitialize it. Just update your arraylist and invoking to adapter.notifyDataSetChanged(); will make it work.

Beena
  • 2,234
  • 18
  • 46
  • I am initialising my adapter only very first time then on loadMoreData() I have only set to adapter.notifyDataSetChanged(). I didn't initialize adapter every time. – A.R. Feb 02 '16 at 09:01
  • There should be something in your code which is reinitialising either your `ArrayList` or Adapter that has stopped notifyDataSetChanged() function. – Beena Feb 02 '16 at 09:07
  • I checked all the code but where is I am wrong? didn't no @ Beena – A.R. Feb 02 '16 at 09:16
0

Like @Beena mentioned, you are creating and setting new adapter ever time, in your success response.

One approach would be to create an adapter and set it to the recycler view only for the first time, and then onSuceess() of your api callback, call a method of your adapter.

In, them adapter method, just add that new data in your main arraylist and do notifyItemInserted() instead of notifyDataSetChanged, in this way you will also see the default adding animation of recyclerView.

Ritesh
  • 2,558
  • 2
  • 15
  • 38
  • for notifyItemInserted() what will be the value of int value. it is 0 or 1?? @Ritesh – A.R. Feb 02 '16 at 09:15
  • it's not necessary to be 0 or 1. maintain a variable somewhere, which will have the size of your array, and onInsert, the int value would be the "size+1". – Ritesh Feb 02 '16 at 09:50
  • because you will inserting the new item at the end of the list. – Ritesh Feb 02 '16 at 09:50
  • 1
    okay but it is not working. I didn't get the result using notifyItemInserted(). @Ritesh – A.R. Feb 02 '16 at 12:15
0

Every time you fill your list call the method below:

if (adapter != null) // it works second time and later
   adapter.notifyDataSetChanged();
else { // it works first time
  adapter = new AdapterClass(context,list);
  listView.setAdapter(adapter);
}
Abdelilah El Aissaoui
  • 2,266
  • 1
  • 16
  • 40
  • 1
    It is not helpful for me. not showing the next dataset on the recyclerview @kadir altinok – A.R. Feb 02 '16 at 08:47
-1

I solved this with added method in RVAdapter that call notifyDataSetChanged().

Simply in RVAdapter:

public void refreshList(){
    notifyDataSetChanged();
}

and call this method in MainActivity when need:

rVAdapter.refreshList();