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?

1

1 Answer 1

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.

Sign up to request clarification or add additional context in comments.

3 Comments

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?
@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
Having read this answer, I now got what pass-by-value really means. Thank you for your time!

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.