title: Combine MVVM and n-layered Architecture with Firestore in Backend
body: <p>I'm trying to re-structure my codebase to implement <code>MVVM</code> architecture and 3-layered architecture using Android Architecture Components.</p>
  <p>The <code>MainActivity.java</code> file contains a <code>Fragment</code>, and this <code>Fragment</code> is where most of the user interactions take place. The user provides an input, and based on that input I want to be able to hit the <code>Firebase Firestore</code> database to fetch the relevant data and then display it on the UI. This approach should follow the <code>Separation of Concerns</code> principle.</p>
  <p>Currently, upon receiving user input on the <code>Fragment</code>, I relay the input to its parent activity, i.e., <code>MainActivity.java</code> using an <code>Interface</code>, and then call a function <strong><code>FetchUserRequestedData</code></strong>. Once I receive the data, I display it appropriately on the UI (not a part of the Fragment).</p>
  <p>However, I want my 1) business logic layer, 2) database access layer, and 3) UI layer in separate packages. (To ensure that I follow the n-layered architecture pattern)</p>
  <p>Also, with <code>Firestore</code> as the database for my app, I'm not sure how the flow of both, input from user and output data from <code>Firestore</code> should be handled all the way from the data layer to the UI model. Note that <code>Firestore</code> database calls are asynchronous.</p>
  <p>How can I set up my codebase to follow the correct communication model between the three layers so that it follows both <code>MVVM</code> and n-layered architecture?</p>
  <p>Code is like this:</p>
  <p>MainActivity.java</p>
  <pre><code>public class MainActivity extends AppCompatActivity implements FragmentClass.DataPasser {
  
      FirebaseAuth firebaseAuth;
      FirebaseUser firebaseUser;
      private ArrayList&lt;DataType&gt; dataList = new ArrayList&lt;&gt;();
      DataProvider dataProvider = new DataProvider();
      .
      .
      .
  
      @Override
      protected void onCreate(Bundle savedInstanceState) {
          super.onCreate(savedInstanceState);
  
          setContentView(R.layout.activity_main);
          .
          .
          .
      }
  
      @Override
      protected void onStart() {
          super.onStart();
  
          .
          .
          .
      }
  
      @Override
      public void onUserInput(DataType input) {
          dataList = dataProvider.ProvideData(input);
          //update UI using this dataList
      }
  }
  </code></pre>
  <p>FragmentClass.java</p>
  <pre><code>public class FragmentClass extends CustomFragmentClass {
  
      DataPasser dataPasser;
  
      @Override
      public void onAttach(Context context) {
          super.onAttach(context);
          dataPasser = (DataPasser) context;
      }
  
      @Override
      public View onCreateView(LayoutInflater inflater, ViewGroup container,
                               Bundle inState) {
          super.onCreateView(inflater, container, inState);
  
          // Do app specific setup logic.
  
  
          return Content.getContentView();
      }
  
      @Override
      public void userProvidedInput(DataType userInput) { //part of CustomFragmentClass
          super.userProvidedInput(userInput);
  
          dataPasser.onUserInput(userInput); //defined in MainActivity.java
      }
  
  
      public interface DataPasser { //interface class to send user input to main activity
  
          public void onUserInput(DataType input);
      }
  
  }
  </code></pre>
  <p>DataProvider.java</p>
  <pre><code>public class DataProvider {
  
      private ArrayList&lt;DataType&gt; dataList = new ArrayList&lt;&gt;();
      DataFetcher dataFetcher = new DataFetcher();
  
      public ArrayList&lt;DataType&gt; ProvideData(String userInput) {
  
          dataList = dataFetcher(userInput);
          return dataList;
      }
  
      private ArrayList&lt;DataType&gt; dataFetcher(String userInput) {
          ArrayList&lt;DataType&gt; fetchedData = new ArrayList&lt;&gt;();
  
          fetchedData = dataFetcher.DatabaseCaller(userInput);
  
          return fetchedData;
      }
  }
  </code></pre>
  <p>DataFetcher.java</p>
  <pre><code>public class DataFetcher {
  
      ArrayList&lt;DataType&gt; dataList;
      FirebaseFirestore firestore = FirebaseFirestore.getInstance();
  
      public ArrayList&lt;DataType&gt; DatabaseCaller(String userInput) {
  
      //formulate query based on userInput
      //hit database and fetch dataList
      
          return dataList;
      }
  }
  </code></pre>