5

I'm trying to add some date on scroll top in a recyclerview. it is work, except the scroll, it mess everything up when some new data is added.

I saw this topics:

Link 1

Link 2

but none of them solved my problem.

maybe someone can help me with this...

I get some data using volley, like so:

try {
                //Getting json
                json = array.getJSONObject(i);

                //Adding data to the object
                PostObj.setImageUrl(json.getString(Config.TAG_PPIC));
                ...


            } catch (JSONException e) {
                e.printStackTrace();
            }
            //Adding object to the list
            listLf.add(0, PostObj); //0, postobj
        }

        //Notifying the adapter that data has been added or changed
        //adapter.notifyDataSetChanged(); the scroll will jump to position 0
        adapter.notifyItemRangeChanged(0, adapter.getItemCount()); // still not working
    }

I tried to add adapter.notifyItemRangeChanged(0, adapter.getItemCount()); but still the same thing.

also I tried:

// Save state
private Parcelable recyclerViewState;
recyclerViewState = recyclerView.getLayoutManager().onSaveInstanceState();

// Restore state
recyclerView.getLayoutManager().onRestoreInstanceState(recyclerViewState);

and it doesn't work too. maybe I place it in the wrong place or something...

I want some suggestions what I'm doing wrong and how can I get the new data, notify the adapter without mess the scroll position?


edit---------------------------------- full class:

public class Comments extends BaseActivity {


    private List<LfGetSet> listLf;

    //Creating Views
    private RecyclerView recyclerView;
    private RecyclerView.LayoutManager layoutManager;
    private RecyclerView.Adapter adapter;

    //Volley Request Queue
    private RequestQueue requestQueue;
    private String requestCount = "0";
    private String lastrequestCount = "0";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        ViewGroup content = (ViewGroup) findViewById(R.id.content_frame);
        getLayoutInflater().inflate(R.layout.activity_comments, content, true);

        //Initializing Views
        recyclerView = (RecyclerView) findViewById(R.id.recyclerViewLf);
        recyclerView.setHasFixedSize(true);
        //layoutManager = new LinearLayoutManager(this);

        final LinearLayoutManager layoutManager = new LinearLayoutManager(this);
        layoutManager.setStackFromEnd(true);

        recyclerView.setLayoutManager(layoutManager);

        //Initializing our list
        listLf = new ArrayList<>();
        requestQueue = Volley.newRequestQueue(this);

        //Calling method to get data to fetch data
        getData();

        recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
            @Override
            public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
                super.onScrolled(recyclerView, dx, dy);
                if (isLastItemDisplaying(recyclerView)) {
                    getData();
                }
            }
        });

        //initializing our adapter
        adapter = new LfAdapter(listLf, this);

        //Adding adapter to recyclerview
        recyclerView.setAdapter(adapter);


    }

    private JsonArrayRequest getDataFromServer(String requestCount) {
        ...
        return jsonArrayRequest;
    }

    //This method will get data from the web api
    private void getData() {
        //Adding the method to the queue by calling the method getDataFromServer
        requestQueue.add(getDataFromServer(requestCount));
        lastrequestCount = requestCount;
        //Incrementing the request counter
        requestCount++;
    }

    //This method will parse json data
    private void parseData(JSONArray array) {
        for (int i = 0; i < array.length(); i++) {
            //Creating the object
            LfGetSet PostObj = new LfGetSet();
            JSONObject json = null;
            try {
                //Getting json
                json = array.getJSONObject(i);

                //Adding data to the object
                PostObj.setImageUrl(json.getString(Config.TAG_PPIC));
                ...


            } catch (JSONException e) {
                e.printStackTrace();
            }
            //Adding object to the list
            listLf.add(0, PostObj); //0, postobj
        }

        //Notifying the adapter that data has been added or changed
        adapter.notifyDataSetChanged();
    }

    //This method would check that the recyclerview scroll has reached the bottom or not
    private boolean isLastItemDisplaying(RecyclerView recyclerView) {
        if (recyclerView.getAdapter().getItemCount() != 0) {
            int lastVisibleItemPosition = ((LinearLayoutManager) recyclerView.getLayoutManager()).findFirstVisibleItemPosition();
            if (lastVisibleItemPosition != RecyclerView.NO_POSITION
                    && lastVisibleItemPosition == 1
                    && lastrequestCount != requestCount
                    && requestCount != "0")
                return true;
        }
        return false;
    }

}
Community
  • 1
  • 1
Gabriela Dias
  • 349
  • 2
  • 12
  • 1
    When you add an item you should use the `notifyItemInserted` method. – RobCo Mar 21 '17 at 00:05
  • I tried `adapter.notifyItemInserted(0);` , `adapter.notifyItemInserted(adapter.getItemCount())` and none of them work. they seems to group all posts in the first position and show them when scroll bottom and top again... Did I do something wrong? @RobCo – Gabriela Dias Mar 21 '17 at 00:39

1 Answers1

1

You can try this approach where you add a new item to the list as per normal and then update the data in the array and put the new one at the top.

   // Add a new item the usual way so it goes at the bottom

    int x = 0;

   // Create a new Data list. New item goes 1st

   // Create a Loop

    myList.remove(x); // Remove item from the array at position

    MyList myList = new MyList();

    myList.add(x, theData); // Add data to array at position


    // Now that new data has been inserted to the Array at position X update the List item at that same Position. I usually do this in the Background.

    Handler handler = new Handler();

    final int finalX = x;
    final Runnable r = new Runnable() {
        public void run() {
            adapter.notifyItemChanged(finalX);  // Notify Adapter that the Items data has changed and Update
        }
    };

    handler.post(r);

    x++;

Code that reads updated data from the DB and then updates List items on the fly with that new data. But in your case you need to add 1 new item and update the List with the new items data at position 0 in the array and on the List. Old items get their position shifted by 1.

public void updateStocks() {

        System.out.println("Updating");
        int rec = db.getRecordsCount() - 1;

        List<Records> record = db.getAllRecords();

        int x = 0;

        for (Records cn : record) {

            stocksList.remove(x);

            Livestocks stocks = new Livestocks();

            stocks.setID(cn.getID());
            stocks.setName(cn.getName());
            stocks.setTicker(cn.getTicker());
            stocks.setPrice(cn.getPrice());
            stocks.setOpen(cn.getOpen());
            stocks.setChange(cn.getChange());
            stocks.setPchange(cn.getPchange());
            stocks.setDhigh(cn.getDhigh());
            stocks.setDlow(cn.getDlow());
            stocks.setYhigh(cn.getYhigh());
            stocks.setYlow(cn.getYlow());
            stocks.setVol(cn.getVol());
            stocks.setShares(cn.getShares());
            stocks.setIown(cn.getIown());
            stocks.setMcap(cn.getMcap());
            stocks.setStatus(cn.getStatus());
            stocks.setExchange(cn.getExchange());

            stocksList.add(x, stocks);

            Handler handler = new Handler();

            final int finalX = x;
            final Runnable r = new Runnable() {
                public void run() {
                    adapter.notifyItemChanged(finalX);
                }
            };

            handler.post(r);

            x++;

            if (rec == x) {
            //do nothing
            }
        }

    }
Tasos
  • 5,321
  • 1
  • 15
  • 26
  • I'll try your solution, thank you! finalX is the number of data I'm inserting isn't it? the i number in for? – Gabriela Dias Mar 21 '17 at 01:01
  • 1
    @Gabriela Dias -- No im copying the value of x to a final integer so it can be read within the handler to update the data of the List item as you see it on screen at the same position as the arrays data -- Array data and List Items have the same postions starting from Zero onwards -- x and finalX have the same value – Tasos Mar 21 '17 at 01:08
  • 1
    @Gabriela Dias -- To explain further, The steps of the code i provided is usually for updating a List item on the fly without having to refresh the whole list. However because you are adding 1 and want it to be on top you will need add 1 the usually way so total array items matches List items No, and lastly you update on the fly but you put the new 1st. You may notice a slight shift of 1 items data – Tasos Mar 21 '17 at 01:17
  • oh, I see! I'll try your solution. it is clever. thanks! – Gabriela Dias Mar 21 '17 at 01:22
  • 1
    @Gabriela Dias -- it will work Ok. After you add 1 new item the usually way all you are doing is shifting old data to a + 1 position on the list and update on the fly as you require the new item to be the 1st on the list. I will add the code i use for a Stocks App i use but all it does is just reads updated data from the DB and updates the list on the fly. – Tasos Mar 21 '17 at 01:26