Encapsulation in different layers of multiple datasources with MediatorLiveData

Multi tool use
can anyone explain me how to design the different layers of an android app with a MediatorLiveData?
I have the following concrete problem: I'm getting a list of appointments (with a start- and enddate) out of my (Room-)database in form of LiveData. In my view, I want to display the appointments in a normalized way, i.e. the height of the appointments depends on the duration and there should be "whitespace" between two appointments, if the following doesn't start at the enddate of the first appointment.
As a second feature the calendar in my view should only begin with the greatest integer hour, that is smaller than or equals to the earliest appointment in a set of appointments for several days. So I'm getting another LiveData out of my database, that contains a Calendar-object with the earliest startdate of the appointments in the specified period.
I'm now confused about the best design with the different abstraction layers.
At the data layer I've a DAO with the following methods:
@Dao
abstract class AppointmentDao {
//Loads the appointments in the specified period:
abstract LiveData> getAppointmentsInPeriod(String startDate, String endDate);
//Returns the minimum starttime of appointments in a specificed period:
abstract LiveData<Calendar> getEarliestBeginning(String startDate, String endDate);
}
As different android guides recommend, I created a repository layer, that just forwards the LiveDatas from the DAO.
I'm struggling now at the ViewModel. Here I have to load the appointments and fill the gaps between them.
But the list of appointments, that should go to the view depends on the list from the repository as well as on the earliest beginning.
So I think, it would be the best way to merge these LiveDatas in a MediatorLiveData, that is forwarded to the view.
So my approach was:
public AppointmentViewModel extends AndroidViewModel {
AppRepository repository;
LiveData<List<Appointment>> appointmentsFromDatabase;
LiveData<Calendar> earliestBeginning;
LiveData<List<Appointment>> appointmentsForView;
public AppointmentViwModel(Application app) {
repository = new AppRepository(app);
appointmentsForView = new MediatorLiveData();
appointmentsForView.addSource(appointmentsFromDatabase, appointments -> {
if(earliestBeginning != null && earliestBeginning.getValue() != null)
appointmentsForView = fillList(appointments, earliestBeginning.getValue());
});
appointmentsForView.addSource(earliestBeginning, beginning -> {
if(appointmentsFromDatabase != null && appointmentsFromDatabase.getValue() != null && !appointmentsFromDatabase.getValue().isEmpty())
appointmentsForView = fillList(appointmentsFromDatabase.getValue(), beginning);
});
}
public LiveData<List<Appointment>> getAppointmentsInPeriod(String startDate, String endDate) {
appointmentsFromDatabase = repository.getAppointmentsInPeriod(startDate, endDate);
earliestBeginning = repository.getEarliestBeginning(startDate, endDate);
return appointmentsForView;
}
private static LiveData<List<Appointment>> fillList(List<Appointment> appointments, Calendar beginning) {
//Fills the gaps in the given list
}
}
I don't actually know, where I have to check a null-reference and an empty collection, because I got so much Exceptions while programming, that I'm always checking on this stuff.
My doubts are in the handling of the MediatorLiveData. In the constructor it points to the class-variables, that are not inititalized, because they need some input values, that are fetched from the view, that calls the getAppointmentsInPeriod-method. But this method overwrites the objects every time, it is called.
So maybe someone can explain me the best practice of this design (pattern).
Thank you very much!

add a comment |
can anyone explain me how to design the different layers of an android app with a MediatorLiveData?
I have the following concrete problem: I'm getting a list of appointments (with a start- and enddate) out of my (Room-)database in form of LiveData. In my view, I want to display the appointments in a normalized way, i.e. the height of the appointments depends on the duration and there should be "whitespace" between two appointments, if the following doesn't start at the enddate of the first appointment.
As a second feature the calendar in my view should only begin with the greatest integer hour, that is smaller than or equals to the earliest appointment in a set of appointments for several days. So I'm getting another LiveData out of my database, that contains a Calendar-object with the earliest startdate of the appointments in the specified period.
I'm now confused about the best design with the different abstraction layers.
At the data layer I've a DAO with the following methods:
@Dao
abstract class AppointmentDao {
//Loads the appointments in the specified period:
abstract LiveData> getAppointmentsInPeriod(String startDate, String endDate);
//Returns the minimum starttime of appointments in a specificed period:
abstract LiveData<Calendar> getEarliestBeginning(String startDate, String endDate);
}
As different android guides recommend, I created a repository layer, that just forwards the LiveDatas from the DAO.
I'm struggling now at the ViewModel. Here I have to load the appointments and fill the gaps between them.
But the list of appointments, that should go to the view depends on the list from the repository as well as on the earliest beginning.
So I think, it would be the best way to merge these LiveDatas in a MediatorLiveData, that is forwarded to the view.
So my approach was:
public AppointmentViewModel extends AndroidViewModel {
AppRepository repository;
LiveData<List<Appointment>> appointmentsFromDatabase;
LiveData<Calendar> earliestBeginning;
LiveData<List<Appointment>> appointmentsForView;
public AppointmentViwModel(Application app) {
repository = new AppRepository(app);
appointmentsForView = new MediatorLiveData();
appointmentsForView.addSource(appointmentsFromDatabase, appointments -> {
if(earliestBeginning != null && earliestBeginning.getValue() != null)
appointmentsForView = fillList(appointments, earliestBeginning.getValue());
});
appointmentsForView.addSource(earliestBeginning, beginning -> {
if(appointmentsFromDatabase != null && appointmentsFromDatabase.getValue() != null && !appointmentsFromDatabase.getValue().isEmpty())
appointmentsForView = fillList(appointmentsFromDatabase.getValue(), beginning);
});
}
public LiveData<List<Appointment>> getAppointmentsInPeriod(String startDate, String endDate) {
appointmentsFromDatabase = repository.getAppointmentsInPeriod(startDate, endDate);
earliestBeginning = repository.getEarliestBeginning(startDate, endDate);
return appointmentsForView;
}
private static LiveData<List<Appointment>> fillList(List<Appointment> appointments, Calendar beginning) {
//Fills the gaps in the given list
}
}
I don't actually know, where I have to check a null-reference and an empty collection, because I got so much Exceptions while programming, that I'm always checking on this stuff.
My doubts are in the handling of the MediatorLiveData. In the constructor it points to the class-variables, that are not inititalized, because they need some input values, that are fetched from the view, that calls the getAppointmentsInPeriod-method. But this method overwrites the objects every time, it is called.
So maybe someone can explain me the best practice of this design (pattern).
Thank you very much!

add a comment |
can anyone explain me how to design the different layers of an android app with a MediatorLiveData?
I have the following concrete problem: I'm getting a list of appointments (with a start- and enddate) out of my (Room-)database in form of LiveData. In my view, I want to display the appointments in a normalized way, i.e. the height of the appointments depends on the duration and there should be "whitespace" between two appointments, if the following doesn't start at the enddate of the first appointment.
As a second feature the calendar in my view should only begin with the greatest integer hour, that is smaller than or equals to the earliest appointment in a set of appointments for several days. So I'm getting another LiveData out of my database, that contains a Calendar-object with the earliest startdate of the appointments in the specified period.
I'm now confused about the best design with the different abstraction layers.
At the data layer I've a DAO with the following methods:
@Dao
abstract class AppointmentDao {
//Loads the appointments in the specified period:
abstract LiveData> getAppointmentsInPeriod(String startDate, String endDate);
//Returns the minimum starttime of appointments in a specificed period:
abstract LiveData<Calendar> getEarliestBeginning(String startDate, String endDate);
}
As different android guides recommend, I created a repository layer, that just forwards the LiveDatas from the DAO.
I'm struggling now at the ViewModel. Here I have to load the appointments and fill the gaps between them.
But the list of appointments, that should go to the view depends on the list from the repository as well as on the earliest beginning.
So I think, it would be the best way to merge these LiveDatas in a MediatorLiveData, that is forwarded to the view.
So my approach was:
public AppointmentViewModel extends AndroidViewModel {
AppRepository repository;
LiveData<List<Appointment>> appointmentsFromDatabase;
LiveData<Calendar> earliestBeginning;
LiveData<List<Appointment>> appointmentsForView;
public AppointmentViwModel(Application app) {
repository = new AppRepository(app);
appointmentsForView = new MediatorLiveData();
appointmentsForView.addSource(appointmentsFromDatabase, appointments -> {
if(earliestBeginning != null && earliestBeginning.getValue() != null)
appointmentsForView = fillList(appointments, earliestBeginning.getValue());
});
appointmentsForView.addSource(earliestBeginning, beginning -> {
if(appointmentsFromDatabase != null && appointmentsFromDatabase.getValue() != null && !appointmentsFromDatabase.getValue().isEmpty())
appointmentsForView = fillList(appointmentsFromDatabase.getValue(), beginning);
});
}
public LiveData<List<Appointment>> getAppointmentsInPeriod(String startDate, String endDate) {
appointmentsFromDatabase = repository.getAppointmentsInPeriod(startDate, endDate);
earliestBeginning = repository.getEarliestBeginning(startDate, endDate);
return appointmentsForView;
}
private static LiveData<List<Appointment>> fillList(List<Appointment> appointments, Calendar beginning) {
//Fills the gaps in the given list
}
}
I don't actually know, where I have to check a null-reference and an empty collection, because I got so much Exceptions while programming, that I'm always checking on this stuff.
My doubts are in the handling of the MediatorLiveData. In the constructor it points to the class-variables, that are not inititalized, because they need some input values, that are fetched from the view, that calls the getAppointmentsInPeriod-method. But this method overwrites the objects every time, it is called.
So maybe someone can explain me the best practice of this design (pattern).
Thank you very much!

can anyone explain me how to design the different layers of an android app with a MediatorLiveData?
I have the following concrete problem: I'm getting a list of appointments (with a start- and enddate) out of my (Room-)database in form of LiveData. In my view, I want to display the appointments in a normalized way, i.e. the height of the appointments depends on the duration and there should be "whitespace" between two appointments, if the following doesn't start at the enddate of the first appointment.
As a second feature the calendar in my view should only begin with the greatest integer hour, that is smaller than or equals to the earliest appointment in a set of appointments for several days. So I'm getting another LiveData out of my database, that contains a Calendar-object with the earliest startdate of the appointments in the specified period.
I'm now confused about the best design with the different abstraction layers.
At the data layer I've a DAO with the following methods:
@Dao
abstract class AppointmentDao {
//Loads the appointments in the specified period:
abstract LiveData> getAppointmentsInPeriod(String startDate, String endDate);
//Returns the minimum starttime of appointments in a specificed period:
abstract LiveData<Calendar> getEarliestBeginning(String startDate, String endDate);
}
As different android guides recommend, I created a repository layer, that just forwards the LiveDatas from the DAO.
I'm struggling now at the ViewModel. Here I have to load the appointments and fill the gaps between them.
But the list of appointments, that should go to the view depends on the list from the repository as well as on the earliest beginning.
So I think, it would be the best way to merge these LiveDatas in a MediatorLiveData, that is forwarded to the view.
So my approach was:
public AppointmentViewModel extends AndroidViewModel {
AppRepository repository;
LiveData<List<Appointment>> appointmentsFromDatabase;
LiveData<Calendar> earliestBeginning;
LiveData<List<Appointment>> appointmentsForView;
public AppointmentViwModel(Application app) {
repository = new AppRepository(app);
appointmentsForView = new MediatorLiveData();
appointmentsForView.addSource(appointmentsFromDatabase, appointments -> {
if(earliestBeginning != null && earliestBeginning.getValue() != null)
appointmentsForView = fillList(appointments, earliestBeginning.getValue());
});
appointmentsForView.addSource(earliestBeginning, beginning -> {
if(appointmentsFromDatabase != null && appointmentsFromDatabase.getValue() != null && !appointmentsFromDatabase.getValue().isEmpty())
appointmentsForView = fillList(appointmentsFromDatabase.getValue(), beginning);
});
}
public LiveData<List<Appointment>> getAppointmentsInPeriod(String startDate, String endDate) {
appointmentsFromDatabase = repository.getAppointmentsInPeriod(startDate, endDate);
earliestBeginning = repository.getEarliestBeginning(startDate, endDate);
return appointmentsForView;
}
private static LiveData<List<Appointment>> fillList(List<Appointment> appointments, Calendar beginning) {
//Fills the gaps in the given list
}
}
I don't actually know, where I have to check a null-reference and an empty collection, because I got so much Exceptions while programming, that I'm always checking on this stuff.
My doubts are in the handling of the MediatorLiveData. In the constructor it points to the class-variables, that are not inititalized, because they need some input values, that are fetched from the view, that calls the getAppointmentsInPeriod-method. But this method overwrites the objects every time, it is called.
So maybe someone can explain me the best practice of this design (pattern).
Thank you very much!


edited Dec 27 at 14:02


Fantômas
32.3k156288
32.3k156288
asked Dec 27 at 13:23
Naryxus
11
11
add a comment |
add a comment |
active
oldest
votes
Your Answer
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53945827%2fencapsulation-in-different-layers-of-multiple-datasources-with-mediatorlivedata%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
active
oldest
votes
active
oldest
votes
active
oldest
votes
active
oldest
votes
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Some of your past answers have not been well-received, and you're in danger of being blocked from answering.
Please pay close attention to the following guidance:
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53945827%2fencapsulation-in-different-layers-of-multiple-datasources-with-mediatorlivedata%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
SnCBUs,zjJaRS8gxtkAWztWMFTN l