In my Android app I have a controller DataManager where I do some data transfer stuff and I have defined (amongst others) an interface ProgressbarCallback to show the progress in another depending Fragment:
public class DataManager {
ProgressbarCallback progressbarCallback;
public interface ProgressbarCallback {
void updateProgress(int progress);
}
//2
ProgressShowerFragment f = ProgressShowerFragment.getInstance();
progressCallback = f.getCallback();
//3
progressCallback.updateProgress(i)
}
there I would like to control the progressbar of a depending Fragment. So I have a ProgressShowerFragment to show my progress:
public class ProgressShowerFragment extends Fragment implements DataManager.ProgressbarCallback {
#Override
public void updateProgress(int progress) {
progresBar.setProgress(progress);
}
//1
public ProgressbarCallback getCallback(){
return this;
}
}
To have a reference in my DataManager I have done a getter (see 1) what returns the Callback. When instantiating ProgressShowerFragment I also get that Callback (see 2).
Later on usage I update the progress like in 3.
For me this seem very ugly. What is an elegant way to do get the Callback?
You can cast f to ProgressbarCallback
((ProgressbarCallback) f).updateProgress(i)
Related
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)).
I have a simple class with an interface enabled and works proper when used.
interface interfacename{
void function1();
void function2();
}
public class asyncfunction(){
public interfacename listener;
...
onasyncStart( ... ){
listener.function1();
}
...
...
onasyncComplete( ... ){
listener.function2();
}
}
public myclass(){
....
....
methodcall(new interfacename(){
#Override
public void function1(){
// executes proper
}
#Override
public void function2(){
// executes proper
}
}
}
So the above method works proper.
But i want to call only the function1() sometimes and only function2() when needed.
I don't want both methods to be implemented always. The code looks big and im not sure if it slows down code or not ( not on the milli second level btw ) but it would be really nice if there was another way to have the option to execute particular call backs when needed.
It sounds like you're really looking at splitting up your interface into multiple interfaces, and change the method that accepts this interface as a parameter, so that it will instead accept the interface that it requires (e.g. InterfaceOne) in order to call a method in that interface (e.g. function1()). Another method might want to call function2(), in which case it will accept an argument of type InterfaceTwo.
If however you need to always call both methods of the interface in your method, but you don't always need to call any code in the methods of that interface, what you're looking at instead is the following.
Instead of creating a new anonymous class of type interfacename, you could use a base class with empty method bodies, and simply override the ones you need. Methods implemented by the abstract base class are essentially optional, while those that are not implemented are required methods.
This is a very common pattern in Java development.
public interface InterfaceName {
void function1();
void function2();
}
public abstract class BaseInterfaceName implements InterfaceName {
public void function1() {
}
public void function2() {
}
}
public class MyClass {
public void myMethod() {
myMethodWithInterface(new BaseInterfaceName() {
#Override
public void function2() {
System.out.println("function2");
}
})
}
public void myMethodWithInterface(InterfaceName intf) {
intf.function1();
intf.function2();
}
}
A possible solution is the one explained by #Nicklas.
But, if you use Java 8, you can use the default method. So you can declare your interface in this way:
public interface InterfaceName {
default void function1(){ /* do nothing */}
default void function2(){ /* do nothing */}
}
So, you can avoid implementing the methods, since you are providing a default implementation. In my example the default is to do nothing, but of course, you can personalize them.
I'm new to interfaces and I'm trying to do the following. What am I missing?
public class MyAdapter implements ItemManager.DoThisInterface {
...
#Override
doThis() {
// Do things specific to my adapter. Define action hre.
}
}
The interface is defined in the Item Manager, which does not know what needs to be done. The adapter should define the actions.
public class ItemManager {
....
private void onCertainEvent() {
doThis(); // do whatever is overriden in adapter.
// this is kind of a placeholder for what i expect to be defined
// in the adapter.
// (this fails to compile because it can't call straight to the interface method)
}
// interface declaration
public interface DoThisInterface {
doThis();
}
}
You may need to create an object.
MyAdapter ma=new MyAdapter();
ma.doThis();
Call this and your problem will be solved.
You should set a DoThisInterface instance on the class ItemManager, and save it in the instance field, then use the instance to call the interface method, like this
public class ItemManager {
private DoThisInterface mDoThisInterface;
....
private void onCertainEvent() {
if(mDoThisInterface != null){
mDoThisInterface.doThis();
}
}
public void setDoThisInterface(DoThisInterface doThisInterface){
mDoThisInterface = doThisInterface;
}
// interface declaration
public interface DoThisInterface {
doThis();
}
}
I always have this problem of java.lang.IllegalStateException:Could not execute method of the activity. I was planning to perform an android component event (ex. Button event - indicating the number of times this button was clicked). Here's the code snippet for this problem:
interface Selection {
public void clicked();
}
public class ParentClass extends FragmentActivity {
// fTabs : FragmentTabHost
// tabs : Map<String, Selection>
private void initialize() {
// fistFrag : FirstChildClass = new FirstChildClass()
// secondFrag : SecondChildClass = new SecondChildClass()
tabs.put("first", firstFrag);
tabs.put("second", secondFrag);
fTabs.add(fTab.newTabSpec("first").setTitle("First"), firstFrag.getClass(), null)
fTabs.add(fTab.newTabSpec("second").setTitle("Second"), secondFrag.getClass(), null)
}
#Override
public void onBackPressed() {
tabs.get(fTabHost.getCurrentTabTag()).clicked();
}
}
public class FirstChildClass extends Fragment implements Selection {
// data : TextView
// hit : int = 0
#Override
public void clicked() {
data.setText(String.format("Hit Count: %d", ++hit));
}
}
public class SecondChildClass extends Fragment implements Selection {
// data : TextView
// hit : int = 0
#Override
public void clicked() {
data.setText(String.format("Hit Count: %d", ++hit));
}
}
I've tried to assure of clicked() works view interfacing approach by invoking a message on Logcat and it worked but when I used Button the error above always prompts me. I've checked if data is null and it returned true. I am a little bit confused, I've tried to check nullity of data from the Activity methods is returns false but when I access any method override by an interface it always return true. Is there a way to solve this?
Here's a way my friend told me to solve this problem. Using getSupportFragmentManager. He told me also that creating an Activity or Fragment using its constructor isn't applicable on the Android platform. So I switched by to the conventional way of adding tabs to FragmentTabHost.
#Override
public void onBackPressed() {
//tabs.get(fTabHost.getCurrentTabTag()).clicked();
((Selection) getSupportFragmentManager().findByFragmentByTag(fTabHost.getCurrentTabTag()).clicked();
}
I ran into a piece of Android code. I don't quite understand the purpose of the callback because it's empty.
In Animation.java
private AnimationCallback callback = null;
public Animation(final AnimationCallback animationCallBack) {
this();
callback = animationCallBack;
}
public void stop() {
if (callback != null) {
callback.onAnimationFinished(this);
}
active = false;
}
public interface AnimationCallback { void onAnimationFinished(final Animation animation); }
but in AnimationCallback there's only
public interface AnimationCallback {
void onAnimationFinished(final Animation animation);
}
I guess my question is what does callback.onAnimationFinished(this) do? There doesn't seem to have anything inside the routine.
The constructor is declared to take anything that implements the AnimationCallback interface. In Java, an interface defines the behavior of an object without specifying any of its behavior.
The actual object that gets passed to the constructor is some concrete class that implements the AnimationCallback interface. You'd have to know the actual class of the object being used to know what it does.
Per request, here's a simple (and fairly useless) class that just logs the fact that an animation has finished:
public AnimationFinishedLogger implements AnimationCallback {
public void onAnimationFinished(final Animation animation) {
Log.i("AnimationLogger", "Animation finished");
}
}