Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Using WeakReference in MvpBasePresenter is flawed #233

Closed
olshevski opened this issue Apr 7, 2017 · 7 comments
Closed

Using WeakReference in MvpBasePresenter is flawed #233

olshevski opened this issue Apr 7, 2017 · 7 comments

Comments

@olshevski
Copy link

Hi,

Using WeakReference inside MvpBasePresenter may potentially lead to NullPointerException in the code like this (taken from the sample code on your site):

if (isViewAttached())
          getView().showHello(greetingText);

There is no guarantee that GarbageCollector will not remove object from memory between two subsequent calls to WeakReference.get(). This way even when isViewAttached() returns true, getView() may return null. The correct and only way to use WeakReference in this case would be to call WeakReference.get() only once and assign the result to strong reference.

@sockeqwe
Copy link
Owner

sockeqwe commented Apr 8, 2017

Thanks for reporting! Indeed, that is true, unlikely but in theory this could happen!
Actually I wanted to deprecate isViewAttached() in 3.0.

The proper way is:

V view = getView();
if (view !=null){
    view.showHello(...);
}

We could add a shorthand like this to MvpBasePresenter:

ifViewAttached(view -> view.showHello(...));

which internally uses View view = getView(); if (view != null) { ... } as shown in the first code snippet.

What do you think?

@olshevski
Copy link
Author

I understand that it is very unlikely considering all conditions that should be met. But still it is a piece of code that feels uncomfortable c:

I guess deprecating isViewAttached() may prevent propagation of this code snippet. But I still can imagine someone writing their code this way:

if (getView() != null) {
    getView().doThis();
    getView().doThat();
}

It seems to be a common practice among various programmers.

ifViewAttached(view -> view.showHello(...)); seems fine.

Personally, I just don't see the point in this WeakReference-bulletproofing of someone else's bad code. But that's a whole another "ideal world" discussion.

@sockeqwe
Copy link
Owner

3.1.0 deprecates getView() and isViewAttached()and adds ifViewAttached(). Thanks for your feedback!

@gim-
Copy link

gim- commented Nov 29, 2017

Wouldn't deprecating isViewAttached() and marking getView() as @Nullable be enough? That way if someone writes something terrible like this:

if (getView() != null) {
    getView().doThis();
    getView().doThat();
}

The lint-check in Android Studio will show a warning that getView().doThis(); and getView().doThat(); can throw NPE. If someone ignores that then app crashing would be his own fault. ifViewAttached() could be just a nice additional helper method.

EDIT: Ok, I just checked it and it seems like Android Studio will not show any warnings inside a block after if (getView() != null).

@sockeqwe
Copy link
Owner

sockeqwe commented Nov 29, 2017

If someone ignores that then app crashing would be his own fault.

Yes but with a more concise API (especially in kotlin) like

ifViewAttached { view -> 
   view.doThis()
   view.doThat()
}

we can avoid pain like NPE. Hence I think the deprecation of isViewAttached() and getView() is justified. What are your concerns about ifViewAttached() or why would you like to stick with getView()?

@jshvarts
Copy link
Contributor

jshvarts commented Nov 29, 2017

In Kotlin, can if checks be avoided and safe call operator be used instead? view?.doThis()

@sockeqwe
Copy link
Owner

yes but still this could happen (theoretically):

view?.toThis()  // this is executed
// gc runs and view == null
view?.toThat() // this is not executed because view == null because of gc

whereas with ifViewAttached() its a do all in the lambda because view is guaranteed not to be null or don't execute the lambda at all. Also we have to take java users into account.

Also this API seems to me more consistent to what MvpQueuingBasePresenter offers:

onceViewAttached { view -> 
   view.doThis()
   view.doThat()
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants