Giter VIP home page Giter VIP logo

nucleus's Introduction

Nucleus

Deprecation notice

Nucleus is not under develpment anymore. It turns out that Redux architecture scales way better than MVP/MVI/MVVM/MVxxx and I do not see further development of Nucleus valuable.

I recommend considering ReKotlin as a simple Redux implementation.

Info

Android Arsenal Maven Central

Nucleus is a simple Android library, which utilizes the Model-View-Presenter pattern to properly connect background tasks with visual parts of an application.

MVP introduction article

Wiki

Introduction

Some time has passed since Model-View-Presenter and RxJava completely superseded Loader and AsyncTask in our applications.

But there are still some defects in our applications even when using such advanced technologies:

  • An application is unable to continue a background task execution after a configuration change.
  • An application does not automatically restart a background task after a process restart.

While most applications work without such capabilities, their absence is an obvious bug that just sits there and waits for a user who pressed "Login" button while being in a subway and switched to another application because his network connection was too slow. Bugs that almost any application produce in such cases are numerous.

Android docs are covering such problems very briefly, take a look at: Processes and Threads - 4. Background process "If an activity implements its lifecycle methods correctly, and saves its current state, killing its process will not have a visible effect on the user experience, because when the user navigates back to the activity, the activity restores all of its visible state."

This is not true - there WILL be a visible effect because we're not restoring background tasks. The application will restore it's visual state, but it will forget what it is doing. So, if an application restores a progress bar, but does not restore the background task itself - a user will see the usual "progress bar forever" bug.

Nucleus' main features

  • In case of configuration change Nucleus automatically re-attaches all running background tasks to the new View. The application will not forget what it is doing.

  • In case of process restart Nucleus automatically restarts background tasks. Even when running on a low memory device or waiting for a long running background task completion, the application is still reliable.

  • The entire library has been built keeping The Kiss Principle in mind. Anyone can read and understand it easily.

  • The library does not depend on Dagger, you don't need to write a whole class just to inject a presenter. One annotation is all you need. Despite presenters are instantiated without Dagger, their dependencies can still be injected.

  • Presenter in Nucleus is an external class that does not depend on View, this automatically prevents any troubles that are connected with activity context leaks.

History

At the moment of the first release, the library main idea was to be the simplest possible MVP implementation.

A couple of months later, I finally realized that RxJava has became the tool number one for smart background threads handling, so RxPresenter appeared. Since that moment, the main focus shifted in the direction of RxJava support.

The correct lifecycle handling was something that seemed obvious to me from the beginning, so I did not make an accent on this feature in the library description. However, since those times, more MVP libraries appeared, now I need to differentiate Nucleus from other implementations. The library description became: "Nucleus is a simple Android library, which utilizes the Model-View-Presenter pattern to properly connect background tasks with visual parts of an application."

Include this library:

dependencies {
    compile 'info.android15.nucleus:nucleus:6.0.0'
}

For additional view classes NucleusSupportFragment, NucleusFragmentActivity include:

dependencies {
    compile 'info.android15.nucleus:nucleus-support-v4:6.0.0'
}

For additional view class NucleusAppCompatActivity include:

dependencies {
    compile 'info.android15.nucleus:nucleus-support-v7:6.0.0'
}

ProGuard config:

-keepclassmembers class * extends nucleus.presenter.Presenter {
    <init>();
}

For RxJava 2:

dependencies {
    compile 'info.android15.nucleus5:nucleus:7.0.0'
}

For additional view classes NucleusSupportFragment, NucleusFragmentActivity include:

dependencies {
    compile 'info.android15.nucleus5:nucleus-support-v4:7.0.0'
}

For additional view class NucleusAppCompatActivity include:

dependencies {
    compile 'info.android15.nucleus5:nucleus-support-v7:7.0.0'
}

Hint: you can just copy/paste those classes code into ANY View class to keep your View classes hierarchy as you like to.

ProGuard config:

-keepclassmembers class * extends nucleus5.presenter.Presenter {
    <init>();
}

nucleus's People

Contributors

bug-assassin avatar cavarzan avatar davidmoten avatar defer avatar inorichi avatar jmreyes avatar konmik avatar lightencc avatar plastix avatar rharter avatar wkovacs64 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

nucleus's Issues

Dagger2 and Nucleus

Not so much an issue as a question of practices:

Most Dagger 2 examples that I see rely on a "context" (generally from the Activity or Application) to get/create components and modules. Presenters don't inherently have a context, and the Presenter itself can have a different lifecycle from it's Activity. This makes me hesitant to use the Activity context. I could get the application context but based on what I have read that seems like bad practice. In my particular case I'm making use of a factory to create my Presenter, so I don't think constructor injection in the Presenter class can work, and integrating Dagger into the factory strikes me as a bit odd.

How would you recommend handling DI in a case like this, using Dagger 2? (I'm currently leaning towards just getting/using the application context, but that feels sloppy)

PresenterStorage.INSTANCE leaks Activity

I can't tell if this is just my code or if it's something to do with Nucleus but I have LeakCanary attached to my app and I am noticing that PresenterStorage.Instance is leaking my activity. This was the trace that was provided:

  • ui.view.SignUpActivity has leaked:
  • GC ROOT static nucleus.factory.PresenterStorage.INSTANCE
  • references nucleus.factory.PresenterStorage.presenterToId
  • references java.util.HashMap.table
  • references array java.util.HashMap$HashMapEntry[].[10]
  • references java.util.HashMap$HashMapEntry.key
  • references ui.presenter.SignUpPhotoFragmentPresenter.view
  • references ui.view.SignUpPhotoFragment.mFragmentManager
  • references android.support.v4.app.FragmentManagerImpl.mActive
  • references java.util.ArrayList.array
  • references array java.lang.Object[].[2]
  • references ui.view.SignUpUsernameFragment.continueButton
  • references android.support.v7.widget.AppCompatButton.mContext
  • leaks ui.view.SignUpActivity instance

It seems to be the Nucleus library that is leaking the activity. Would you be able to shed more light into the issue? Let me know if you would like more details.

Timing issue?

I have a normal presenter and an activity. In onTakeView the presenter passes a boolean to a method in the activity which sets the drawable of a button to an image on true or to null on false.

What happens is that since I switched to nucleus I can see the image for the fraction of a second before it vanishes (when the presenter calls it).

This causes an annoying visual flicker. How can I fix that? Or is it a bug? I don't use any other threads than the main thread.

Version 1.3.1?

First, thanks a lot for your work on nucleus.

It seems that master holds version 1.3.1, whereas "only" 1.3.0 is available using Gradle. When can we expect to see the new version available as a library from Gradle?
Thanks!

Q/A (was: Some doubts)

Hi!

I'm working on an app I want to use Nucleus for MVP+Rx.

I have some doubts, and I couldn't find any solution in the documentation/wiki. Could you please help me?:

  1. How can I use two instances of the same view, and make each of them have their own instances of their presenters? Is it possible by telling the PresenterStorage with ID to use? Or by any other way?

  2. Why is the presenter being destroyed and pointed to null in the onPause method instead of doing so in onDestroy? The documentation seems to be out of date. What if I want to stack several activities of the same type, and want them to keep their presenters while not destroyed by the system? Is that working because you pass isFinishing() to the delegate?

  3. I think we need more documentation about the restartable* methods in RxPresenter. I know that it is documented in the code with Javadoc, but I think it would be great to add some explanation in the wiki. Something like the deliver* methods documentation (btw, some of them seem to be out of date since you released version 2.0.1).

Thank you very much.
Your library is great.
Cheers,
M.

[Question] - Use same presenter for multiple Fragments

Hi!

I'm starting to implement the library now, but I have a question for reuse of fragments.

Let me explain my doubt:

Considering I have two fragments, one is a map, and another a list, put into a ViewPager. Can I use the same presenter in two fragments to reuse the API calls? In this hypothetical example both fragments query for the same data in API.

Or the best approach is use the Activity presenter to query the data and than delivery to the fragments?

It's just a question about architecture and things that I can archieve using the library, fell free to close this issue if you think is off-topic.

And thanks for the amazing project.

when view onresume๏ผŒrxpresenter will onNext again

a view contain a list๏ผŒlist have add more data interface
I use Rxpresenter๏ผŒwhen getData in backgroud๏ผŒthen i offen lock screen and open screen๏ผŒthen presenter would try view.onNext again๏ผŒthen view will be add more the same dataใ€‚
can you change onNext will call once again for list then load more๏ผŸ

Nucleus 2.0.0

Is currently under testing.

I hope that it will be production-ready in the middle of August.

Want to join beta?

compile "info.android15.nucleus:nucleus:2.0.0-beta8"

Primary goals are:

  • Make RxPresenter to be completely usable without getView() - 100% done!
  • Replace OperatorSemaphore with standard RxJava operators. - 100% done!
  • Simplify internal structure: remove manager and helper. - 100% done!
  • Move all tests into unit tests to be testable without device. - 80%.

Update: a little note about the new rx.Single. rx.Single is awesome and I'm already playing with it. However, creation of additional methods for it will cause much more confusion than advantage (I already implemented this, but dropped the implementation because it just looks bulky, imagine stranger method names like deliverSingleCache, restartableSingleCache). The right way to handle rx.Single in Nucleus is to cast it to Observable.

How to use restartableLatestCache properly?

What is proper way to use restartables? create one per task or reuse it?
Below are 2 examples (in kotlin)

...
val LOAD_TRACKS = 1
val SAVE_TRACK = 2
var track: Track

    override fun onCreate(savedState: Bundle?) {
        super.onCreate(savedState)

        restartableLatestCache(LOAD_TRACKS,
                { TrackModel.getTracks().applySchedulers() },
                { view, content -> view.showContent(content) })
        { view, error -> view.showError(error) }

        restartableLatestCache(SAVE_TRACK,
                { TrackModel.saveTrack(track).applySchedulers() },
                { view, content -> view.showContent(content) })
        { view, error -> view.showError(error) }
    }

    fun getTracks() {
        start(LOAD_TRACKS)
    }

    fun saveTrack(track Track) {
        this.track = track
        start(SAVE_TRACK)
    }
...
...
    val RESTARTABLE_ID = 1
    var SAVE_LOAD_FLAG
    var track: Track

    override fun onCreate(savedState: Bundle?) {
        super.onCreate(savedState)

        restartableLatestCache(RESTARTABLE_ID,
                when(save_load_flag){
                    save_flag -> save
                    load_flag -> load
                },
                { view, content -> view.showContent(content) })
        { view, error -> view.showError(error) }

    }   

    val save = fun(track: Track): Observable<List<Track>> { return TrackModel.saveTrack(track) }

    val load = fun(): Observable<List<Track>> { return TrackModel.getTracks() }

    fun request(save_load_flag default load, track default null) {      
        this.save_load_flag = save_load_flag
        this.track = track
        start(RESTARTABLE_ID)
    }
... 

2.0.0 forces rx/observables

The only real Presenter class in 2.0.0 is now RxPresenter. This seems kind of silly. Can we get a basic presenter that at least has "getView()" something similar?

leaks when using with addView/removeView

I'm attempting to use a NucleusLayout as the base class for my view. Because the view life cycle is not tied to the activity life cycle, Nucleus is creating a new Presenter each time addView() is used, but not destroying it when removeView() is used. Due to the way PresenterHelper and NucleusLayour are implemented I am unsure how to fix this issue without duplicating the classes in their entirety.

Update version

The current version, 1.3.1, is not available in the gradle repositories. Can I help to update?

Delivery: Overload instead of @Nullable

At the moment its (=Delivery) split function takes two Action2 parameters: One for onNext the other for onError.
If you are not interested in onError you can pass null to that. (do I understand correctly?)

I want to propose to add a simple overload:

public void split(Action2<View, T> onNext) {
    split(onNext, null);
}

This would make it clearer and more consistent to RxJava. I generally don't like to study the javadoc of each method to find out what happens when I pass null and find that approach quite error prone.

a better restartable interface

There is a possibility so slightly improve restartable API.

Instead of

        registerRestartable(REQUEST_ITEMS, new Func0<Subscription>() {
            @Override
            public Subscription call() {
                final String name1 = name;
                return App.getServerAPI()
                    .getItems(name.split("\\s+")[0], name.split("\\s+")[1])
                    .observeOn(AndroidSchedulers.mainThread())
                    .compose(MainPresenter.this.<ServerAPI.Response>deliverLatestCache())
                    .subscribe(new Action1<ServerAPI.Response>() {
                        @Override
                        public void call(ServerAPI.Response response) {
                            getView().onItems(response.items, name1);
                        }
                    }, new Action1<Throwable>() {
                        @Override
                        public void call(Throwable throwable) {
                            getView().onNetworkError(throwable);
                        }
                    });
            }
        });

we can write something like this:

        restartable(REQUEST_ITEMS)
            .switchMap(new Func1<Object, Observable<ServerAPI.Response>>() {
                @Override
                public Observable<ServerAPI.Response> call(Object o) {
                    return App.getServerAPI()
                        .getItems(name.split("\\s+")[0], name.split("\\s+")[1])
                        .observeOn(AndroidSchedulers.mainThread());
                }
            })
            .compose(this.<ServerAPI.Response>deliverLatestCache())
            .subscribe(new Action1<ServerAPI.Response>() {
                @Override
                public void call(ServerAPI.Response response) {
                    getView().onItems(response.items, name);
                }
            }, new Action1<Throwable>() {
                @Override
                public void call(Throwable throwable) {
                    getView().onNetworkError(throwable);
                }
            });

Pros:

  • Looks more rx-like.

Cons:

  • Can't save request arguments in a final variable, so more code will be used for this in some cases.
  • The chain is subscribed during onCreate, so a tiny bit of memory will be used for this.

Are there any other pros and cons of having such API?

Inject presenter with Dagger

Hello!

Is it possible to inject the presenters into the activities with Dagger instead of using the @RequiresPresenter annotation?

Thanks,
Martin

getView is null in onActivityResult()

Inside my fragment, I call startActivityForResult where I launch a camera activity, and I get back a result and ask the presenter to do some work on the returned data. When the presenter calls getView(), it returns a null object.

Seems to be similar to this issue: #35

For now I am doing this (the suggestion from issue #35) :

protected void onActivityResult(int requestCode, int resultCode, Intent intent) {

     getPresenter().takeView(this);
     getPresenter().doXYZ();

}

I am using nucleus ver. 2.0.3

Issue with Paging Example

I was going through Paging Example and implemented it but it never did more then one extra page request. I noticed the following snippet in RxPager.

 public Observable<Integer> pages() {
        return requests
            .concatMap(targetPage -> targetPage <= requestedCount ?
                Observable.<Integer>never() :
                Observable.range(requestedCount, targetPage - requestedCount))
            .startWith(Observable.range(0, initialPageCount))
            .doOnNext(it -> requestedCount = it + 1);
    }

The logic seems to handle the case if you would try to request the same page number over and over again.
Shouldn't Observable.<Integer>never() be replaced with Observable.<Integer>empty()? If a requestNext(page) is fired multiple times (as can happen if you don't block it in OnScrollPaging, the Observable.<Integer>never() will seem to block the stream and no more valid requests will seem to get fired anymore. I replaced it with an empty Observable and then everything seems to work fine.

Can you give me your thoughts on this?

Prevent subclassing

It seems the subclassing of NucleusActivity is the only option for now. I can see from your code that all the logic actually lies in PresenterHelper, but it would probably be a little bit verbose to use it in all activities. I guess that's why you introduced NucleusActivity.

Starting from API 14 we can register callbacks on activity lifecycle, so the subclassing could probably be replaced by a simple call to something like Nucleus.bind(this) in the onCreate() of each activity.

What do you think?

EDIT: It would probably be a second option rather than a replacement, since it wouldn't be compatible with API < 14.

Backfiring pattern?

Imagine this scenario:

public class LauncherPresenter extends RxPresenter<LauncherActivity> {
        protected void onCreate(Bundle savedState) {
            super.onCreate(savedState);

            SettingsModel settings = Settings.getInstance(view).readSavedSelectedUsageMode();
            if (settings != null && settings.getMode() != SettingsModel.NONE) {
                switch (settings.getMode()) {
                    case SettingsModel.ONE:
                        getView().ShowOnething();
                        break;
                    case SettingsModel.TWO:
                        getView().ShowAnotherThing();
                        break;
                }
            } else {
                getView().ShowSomethingCompletlyDifferent();
            }
        }
    }

Using nucleus i'd imagine you want to handle this from the Presenter. You load a saved setting from your chosen persistence library. Check what setting was loaded and then tell the activity it should show something specific. Now the problem here is that this can only take place in the onTakeView()-method of nucleaus, because before that the Activity has not yet been created.

Would it be correct to implement this code in onTakeView? Or would you rather just implement it into the Activity all together? I'd rather keep being consistent in using presenters in all activities.

How to test process restart?

How can we restart the process manually when the app is in the background and make sure that everything works properly? Thanks.

Nucleus for DialogFragments

I have some DIalogFragments where I want to enforce MVC. Can the library add this functionallity?

I think it should work if all code from Fragment is just copied to DialogFragment as it inherits from it.

Toolbar

Can you please give an example of using Nucleus with Material Design - like Toolbar (with tabs)? Right now your sample has hard-coded tabs and no Toolbar.

Extract destroy from the PresenterHelper.

Currently, the PresenterHelper class requires the Activity in the takeView() method for the sole purpose of determining whether the presenter should be destroyed when dropView is called.

This logic, of deciding whether or not to destroy the presenter should be extracted from the PresenterHelper, completely freeing it from ties to the Activity.

I propose updating the dropView() method to something like dropView(boolean destroy). This way, it's up to the container (ViewGroup, Fragment, Activity, View, Service, etc) to determine when the presenter should be destroyed.

This will better support things like single activity, fragment/view only setups, and ensure the PresenterHelper performs only it's very specific tasks.

return onActivityResult, presenter getView() is null

Hi, Not sure if this is an issue, or I just don't know the correct way to handle this.

In my MainActivity, I fired: startActivityForResult()...
Then onActivityResult() comes back, and I do stuff with my presenter. getPresenter() is fine, but within my presenter, getView() returns null.

Some logging tells me this is the flow:

onResume
startActivityForResult
onPause
onActivityResult
onResume
....

Thanks,
Jia

Nucleus + Dagger 2

Hi there!

Thank you for this great library! But I have a little question about usage it along with Dagger 2.
How can I inject my precious arguments in presenter's constructor and do not break functionality of Nucleus?

If I use @RequiresPresenter(RxMainPresenter.class), I can't pass arguments to my presenter.
If I use @Inject RxMainPresenter mainPresenter;, my presenter will not be cached.

Thank you in advance!

Here is some code:

public class RxMainPresenter extends RxAbstractPresenter<RxMainPresenter.View> {
    private final RxInstancesObservable instancesObservable;

    @Inject
    public RxMainPresenter(final ExecutorService executorService, final RxInstancesObservable instancesObservable) {
        super(executorService);
        this.instancesObservable = instancesObservable;
    }

    @Override
    protected void onCreate(final Bundle savedState) {
        super.onCreate(savedState);

        Observable.create(instancesObservable)
                .retry(3)
                .subscribeOn(Schedulers.from(executorService))
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Subscriber<CabinetInstance[]>() {
                    @Override
                    public void onCompleted() {

                    }

                    @Override
                    public void onError(final Throwable e) {
                        getView().displayInstancesError(e);
                    }

                    @Override
                    public void onNext(final CabinetInstance[] instances) {
                        getView().displayInstances(instances);
                    }
                });
    }

    public interface View extends RxAbstractPresenter.View {
        void displayInstances(final CabinetInstance[] instances);

        void displayInstancesError(final Throwable throwable);
    }
}

null bundle onCreate

Hello!

Is there any issue with RxPresenter that makes the onCreate(Bundle savedState) receive the bunde always null after orientation changes?

I notice that every time a new Presenter is created, this is causing the null Bundle at onCreate...

captura de tela 2015-05-05 as 01 22 59

Also, this seems to make the presenter's deliverLatestCache() being called several times after the fragment onResume is called.

Passing values between presenters

My current predicament is one where an item is selected in activity A, moving to activity B, where the itemId is passed via an intent from activity A to B. Pre-2.0 it was possible to simply execute any call in the onTakeView method getting the itemId from the activity, but now this seems like it would less practical (calling both start and restartable in the onTakeView method seems unnecessary). What is the best practice for passing data between presenters/activities in 2.0?

More complex example.

First of all - thanks for this gr8 library! It's really osom!
Would be nice to see a more complex example of using Nucleus. For example, let's say we have a Social Network with user profile page (RecyclerView). This page has basic user info (getProfile(id) request), and user's posts (getUserPost(offset) request) which could be lazily loaded. How would you code a Presenter? How would u save/restore RecyclerView state (with deliverLatestCache?))? I'm new to RxJava also and i think this example will help a lot of people to get in MVP much faster!

OnNext called twice if I use deliverLatestCache()

I have this piece of code if my presenter:

add(instancesProvider
                .provideObservable()
                .retry(1)
                .compose(this.<CabinetInstance[]>deliverLatestCache())
                .observeOn(uiScheduler)
                .subscribeOn(ioScheduler)
                .subscribe(new Action1<CabinetInstance[]>() {
                    @Override
                    public void call(final CabinetInstance[] instances) {
                        Logger.i("instances");
                        getView().displayInstances(instances);
                    }
                }, new Action1<Throwable>() {
                    @Override
                    public void call(final Throwable throwable) {
                        getView().displayInstancesError(throwable);
                    }
                }));

And here is provide method:

@Override
    public Observable<CabinetInstance[]> provideObservable() {
        return Observable.create(new Observable.OnSubscribe<CabinetInstance[]>() {
            @Override
            public void call(final Subscriber<? super CabinetInstance[]> subscriber) {
                try {
                    Logger.i("server");
                    JSONObject jsonObject = cabinetApi.getInstances(session.getToken());
                    subscriber.onNext(CabinetInstance.createArrayFromJson(jsonObject.optJSONArray(ALIAS)));
                    subscriber.onCompleted();
                } catch (final Exception e) {
                    session.invalidateToken();
                    subscriber.onError(e);
                }
            }
        });
    }

As result I can see instances message twice. If I remove deliver* method from the chain, onNext is called only once.

Logger prints:

server
instances
instances (with a delay)

Regarding SubscriptionList on config changes

Hi!

First of all, thank you for this awesome approach to handling MVP and configuration changes! I have run into some doubts/problems regarding the RxPresenter implementation, hope you could help me clear them up.

The SubscriptionList inside the presenter gets only unsubscribed onDestroy. This apparently means that when we have a configuration change (isFinishing() not called) it's causing a "transient" memory leak (it gets detected by LeakCanary), where the Subscriptions inside SubscriptionList will keep a reference to the views that were active before the config change. The following screenshot shows what I mean, as found in MAT:

mvp_leak

I mean "transient" since as soon as the current view is really destroyed the presenter is gone for good, so the old views can finally be garbage collected; there's however a period of time where we can have whole view hierarchies leaked.

The workaround I found was simply not adding the Subscriptions to the SubscriptionList with add() (note that I am not using the restartable functionality, and always using DeliverFirst). What's the downside of this? Everything seems to work as expected, but I've noticed the Presenter is kept around until the task is finished, which is bad but at least the views are not kept (avoiding all the problems this brings). Moreover, this way makes LeakCanary not complain any more.

Am I missing something? Please also note that I'm a novice in RxJava matters, so that could be my main problem.

Thanks a lot!

Nucleus for MVVM?

Hi Konmik,
what is your opinion about MVVM pattern and its implementation that provides Google?
Is there any chance to see nucleus for MVVM?

Common pattern for binding model to view in RxPresenter

I am not sure what the best way is to bind to a view.

I always am not sure and have two approaches so far. They are both supposed to do the same thing.

Approach 1

add(view().flatMap { view -> bookChest.removedObservable().map { Pair(view, it) } }
    .observeOn(AndroidSchedulers.mainThread())
    .subscribe { it.first.bookRemoved(it.second) })

Approach 2

add(bookChest.removedObservable()
    .observeOn(AndroidSchedulers.mainThread())
    .subscribe { view?.bookRemoved(it) })

The removedObservable is a PublishSubject. I am only interested in the emissions while the view exists.

I find Approach 1 kind of hacky-ish. And it creates lots of Pair Objects.

Approach 2 has a serious problem: It throws backpressure exceptions when the subject emits at the start at observeOn. I thik this is because the view is being created at that time.
I could add a onBackPressureDrop to Approach 2, but that seems also hacky.

What is a common pattern to handle this?

It is written in kotlin but it should be clear what happens. the view?.bookRemoved... would translate to a if (view != null) view.bookRemoved... in java. The it is just short for the single emission.

DeliverLatestCache & RecyclerView Restoring State Question

I wanted to use a RecyclerView inside my fragment and I noticed that I could use deliverLatestCache() to handle restoring state during a config change (like rotation). But I don't want to set the adapter when the fragment is resumed (i.e. coming back to the fragment after navigating away). So from the onNext I call this method in my view:

public void setAdapter(List<Item> items){
        if(recyclerView.getAdapter() == null){
            recyclerView.setAdapter(new ItemListAdapter(items));
        }
    }

deliverLatestCache() will call setAdapter() both during rotation and when the fragment is resumed. And since I only want it to set the adapter during a config change, I check to see if recyclerView already has an adapter. If it doesn't I assign it one using the data given back from the Presenter.

I wanted to know if this sort of approach is what you had envisioned when you wrote deliverLatestCache() or am I using it wrong?

An exception should be thrown if super.onTakeView() is not called

Much like how an Activity will throw an exception if super.onCreate(bundle) is not called, a presenter should do the same if super.onTakeView(view) is not called. Failing to call the super method means that no deliver*() calls will ever hit onNext(). For an such easily missable mistake with such a large impact, it seems reasonable to just throw an exception instead of failing silently. Thoughts?

getview is null

hello

i use this lib

if press phone home key
and netowrk thread run
call getView() is null....

why getview() null?
i want background thread run and ui change

ps : sry im not write english very well...

getPresenterFactory not called in fragment - v2.0.0-beta8

Overrides to getPresenterFactory() is not called in version 2.

    @Override
    public PresenterFactory<NetworkListPresenter> getPresenterFactory() {
        return new PresenterFactory<NetworkListPresenter>() {
            @Override
            public NetworkListPresenter createPresenter() {
                return presenter;
            }
        };
    }

This is working only by setting manually the presenter via setPresenterFactory:

    @Override
    protected void inject() {
        getComponent(SetupNetworkComponent.class).inject(this);
        setPresenterFactory(new PresenterFactory<NetworkListPresenter>() {
            @Override
            public NetworkListPresenter createPresenter() {
                return presenter;
            }
        });
    }

deliverLatestCache() example

Hi konmik,
I'm using this library into my app and I find it great and easy to use. I have a little problem with deliverLatestCache() method. You said that:

deliverLatestCache() is the same as deliverLatest() but in addition it will keep the latest result in memory and will re-deliver it when another instance of a view becomes available (i.e. on configuration change). If you don't want to organize save/restore of a request result in your view (in case if a result is big or it can not be easily saved into Bundle) this method will allow you to make user experience better.

and I'm trying to get this latest result but I don't understand what I have to do with it. Can you make an example of use for this method?

Thanks a lot.

Using RxBinding with Nucleus

This is more of a general question than an issue.

I wanted to use RxView.clicks()from the RxBinding library inside an RxPresenter. Because the RxPresenter has the handy add(subscription) method, it seemed fitting to write something in onTakeView() like

add(RxView.clicks(getView().getActionReload()).subscribe(new ReloadSubscriber()));

But then i noticed the subscription will only get auto-destroyed if onDestroy() in RxPresenter is called. But this is not the case when you rotate the device, because the presenter is cached and so any subscriptions are not cancelled. This would leak the Activity through the listener which is added with RxView.click().

I would like to hear your input on how to use Nucleus with Observables that are tied to their Activities.

Kotlin support

Hi. Thank you for this great lib. I just wonder if it can be used when programming in Kotlin.
Are there any issues with annotations such as @RequiresPresenter?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.