MVC - Two classes with same reference in Controller - java

I have been searching and can't seem to find the solution. I have two views, one controller, one model, and a Factory class. However the model is not important in this question.
I want to be able to use the same variable name for both classes depending on the user's choice. For example:
public class Controller {
public Controller(){
m = new Model();
}
//This method is called from Factory
/*Only one of these two will be called SetViewSwing() or SetViewKonsoll()*/
public void SetViewSwing(){
v = new View(this);
}
public void SetViewKonsoll(){
v = new ViewKonsoll(this);
}
}
And then further down in the controller class I could do something like:
v.updateGui(String text);
So depending on if SetViewSwing is called or SetViewKonsoll is called I want to assign the class to v, which can I then use later on in my controller class to execute methods in the viewclass the user selected

I don't know what you are going to do. But according to your question you want to access same view variable from controller so you need to follow this. You need a interface for this.
Declare a Common interface
public interface CommonView {
void updateGui(String text);
}
Then you have to implement this interface to both concrete view classes
public class View implements CommonView {
public View(ViewController viewController) {
}
#Override
public void updateGui(String text) {
System.out.println("Swing View");
}
}
And another class
public class ViewKonsoll implements CommonView {
public ViewKonsoll(ViewController viewController) {
}
#Override
public void updateGui(String text) {
System.out.println("KonsolView");
}
}
Then At Controller you can define like this
public class ViewController {
Model m;
CommonView v;
ViewController(){
m = new Model();
}
public void SetViewSwing(){
v = new View(this);
}
public void SetViewKonsoll(){
v = new ViewKonsoll(this);
}
}
Then you can set view from your controller or any places and call v.updateGui(String text) .

Related

How to unit test observer called from a private method?

I have a view model class, SampleViewModel, that has an observer, DataSourceObserver, whose event's (e.g. onDataUpdated) are triggered from a private method of the view model's data source class.
I am trying to add a unit test for how the view model's observer handles the onDataUpdated.
#HiltViewModel
public class SampleViewModel extends ViewModel {
private final #NonNull ViewModelDataSource viewModelDataSource;
private final #NonNull ViewModelDataSource.DataSourceObserver observer = new ViewModelDataSource.DataSourceObserver() {
#Overrode
public void onDataUpdated(){
// some sort of handling
}
};
#Inject
public SampleViewModel(final #NonNull ViewModelDataSource dataSource){
viewModelDataSource = dataSource;
viewModelDataSource.setObserver(observer);
}
}
public class ViewModelDataSource{
public interface DataSourceObserver {
void onDataUpdated();
}
private final ContactObservers.Observer contactObserver = new ContactObservers.Observer(){
#Override
public void onContactUpdated(){
if (myObserver != null){
myObserver.onDataUpdated();
}
}
};
private #Nullable DataSourceObserver myObserver;
#Inject
public ViewModelDataSource(){
// other initialization here
}
public void setObserver(DataSourceObserver observer){
myObserver = observer;
}
}
I have Mockito for mocking/stubbing objects, but I have no idea how to approach such a problem so that I can at least trigger something like observer.onDataUpdated and verify the method calls within the handling of onDataUpdated
Found a solution to use ArgumentCaptor to capture the initialized observer in the view model when viewModelDataSource.setObserver(observer); is called.
In my unit test:
ArgumentCaptor<ViewModelDataSource.DataSourceObserver> capturedObserver = ArgumentCaptor.forClass(ViewModelDataSource.DataSourceObserver.class);
SampleViewModel viewModel = new SimpleViewModel( ...);
assertNotNull(capturedObserver);

Java - Overriding method which has generic type parameter and type casting it while invoking it

I have a utility class OldRemote which has been deprecated now, but still it will be used for a while till the new class NewRemote is stable. And both the utility classes has the same method names and parameters, But the return type pojo classes are different. Even return type pojo structure is same, but naming is different.
In simple, both the function return types are pojo's with different field names.
Is there any generic way to handle this below usecase ?
I have created a service interface which has the generic method contract of both old and new class.
public interface RemoteService {
//contract [ return type is object to receive all/any Pojo classes ]
Object turnOnTV();
static Service GetRemoteservice(boolean isOldRemote){
if(isOldRemote){
return new OldRemote();
}
return new NewRemote();
}
}
OldRemote Class
public class OldRemote implements RemoteService{
#Override
public OldPojo turnOnTV() {
OldPojo oldPojo = new OldPojo();
System.out.println("OldPojo");
return oldPojo;
}
}
NewRemote Class
public class NewRemote implements Service{
#Override
public NewPojo turnOnTV() {
NewPojo newPojo = new NewPojo();
System.out.println("NewPojo");
return newPojo;
}
}
Demo usage of above implementation.
public class DemoTvRemote {
public static void main(String[] args) {
RemoteService remoteService1 = RemoteService.GetRemoteservice(true);
OldPojo oldRemote = (OldPojo) remoteService1.turnOnTV();
RemoteService remoteService2 = RemoteService.GetRemoteservice(false);
NewPojo shr = (NewPojo) Service2.test();
}
}
This above code works fine. But the problem is I don't want to type cast in all the places where turnOnTV() is used in my entire code base. Even If I have to do that, I will have to write a condition to switch between OldPojo and NewPojo where ever the turnOnTV() is invoked.
Is there any way to solve this problem ?
You could create a base class or interface they both extend/implement.
public abstract class RemoteServiceBase<E> {
public abstract E turnOnTv();
}
public class NewRemoteService extends RemoteServiceBase<NewRemotePojo >{
public NewRemotePojo turnOnTv() {
return new NewRemotePojo();
}
}
public class OldRemoteService extends RemoteServiceBase<OldRemotePojo >{
public OldRemotePojo turnOnTv() {
return new OldRemotePojo();
}
}
This would still only work if you know the service type. Otherwise you work with the common generic type as one would expect.
We can deal with this with the following approach :
1) We can create a dummy POJO class in a common location with having the reference of both OldPojo and NewPojo as data members
public class CommonPojo {
OldPojo oldPojo;
NewPojo newPojo;
public void setOldPojo(OldPojo oldPojo){
this.oldPojo=oldPojo;
}
public void setNewPojo(NewPojo newPojo){
this.newPojo=newPojo;
}
public OldPojo getOldPojo(){
return oldPojo;
}
public NewPojo getNewPojo(){
return newPojo;
}
}
2)We can write a Utility method as follow which can give an object of commonpojo :
public class CommonRemote {
public static CommonPojo turnOnTv(Boolean isOldRemote){
CommonPojo commonPojo = new CommonPojo
if(isOldRemote){
OldPojo oldPojo =new OldPojo();
commonPojo.setOldPojo(oldPojo);
}else{
NewPojo newPojo =new NewPojo();
commonPojo.setNewPojo (newPojo);
}
}
}
3) Use this method as turnOnTv() as Follows :
public class DemoTvRemote {
public static void main(String[] args) {
CommonPojo remote1 = CommonRemote.turnOnTv(true);
OldPojo oldRemote = remote1.getOldPojo();
CommonPojo remote2 = CommonRemote.turnOnTv(false);
NewPojo newRemote = remote2.getNewPojo();
}
}
with this approach with little changes in code We can achieve your requirement without any typecasting.

Multiple Activities Implementing Same Listener

I know there are similar questions but it still doesn't answer my question in the manner I need for my current situation.
I have three activity presenters that each need to call a certain data remotely which will therefore call the activity presenter back when data arrives. To create this data listener I created an interface listener and since all three Presenters ask for the same data and retrieve it, all three presenters implement this interface listener.
Interface listener:
interface ListenerInterface {
onGotData();
}
Presenter one:
class PresenterOne implements ListenerInterface{
public void getData() {
DataManager dataManager = new DataManager();
dataManager.getData(this);
}
#Override
public void onGotData(Data data) {
//Do something with data
}
}
Presenter two very similar to presenter one:
class PresenterTwo implements ListenerInterface{
public void getData() {
DataManager dataManager = new DataManager();
dataManager.getData(this);
}
#Override
public void onGotData(Data data) {
//Do something with data
}
}
Assume Presenter three is exactly the same as the previous. The data manager class:
class DataManager {
public void getData(final ListenerInterface listener) {
//Gets data
addOnCompleteListener(new OnCompleteListener<Data data > () {
#Override
public void onComplete (#NonNull DataCall < Data > dataCall) {
listener.onGotData(dataCall.getResults());
}
});
}
}
Would doing so someone call all three presenters since the interface is the one doing the calling or only call the presenter that is passed? Is there anything I should worry about if I followed way? If anyone who knows the Android framework well could provide a detailed answer so I could learn from it more that would be great.
The reason I want to do this is I want to communicate through interfaces between classes.
Sorry if this question is simple for some people but I am still learning.
Thank you very much in advance.
you can use RxBus implementation to make global event (e.g. your onGotData).
First you have to create RxBus class.
public class RxBus {
private static RxBus instance;
private PublishSubject<Event> subject = PublishSubject.create();
public static synchronized RxBus getInstance() {
if (instance == null) {
instance = new RxBus();
}
return instance;
}
private RxBus(){}
public void postEvent(Event event){
subject.onNext(event);
}
public Observable<Event> getEvents(){
return subject;
}
}
And now, you should subscribe to it in BaseActivity or something like this (depends or your project structure).
private RxBus rxbus;
private Subscription rxBusSubscription;
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
rxBus = RxBus.getInstance();
}
#Override
protected void onResume() {
super.onResume();
if (shouldSubscribeRxBus()) {
rxBusSubscription = rxBus.getEvents()
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(event -> {
if (event.getEventType() == Event.EventType.DATA_RECEIVED) {
onGotData(data);
}
});
}
}
Now implement you onGotData as you want.
When you catch data received call:
class DataManager {
public void getData(final ListenerInterface listener) {
//Gets data
addOnCompleteListener(new OnCompleteListener<Data data > () {
#Override
public void onComplete (#NonNull DataCall < Data > dataCall) {
RxBus.getInstance().postEvent(new GotDataEvent(dataCall.getResults()));
}
});
}
}
You can create your Event classes structure as you want.

MVP pattern for retriving model

i'm developing an android app using MVP pattern.
I'd like to have different presenters, and each one implements getItems, that call a getAll static method of the associated model.
I thought to use generics, ended up like this:
public class BasePresenter<T> {
protected T mModel;
List getItems() {
mModel.getAll();
}
}
public class Presenter extends BasePresenter<Model> {
}
but i cannot access getAll methods using generics, because is not an Object's method.
Since for me would be dumb to write the same boring method getAll() for all presenter, changing only the model, is there there any way to accomplish that?
I'm asking because even in Google's official MVP guide, it use always the same method to retrive data, overriding it on each presenter, and i'm hoping that there is a better way.
I thought to "cast" the superclass mModel, but i don't know how and if it's possible to do, though.
Try this
public class BasePresenter<M extends BaseModel<M>> {
#Nullable
private M mModel;
#Nullable List<M> getItems() {
if (mModel != null) {
return mModel.getModelList();
}
return null;
}
}
And the BaseModel is
public abstract class BaseModel<M> {
private List<M> modelList;
public List<M> getModelList() {
return modelList;
}
public void setModelList(List<M> modelList) {
this.modelList = modelList;
}
}
Sub model
public class LoginModel extends BaseModel<LoginModel> {
#Override
public List<LoginModel> getModelList() {
return super.getModelList();
}
#Override
public void setModelList(List<LoginModel> modelList) {
super.setModelList(modelList);
}
}
And finally presenter is like this
public class LoginPresenter extends BasePresenter<LoginModel> {
//do your code
}
Hope it helps you.
Maybe this can help you:
List getItems(){
if(mModel instanceof TheSuperClassOrInterface){
return ((TheSuperClassOrInterface)mModel).getAll();
}else{
return null;
}
}

How to call Activity method from Presenter in Clean architecture?

I am developing an app where I am using clean architecture. In presenter, when something comes to method onCompleted then I must call function from Main activity.
this is my Presenter:
public class CheckInPresenter implements Presenter {
UseCase postCheckInUseCase;
Context context;
#Inject
CheckInPresenter(#Named("putCheckIn") UseCase postCheckInUseCase){
this.postCheckInUseCase = postCheckInUseCase;
}
public void initialize(){this.initializeCheckIn();}
public void initializeCheckIn(){this.putCheckIn();}
public void putCheckIn(){
this.postCheckInUseCase.execute(new CheckInSubscriber());
}
#Override
public void resume() {
}
#Override
public void pause() {
}
#Override
public void destroy() {
}
private final class CheckInSubscriber extends DefaultSubscriber<EventEntity>{
#Override
public void onCompleted() {
Log.d("onCompleted", "OnCompleted");
}
#Override
public void onError(Throwable e) {
Log.d("onError", "OnError: " + e.getMessage());
}
#Override
public void onNext(EventEntity eventEntity) {
Log.d("onNext", "OnNext");
}
}
}
And this is my function from MainActivity that I have to call:
public void getDataForToolbar() {
SharedPreferences sharedPreferences = getSharedPreferences(getResources().getString(R.string.Account_json), Context.MODE_PRIVATE);
final String account = sharedPreferences.getString(getResources().getString(R.string.account_json), null);
if (account != null) {
Gson gson = new Gson();
mAccount = gson.fromJson(account, AccountModel.class);
for (CompanyModel com : mAccount.getCompanies()) {
String name = com.getName();
company_name.setText(name);
logo_url = com.getLogo_url();
}
if (logo_url == null || logo_url.isEmpty()) {
Picasso
.with(this)
.load(R.drawable.default_company)
.resize(70, 58)
.transform(new RoundedTransformation(8, 0))
.into(toolbarImage);
} else {
picassoLoader(this, toolbarImage, logo_url);
}
String username = mAccount.getUsername();
if(mAccount.getStatus()){
aUsername.setText(username + "/" + getResources().getString(R.string.on_duty));
aUsername.setBackgroundColor(ContextCompat.getColor(mContext, R.color.colorGreen));
}else{
aUsername.setText(username + "/" + getResources().getString(R.string.off_duty));
aUsername.setBackgroundColor(ContextCompat.getColor(mContext, R.color.colorWhite));
}
}
}
Could someone helps me how to call this function into my onCompleted method in Presenter? Thanks in advance.
If you want to call some Activity's function from another object, you'll have to pass Activity's reference to that object. This means that you need to add Activity parameter to presenter's constructor.
Side note
I know that what you're implementing is called a "clean architecture" in many places (including the official MVP tutorials by Google), but you might want to read my posts on the subject in order to get an alternative view on what "clean" on Android should look like.
Why activities in Android are not UI elements
MVC and MVP architectural patterns in Android
Create interface IView and make your Activity to implement it.
In IView create method void getDataForToolbar();
I see #Inject annotation in your CheckInPresenter, so if you are using Dagger 2, update you Dagger module's constructor with IView, create a provider method for it and provide it for CheckInPresenter in this module.
Place IView in constructor of CheckInPresenter and update provider method for CheckInPresenter in Dagger module and Dagger component initialization in your Activity.
For example, it might look like this:
public class YourActivity implements IView {
...
}
#Module
public class YourModule {
private IView view;
public YourModule(IView view) {
this.view = view;
}
#Provides
public IView provideView() {
return view;
}
#Provides
#YourScope
public Presenter providePresenter() {
return new YourPresenter(view);
}
}
Just complete your existing Presenter and Module with IView.
After that call in your onCompleted method view.getDataForToolbar().

Categories

Resources