TaskCompletionSource和dismiss导致多个自定义alertdialogs没有出现

时间:2017-05-28 15:14:13

标签: c# android xamarin xamarin.android

我遇到了与TaskCompletionSource对象和警报的Dismiss函数相关的问题。此问题不会出现在应用程序的IOS版本中

当应用程序发送通知时,当用户激活应用程序时,将显示两个具有工作功能的警报:

  1. 验证
  2. 填写一个值。
  3. 但是,当我进入应用程序时,我只能看到身份验证(因为此警报首先在应用程序中被调用),第二个警报从未显示。我已经尝试覆盖Dismiss函数并将TaskCompletionSource对象结果设置为null,但这会导致相同的警报在应用程序崩溃之前出现X次。有没有办法重复TaskCompletionSource对象,以便我可以看到所有警报?或者我需要对Dismiss函数进行哪些修改,以便在显示所有警报后完成TaskCompletionSource?

    Android Fragment示例代码:

    public static readonly int AlertWidth = Device.Idiom == TargetIdiom.Phone ? 270 : 320;
    
        class AlertDialogFragment : DialogFragment
        {
            public string Title;
            public string Body;
            public View Content;
            public List<AlertButton> Buttons;
            public TaskCompletionSource<object> tsc;
    
    
            public Dialog AndroidCustomAlert(Activity activ)
            {
                Android.Views.LayoutInflater inflater = Android.Views.LayoutInflater.From(activ);
                Android.Views.View view = inflater.Inflate(Resource.Layout.AlertDialogLayout, null);
    
                AlertDialog.Builder builder = new AlertDialog.Builder(activ);
                builder.SetView(view);
                Android.Widget.TextView title = view.FindViewById<Android.Widget.TextView>(Resource.Id.Login);
                title.Text = Title;
    
                Android.Widget.TextView body = view.FindViewById<Android.Widget.TextView>(Resource.Id.pincodeText);
                body.Text = Body;
                body.MovementMethod = new Android.Text.Method.ScrollingMovementMethod();
    
                Android.Widget.EditText pincode = view.FindViewById<Android.Widget.EditText>(Resource.Id.pincodeEditText);
                Android.Widget.Button btnPositive = view.FindViewById<Android.Widget.Button>(Resource.Id.btnLoginLL);
                Android.Widget.Button btnNegative = view.FindViewById<Android.Widget.Button>(Resource.Id.btnClearLL);
                Android.Widget.Button btnNeutral = view.FindViewById<Android.Widget.Button>(Resource.Id.btnNeutral);
    
                if (Title.Contains("Time"))
                {
                    Android.Views.View secondView = inflater.Inflate(Resource.Layout.TimePickerLayout, null);
                    builder.SetView(secondView);
    
                    btnPositive = secondView.FindViewById<Android.Widget.Button>(Resource.Id.btnLoginLL);
                    btnNegative = secondView.FindViewById<Android.Widget.Button>(Resource.Id.btnClearLL);
                    var tp = secondView.FindViewById<Android.Widget.TimePicker>(Resource.Id.timePicker1);
                    tp.SetIs24HourView((Java.Lang.Boolean)true);
                    //Positive button feedback
                    btnPositive.Text = Buttons.Last().Text;
                    btnPositive.Click += delegate
                    {
                        var car = (Xamarin.Forms.TimePicker)Content;
                        var ts = new TimeSpan(tp.Hour, tp.Minute, 0);
                        car.Time = ts;
    
                        CommandsForButtons(Buttons.Last());
                    };
    
                    //Negative button feedback
                    btnNegative.Text = Buttons.First().Text;
                    btnNegative.Click += delegate
                    {
    
                        CommandsForButtons(Buttons.First());
                    };
                }
                else if (Title.Contains("How are you"))
                {
                    btnPositive.Visibility = Android.Views.ViewStates.Gone;
                    btnNegative.Visibility = Android.Views.ViewStates.Gone;
                    btnNeutral.Visibility = Android.Views.ViewStates.Visible;
                    pincode.Visibility = Android.Views.ViewStates.Gone;
    
                    var happySlider = view.FindViewById<Android.Widget.SeekBar>(Resource.Id.happinessSlider);
                    happySlider.SetProgress(5, false);
                    happySlider.Visibility = Android.Views.ViewStates.Visible;
                    btnNeutral.Text = Buttons.First().Text;
                    btnNeutral.Click += delegate
                    {
                        var car = (StackLayout)Content;
    
                        var layoutView = (Xamarin.Forms.AbsoluteLayout)car.Children[1];
                        var slider = (Slider)layoutView.Children[1];
    
                        var totalHappyValue = happySlider.Progress / 10;
                        slider.Value = totalHappyValue;
    
                        CommandsForButtons(Buttons.First());
                    };
                }
                else
                {
    
                    //Checks if there are no buttons, and if there aren't any, creates a neutral one
                    if (Buttons == null || Buttons.Count == 0)
                    {
                        btnPositive.Visibility = Android.Views.ViewStates.Gone;
                        btnNegative.Visibility = Android.Views.ViewStates.Gone;
                        btnNeutral.Visibility = Android.Views.ViewStates.Visible;
                        pincode.Visibility = Android.Views.ViewStates.Gone;
    
                        Buttons = new List<AlertButton> {
                    new AlertButton {
                        Text = "Oké",
                        IsPreferred = true,
                        Action = () => false
                        }
                    };
                        btnNeutral.Text = Buttons.First().Text;
                        btnNeutral.Click += delegate
                        {
    
                            CommandsForButtons(Buttons.First());
                        };
                    }
    
                    if (Content == null)
                    {
                        pincode.Visibility = Android.Views.ViewStates.Gone;
                    }
    
                    //Positive button feedback
                    btnPositive.Text = Buttons.Last().Text;
                    btnPositive.Click += delegate
                    {
                        var test = (StackLayout)Content;
    
                        if (test != null)
                        {
                            var car = (Entry)test.Children[0];
                            car.Text = pincode.Text;
                        }
    
                        CommandsForButtons(Buttons.Last());
                    };
    
                    //Negative button feedback
                    btnNegative.Text = Buttons.First().Text;
                    btnNegative.Click += delegate
                    {
    
                        CommandsForButtons(Buttons.First());
                    };
                }
                return builder.Create();
            }
    
            public void CommandsForButtons(AlertButton button)
            {
                Func<Task> dismiss = null;
                var command = new Command(async () =>
                {
                    var ab = button;
                    var cont = true;
                    if (ab.Action != null)
                        cont = ab.Action();
                    if (ab.ActionAsync != null)
                    {
                        cont = cont && await ab.ActionAsync();
                    }
                    if (!cont)
                    {
                        await dismiss();
                    }
                });
    
                dismiss = async () =>
                {
                    dismiss = async () => { };
                    await Task.Run(() =>
                    {
                        Dismiss();
                        tsc.SetResult(null);
                    });
    
                    Log.Debug("TSC", tsc.Task.Status.ToString());
    
                };
    
                command.Execute(this);
            }
    
            public override Dialog OnCreateDialog(Bundle savedInstanceState)
            {
                var test = AndroidCustomAlert(Activity);
                test.SetCanceledOnTouchOutside(false);
                return test;
            }
    
            public override void Dismiss()
            {
                base.Dismiss();
    
            }
        }
    
        public async Task Show(string title, string body, View content, List<AlertButton> buttons)
        {
    
            var tcs = new TaskCompletionSource<object>();
    
            var adf = new AlertDialogFragment
            {
                Title = title,
                Body = body,
                Content = content,
                Buttons = buttons,
                tsc = tcs
            };
            var FragmentManager = ((Activity)Forms.Context).FragmentManager;
            FragmentTransaction ft = FragmentManager.BeginTransaction();
    
            //Remove fragment else it will crash as it is already added to backstack
            Fragment prev = FragmentManager.FindFragmentByTag("alert");
            if (prev != null)
            {
                ft.Remove(prev);
            }
    
            ft.AddToBackStack(null);
            adf.Show(ft, "alert");
            await tcs.Task;
        }
    

    方法:

    await Authentication();
    await UserCheck();
    

    和IOS代码:

    public static readonly int AlertWidth = Device.Idiom == TargetIdiom.Phone ? 270 : 320;
    
        public async Task Show(string title, string body, View content, List<AlertButton> buttons)
        {
            if (buttons == null || buttons.Count == 0)
            {
                buttons = new List<AlertButton> {
                    new AlertButton {
                        Text = "Oké",
                        IsPreferred = true,
                        Action = () => false
                    }
                };
            }
    
            Func<Task> dismiss = null;
    
            var captionSize = (double)StyleKit.PhoneDarkLabelStyles.Caption.Setters.First(s => s.Property == Label.FontSizeProperty).Value;
            var titleSize = (double)StyleKit.PhoneDarkLabelStyles.Title.Setters.First(s => s.Property == Label.FontSizeProperty).Value;
    
            var top = new StackLayout {
                Padding = new Thickness(15, 20, 15, 20),
                Spacing = 3,
                Children = {
                    new Label {
                        Text = title,
                        Style = StyleKit.PhoneDarkLabelStyles.Title,
                        FontSize = Math.Max(16, titleSize),
                        HorizontalTextAlignment = TextAlignment.Center
                    },
                    new Label {
                        Text = body,
                        Style = StyleKit.PhoneDarkLabelStyles.Body,
                        //FontSize = ,
                        FontSize = Math.Max(14, captionSize),
                        HorizontalTextAlignment = TextAlignment.Center
                    } ,
                    new ContentView {
                        Padding = new Thickness(0,5,0,-10),
                        VerticalOptions = LayoutOptions.EndAndExpand,
                        Content = content
                    } 
                }
            };
    
            var buttonViews = buttons.Select(ab => new Button {
                FontSize = Math.Max(16, titleSize),
                Text = ab.Text,
                FontAttributes = ab.IsPreferred ? FontAttributes.Bold : FontAttributes.None,
                TextColor = ab.IsDestructive ? Color.Red : Color.Default,
                Command = new Command(async () => {
                    var cont = true;
                    if (ab.Action != null)
                        cont = ab.Action();
                    if (ab.ActionAsync != null)
                        cont = cont && await ab.ActionAsync();
                    if (!cont)
                        await dismiss();
                })
            }).ToList();
    
            var grid = new Grid {
                RowDefinitions = {
                    new RowDefinition { Height = GridLength.Auto },
                    new RowDefinition { Height = GridLength.Auto }
                },
                ColumnSpacing = 0,
                RowSpacing = 0
            };
            buttons.ForEach(button => {
                grid.ColumnDefinitions.Add(
                    new ColumnDefinition {
                        Width = AlertWidth / buttonViews.Count
                    }
                );
            });
    
            for (int i = 0; i < buttonViews.Count; i++)
            {
                grid.Children.Add(new BorderView {
                    BorderColor = Color.FromRgba(0,0,0,0.2),
                    Thickness = new Thickness(0, 1, (i + 1 < buttonViews.Count) ? 1 : 0, 0)
                }, i, 1);
                grid.Children.Add(buttonViews[i], i, 1);
            }
            grid.Children.Add(top, 0, buttons.Count, 0, 1);
    
            var box = new Frame {
                WidthRequest = AlertWidth,
                BackgroundColor = Color.FromRgba(1,1,1,0.96),
                Padding = 0,
                Content = grid
            };
            var outer = new AbsoluteLayout {
                BackgroundColor = Color.FromRgba(0,0,0,0.65),
                Opacity = 0,
                Children = { box }
            };
            AbsoluteLayout.SetLayoutFlags(box, AbsoluteLayoutFlags.PositionProportional);
            AbsoluteLayout.SetLayoutBounds(box,
                new Rectangle(0.5, 0.5, AbsoluteLayout.AutoSize, AbsoluteLayout.AutoSize));
    
            var page = new ContentPage {
                Content = /* new ScrollView { Content = */ outer // }
            };
    
            var tcs = new TaskCompletionSource<object>();
    
            var topVC = UIApplication.SharedApplication.KeyWindow.RootViewController;
            while (topVC.PresentedViewController != null) {
                topVC = topVC.PresentedViewController;
            }
    
            var vc = page.CreateViewController();
            topVC.Add(vc.View);
            var innerView = vc.View.Subviews[0].Subviews[0];
            vc.View.RemoveFromSuperview();
    
            dismiss = async () => {
                dismiss = async () => {};
                await outer.FadeTo(0, 50);
                innerView.RemoveFromSuperview();
                tcs.SetResult(null);
            };
    
            topVC.Add(innerView);
    
            var kbh = new KeyboardHelper();
            kbh.KeyboardChanged += async (sender, e) => {
                await box.TranslateTo(0, e.Visible ? (-e.Height / 2f) : 0, 100, Easing.CubicInOut);
            };
    
            await outer.FadeTo(1, 100);
    
            await tcs.Task;
        }
    

1 个答案:

答案 0 :(得分:1)

这看起来像是线程之间的问题和/或问题,或者根本就没有设置任务完成。

在IOS版本中你有

     dismiss = async () => {
        dismiss = async () => {};
        await outer.FadeTo(0, 50);
        innerView.RemoveFromSuperview();
        tcs.SetResult(null);
    };

Android版本中没有匹配的tcs.SetResult(null);语句。

同样值得注意的是异步调用,因为等待调用SetResult会在没有它的情况下阻塞主线程。