Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -16,51 +16,68 @@

package com.uber.autodispose.recipes;

import android.support.annotation.Nullable;
import android.support.v7.widget.BindAwareViewHolder;
import android.view.View;
import com.uber.autodispose.ScopeProvider;
import io.reactivex.Maybe;
import io.reactivex.subjects.MaybeSubject;

import com.uber.autodispose.LifecycleEndedException;
import com.uber.autodispose.LifecycleScopeProvider;

import javax.annotation.Nullable;

import io.reactivex.Observable;
import io.reactivex.functions.Function;
import io.reactivex.subjects.BehaviorSubject;

/**
* Example implementation of a {@link android.support.v7.widget.RecyclerView.ViewHolder}
* implementation that implements {@link ScopeProvider}. This could be useful for cases where you
* have subscriptions that should be disposed upon unbinding or otherwise aren't overwritten
* in future binds.
* implementation that implements {@link LifecycleScopeProvider}. This could be useful for cases
* where you have subscriptions that should be disposed upon unbinding or otherwise aren't
* overwritten in future binds.
*/
public abstract class AutoDisposeViewHolder extends BindAwareViewHolder implements ScopeProvider {
public abstract class AutoDisposeViewHolder
extends BindAwareViewHolder
implements LifecycleScopeProvider<AutoDisposeViewHolder.ViewHolderEvent> {

public enum ViewHolderEvent {
BIND, UNBIND
}

private static final Object NOTIFICATION = new Object();
private static final Function<ViewHolderEvent, ViewHolderEvent> CORRESPONDING_EVENTS =
new Function<ViewHolderEvent, ViewHolderEvent>() {
@Override
public ViewHolderEvent apply(final ViewHolderEvent viewHolderEvent) throws Exception {
switch (viewHolderEvent) {
case BIND:
return ViewHolderEvent.UNBIND;
default:
throw new LifecycleEndedException("Cannot use ViewHolder lifecycle after unbind.");
}
}
};

@Nullable private MaybeSubject<Object> unbindNotifier = null;
private final BehaviorSubject<ViewHolderEvent> lifecycleEvents = BehaviorSubject.create();

public AutoDisposeViewHolder(View itemView) {
super(itemView);
}

private synchronized MaybeSubject<Object> notifier() {
MaybeSubject<Object> n = unbindNotifier;
if (n == null) {
n = MaybeSubject.create();
unbindNotifier = n;
}
return n;
@Override public Function<ViewHolderEvent, ViewHolderEvent> correspondingEvents() {
return CORRESPONDING_EVENTS;
}

@Override protected void onUnbind() {
emitUnbindIfPresent();
unbindNotifier = null;
@Override public Observable<ViewHolderEvent> lifecycle() {
return lifecycleEvents.hide();
}

@Nullable @Override public ViewHolderEvent peekLifecycle() {
return lifecycleEvents.getValue();
}

private void emitUnbindIfPresent() {
MaybeSubject<Object> notifier = unbindNotifier;
if (notifier != null && !notifier.hasComplete()) {
notifier.onSuccess(NOTIFICATION);
}
@Override protected void onBind() {
lifecycleEvents.onNext(ViewHolderEvent.BIND);
}

@Override public final Maybe<?> requestScope() {
return notifier();
@Override protected void onUnbind() {
lifecycleEvents.onNext(ViewHolderEvent.UNBIND);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,44 +19,47 @@ package com.uber.autodispose.recipes
import android.support.v7.widget.BindAwareViewHolder
import android.support.v7.widget.RecyclerView.ViewHolder
import android.view.View
import com.uber.autodispose.ScopeProvider
import io.reactivex.Maybe
import io.reactivex.subjects.MaybeSubject
import com.uber.autodispose.LifecycleEndedException
import com.uber.autodispose.LifecycleScopeProvider
import com.uber.autodispose.recipes.AutoDisposeViewHolderKotlin.ViewHolderEvent.BIND
import com.uber.autodispose.recipes.AutoDisposeViewHolderKotlin.ViewHolderEvent.UNBIND
import io.reactivex.Observable
import io.reactivex.functions.Function
import io.reactivex.subjects.BehaviorSubject

private object NOTIFICATION

/**
* Example implementation of a [ViewHolder] implementation that implements
* [ScopeProvider]. This could be useful for cases where you have subscriptions that should be
* [LifecycleScopeProvider]. This could be useful for cases where you have subscriptions that should be
* disposed upon unbinding or otherwise aren't overwritten in future binds.
*/
abstract class AutoDisposeViewHolderKotlin(itemView: View)
: BindAwareViewHolder(itemView), ScopeProvider {
: BindAwareViewHolder(itemView), LifecycleScopeProvider<AutoDisposeViewHolderKotlin.ViewHolderEvent> {

private var unbindNotifier: MaybeSubject<Any>? = null
private val lifecycleEvents by lazy { BehaviorSubject.create<ViewHolderEvent>() }

private val notifier: MaybeSubject<Any>
get() {
synchronized(this) {
return unbindNotifier ?: MaybeSubject.create<Any>().also { unbindNotifier = it }
}
}

override fun onUnbind() {
emitUnbindIfPresent()
unbindNotifier = null
enum class ViewHolderEvent {
BIND, UNBIND
}

private fun emitUnbindIfPresent() {
unbindNotifier?.let {
if (!it.hasComplete()) {
it.onSuccess(NOTIFICATION)
override fun onBind() = lifecycleEvents.onNext(BIND)

override fun onUnbind() = lifecycleEvents.onNext(UNBIND)

override fun lifecycle(): Observable<ViewHolderEvent> = lifecycleEvents.hide()

override fun correspondingEvents(): Function<ViewHolderEvent, ViewHolderEvent> = CORRESPONDING_EVENTS

override fun peekLifecycle(): ViewHolderEvent? = lifecycleEvents.value

companion object {

private val CORRESPONDING_EVENTS = Function<ViewHolderEvent, ViewHolderEvent> { viewHolderEvent ->
when (viewHolderEvent) {
BIND -> UNBIND
else -> throw LifecycleEndedException("Cannot use ViewHolder lifecycle after unbind.")
}
}
}

override fun requestScope(): Maybe<*> {
return notifier
}

}