1

I'm learning Android MVP architecture given here. Based on the example I created my own simple app that just displays list with recyclerview with pull to refresh functionality.

When list is pulled I want first to clear the recyclerview and then reload the data again from the repository (with fake latency delay). But, when I clear the data inside RecyclerViewAdpater, all data inside repository are also being cleared and there is nothing to show. I just can't understand the reason.

Here's my activity that creates both Presenter and View (that is Fragment):

    protected void onCreate(Bundle savedInstanceState) {

            mainFragment = MainFragment.newInstance();

            FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
            transaction.add(R.id.contentFrame, mainFragment);
            transaction.commit();

            new MainPresenter(new MainDataRepository(), mainFragment);
    }

Here's my Fragment (MainFragment) - ATTENTION: updateList(null) - This is where it clears all data, including inside Repository:

    public MainFragment() {
    }

    public static MainFragment newInstance() {
        return new MainFragment();
    }

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        //....

        swipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
            @Override
            public void onRefresh() {
                recyclerAdapter.updateList(null); // **This is where it clears all data, including inside Repository**

                Handler handler = new Handler();
                handler.postDelayed(new Runnable() {
                    @Override
                    public void run() {
                        mPresenter.loadList(); // to reload the list
                    }
                }, 1500);
            }
        });

        //...
    }

    @Override
    public void onResume() {
        super.onResume();

        Handler handler = new Handler();
        handler.postDelayed(new Runnable() {
            @Override
            public void run() {
                mPresenter.loadList();
            }
        }, 3000);
    }

    @Override
    public void setPresenter(MainContractor.Presenter presenter) {
        mPresenter = presenter;
    }

    @Override
    public void showList(List<String> mainDataList) {
        if(recyclerAdapter == null) {
            recyclerAdapter = new RecyclerAdapter(mainDataList);
            recyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
            recyclerView.setAdapter(recyclerAdapter);
        }else{
            recyclerAdapter.updateList(mainDataList);
        }
    }

Here's my presenter (MainPresenter):

    public MainPresenter(MainDataRepository mainDataRepository, MainContractor.View view){
        mMainDataRepository = mainDataRepository;
        mMainContractorView = view;

        view.setPresenter(this);
    }

    @Override
    public void loadList() {
        ArrayList<String> strings = mMainDataRepository.getList();

        mMainContractorView.showList(strings);
    }

Here's my repository (MainDataRepository):

private ArrayList<String> repositoryList;

    public MainDataRepository() {
        createList();
    }

    private void createList() {
        if(repositoryList == null){
            repositoryList = new ArrayList<>();
        }

        for (int i = 1; i <= 10; i++) {
            repositoryList.add("Item " + i);
        }
    }

    public ArrayList<String> getList(){
        return repositoryList;
    }

And the last one, This is how I am updating recyclerview inside RecyclerAdapter:

public class RecyclerAdapter extends RecyclerView.Adapter<RecyclerAdapter.MyViewHolder> {

    private List<String> stringsList;

    public RecyclerAdapter(List<String> stringsList) {
        this.stringsList = stringsList;
    }

    public void updateList(List<String> newStrings){
            if(newStrings != null){
                stringsList = newStrings;
            }else{
                stringsList.clear();
            }
            notifyDataSetChanged();
        }

       //....
}

Why updateList mehod inside RecyclerAdapter also clears the data inside repository that is ArrayList<String> repositoryList?

SpiralDev
  • 7,011
  • 5
  • 28
  • 42
  • You can take a look at this sample project http://github.com/mmirhoseini/marvel and this article https://hackernoon.com/yet-another-mvp-article-part-1-lets-get-to-know-the-project-d3fd553b3e21 to get more familiar with MVP. – Mohsen Mirhoseini Dec 29 '16 at 09:03

1 Answers1

1

It is because you have reference to the same object. Here where you return your list from Repository, better option is to return its copy:

public ArrayList<String> getList(){
    return new ArrayList<>(repositoryList);
}

Then it will be another object with copied items.

Orest Savchak
  • 4,529
  • 1
  • 18
  • 27
  • Your tweak got it working correctly! But I though that this `mMainContractorView.showList(strings);` would pass `strings` object by value not reference. Is not Java passing by-value in this scenerio? – SpiralDev Dec 28 '16 at 14:11
  • @Umarov it is pass-by-value, you pass a list, then you assign it to other reference, then you clear it, but it is still the same list. pass-by-reference mean that if you assign something to the reference you past, it will override the value in incoming reference, and pass-by-value means that new reference will hold your object, and after assigning something to it, you will just lose a reference to previous object. you can read more in related questions, there are a lot of explanations – Orest Savchak Dec 28 '16 at 14:16
  • Having read [this](http://stackoverflow.com/a/7893495/5985958) answer, I now got what pass-by-value really means. Thank you for your time! – SpiralDev Dec 28 '16 at 15:05