xamarin.forms - Xamarin.Forms 中是否可以有多个依赖项实例?

标签 xamarin.forms

我从 XLabs 镜像了一些代码,从这里获取我设备上的网络状态跟踪:Xlabs INetwork Android Implementation

我已将其与此处的编码标准基本保持一致并更改了一些方法名称 - 一切正常,除了 android 实现上的某些原因外,我无法让我的事件处理程序响应,就像它们在iOS。

这是我对 Android 的改编:

[assembly: Dependency(typeof(STM.Droid.DependencyInjection.Network))]
[assembly: UsesPermission("android.permission.ACCESS_NETWORK_STATE")]
[assembly: UsesPermission("android.permission.ACCESS_WIFI_STATE")]
[assembly: UsesPermission("android.permission.CHANGE_NETWORK_STATE")]
[assembly: UsesPermission("android.permission.CHANGE_WIFI_STATE")]
namespace Namespace.Droid
{
    [BroadcastReceiver(Enabled = true)]
    [IntentFilter(new [] { Android.Net.ConnectivityManager.ConnectivityAction })]
    public class Network : BroadcastReceiver, INetwork
    {
        /// <summary>
        /// Internets the connection status.
        /// </summary>
        /// <returns>NetworkStatus.</returns>
        public NetworkStatus GetConnectionStatus()
        {
            var status = NetworkStatus.NotReachable;

            using (var cm = (ConnectivityManager)Application.Context.GetSystemService(Context.ConnectivityService))
            using (var ni = cm.ActiveNetworkInfo)
            {
                if (ni != null && ni.IsConnectedOrConnecting)
                {
                    var name = ni.TypeName.ToUpper();
                    if (name.Contains("WIFI"))
                    {
                        status = NetworkStatus.ReachableViaWiFiNetwork;
                    }
                    else if (name.Contains("MOBILE"))
                    {
                        status = NetworkStatus.ReachableViaCarrierDataNetwork;
                    }
                    else
                    {
                        status = NetworkStatus.ReachableViaUnknownNetwork;
                    }
                }
            }

            return status;
        }

        private readonly object lockObject = new object();
        private EventHandler<NetworkStatus> _reachabilityChanged;
        public event EventHandler<NetworkStatus> ReachabilityChanged
        {
            add
            {
                lock (this.lockObject)
                {
                    this._reachabilityChanged += value;
                }
            }

            remove
            {
                lock (this.lockObject)
                {
                    this._reachabilityChanged -= value;
                }
            }
        }

        /// <summary>
        /// Occurs when [reachability changed].
        /// </summary>
//      public event EventHandler<NetworkStatus> ReachabilityChanged;

        /// <summary>
        /// Determines whether the specified host is reachable.
        /// </summary>
        /// <param name="host">The host.</param>
        /// <param name="timeout">The timeout.</param>
        public Task<bool> IsReachableAsync(string host, TimeSpan timeout)
        {
            return Task.Run(
                () =>
                {
                    try
                    {
                        var address = InetAddress.GetByName(host);

                        return address != null; // && (address.IsReachable((int)timeout.TotalMilliseconds) || );
                    }
                    catch (UnknownHostException)
                    {
                        return false;
                    }
                });
        }

        /// <summary>
        /// Determines whether [is reachable by wifi] [the specified host].
        /// </summary>
        /// <param name="host">The host.</param>
        /// <param name="timeout">The timeout.</param>
        public async Task<bool> IsReachableByWifiAsync(string host, TimeSpan timeout)
        {
            return GetConnectionStatus() == NetworkStatus.ReachableViaWiFiNetwork && await IsReachableAsync(host, timeout);
        }

        /// <summary>
        /// This gets called by OS when the <see cref="ConnectivityManager.ConnectivityAction"/> <see cref="Intent"/> fires.
        /// </summary>
        /// <param name="context">Context for the intent.</param>
        /// <param name="intent">Intent information.</param>
        public override void OnReceive(Context context, Intent intent)
        {
            // this is a workaround - which oddly enough forwards events the way i would expect it to.
            MessagingCenter.Send(this as INetwork, string.Empty, GetConnectionStatus());

            // THIS IS ALWAYS NULL!
            var handler = _reachabilityChanged;
            if (handler != null)
            {
                var connectionStatus = this.GetConnectionStatus();
                handler(this, connectionStatus);
            }
        }
    }
}

问题中的错误发生在 OnReceive 中。

在调试过程中,我确实注意到处理程序已正确附加到 PCL 端 - 奇怪的是,_reachabilityChanged 字段上只有 null。

由于调试表明我显然得到了

{md50e2cce2f1202796e628729fe0540389b.Network@b422684}

关于“this”的机器人 OnReceive 方法

在 PCL 方面我得到了

{md50e2cce2f1202796e628729fe0540389b.Network@b562641}

调用 DependencyService.Get 时

对我来说,这看起来像是处理程序列表为空的原因,因为我在另一个实例上订阅了我的处理程序,因此当网络的另一个实例调用 OnReceive 时,我没有得到任何处理程序。

Xamarin.Forms DependencyService 是否有可能提供一个实例的 2 个或更多实例?因为那会让我大吃一惊...

更新:

如果有人需要解决方法 - 这也适用:

public event EventHandler<NetworkStatus> ReachabilityChanged
        {
            add { MessagingCenter.Subscribe(value.Target, string.Empty, (INetwork d, NetworkStatus a) => value(d, a)); }
            remove { MessagingCenter.Unsubscribe<INetwork>(value.Target, string.Empty); }
        }

最佳答案

对于新实例 _client = DependencyService.Get<YOUINTERFACE>(DependencyFetchTarget.NewInstance); 默认 DependencyService是保持单例

关于xamarin.forms - Xamarin.Forms 中是否可以有多个依赖项实例?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38639069/

相关文章:

c# - 如何在 C# 中绑定(bind)到 Grid ColumnDefinition Width

xaml - Xamarin.Forms BoxView 高度匹配宽度

xaml - 根据数据绑定(bind)值设置背景颜色

xamarin.ios - Xamarin.Forms.DatePicker 文本颜色

android - Xamarin Forms Android显示图片抛出异常

c# - 从共享项目中获取嵌入式资源

xamarin - 图像在 xamarin.forms 中没有绑定(bind)?

xaml - 如何使用 XAML/.NET Maui 设置具有 AspectFill 行为但左对齐的背景图像?

xamarin - 无法从程序集中加载 "Xamarin.Build.Download.XamarinBuildAndroidAarProguardConfigs"任务

c# - 如何在顶部导航中没有后退按钮的情况下在 Xamarin Shell 中切换页面