Skip to content

Infrastructure

rustie edited this page Mar 17, 2019 · 1 revision

Infrastructure Docs 1.0

Models

POJO models used by infrastructure. Contain annotations to inflate from various backends. Need to be transformed into domain models.

Transformers

Transform infrastructure to domain models

Repository pattern

Abstraction for infrastructure data access. As it is right now, we don't need to do anything other than scan all data objects from the backend, so the Repository.java interface is very empty.

public interface Repository<T> {

    public List<T> scanAll(final List<T> list, RepositoryCallback<T> callback);
}

We want our Repository operations to be mainly asynchronous, so we use shared memory model, passing in a final List<T> list to be populated as the data comes in. We may also want to trigger code to run after data is fetched from the backend, so we require RepositoryCallback<T> callback for each of our Repository operations. The callback can be used to update UI, trigger other network requests, etc. More info below in the next section.

Repositories at the moment have been written to interact with both Retrofitted BM backend service (BMService) as well as Firebase Firestore NoSQL database. Each repository simply wraps network requests for each, and optionally includes mechanism for caching. At the moment, Retrofit (as defined in dagger/modules/RetrofitModule) is configured with okhttp caching. Firestore also caches by default.

Repository callbacks

Repository callbacks allow arbitrary functions to be triggered on success or on failure of a repository access.

cafeRepository.scanAll((List<Cafe>) (List<?>) mCafeList, new RepositoryCallback<Cafe>() {
            @Override
            public void onSuccess() {

                mCafeLabel.setVisibility(View.VISIBLE);
                mCafeRecyclerView.setVisibility(View.VISIBLE);
                mCafeLabel.setOnClickListener(new View.OnClickListener() {
                    @Override
                    public void onClick(View v) {
                        if (cafeHidden) {
                            mCafeRecyclerView.setVisibility(View.VISIBLE);
                            mCafeLabel.setCompoundDrawablesRelativeWithIntrinsicBounds(0, 0, R.drawable.ic_up_arrow, 0);
                        } else {
                            mCafeRecyclerView.setVisibility(View.GONE);
                            mProgressBar.setVisibility(View.GONE);
                            mCafeLabel.setCompoundDrawablesRelativeWithIntrinsicBounds(0, 0, R.drawable.ic_down_arrow, 0);
                        }
                        cafeHidden = !cafeHidden;
                    }
                });
                mProgressBar.setVisibility(View.GONE);
                mCafeRecyclerView.setAdapter(new FoodPlaceAdapter(getContext(), mCafeList, FoodPlaceAdapter.FoodType.Cafe));

            }

            @Override
            public void onFailure() {
                mProgressBar.setVisibility(View.GONE);
                mRefreshWrapper.setVisibility(View.VISIBLE);
                Toast.makeText(getContext(), "Unable to retrieve cafe data, please try again",
                        Toast.LENGTH_SHORT).show();
            }
        });

Above, we are scanning backend for all cafes. On success, we're updating the UI, specifically enabling the underlying RecyclerView and toggle (and its associated listeners). On failure, we set the refresh wrapper and inform the user that data fetch failed via toast.

In general, we most likely should include at least a log or toast in these callbacks. However, they can be powerful in informing the user about the state of the app's data. Keep in mind the modularity this achieves; extending task of UI update/other updates outside the responsibility of the repository and into the responsibility of whichever context the repository is called (e.g. UI components like fragments or activities.)

Clone this wiki locally