问题描述
我有一个Xamarin.Android应用,其中包含一些活动和片段。该应用程序使用SignalR,并与.net核心后端Web应用程序连接。根据服务器调用的事件,可能需要进行一些可视化修改的活动。活动在创建时是否可以订阅任何类型的应用内事件来处理那些所需的视觉变化?
例如: 我正在进行一个活动,该活动显示与出版物相关的5张图像,然后服务器发送通知,通知已编辑出版物,因此图像已更改。在这种情况下,我希望SignalR客户端触发一些应用程序内事件,以更新此类活动中更改的图像。
解决方法
我想出了一些解决方案。我创建了一个名为EventSubscriber的类,该类完全按照我的意愿进行操作。
public class EventSubscriber<T> : IEventSubscriber
{
#region Private members
private List<Tuple<T,Func<T,bool>>> Subscribtions { get; set; }
private ConcurrentDictionary<int,bool>> WaitingObjectSubscribtions { get; set; }
#endregion
public EventSubscriber()
{
Subscribtions = new List<Tuple<T,bool>>>();
WaitingObjectSubscribtions = new ConcurrentDictionary<int,bool>>();
}
#region Subscribe
public void Subscribe(T adapter,bool> function)
{
lock (Subscribtions)
{
Subscribtions.Add(new Tuple<T,bool>>(adapter,function));
}
}
public int Subscribe(Func<T,bool> function)
{
lock (WaitingObjectSubscribtions)
{
int id = WaitingObjectSubscribtions.Count;
WaitingObjectSubscribtions.TryAdd(id,function);
return id;
}
}
#endregion
#region Unsubscribe
public void UnSubscribe(Tuple<T,bool>> item)
{
lock (Subscribtions)
{
Subscribtions.Remove(item);
}
}
public void UnSubscribe(int id)
{
lock (WaitingObjectSubscribtions)
{
Func<T,bool> func;
WaitingObjectSubscribtions.TryRemove(id,out func);
}
}
public void UnSubscribeAll()
{
lock (Subscribtions)
{
Subscribtions.Clear();
}
WaitingObjectSubscribtions.Clear();
}
#endregion
#region Call Subscribed
public void CallSubscribed()
{
lock (Subscribtions)
{
foreach (var item in Subscribtions)
{
(var adapter,var function) = item;
if (!function(adapter))
{
Log.Debug("[EventSubscriber]","Failed to notify adapter,will be automatically unsubscribed from this event");
UnSubscribe(item);
}
}
}
}
public void CallSubscribedWith(T adapter)
{
foreach (var id in WaitingObjectSubscribtions.Keys)
{
var function = WaitingObjectSubscribtions[id];
try
{
if (!function(adapter))
{
Log.Debug("[EventSubscriber]","Failed to execute function");
UnSubscribe(id);
}
}
catch (Exception)
{
Log.Debug("[EventSubscriber]","Failed to execute function");
UnSubscribe(id);
}
}
}
#endregion
}
要管理多个应用内使用的EventSubscribed,我创建了一个静态类,可访问包含所有所需事件的每个Activity或Fragment:
public static class EventBoard
{
#region Products and Favorites
public static EventSubscriber<SwipeRefreshLayout> FinishedLoadingProducts = new EventSubscriber<SwipeRefreshLayout>();
public static EventSubscriber<List<Product>> SuccessfullyLoadedProducts = new EventSubscriber<List<Product>>();
public static EventSubscriber<RecyclerView.Adapter> UnsuccessfullyLoadedProducts = new EventSubscriber<RecyclerView.Adapter>();
//Search
public static EventSubscriber<SwipeRefreshLayout> FinishedLoadingProductsForSearch = new EventSubscriber<SwipeRefreshLayout>();
public static EventSubscriber<RecyclerView.Adapter> SuccessfullyLoadedProductsForSearch = new EventSubscriber<RecyclerView.Adapter>();
public static EventSubscriber<RecyclerView.Adapter> UnsuccessfullyLoadedProductsForSearch = new EventSubscriber<RecyclerView.Adapter>();
public static EventSubscriber<RecyclerView.Adapter> SearchNotFound = new EventSubscriber<RecyclerView.Adapter>();
//favorites
public static EventSubscriber<LocalProduct> ConfirmNewFavoriteEvent = new EventSubscriber<LocalProduct>();
public static EventSubscriber<LocalProduct> ConfirmRemoveFavoriteEvent = new EventSubscriber<LocalProduct>();
public static EventSubscriber<LocalProduct> NewFavoriteEvent = new EventSubscriber<LocalProduct>();
public static EventSubscriber<LocalProduct> RemoveFavoriteEvent = new EventSubscriber<LocalProduct>();
public static EventSubscriber<List<LocalProduct>> SetFavoritesEvent = new EventSubscriber<List<LocalProduct>>();
#endregion
}
因此,基本上,如果创建了一个新活动,它可以订阅其偏好的EventSubscriber。而且,它可以提供接收任何种类的对象的功能,因此它可以尽可能地灵活。
唯一引起我关注的事情是,确保在活动或片段视图被破坏时取消订阅事件,因为它们可能是内存泄漏的良好来源。
,要与实时服务器通信,您必须使用服务器软件包中的方法。通过研究,您可以使用HubConnection.On
方法。构建集线器时,Signalr会注册发送和接收方法:
public class MyHub : Hub{
public async Task Send(string user,string message){
// Receive is the name of the listener method
await Clients.All.SendAsync("Receive",user,message);
}
}
然后,在您的Android活动中,您可以使用HubConnection
方法注册到侦听器方法的On
(假设您已经发送了有关已编辑图像的消息):
myHubConnection.On<string,string>("Receive",(user,message) =>
{
/* change UI here */
});