0

So I need to get clipboard data in presenter. This means I need context. Unfortunately I don't have any knowledge of dependency injection if it is the only standard way. I studied some solutions but they are stated as faulty solutions.

public class MainActivityPresenter implements MainActivityInterfaces.MainToPresenter {

MainActivityInterfaces.PresenterToMain main;


public MainActivityPresenter (MainActivityInterfaces.PresenterToMain main) {
    this.main = main;
}


@Override
public void processUrl() {
    String url = Utils.getClipboardData(context);
    if (url.isEmpty()) {

    } else {

    }
}


}

And this is the method in Utils class

public static String getClipboardData (Context context) {
    if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.HONEYCOMB) {
        android.text.ClipboardManager cm = (android.text.ClipboardManager) context.getSystemService(CLIPBOARD_SERVICE);
        String result = cm.getText().toString();
        return result==null?"":result;
    } else {
        ClipboardManager cm = (ClipboardManager) context.getSystemService(CLIPBOARD_SERVICE);
        ClipData.Item item = cm.getPrimaryClip().getItemAt(0);
        if (item != null)
            return item.getText().toString();
        else
            return "";
    }
}
SSP
  • 431
  • 4
  • 16

4 Answers4

1

The right way, The presenter shouldn't know about any specific Android element, ClipboardManager or Context (ie: it should be pure Java). The clipboard logic should be taking place within the View and returning whatever it needs to the Presenter.

The ugly way, if you want to continue with this design, processUrl should take Context, presumably this method is being called from the view? So that is where context can be provided.

@Override
public void processUrl(Context context) {
    String url = Utils.getClipboardData(context);
    if (url.isEmpty()) {

    } else {

    }
}

In the view:

presenter.processUrl(getApplicationContext());

Another solution is to ask for context from the presenter to the view:

@Override
public void processUrl() {
    final Context context = view.getContext();
    String url = Utils.getClipboardData(context);
    if (url.isEmpty()) {

    } else {

    }
}

//In the view
void Context getContext() {
    return getApplicationContext();
}
JakeB
  • 2,043
  • 3
  • 12
  • 19
0

Using context in Presenter is not a good idea.

What if I need the Context?

Well, get rid of it. In cases like this, you should ask yourself why you need the context. You may need the context to access shared preferences or resources, for example. But you shouldn’t do that in the presenter: you should access to resources in the view and to preferences in the model. These are just two simple examples, but I can bet that the most of the times it is just a problem of wrong responsibilities.

You can pass url in constructor from View.

public class MainActivityPresenter implements MainActivityInterfaces.MainToPresenter {

MainActivityInterfaces.PresenterToMain main;
private String mUrl;

public MainActivityPresenter (MainActivityInterfaces.PresenterToMain main, String mUrl) {
    this.main = main;
    this.mUrl = mUrl;
}

@Override
public void processUrl() {
    if (mUrl.isEmpty()) {

    } else {

    }
}
interface SomeView {
    void onUrlProcessed();
}
}

In your MainActivity:

class MainActivity {

String url = Utils.getClipboardData(getContext());
}

You can refer other answers here .

Does the presenter having knowledge of the Activity / Context a bad idea in the MVP pattern?

Android MVP: safe use Context in Presenter

Machavity
  • 30,841
  • 27
  • 92
  • 100
pandey_shubham
  • 423
  • 5
  • 14
  • 1
    friendly tip : link only answers are typically down-voted and not seen as answers, consider posting some of the information from these articles as part of your answer instead, remember links and articles can be moved/deleted/changed and any future viewer of this question then has no answer – a_local_nobody Aug 23 '19 at 08:51
  • 1
    thanks @a_local_nobody for the suggestion , will take care in future. – pandey_shubham Aug 23 '19 at 09:18
0

At MVP, when the View propagates an event to the Presenter, it is very common for certain information to be sent to the Presenter. In your case, it would be quite logical to rename your method as follows:

@Override
public void processUrl(String url) {
  if (url.isEmpty()) {

  } else {

  }
}

In this way, the View will be in charge of propagating the information along with the event. And you also keep in the Presenter the ignorance about the peculiarities of the View (Android things), something very important in the MVP pattern.

Good luck!

Jose Angel Maneiro
  • 1,226
  • 9
  • 20
0

I know this won't help your question. But aside from MVP, MVVM is much robust and cleaner pattern that doesn't require as much boilerplate code as MVP does, so if you are still in a phase where you are starting a project and deciding or an architecture, I can, as a professional Android developer, only recommend MVVM. MVVM also does the state saves due to LiveData living inside ViewModels so you don't have to painfully add the ability to the presenter via saved instance bundles.

If you need DI in order to inject the context into the presenter (which isn't desirable, context shouldn't get into presenters ideally but sometimes it happens as it is harder to create entities that do the context required job in the presenter), and you are new and unexperienced in DI, then with Java you need to go with Dagger 2, which has a steep learning curve. Switching to Kotlin and then using Koin would be perhaps easier than learning Dagger 2, but if you are into it, try it. In any way it is a required to have DI in a professional projects.

If you don't want to use DI in order to pass the context into the presenter, then pass it into the constructor. I guess the Activity or Fragment is where you initialise your presenter (creating a new instance of it) and where you pass the 'view' concept into the presenter. If you need context in the presenter (again, not the best thing to do but ok, you are a new into patterns I understand), then just pass it into the constructor and set it in the presenter.

Stanislav Kinzl
  • 370
  • 4
  • 6
  • Actually I am starting the project. I have 5 years of experience in Android programming, but never been into MVP/MVVM stuff. I found it hard to convince myself to switch to another design pattern other than MVC cuz I think other patterns limit the developer to some bounds despite the fact they also add some benefits. – SSP Aug 23 '19 at 14:30
  • @SSP Well MVP does not add many benefits other than separation of concerns and so easier unit testing of the business logic layer. I would actually say that MVP makes the project much more hard to navigate in. This doesn't apply to MVVM, it is lighter as it doesn't require abstractions. And MVVM has clear benefit of, well, having a ViewModels which is a pretty nifty stuff – Stanislav Kinzl Aug 30 '19 at 14:59