Android: How to best pass data to a view? - android

I have a view that displays all the levels of my game. These levels are read by the activity and then passed into the view. I could read them from the view, but it's not really its responsibility, and I'm a fan of separation of concerns.
Right now, I'm calling a setter for this:
((GameView) findViewById(R.id.game)).setLevels(loadLevels());
However, I don't like the fact that the view will be dysfunctional if I forget to call the setter. Is there a better way to pass the levels in?

It is also a bit a matter of preference. Theoretically it's perfectly fine to pass the levels as you're doing. Alternatively, if you need more than just set the levels, but provide further functionalities (i.e. also saving of levels) I normally use a separate class responsible for handling such things (i.e. a Repository, some "Manager" class etc...). This class is then passed into the View on the constructor preferably s.t. one is forced to provide it. Of course, in order to separate things, I use interfaces rather than specific implementations s.t. it may then look as follows:
public class MyView {
public MyView(ILevelLoader levelLoader){
this.levelLoader = levelLoader;
}
...
}
Often, this may not work, because the view is something instantiated by the framework directly rather than by the application. In such a situation you're forced to do it through an appropriate setter. It is some sort of MVC/MVP pattern.
Just for your interest, you might also want to take a look at IoC containers and dependency injection. Guice provided by Google is a nice framework I've already used on Android.

I hope I didn't miss the point, but here goes:
Generally you have either a function setting something (like the text for a textview), or an attribute you set in the xml.
Take a look over at this answer I got on a question: How to layout a 'grid' of images in the center of the screen
There are some things the custom view needs, but lets take an example: 'numColumns'.
you can set it using setNumColumns (that would be the equivalent of your loadLevels() ? )
you can ignore it, it'll revert to default.
you can set it as an attribute lik so: app:numColumns="3"
You can try to use the attribute or the default in the class to accomplish this.

Make your view an abstract class with an abstract method getLevels()? This way, when you instantiate the class if you forget to pass the levels in your code won't compile.
Whether or not this is better is a matter of taste I guess :)

Related

Android MVP (Repository pattern) get Camera/Gallery Image?

I am trying to implement MVP architecture using google sample code for mvp. I have an activity as View that has a presenter and model. On button click user can capture and save image in external storage. And on capture click, I also need to play a sound.
I am not sure which code should be put in which class because I cannot put camera capture and play sound code in Activity (which I treat as view) to keep the view as dumb as possible and I cannot put that code in Presenter because it uses Android framework classes (context etc).
So, the only option is to put it in model but in sample code, model only has Repositories (that I believe is relevant to data sources only local/remote).
How to put this code in model and how to link it with other components like View and Presenter? Any guidelines?
Here's one way you can go about solving an issue like that.
Your problem is that some code makes sense to go into a presenter, however it's too Androidy, so you can simply interface around it.
What you basically need is two things that can do certain functions.
interface CapturingSoundPlayer {
void playSound();
}
interface ImageCapturer {
void captureImage();
}
Please note that names and method signatures are up to you and what you need, I am merely using them to make a point.
Now it's perfectly safe for your application to have those two interfaces as dependencies, they have nothing to do with Android, we have simply take then technology out of the equation and only left the behaviour.
You need to pass these dependencies to your presenter and use them whenever needed.
class Presenter {
private final CapturingSoundPlayer soundPlayer;
private final ImageCapturer capturer;
Presenter(CapturingSoundPlayer soundPlayer, ImageCapturer capturer) {
this.soundPlayer = soundPlayer;
this.capturer = capturer;
}
void onCaptureButtonClicked() {
soundPlayer.playSound();
capturer.captureImage();
}
}
Now the implementation for those interfaces can be completely separate from your Activity, making your view still stupid.
Those interfaces (and their implementation) are simply logical units/entities that your presenter uses to split up the logic. I simply think of the functions of "capture" and "playSound" as simple actions, just like view.showLoading, and your presenter plays an orchestrator, it uses "something" to manipulate the view, which is the view interface, and it uses something else to manipulate sound, which is the interface for doing that.
if repositories are considered to be data sources, then in my opinion those helpers don't fit under that definition.
If you have a utility to retrieve the images that has been captured, that would basically can be considered as a repo for your images, but simply taking an image, is just another action.
You can structure/organise them as you feel fit, but just because you are using MVP, not every class you create has to be either one of those letters (M/V/P).
Sometimes any of those layers will need classes that logical units to do something, so that you have better separation of concerns.
Consider you have quite complex formatting logic, it would make sense to separate that in a separate class other than the presenter, but does that mean that the separate class is now model? It could, but it doesn't have to be.

Why android made View a base class but not an interface?

Recently I was thinking about View hierarchy in android and I faced with question in my mind, why Android SDK have base class View, but not, for example, interface View and base class BaseView.
As I know similar situation we have, for example, for Collections in Java. We have interface List and abstract class AbstractList, which implements it. Thus, we can provide on the one side a common logic for all 'sub'-views and on the other side common interface for, for example, mocking it in testing or something like that.
But instead of that, we need to use in tests emulator to retrieve some context, that we will pass to constructor of our 'stub' view, or for example mock context somehow (using robolectric, or try to mock yourself).
Moreover, I think it would be better to have sub-interfaces for TextView, EditText, or something like that. So, for example, if you have to implement your own CustomView class, you would need to create an interface CustomView and it's implementor. Something like: class MyCustomView extends BaseView implements CustomView and if it is needed interface CustomView extends View. I think, besides it askes from your side to write more code, It could make development process more flexible. For example, as I said for tests or for providing recently popular MVP (in other words to provide more loose coupling for components).
I don't know, maybe I missed something, and this approach is bad in Android, so could you, please, explain me why it is bad, or maybe share your thoughts about how it could be, or maybe current approach is just more simple, or we need to restrict developer from creating custom implementations of View interface (for example there is have to be a context reference in view, or something like that), or it's not bad approach, but because of backward compatability we need to use old way?
I will glad to hear your advize or thoughts. Thank you.

Where to put helper methods?

I have a method that darkens a given hex color and percent. Currently, the only place I use this method is within one of my Activity classes (I may or may not end up using it in other classes later on).
public static int darkenColor(int color, int percent) { ... }
However, where should I put this method? Should I create a new class called Helpers that contains all of these methods that I may use only once throughout the entire app?
This is just a matter of choice. You can have Set of utility classes and have these helper methods to be in those classes. But, This method is for not used in one of your activity, and If you do not see that it will get reused in the near future in some other point, Put it as a private method inside your Activity. I say this because you do not want to over complicate the code and also By this way another developer can easily follow the flow of execution.
But after sometimes if you feel, that this code is getting reused, put that into a logically meaningful Utility class. When the code base is huge, you do not have any choice to follow a solid standardization of there to put your code, That is why there are things like Layered architectures etc.

Is there a way to customize the threshold for ViewPager scrolling?

I am not able to find a way to change the touch threshold for scrolling pages in ViewPager:
http://developer.android.com/reference/android/support/v4/view/ViewPager.html
Looking at the source code, ViewPager has a method called determineTargetPage that checks to see if the move touch gesture distance > threshold range, but looks like there's no way to modify this range.
Any suggestions on how I can control this threshold (if at all possible)?
Going out on a bit of a limb here; I have no doubt that you may have to tweak this concept and/or code.
I will recommend what I did in the comments above; to extend ViewPager and override its public constructors, and call a custom method which is a clone of initViewPager() (seen in the source you provided). However, as you noted, mFlingDistance, mMinimumVelocity, and mMaximumVelocity are private fields, so they can't be accessed by a subclass.
(Note: You could also change these methods after the constructors are called, if you wanted to.)
Here's where it gets a bit tricky. In Android, we can use the Java Reflection API to make those fields accessible.
It should work something like this:
Class clss = getClass.getSuperClass();
Field flingField = clss.getDeclaredField("mFlingDistance"); // Of course create other variables for the other two fields
flingField.setAccessible(true);
flingField.setInt(this, <whatever int value you want>); // "this" must be the reference to the subclass object
Then, repeat this for the other two variables with whatever values you want. You may want to look at how these are calculated in the source.
Unfortunately, as much as I would like to recommend using Reflection to override the private method determineTargetPage(), I don't believe it's possible to do this--even with the expansive Reflection API.

Robolectric Custom Shadow Object

OOTB, Robolectric does not support Locales that well. Therefore, if your app is dependent on locales (which a lot of apps are if they are i18n'nd properly) this can be a royal pain. Long story short, I created my own ShadowFooGeocoder and ShadowFooAddress that allow me to simulate the locale I want. They're basically re-implementations of the existing shadows.
However, when I bind my class as such: bindShadowClass(ShadowFooGeocoder.class), this works great. At runtime, the correct shadow is returned. The problem is that I want to set up the simulations on this object and I'm not sure how. shadowOf(instance) where instance is an injected GeoCoder returns ShadowGeoCoder. I've tried working directly with the ShadowWrangler, but that also returns a ShadowGeocoder.
How can I get at my shadowed class that I've bound through the bindShadowClass(...) call so I can set my expectations (simulations)?
Note: This is a repost of the same question on the Robolectric group here. I posted here because my success rate of getting anyone to answer questions on the group is fairly low. I'm hoping for a better result here.
What I've basically done here is extend ShadowGeocoder like this:
#SuppressWarnings({"UnusedDeclaration"})
#Implements(Geocoder.class)
public class ShadowFooBarGeocoder extends ShadowGeocoder {
// implementation stuff
}
Then I would bind it using the bindShadowClasss(...) and when I retreive the shadow via the static shadowOf(...) call I get back a "ShadowGeocoder" which is an instance of ShadowFooBarGeocoder. I then cast it to that type and perform whatever work I need to.

Categories

Resources