Skip to content

Commit

Permalink
Managing bindings in bindable RecyclerView adapter and view holders (#…
Browse files Browse the repository at this point in the history
…561)

* Added possibility to attach/detach bindings in existing BindableViewHolders

* Renamed OnDestroy -> CleanUp

* Fixed NullReference

* Fixed attaching bindings multiple times in BindableViewHolder inheritors

---------

Co-authored-by: Pavel Leonenko <[email protected]>
  • Loading branch information
pavel-leonenko and Pavel Leonenko authored Sep 27, 2024
1 parent 3aae257 commit 73280be
Show file tree
Hide file tree
Showing 4 changed files with 64 additions and 20 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -13,21 +13,23 @@
using Softeq.XToolkit.Common.Collections;
using Softeq.XToolkit.Common.Collections.EventArgs;
using Softeq.XToolkit.Common.Commands;
using Softeq.XToolkit.Common.Extensions;
using Softeq.XToolkit.Common.Weak;

#nullable disable

namespace Softeq.XToolkit.Bindings.Droid.Bindable
{
public abstract class BindableRecyclerViewAdapterBase<TItem, TItemHolder> : RecyclerView.Adapter
public abstract class BindableRecyclerViewAdapterBase<TItem, TItemHolder> : RecyclerView.Adapter, IBindableRecyclerViewAdapter
where TItemHolder : BindableViewHolder<TItem>
{
protected readonly IList<FlatItem> _flatMapping = new List<FlatItem>();
private readonly List<IBindableViewHolder> _existingBindableViewHolders = new();

protected IDisposable _subscription;
private protected ICommand<TItem> _itemClick;
private ICommand<TItem> _itemClick;

public BindableRecyclerViewAdapterBase(
protected BindableRecyclerViewAdapterBase(
Type headerViewHolder,
Type footerViewHolder)
{
Expand Down Expand Up @@ -93,24 +95,51 @@ public override void OnViewDetachedFromWindow(Java.Lang.Object holder)
base.OnViewDetachedFromWindow(holder);
}

public override RecyclerView.ViewHolder OnCreateViewHolder(ViewGroup parent, int viewType)
public sealed override RecyclerView.ViewHolder OnCreateViewHolder(ViewGroup parent, int viewType)
{
var itemType = (ItemType) viewType;
var result = DoCreateViewHolder(parent, viewType);

switch (itemType)
if (result is IBindableViewHolder bindableViewHolder)
{
case ItemType.Header:
return OnCreateHeaderViewHolder(parent);
_existingBindableViewHolders.Add(bindableViewHolder);
}

case ItemType.Item:
return OnCreateItemViewHolder(parent, itemType);
return result;
}

case ItemType.Footer:
return OnCreateFooterViewHolder(parent);
public void DoAttachBindings()
{
// ReSharper disable once ConditionIsAlwaysTrueOrFalse
_existingBindableViewHolders
.Where(x => !x.AreBindingsAttached && x.DataContext != null)
.Apply(x => x.DoAttachBindings());
}

default:
throw new ArgumentException($"Unable to create a view holder for \"{viewType}\" view type.", nameof(viewType));
}
public void DoDetachBindings()
{
_existingBindableViewHolders.ForEach(x => x.DoDetachBindings());
}

public void CleanUp()
{
_subscription?.Dispose();
DoDetachBindings();
_existingBindableViewHolders.Clear();
}

protected virtual RecyclerView.ViewHolder DoCreateViewHolder(ViewGroup parent, int viewType)
{
var itemType = (ItemType) viewType;

return itemType switch
{
ItemType.Header => OnCreateHeaderViewHolder(parent),
ItemType.Item => OnCreateItemViewHolder(parent, itemType),
ItemType.Footer => OnCreateFooterViewHolder(parent),
_ => throw new ArgumentException(
$"Unable to create a view holder for \"{viewType}\" view type.",
nameof(viewType))
};
}

public override void OnBindViewHolder(RecyclerView.ViewHolder holder, int position)
Expand Down Expand Up @@ -139,8 +168,6 @@ public override void OnViewRecycled(Java.Lang.Object holder)
base.OnViewRecycled(holder);
}

public void StopListeningToSourceUpdates() => _subscription?.Dispose();

protected virtual RecyclerView.ViewHolder OnCreateHeaderViewHolder(ViewGroup parent)
{
return CreateViewHolder(parent, HeaderViewHolder);
Expand Down Expand Up @@ -351,7 +378,7 @@ public BindableRecyclerViewAdapter(

public override int ItemCount => _flatMapping.Count;

public override RecyclerView.ViewHolder OnCreateViewHolder(ViewGroup parent, int viewType)
protected override RecyclerView.ViewHolder DoCreateViewHolder(ViewGroup parent, int viewType)
{
var itemType = (ItemType) viewType;

Expand All @@ -363,7 +390,7 @@ public override RecyclerView.ViewHolder OnCreateViewHolder(ViewGroup parent, int
return OnCreateSectionFooterViewHolder(parent, ItemType.SectionFooter);

default:
return base.OnCreateViewHolder(parent, viewType);
return base.DoCreateViewHolder(parent, viewType);
}
}

Expand Down Expand Up @@ -396,7 +423,7 @@ protected virtual RecyclerView.ViewHolder OnCreateSectionFooterViewHolder(ViewGr
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
StopListeningToSourceUpdates();
CleanUp();
}

protected void ReloadMapping()
Expand Down
4 changes: 4 additions & 0 deletions Softeq.XToolkit.Bindings.Droid/Bindable/BindableViewHolder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ protected BindableViewHolder(View itemView) : base(itemView)

public object DataContext { get; private set; }

public bool AreBindingsAttached { get; private set; }

protected TViewModel ViewModel => (TViewModel) DataContext;

void IBindable.SetDataContext(object dataContext)
Expand Down Expand Up @@ -67,6 +69,7 @@ protected virtual void OnItemViewClick(object sender, EventArgs e)

public virtual void DoAttachBindings()
{
AreBindingsAttached = true;
_subscriptionsComponent.CreateSubscriptions();
}

Expand All @@ -75,6 +78,7 @@ public virtual void DoDetachBindings()
this.DetachBindings();

_subscriptionsComponent.DisposeSubscriptions();
AreBindingsAttached = false;
}

protected virtual IEnumerable<IDisposable> SetCommandsWithDisposing()
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// Developed for PAWS-HALO by Softeq Development Corporation
// http://www.softeq.com

namespace Softeq.XToolkit.Bindings.Droid.Bindable;

public interface IBindableRecyclerViewAdapter
{
void DoAttachBindings();
void DoDetachBindings();
void CleanUp();
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ public interface IBindableViewHolder : IBindableView
{
event EventHandler ItemClicked;

bool AreBindingsAttached { get; }

void OnAttachedToWindow();
void OnDetachedFromWindow();
void OnViewRecycled();
Expand Down

0 comments on commit 73280be

Please sign in to comment.