Is there any way to avoid the use of instanceOf in Android? - android

We all agree that the use of instanceOf is usually not the best solution. There are plenty of examples in the web.
But lets consider for a second the following example, where we need to call a method from a fragment to its activity:
public class BaseActvity extends FragmentActivity implements ISomething {
#Override
public void doSomething();
}
Then lets say we have a fragment in the app that needs to call doSomething() :
public MyFragment extends Fragment() {
public void onCreate() {
public void onResume() {
Activity activity = getActivity();
if (activity != null && activity instanceOf ISomething) {
ISomething something = (ISomething) activity;
something.doSomething();
}
}
}
public interface ISomething {
void doSomething();
}
As you can see, we cannot guarantee that getActivity() will return an object of ISomething, so we check the type. An improvement would be to add an interface, but we would still to check the getActvity() return type to protect our code.
Because of the nature of the Android Framework and the getActivity() call, I can't find a better solution. Maybe someone can help with some input..
NOTE: Ive added an interface to follow the visitor pattern. Notice that I still have to use instanceOf to assure that the parent activity is implementing it.
Thank you .
Gaspar de Elais

You are correct, it would be better to define an interface in your Fragment and require the Activity to implement it. Then, in your onAttach() you cast your Activity to the interface in a try/catch and if it throws a ClassCastException you can throw your own exception.
public MyFragment extends Fragment {
private Callback mCallback;
public interface Callback {
void doSomething();
}
...
#Override
public void onAttach(Activity activity) {
try {
mCallback = (Callback)activity;
} catch (ClassCastException e) {
throw new IllegalArgumentException("Activity must implement Callback");
}
}
}
In fact, this is what is recommended/described in this Fragment page on the main Android developer site: http://developer.android.com/training/basics/fragments/communicating.html

You could take a look at the Visitor Pattern. Here is an explanation and some Java code.

Related

ClassCastException onAttach() when unit testing Android Fragment

I'm trying to test a Fragment that has in interface that must be implemented by the hosting Activity and gets casted to that specific interface's type through onAttach().
Problem: I'm not sure how to implement the necessary interface methods within an Android Unit Test or if it's even necessary to do so. Surprisingly, I haven't found any posts or forums that address this issue.
Test:
public class FragmentTest {
private ActivityForUnitTesting fragmentHostActivity;
private ExampleFragment fragmentToTest;
#Rule
public ActivityTestRule activityTestRule = new ActivityTestRule<>(ActivityForUnitTesting.class);
#Before
public void setUp() {
fragmentHostActivity = (ActivityForUnitTesting) activityTestRule.getActivity();
fragmentManager = fragmentHostActivity.getSupportFragmentManager();
fragmentToTest = new ExampleFragment();
}
#Test
public void testExample() {
fragmentManager.beginTransaction()
.replace(R.id.frame_layout_container, fragmentToTest)
.commit();
}
}
Fragment:
public class ExampleFragment extends Fragment {
private ExampleFragmentListener exampleFragmentListener;
...
#Override
public void onAttach(Context context) {
super.onAttach(context);
try {
exampleFragmentListener = (ExampleFragmentListener) context;
} catch (ClassCastException e) {
throw new ClassCastException(context.toString() + " must implement ExampleFragmentListener");
}
}
...
}
but when I try running a simple test I get:
java.lang.ClassCastException: com.example.package.ActivityForUnitTesting#1234567 must implement ExampleFragmentListener
at com.example.package.ExampleFragment.onAttach(ExampleFragment.java:)
I know that the issue is that my Unit Test ActivityForUnitTesting object does not implement the required interface methods. My question is, how do I safely implement those methods within my Unit Test. I haven't had any luck finding a similar question or a solid example.
I didn't find a solution to this, but I did find a "workaround". Instead of using onAttach(), explicitly set your listener through a public method.
public class ExampleFragment extends Fragment {
private ExampleFragmentListener exampleFragmentListener;
...
//#Override
//public void onAttach(Context context) {
// super.onAttach(context);
// try {
// exampleFragmentListener = (ExampleFragmentListener) context;
// } catch (ClassCastException e) {
// throw new ClassCastException(context.toString() + " must implement ExampleFragmentListener");
// }
//}
public void setExampleFragmentListener(ExampleFragmentListener exampleFragmentListener) {
this.exampleFragmentListener = exampleFragmentListener;
}
...
}
then, you should already have ExampleFragmentListener implemented in your host Activity. Just call
setExampleFragmentListener(ActivityOrClassThatImplementsExampleFragmentListener)
from wherever you perform your Activity setup. As a result, the test shouldn't complain about unimplemented methods.

Is it possible to skip onPause() method of BaseActivity in MainActivity when latter extends former? [duplicate]

I read this question and thought that would easily be solved (not that it isn't solvable without) if one could write:
#Override
public String toString() {
return super.super.toString();
}
I'm not sure if it is useful in many cases, but I wonder why it isn't and if something like this exists in other languages.
What do you guys think?
EDIT:
To clarify: yes I know, that's impossible in Java and I don't really miss it. This is nothing I expected to work and was surprised getting a compiler error. I just had the idea and like to discuss it.
It violates encapsulation. You shouldn't be able to bypass the parent class's behaviour. It makes sense to sometimes be able to bypass your own class's behaviour (particularly from within the same method) but not your parent's. For example, suppose we have a base "collection of items", a subclass representing "a collection of red items" and a subclass of that representing "a collection of big red items". It makes sense to have:
public class Items
{
public void add(Item item) { ... }
}
public class RedItems extends Items
{
#Override
public void add(Item item)
{
if (!item.isRed())
{
throw new NotRedItemException();
}
super.add(item);
}
}
public class BigRedItems extends RedItems
{
#Override
public void add(Item item)
{
if (!item.isBig())
{
throw new NotBigItemException();
}
super.add(item);
}
}
That's fine - RedItems can always be confident that the items it contains are all red. Now suppose we were able to call super.super.add():
public class NaughtyItems extends RedItems
{
#Override
public void add(Item item)
{
// I don't care if it's red or not. Take that, RedItems!
super.super.add(item);
}
}
Now we could add whatever we like, and the invariant in RedItems is broken.
Does that make sense?
I think Jon Skeet has the correct answer. I'd just like to add that you can access shadowed variables from superclasses of superclasses by casting this:
interface I { int x = 0; }
class T1 implements I { int x = 1; }
class T2 extends T1 { int x = 2; }
class T3 extends T2 {
int x = 3;
void test() {
System.out.println("x=\t\t" + x);
System.out.println("super.x=\t\t" + super.x);
System.out.println("((T2)this).x=\t" + ((T2)this).x);
System.out.println("((T1)this).x=\t" + ((T1)this).x);
System.out.println("((I)this).x=\t" + ((I)this).x);
}
}
class Test {
public static void main(String[] args) {
new T3().test();
}
}
which produces the output:
x= 3
super.x= 2
((T2)this).x= 2
((T1)this).x= 1
((I)this).x= 0
(example from the JLS)
However, this doesn't work for method calls because method calls are determined based on the runtime type of the object.
I think the following code allow to use super.super...super.method() in most case.
(even if it's uggly to do that)
In short
create temporary instance of ancestor type
copy values of fields from original object to temporary one
invoke target method on temporary object
copy modified values back to original object
Usage :
public class A {
public void doThat() { ... }
}
public class B extends A {
public void doThat() { /* don't call super.doThat() */ }
}
public class C extends B {
public void doThat() {
Magic.exec(A.class, this, "doThat");
}
}
public class Magic {
public static <Type, ChieldType extends Type> void exec(Class<Type> oneSuperType, ChieldType instance,
String methodOfParentToExec) {
try {
Type type = oneSuperType.newInstance();
shareVars(oneSuperType, instance, type);
oneSuperType.getMethod(methodOfParentToExec).invoke(type);
shareVars(oneSuperType, type, instance);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
private static <Type, SourceType extends Type, TargetType extends Type> void shareVars(Class<Type> clazz,
SourceType source, TargetType target) throws IllegalArgumentException, IllegalAccessException {
Class<?> loop = clazz;
do {
for (Field f : loop.getDeclaredFields()) {
if (!f.isAccessible()) {
f.setAccessible(true);
}
f.set(target, f.get(source));
}
loop = loop.getSuperclass();
} while (loop != Object.class);
}
}
I don't have enough reputation to comment so I will add this to the other answers.
Jon Skeet answers excellently, with a beautiful example. Matt B has a point: not all superclasses have supers. Your code would break if you called a super of a super that had no super.
Object oriented programming (which Java is) is all about objects, not functions. If you want task oriented programming, choose C++ or something else. If your object doesn't fit in it's super class, then you need to add it to the "grandparent class", create a new class, or find another super it does fit into.
Personally, I have found this limitation to be one of Java's greatest strengths. Code is somewhat rigid compared to other languages I've used, but I always know what to expect. This helps with the "simple and familiar" goal of Java. In my mind, calling super.super is not simple or familiar. Perhaps the developers felt the same?
There's some good reasons to do this. You might have a subclass which has a method which is implemented incorrectly, but the parent method is implemented correctly. Because it belongs to a third party library, you might be unable/unwilling to change the source. In this case, you want to create a subclass but override one method to call the super.super method.
As shown by some other posters, it is possible to do this through reflection, but it should be possible to do something like
(SuperSuperClass this).theMethod();
I'm dealing with this problem right now - the quick fix is to copy and paste the superclass method into the subsubclass method :)
In addition to the very good points that others have made, I think there's another reason: what if the superclass does not have a superclass?
Since every class naturally extends (at least) Object, super.whatever() will always refer to a method in the superclass. But what if your class only extends Object - what would super.super refer to then? How should that behavior be handled - a compiler error, a NullPointer, etc?
I think the primary reason why this is not allowed is that it violates encapsulation, but this might be a small reason too.
I think if you overwrite a method and want to all the super-class version of it (like, say for equals), then you virtually always want to call the direct superclass version first, which one will call its superclass version in turn if it wants.
I think it only makes rarely sense (if at all. i can't think of a case where it does) to call some arbitrary superclass' version of a method. I don't know if that is possible at all in Java. It can be done in C++:
this->ReallyTheBase::foo();
At a guess, because it's not used that often. The only reason I could see using it is if your direct parent has overridden some functionality and you're trying to restore it back to the original.
Which seems to me to be against OO principles, since the class's direct parent should be more closely related to your class than the grandparent is.
Calling of super.super.method() make sense when you can't change code of base class. This often happens when you are extending an existing library.
Ask yourself first, why are you extending that class? If answer is "because I can't change it" then you can create exact package and class in your application, and rewrite naughty method or create delegate:
package com.company.application;
public class OneYouWantExtend extends OneThatContainsDesiredMethod {
// one way is to rewrite method() to call super.method() only or
// to doStuff() and then call super.method()
public void method() {
if (isDoStuff()) {
// do stuff
}
super.method();
}
protected abstract boolean isDoStuff();
// second way is to define methodDelegate() that will call hidden super.method()
public void methodDelegate() {
super.method();
}
...
}
public class OneThatContainsDesiredMethod {
public void method() {...}
...
}
For instance, you can create org.springframework.test.context.junit4.SpringJUnit4ClassRunner class in your application so this class should be loaded before the real one from jar. Then rewrite methods or constructors.
Attention: This is absolute hack, and it is highly NOT recommended to use but it's WORKING! Using of this approach is dangerous because of possible issues with class loaders. Also this may cause issues each time you will update library that contains overwritten class.
#Jon Skeet Nice explanation.
IMO if some one wants to call super.super method then one must be want to ignore the behavior of immediate parent, but want to access the grand parent behavior.
This can be achieved through instance Of. As below code
public class A {
protected void printClass() {
System.out.println("In A Class");
}
}
public class B extends A {
#Override
protected void printClass() {
if (!(this instanceof C)) {
System.out.println("In B Class");
}
super.printClass();
}
}
public class C extends B {
#Override
protected void printClass() {
System.out.println("In C Class");
super.printClass();
}
}
Here is driver class,
public class Driver {
public static void main(String[] args) {
C c = new C();
c.printClass();
}
}
Output of this will be
In C Class
In A Class
Class B printClass behavior will be ignored in this case.
I am not sure about is this a ideal or good practice to achieve super.super, but still it is working.
Look at this Github project, especially the objectHandle variable. This project shows how to actually and accurately call the grandparent method on a grandchild.
Just in case the link gets broken, here is the code:
import lombok.val;
import org.junit.Assert;
import org.junit.Test;
import java.lang.invoke.*;
/*
Your scientists were so preoccupied with whether or not they could, they didn’t stop to think if they should.
Please don't actually do this... :P
*/
public class ImplLookupTest {
private MethodHandles.Lookup getImplLookup() throws NoSuchFieldException, IllegalAccessException {
val field = MethodHandles.Lookup.class.getDeclaredField("IMPL_LOOKUP");
field.setAccessible(true);
return (MethodHandles.Lookup) field.get(null);
}
#Test
public void test() throws Throwable {
val lookup = getImplLookup();
val baseHandle = lookup.findSpecial(Base.class, "toString",
MethodType.methodType(String.class),
Sub.class);
val objectHandle = lookup.findSpecial(Object.class, "toString",
MethodType.methodType(String.class),
// Must use Base.class here for this reference to call Object's toString
Base.class);
val sub = new Sub();
Assert.assertEquals("Sub", sub.toString());
Assert.assertEquals("Base", baseHandle.invoke(sub));
Assert.assertEquals(toString(sub), objectHandle.invoke(sub));
}
private static String toString(Object o) {
return o.getClass().getName() + "#" + Integer.toHexString(o.hashCode());
}
public class Sub extends Base {
#Override
public String toString() {
return "Sub";
}
}
public class Base {
#Override
public String toString() {
return "Base";
}
}
}
Happy Coding!!!!
I would put the super.super method body in another method, if possible
class SuperSuperClass {
public String toString() {
return DescribeMe();
}
protected String DescribeMe() {
return "I am super super";
}
}
class SuperClass extends SuperSuperClass {
public String toString() {
return "I am super";
}
}
class ChildClass extends SuperClass {
public String toString() {
return DescribeMe();
}
}
Or if you cannot change the super-super class, you can try this:
class SuperSuperClass {
public String toString() {
return "I am super super";
}
}
class SuperClass extends SuperSuperClass {
public String toString() {
return DescribeMe(super.toString());
}
protected String DescribeMe(string fromSuper) {
return "I am super";
}
}
class ChildClass extends SuperClass {
protected String DescribeMe(string fromSuper) {
return fromSuper;
}
}
In both cases, the
new ChildClass().toString();
results to "I am super super"
It would seem to be possible to at least get the class of the superclass's superclass, though not necessarily the instance of it, using reflection; if this might be useful, please consider the Javadoc at http://java.sun.com/j2se/1.5.0/docs/api/java/lang/Class.html#getSuperclass()
public class A {
#Override
public String toString() {
return "A";
}
}
public class B extends A {
#Override
public String toString() {
return "B";
}
}
public class C extends B {
#Override
public String toString() {
return "C";
}
}
public class D extends C {
#Override
public String toString() {
String result = "";
try {
result = this.getClass().getSuperclass().getSuperclass().getSuperclass().newInstance().toString();
} catch (InstantiationException ex) {
Logger.getLogger(D.class.getName()).log(Level.SEVERE, null, ex);
} catch (IllegalAccessException ex) {
Logger.getLogger(D.class.getName()).log(Level.SEVERE, null, ex);
}
return result;
}
}
public class Main {
public static void main(String... args) {
D d = new D();
System.out.println(d);
}
}
run:
A
BUILD SUCCESSFUL (total time: 0 seconds)
I have had situations like these when the architecture is to build common functionality in a common CustomBaseClass which implements on behalf of several derived classes.
However, we need to circumvent common logic for specific method for a specific derived class. In such cases, we must use a super.super.methodX implementation.
We achieve this by introducing a boolean member in the CustomBaseClass, which can be used to selectively defer custom implementation and yield to default framework implementation where desirable.
...
FrameworkBaseClass (....) extends...
{
methodA(...){...}
methodB(...){...}
...
methodX(...)
...
methodN(...){...}
}
/* CustomBaseClass overrides default framework functionality for benefit of several derived classes.*/
CustomBaseClass(...) extends FrameworkBaseClass
{
private boolean skipMethodX=false;
/* implement accessors isSkipMethodX() and setSkipMethodX(boolean)*/
methodA(...){...}
methodB(...){...}
...
methodN(...){...}
methodX(...){
if (isSkipMethodX()) {
setSKipMethodX(false);
super.methodX(...);
return;
}
... //common method logic
}
}
DerivedClass1(...) extends CustomBaseClass
DerivedClass2(...) extends CustomBaseClass
...
DerivedClassN(...) extends CustomBaseClass...
DerivedClassX(...) extends CustomBaseClass...
{
methodX(...){
super.setSKipMethodX(true);
super.methodX(...);
}
}
However, with good architecture principles followed in framework as well as app, we could avoid such situations easily, by using hasA approach, instead of isA approach. But at all times it is not very practical to expect well designed architecture in place, and hence the need to get away from solid design principles and introduce hacks like this.
Just my 2 cents...
IMO, it's a clean way to achieve super.super.sayYourName() behavior in Java.
public class GrandMa {
public void sayYourName(){
System.out.println("Grandma Fedora");
}
}
public class Mama extends GrandMa {
public void sayYourName(boolean lie){
if(lie){
super.sayYourName();
}else {
System.out.println("Mama Stephanida");
}
}
}
public class Daughter extends Mama {
public void sayYourName(boolean lie){
if(lie){
super.sayYourName(lie);
}else {
System.out.println("Little girl Masha");
}
}
}
public class TestDaughter {
public static void main(String[] args){
Daughter d = new Daughter();
System.out.print("Request to lie: d.sayYourName(true) returns ");
d.sayYourName(true);
System.out.print("Request not to lie: d.sayYourName(false) returns ");
d.sayYourName(false);
}
}
Output:
Request to lie: d.sayYourName(true) returns Grandma Fedora
Request not to lie: d.sayYourName(false) returns Little girl Masha
I think this is a problem that breaks the inheritance agreement.
By extending a class you obey / agree its behavior, features
Whilst when calling super.super.method(), you want to break your own obedience agreement.
You just cannot cherry pick from the super class.
However, there may happen situations when you feel the need to call super.super.method() - usually a bad design sign, in your code or in the code you inherit !
If the super and super super classes cannot be refactored (some legacy code), then opt for composition over inheritance.
Encapsulation breaking is when you #Override some methods by breaking the encapsulated code.
The methods designed not to be overridden are marked
final.
In C# you can call a method of any ancestor like this:
public class A
internal virtual void foo()
...
public class B : A
public new void foo()
...
public class C : B
public new void foo() {
(this as A).foo();
}
Also you can do this in Delphi:
type
A=class
procedure foo;
...
B=class(A)
procedure foo; override;
...
C=class(B)
procedure foo; override;
...
A(objC).foo();
But in Java you can do such focus only by some gear. One possible way is:
class A {
int y=10;
void foo(Class X) throws Exception {
if(X!=A.class)
throw new Exception("Incorrect parameter of "+this.getClass().getName()+".foo("+X.getName()+")");
y++;
System.out.printf("A.foo(%s): y=%d\n",X.getName(),y);
}
void foo() throws Exception {
System.out.printf("A.foo()\n");
this.foo(this.getClass());
}
}
class B extends A {
int y=20;
#Override
void foo(Class X) throws Exception {
if(X==B.class) {
y++;
System.out.printf("B.foo(%s): y=%d\n",X.getName(),y);
} else {
System.out.printf("B.foo(%s) calls B.super.foo(%s)\n",X.getName(),X.getName());
super.foo(X);
}
}
}
class C extends B {
int y=30;
#Override
void foo(Class X) throws Exception {
if(X==C.class) {
y++;
System.out.printf("C.foo(%s): y=%d\n",X.getName(),y);
} else {
System.out.printf("C.foo(%s) calls C.super.foo(%s)\n",X.getName(),X.getName());
super.foo(X);
}
}
void DoIt() {
try {
System.out.printf("DoIt: foo():\n");
foo();
Show();
System.out.printf("DoIt: foo(B):\n");
foo(B.class);
Show();
System.out.printf("DoIt: foo(A):\n");
foo(A.class);
Show();
} catch(Exception e) {
//...
}
}
void Show() {
System.out.printf("Show: A.y=%d, B.y=%d, C.y=%d\n\n", ((A)this).y, ((B)this).y, ((C)this).y);
}
}
objC.DoIt() result output:
DoIt: foo():
A.foo()
C.foo(C): y=31
Show: A.y=10, B.y=20, C.y=31
DoIt: foo(B):
C.foo(B) calls C.super.foo(B)
B.foo(B): y=21
Show: A.y=10, B.y=21, C.y=31
DoIt: foo(A):
C.foo(A) calls C.super.foo(A)
B.foo(A) calls B.super.foo(A)
A.foo(A): y=11
Show: A.y=11, B.y=21, C.y=31
It is simply easy to do. For instance:
C subclass of B and B subclass of A. Both of three have method methodName() for example.
public abstract class A {
public void methodName() {
System.out.println("Class A");
}
}
public class B extends A {
public void methodName() {
super.methodName();
System.out.println("Class B");
}
// Will call the super methodName
public void hackSuper() {
super.methodName();
}
}
public class C extends B {
public static void main(String[] args) {
A a = new C();
a.methodName();
}
#Override
public void methodName() {
/*super.methodName();*/
hackSuper();
System.out.println("Class C");
}
}
Run class C Output will be:
Class A
Class C
Instead of output:
Class A
Class B
Class C
If you think you are going to be needing the superclass, you could reference it in a variable for that class. For example:
public class Foo
{
public int getNumber()
{
return 0;
}
}
public class SuperFoo extends Foo
{
public static Foo superClass = new Foo();
public int getNumber()
{
return 1;
}
}
public class UltraFoo extends Foo
{
public static void main(String[] args)
{
System.out.println(new UltraFoo.getNumber());
System.out.println(new SuperFoo().getNumber());
System.out.println(new SuperFoo().superClass.getNumber());
}
public int getNumber()
{
return 2;
}
}
Should print out:
2
1
0
public class SubSubClass extends SubClass {
#Override
public void print() {
super.superPrint();
}
public static void main(String[] args) {
new SubSubClass().print();
}
}
class SuperClass {
public void print() {
System.out.println("Printed in the GrandDad");
}
}
class SubClass extends SuperClass {
public void superPrint() {
super.print();
}
}
Output: Printed in the GrandDad
The keyword super is just a way to invoke the method in the superclass.
In the Java tutorial:https://docs.oracle.com/javase/tutorial/java/IandI/super.html
If your method overrides one of its superclass's methods, you can invoke the overridden method through the use of the keyword super.
Don't believe that it's a reference of the super object!!! No, it's just a keyword to invoke methods in the superclass.
Here is an example:
class Animal {
public void doSth() {
System.out.println(this); // It's a Cat! Not an animal!
System.out.println("Animal do sth.");
}
}
class Cat extends Animal {
public void doSth() {
System.out.println(this);
System.out.println("Cat do sth.");
super.doSth();
}
}
When you call cat.doSth(), the method doSth() in class Animal will print this and it is a cat.

Android MVP Strategy

I am migrating my apps to MVP. Have taken hints on a static presenter pattern from this konmik
This is my brief MVP strategy. Removed most of the boilerplate and MVP listeners for brevity. This strategy has helped me orientation change proof my background processes. The activity correctly recovers from a normal pause compared to pause which is finishing the activity. Also the Presenter only has application context so it does not hold onto activity context.
I am not a java expert and this is my first foray into MVP and using a static presenter has made me uncomfortable. Am I missing something? My app is working fine and has become much more responsive.
View
public class MainActivity extends Activity{
private static Presenter presenter;
protected void onResume() {
if (presenter == null)
presenter = new Presenter(this.getApplicationContext());
presenter.onSetView(this);
presenter.onResume();
}
protected void onPause() {
presenter.onSetView(null);
if(isFinishing())presenter.onPause();
}
}
Presenter
public class Presenter {
private MainActivity view;
Context context;
public Model model;
public Presenter(Context context) {
this.context = context;
model = new Model(context);
}
public void onSetView(MainActivity view) {
this.view = view;
}
public void onResume(){
model.resume();
}
public void onPause(){
model.pause();
}
}
Model
public class Model {
public Model(Context context){
this.context = context;
}
public void resume(){
//start data acquisition HandlerThreads
}
public void pause(){
//stop HandlerThreads
}
}
I would suggest two things.
Make Model, View, and Presenter into interfaces.
Your MVP-View (an Activity, Fragment, or View) should be so simple it does not need to be tested.
Your MVP-Presenter never directly interacts with the Activity/Fragment/View so it can be tested with JUnit. If you have dependencies on the Android Framework is bad for testing because you need to Mock out Android objects, use emulator, or use a Testing Framework like Roboelectric that can be really slow.
As an example of the interfaces:
interface MVPView {
void setText(String str);
}
interface MVPPresenter {
void onButtonClicked();
void onBind(MVPView view);
void onUnbind();
}
The MVPPresenter class now does not depend on the Android Framework:
class MyPresenter implements MVPPresenter{
MVPView view;
#Override void bind(MVPView view){ this.view = view; }
#Override void unbind() {this.view = null; }
#Override void onButtonClicked(){
view.setText("Button is Clicked!");
}
}
Instead of making the Presenter a static class, I would make it a Retained Fragment. Static objects need to be tracked carefully and removed for GC manually whenever they are not needed (otherwise it's considered a memory leak). By using a retain fragment, it is much easier to control the lifetime of the presenter. When the fragment that owns the retain fragment finishes, the retain fragment is also destroyed and the memory can be GC'd. See here for an example.
Activity, Fragments should have only overidden methods of View interface and other Android Activity, Fragment's methods.
View has methods like navigateToHome, setError, showProgress etc
Presenter interacts with both View and Interactor(has methods like onResume, onItemClicked etc)
Interactor has all the logics and calculations, does time intensive tasks such as db, network etc.
Interactor is android free, can be tested with jUnit.
Activity/fragment implements view, instantiate presenter.
Suggest edits to my understanding. :)
An example is always better than words, right?
https://github.com/antoniolg
You're on the right track, and you are correct to ask about static - whenever you notice that you have written that keyword, it's time to pause and reflect.
The Presenter's life should be tied directly to the Activity's/Fragment's. So if the Activity is cleaned up by GC, so should the presenter. This means that you should not hold a reference to the ApplicationContext in the presenter. It's ok to use the ApplicationContext in the Presenter, but it's important to sever this reference when the Activity is destroyed.
The Presenter should also take the View as a constructor parameter:
public class MainActivity extends Activity implements GameView{
public void onCreate(){
presenter = new GamePresenter(this);
}
}
and the presenter looks like:
public class GamePresenter {
private final GameView view;
public GamePresenter(GameView view){
this.view = view;
}
}
then you can notify the Presenter of the Activity LifeCycle Events like so:
public void onCreate(){
presenter.start();
}
public void onDestroy(){
presenter.stop();
}
or in onResume/onPause - try to keep it symmetrical.
In the end you only have 3 files:
(I'm taking some code from another explanation I gave here but the idea is the same.)
GamePresenter:
public class GamePresenter {
private final GameView view;
public GamePresenter(GameView view){
this.view = view;
NetworkController.addObserver(this);//listen for events coming from the other player for example.
}
public void start(){
applicationContext = GameApplication.getInstance();
}
public void stop(){
applicationContext = null;
}
public void onSwipeRight(){
// blah blah do some logic etc etc
view.moveRight(100);
NetworkController.userMovedRight();
}
public void onNetworkEvent(UserLeftGameEvent event){
// blah blah do some logic etc etc
view.stopGame()
}
}
I'm not sure exactly why you want the ApplicationContext instead of the Activity context, but if there's no special reason for that, then you can alter the void start() method to void start(Context context) and just use the Activity's context instead. To me this would make more sense and also rule out the need to create a singleton in your Application class.
GameView
is an interface
public interface GameView {
void stopGame();
void moveRight(int pixels);
}
GameFragment is a class that extends Fragment and implements GameView AND has a GamePresenter as a member.
public class GameFragment extends Fragment implements GameView {
private GamePresenter presenter;
#Override
public void onCreate(Bundle savedInstanceState){
presenter = new GamePresenter(this);
}
}
The key to this approach is to clearly understand the role of each file.
The Fragment is in control of anything view related (Buttons, TextView etc). It informs the presenter of user interactions.
The Presenter is the engine, it takes the information from the View (in this case it is the Fragment, but notice that this pattern lends itself well to Dependency injection? That's no coincidence. The Presenter doesn't know that the View is a Fragment - it doesn't care) and combines it with the information it is receiving from 'below' (comms, database etc) and then commands the View accordingly.
The View is simply an interface through which the Presenter communicates with the View. Notice that the methods read as commands, not as questions (eg getViewState()) and not to inform (eg onPlayerPositionUpdated()) - commands (eg movePlayerHere(int position)).

Registering a presenter class to EventBus (android MVP)

I'm using greenrobot's EventBus in my android apps and I absolutely like it.
However, now I'd like to seperate the logic from my fragments by using presenters (MVP).
Is the following possible and is it useful?
Fragment:
public class MyFragment implements IMyFragment {
IMyPresenter mPresenter;
#Override
public View onCreateView(...) {
mPresenter = new MyPresenter(this);
}
#Override
public void onResume() {
// EventBus.getDefault().register(mPresenter); // register presenter to bus
mPresenter.resume();
}
#Override
public void onPause() {
// EventBus.getDefault().unregister(mPresenter); // unregister presenter from bus
mPresenter.pause();
}
#Override
public void doSomething() { // gets called via presenter
// ...
}
}
Presenter:
public class MyPresenter implements IMyPresenter {
IMyFragment mFragment;
// constructor to inject fragment
public MyPresenter(IMyFragment mFragment) {
this.mFragment = mFragment;
}
// handle event
public void onEvent(SomeEvent event) {
mFragment.doSomething();
}
public void resume() {
EventBus.getDefault.register(this);
}
public void pause() {
EventBus.getDefault.unregister(this);
}
}
Does this make sense?
Or is it even dangerous regarding unregistering the presenter from the bus and the complex fragment lifecycle?
Edit: Moved bus registration to presenter itself (Thanks to Nicklas).
Any more comments on this architecture?
You're putting too much responsibility on the View. What you want to do instead is have your Presenter expose a resume() and pause() method, and call those in your View. In those methods you'll register() and unregister() on the EventBus.
This puts all the event-handling code in your Presenter. It also means that you can change the event mechanism you use in your presenter, at any time, without having to change a line of code in your View.
In MVP, the only object you'll want to call non-view-related methods on, from the View, is the associated Presenters.

Android: Implement inner class in outer class; callback from inner class and outer class

I have multiple fragments in one activity that should be able to pass data inbetween them. I have used tutorials to implement callbacks. My MainActivity is the outer class in which my fragment classes are. Furthermore I have a FragmentPagerAdapter that handles the fragment transitions.
Well the thing is, Eclipse wont let me implement my callback interface, that is included in one of the Fragments, for my MainActivity outer class.
This is the structure of my code:
public class MainActivity extends FragmentActivity **implements ConnectionFragment.dataCallback**{
//compiler error here:"ConnectionFragment cannot be resolved to a type"
//when i leave this out i get runtime error: "MainActivity java must
//implement dataCallback"
...
public class SectionsPagerAdapter extends FragmentPagerAdapter implements ConnectionFragment.dataCallback{
#Override
public void updateLog(View v, String line) {
DataFragment dataFrag = (DataFragment)getSupportFragmentManager().findFragmentByTag(DataFragment.class.getName());
if (dataFrag != null){
dataFrag.updateLog(v,line);
}
}
...
}
public static class ConnectionFragment extends Fragment {
...
public interface dataCallback{
public void updateLog(View v, String line);
}
dataCallback mCallback;
private static dataCallback dummyCallback=new dataCallback(){
#Override
public void updateLog(View v, String line){
}
};
#Override
public void onAttach(Activity activity){
super.onAttach(activity);
try {
mCallback = (dataCallback)activity;
} catch (ClassCastException e){
throw new ClassCastException(activity.toString() + " must implement dataCallback");
}
}
}
public static class DataFragment extends Fragment implements ConnectionFragment.dataCallback{
public void updateLog(View v,String line){
TextView logTextView=(TextView)v.findViewById(R.id.log_view);
logTextView.append("\n"+line);
}
...
}
public static class GraphFragment extends Fragment {
...
}
}
ConnectionFragment should be able to send data to DataFragment.
I appreciate your help!
You can't implement an inner-interface or extend an inner-class. Simply move ConnectionFragment to its own file.
This is because at compile time, these inner classes are dependent on the parent class - and NEVER the other way around. As proof, if you look at the compiled .class files, these inner-Objects are compiled as MainActivity$ConnectionFragment.class or something there-abouts. If, however, ConnectionFragment is compiled into its own file (ConnectionFragment.cass), then MainActivity.class can depend on it, and Eclipse will automatically handle the build-order.
Fragments should never directly interact with each other since this creates undesired coupling.
Your fragment should call the interface method implemented by the Activity to communicate with the Activity, then the Activity can communicate/relay that interaction with the other fragment.
It's seem that you can't use an interface before you declare it.

Categories

Resources