I have this class
public class ClusterMapPresenter<T extends ClusterItem>{
private ClusterMapView<T> clusterMapView;
public ClusterMapPresenter(ClusterMapView<T> clusterMapView){
this.clusterMapView = clusterMapView;
}
public void createView() {
setItems(getMockItems());
}
private List<T> getMockItems() {
List<T> items = new ArrayList<>();
items.add( new SpeditionClusterItem(new Spedition(Constants.MOCK)));
return items;
}
public void setItems(List<T> clusterItems){
clusterMapView.setMarkers(clusterItems);
}
}
Where SpeditionClusterItem implements ClusterItem.
I only managed to make it work by adding the casting to T to
items.add((T)new SpeditionClusterItem(new Spedition(Constants.MOCK)));
However I don't really like this approach, is there a better way to design this class?
I'll add the next pieces of code:
public interface ClusterMapView<T extends ClusterItem> extends BaseView {
public void setMarkers(List<T> markers);
}
This interface is implemented in the follow activity:
public class Activity implements ClusterMapView<SpeditionClusterItem> {
private ClusterMapPresenter<SpeditionClusterItem> mClusterMapPresenter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
...
mClusterMapPresenter = new ClusterMapPresenter<>(this);
...
}
#Override
public void setMarkers(List<SpeditionClusterItem> markers) {
mMapFragment.addItemsToMap(markers);
}
}
The point is, I want the activity to show the method with the parameter set in the implementation.
Well, I kind of resolved it by separating the list retrieval from the presenter, adding the list in the constructor.
public ClusterMapPresenter(ClusterMapView<T> clusterMapView, List<T> clusterItems){
this.clusterMapView = clusterMapView;
this.clusterItems = clusterItems;
}
I am not really sure this is good design, but it works. Any suggestion on how to improve it are welcome.
Related
Following a brilliant tutorial I've come stuck with a casting issue .
The app is basically a stackoverflow api which uses retrofit and makes calls to retrieve questions and question details etc...
This all said and done I'm lost why it longer launches.
Something is wrong with the cast inn the base activity:
BaseActivity
public class BaseActivity extends AppCompatActivity {
private ControllerCompositionRoot mControllerCompositionRoot;
protected ControllerCompositionRoot getCompositionRoot() {
if(mControllerCompositionRoot == null) {
mControllerCompositionRoot = new ControllerCompositionRoot(
((CustomApplication) getApplication()).getCompositionRoot(),
this
);
}
return mControllerCompositionRoot;
}
}
which gets called inn this class activity
public class QuestionsListActivity extends BaseActivity implements QuestionsListViewMvcImpl.Listener {
private StackoverflowApi mStackoverflowApi;
private QuestionsListViewMvc questionsListViewMvc;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
questionsListViewMvc = getCompositionRoot().getViewMvcFactory().getQuestionListViewMvc(null);
questionsListViewMvc.registerListener(this);
mStackoverflowApi = getCompositionRoot().getStackoverflowApi();
setContentView(questionsListViewMvc.getRootView());
}
#Override
protected void onStart() {
super.onStart();
fetchQuestions();
}
private void fetchQuestions() {
mStackoverflowApi.fetchLastActiveQuestions(Constants.QUESTIONS_LIST_PAGE_SIZE)
.enqueue(new Callback<QuestionsListResponseSchema>() {
#Override
public void onResponse(Call<QuestionsListResponseSchema> call, Response<QuestionsListResponseSchema> response) {
if (response.isSuccessful()) {
bindQuestions(response.body().getQuestions());
} else {
networkCallFailed();
}
}
#Override
public void onFailure(Call<QuestionsListResponseSchema> call, Throwable t) {
networkCallFailed();
}
} );
}
private void bindQuestions(List<QuestionSchema> questionSchemas) {
List<Question> questions = new ArrayList<>(questionSchemas.size());
for (QuestionSchema questionSchema : questionSchemas) {
questions.add(new Question(questionSchema.getId(), questionSchema.getTitle()));
}
questionsListViewMvc.bindQuestions(questions);
}
private void networkCallFailed() {
Toast.makeText(this, R.string.error_network_call_failed, Toast.LENGTH_SHORT).show();
}
#Override
public void onQuestionClicked(Question question) {
QuestionDetailsActivity.start(this, question.getId());
}
}
I would understand first why the cast has to be made which is what I was following in the tutorial buttheres little way I can keep plugging at this wiithout understanding the whole concept of MVC etc..and the implications of how to implement that in an android app.
Any help would be greatly welcome and elaborations as well also.
repo - github
Register the custom application class in manifest.
I checked the repo and found the custom class is not registered. So your custom class is not used as application class.
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.
I am beginning to learn Guice, but I have already encountered a problem. When I try to bind TypeLiteral I receive Cannot resolve method 'to(anonymous com.google.inject.TypeLiteral<>. I tried to look for cause of the problem, but no effect. Maybe anyone knows how to solve it?
Here is the class where I want to use bind().
public class MainModule extends AbstractModule {
protected void configure(){
bind(DeckFactory.class).to(BlackjackDeckCreator.class);
bind(CardFactory.class).to(BlackjackCardCreator.class);
bind(PointsCalculator.class)
.to(BlackjackPointsCalculator.class);
bind(Logic.class)
.toProvider(CompositeGameLogicStrategyProvider.class);
// Problem
bind(new TypeLiteral<Randomizer<BlackjackCard>>() { })
.to(new TypeLiteral<BlackjackCardRandomizer>() {});
//
bind(DecisionTaker.class)
.toProvider(CompositeDecisionTakerProvider.class);
bind(StatisticPrinter.class)
.to(ConsoleStatisticPrinter.class);
bind(HitGameLogicStrategy.class)
.toProvider(HitGameLogicProvider.class);
bind(StandGameLogicStrategy.class)
.toProvider(StandGameLogicProvider.class);
install(new FactoryModuleBuilder().build(GameFactory.class));
install(new FactoryModuleBuilder()
.build(PlayerFactory.class));
bind(StatisticsTemplate.class)
.toProvider(StatisticsTemplateProvider.class);
}
}
Randomizer.java
public interface Randomizer<T extends Card> {
T randomizeCard(List<T> deck);
}
BlackjackCardRandomizer.java
public class BlackjackCardRandomizer implements Randomizer {
private static final Random RANDOM = new Random();
#Override
public Card randomizeCard(List deck) {
Integer randIndex = RANDOM.nextInt(deck.size());
return (Card) deck.get(randIndex);
}
}
Thanks in advance!
You should use the following instead:
bind(new TypeLiteral<Randomizer<BlackjackCard>>() { })
.to(BlackjackCardRandomizer.class);
Just because you have a TypeLiteral as interface doesn't mean you have to use type literals as implementation.
Also, change your extends:
public class BlackjackCardRandomizer implements Randomizer<BlackjackCard> {
private static final Random RANDOM = new Random();
#Override
public BlackjackCard randomizeCard(List<BlackjackCard> deck) {
Integer randIndex = RANDOM.nextInt(deck.size());
return (Card) deck.get(randIndex);
}
}
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;
}
}
I have an abstract class with a single abstract method; and a number of implementing classes (about 6).
The method returns an object that "needs" two parameters.
However, in some cases, only one of the two parameters is required.
Is there an elegant way to implement this case? (instead of return this parameter as empty)
public class NormResult {
protected List<String> normWords;
protected List<String> unNormWords;
public NormResult(List<String> normWords,List<String> unNormWords) {
this.normWords = normWords;
this.unNormWords = unNormWords;
}
public NormResult(List<String> normWords) {
this.normWords = normWords;
this.unNormWords = Collections.emptyList();
}
}
public abstract class AbstractNormalizer {
protected abstract List<NormResult> doNorm();
}
public class FirstNormImpl extends AbstractNormalizer {
protected List<NormResult> doNorm() {
List<String> normWords = new ArrayList<>(5);
List<String> unNormWords = new ArrayList<>(7);
NormResult result = new NormResult(normWords, unNormWords);
return result;
}
}
public class SecondNormImpl extends AbstractNormalizer {
protected List<NormResult> doNorm() {
List<String> normWords = new ArrayList<>(8);
NormResult result = new NormResult(normWords);
return result;
}
}
if you do this to members final:
protected final List<String> normWords;
protected final List<String> unNormWords;
then in the constructor you have to initialize them both... then you can set to an empty collection or a null reference the one you dont have/need
and your overloaded constructor can look like:
public NormResult(List<String> normWords, List<String> unNormWords) {
this.normWords = normWords;
this.unNormWords = unNormWords;
}
public NormResult(List<String> normWords) {
this(normWords, Collections.emptyList());
}
The two changes I would make:
Make the fields final
Use constructor telescoping
as in:
public NormResult(List<String> normWords) {
this(normWords(), Collections.emptyList());
}
to avoid even that simple "code duplication" of assigning values twice.
Beyond that; I agree with the comments; this approach looks reasonable.