I was reading the source code for Android's RecyclerView
and I was using the SimpleOnItemTouchListener
and reading the documentation about this class. But I'm not sure that I understand the meaning of this:
Another benefit of using this class is future compatibility. As the interface may change, we'll always provide a default implementation on this class so that your code won't break when you update to a new version of the support library
Is this because the SimpleOnItemTouchListener
implements the OnItemTouchListener
and provides some default behavior? So if the OnItemTouchListener
gets updated the SimpleOnItemTouchListener
would still return the default behavior.
The part about "if the interface may change". Are they talking about the OnItemTouchListener
?
However, the SimpleOnItemTouchListener
just seems to have empty methods and nothing else.
Let's say you have this interface:
public interface OnItemTouchListener {
boolean onInterceptTouchEvent(@NonNull RecyclerView rv, @NonNull MotionEvent e);
void onTouchEvent(@NonNull RecyclerView rv, @NonNull MotionEvent e);
void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept);
}
And you decide to implement it on your own:
public class MyOwnOnItemTouchListener implements OnItemTouchListener {
@Override
boolean onInterceptTouchEvent(@NonNull RecyclerView rv, @NonNull MotionEvent e) {
boolean result = doSomething(e);
return result;
}
@Override
void onTouchEvent(@NonNull RecyclerView rv, @NonNull MotionEvent e) {
doSomethingElse(rv, e);
doSomethingMore(rv);
}
@Override
void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {
if (disallowIntercept) {
doADifferentThing();
}
}
}
Everything is fine...
... until, six months from now, OnItemTouchListener
is modified to introduce a new method:
public interface OnItemTouchListener {
boolean onInterceptTouchEvent(@NonNull RecyclerView rv, @NonNull MotionEvent e);
void onTouchEvent(@NonNull RecyclerView rv, @NonNull MotionEvent e);
void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept);
// New method
void onMultiTouchEvent(@NonNull RecyclerView rv, @NonNull MotionEvent e);
}
And all of a sudden your app won't compile anymore 😱
Error: MyOwnOnItemTouchListener is not abstract and does not override abstract method onMultiTouchEvent() in OnItemTouchListener
And it's not even your fault, you didn't change anything! It's just that the interface changed and your code is not up to date with that change.
To avoid this, the API developers offer you a "default" implementation class, SimpleOnItemTouchListener
, that is guaranteed to always be up to date with the interface, and that you can extend instead:
public class SimpleOnItemTouchListener implements OnItemTouchListener {
// empty, override in your class
boolean onInterceptTouchEvent(@NonNull RecyclerView rv, @NonNull MotionEvent e) { return false; }
// empty, override in your class
void onTouchEvent(@NonNull RecyclerView rv, @NonNull MotionEvent e) {}
// empty, override in your class
void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {}
}
So instead of directly implementing the interface, you can do this:
public class MyOwnOnItemTouchListener extends SimpleOnItemTouchListener { //extend Simple instead of implementing interface
@Override
boolean onInterceptTouchEvent(@NonNull RecyclerView rv, @NonNull MotionEvent e) {
boolean result = doSomething(e);
return result;
}
@Override
void onTouchEvent(@NonNull RecyclerView rv, @NonNull MotionEvent e) {
doSomethingElse(rv, e);
doSomethingMore(rv);
}
@Override
void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {
if (disallowIntercept) {
doADifferentThing();
}
}
}
Now, if in six months the API devs need to introduce a new method, they will change both classes, as guaranteed:
public interface OnItemTouchListener {
boolean onInterceptTouchEvent(@NonNull RecyclerView rv, @NonNull MotionEvent e);
void onTouchEvent(@NonNull RecyclerView rv, @NonNull MotionEvent e);
void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept);
// New method
void onMultiTouchEvent(@NonNull RecyclerView rv, @NonNull MotionEvent e);
}
public class SimpleOnItemTouchListener implements OnItemTouchListener {
// empty, override in your class
boolean onInterceptTouchEvent(@NonNull RecyclerView rv, @NonNull MotionEvent e) { return false; }
// empty, override in your class
void onTouchEvent(@NonNull RecyclerView rv, @NonNull MotionEvent e) {}
// empty, override in your class
void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {}
// New method
// empty, override in your class
void onMultiTouchEvent(@NonNull RecyclerView rv, @NonNull MotionEvent e) {}
}
And now, despite this changes, MyOwnOnItemTouchListener
will still compile, even though it doesn't implement onMultiTouchEvent
, because if at any point MyOwnOnItemTouchListener.onMultiTouchEvent()
is called it will just use the (empty) implementation from its parent, SimpleOnItemTouchListener
.
And your app will keep working 💪
Now, answering your exact questions:
Is this because the
SimpleOnItemTouchListener
implements theOnItemTouchListener
and provides some default behavior?
Yes. Though here, the "default behavior" is "do nothing at all", so you still need to implement the methods in your own listener if you want to actually do something.
So if the
OnItemTouchListener
gets updated theSimpleOnItemTouchListener
would still return the default behavior.
Yes, exactly.
The part about "if the interface may change". Are they talking about the
OnItemTouchListener
?
Yes.
However, the
SimpleOnItemTouchListener
just seems to have empty methods and nothing else.
Yes. The "default behavior" they provide is just "do nothing". It's just a way of avoiding compilation failures.
You still have to implement the methods in a meaningful way. But now you have a safety net if new methods are ever introduced.
I'd say you actually understood the gist of it, it's just that the empty default implementation was confusing.
Is this because the SimpleOnItemTouchListener implements the OnItemTouchListener and provides some default behavior?
no, it simply implements interface with empty methods. As you know when you implement interface, then you need to add definitions for all the interface methods, otherwise you will get compile error. But if you extend a class then you dont need to override all the base methods (well... unless they are not abstract - but that is not a case here).
The part about if the interface may change. Are they talking about the OnItemOnTouchListener?
yes, they talk about the interface RecyclerView.OnItemTouchListener being changed:
http://androidxref.com/9.0.0_r3/xref/frameworks/support/v7/recyclerview/src/main/java/androidx/recyclerview/widget/RecyclerView.java#OnItemTouchListener
suppose they add to RecyclerView.OnItemTouchListener a new method : void foo()
, then if you upgrade support library and you had directly implemented in your class RecyclerView.OnItemTouchListener
, then you will get compiler error (you will need to implement foo()
in your class). In the comment you quote android team is making a promiss that they will implement foo() in SimpleOnItemTouchListener so if you extend it in your MyOnItemTouchListener
they will already have empty implementation - so no compile error.
I find it more or less a Adapter implementation. As android is continuously evolving , the interactions are never going to be the same and will keep evolving with the OS.
Here, the root interface OnItemTouchListener
can be implemented, so that the application gets control on the touch events that was consumed or being consumed. To put in simple words,OnItemTouchListener
says "Do you want to handle the touch events? Implement me! But be ready to handle all kinds of new gestures I catch for you.I'm dynamic"
Now another guy SimpleOnItemTouchListener
comes in between and says, "Hey, I can be
your consultant with the OnItemTouchListener
.We can have an agreement on what is to be handled . Even if OnItemTouchListener
goes mad with new stuff, I will help you to remain calm and not change. I will take the pain and make sure you are not disturbed "
So its simple, OnItemTouchListener
may evolve in time with Android. SimpleOnItemTouchListener
might evolve with OnItemTouchListener
, but will not deprecate or become vestigial in any of the current behaviours.
Adding more, since SimpleOnItemTouchListener
gives you a default implementation, your code will look neat because you need to override only what you need.
I'm currently working on a plugin framework for the project I'm working on. I've attempted to solve this problem through versioning my interface. I do have a base implementation like walen talks about. However, I worry about the people who implemented the interface instead of the base implementation. Surely if I change my interface and release I've just broken those plugins that decided not to extend my base class.
The core application uses whatever version of the interface is required for that part of the code. A V2 version of the interface would extend the V1, a V3 extending V2, etc. Instead of calling all of the plugins directly I have a manager class that does that work. That allows me to ensure that if a V3 feature is attempting to execute I'm only doing so on plugins that implemented the V3 version of the plugin interface.
If I was only exposing the base class and hide the interface from the public API I could probably get by with just a base implementation that others extend. Unfortunately since the interface is also public I have to make sure I don't break developers that didn't extend the base class.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With