Любое событие, возникающее после асинхронной функции, не обновляет пользовательский интерфейс должным образом - PullRequest
0 голосов
/ 09 июля 2019

Я пытаюсь добавить базовый обратный вызов в мое приложение, в результате чего метка состояния загрузки обновляется по мере выполнения приложением задачи обновления.Однако по какой-то причине после вызова одного конкретного асинхронного метода любые события, возникающие после этого, не обновляют пользовательский интерфейс.

Я пробовал различные настройки configure await и просматривал сам асинхронный метод, но ничего не могу найтиочевидно, неправильно.

public async Task RefreshTable<T>() where T : class, IEntity
    {
        try
        {
            OnContentUpdateProgressChange(this, new MessageEventArgs($"RefreshTable before {typeof(T).Name}"));
            var tableJsonData = await ApiService.GetEntityListAsync<T>();
            OnContentUpdateProgressChange(this, new MessageEventArgs($"RefreshTable after {typeof(T).Name}"));
            await LoadTableData(Set<T>(), tableJsonData);
        }
        catch (Exception e)
        {
            System.Diagnostics.Debug.WriteLine(e.Message);
        }
    }

public async Task<List<T>> GetEntityListAsync<T>(string url = null) where T : class
    {
        if (string.IsNullOrEmpty(url))
        {
            url = typeof(T).Name.Replace("_", "");
        }
        try
        {
            string entityList = null;
            HttpResponseMessage response = await Client.GetAsync(url);
            if (response.IsSuccessStatusCode)
            {
                entityList = await response.Content.ReadAsStringAsync();
                var backupFile = Path.Combine(System.Environment.GetFolderPath(System.Environment.SpecialFolder.Personal), typeof(T).Name);
                using (var writer = File.CreateText(backupFile))
                {
                    await writer.WriteLineAsync(entityList.ToString());
                }
            }
            return await Task.Factory.StartNew(() => JsonConvert.DeserializeObject<List<T>>(entityList));
        }
        catch (Exception e)
        {
            System.Diagnostics.Debug.WriteLine(e.Message);
            throw;
        }
    }


    private void DB_OnContentUpdateProgressChange(object sender, library.EventArguments.MessageEventArgs e)
    {
        lblLoadingState.Text = e.Message;
    }

Событие, возникшее до вызова GetEntityListAsync, успешно обновляет пользовательский интерфейс, а после - нет.

1 Ответ

0 голосов
/ 09 июля 2019

из того, что я прочитал, насколько я понимаю, это говорит о том, что это проблема потока пользовательского интерфейса. Когда вы вносите некоторые изменения в фоновый поток в вашем случае, асинхронный метод всегда рекомендуется, чтобы изменения, которые вы внесли, которые повлияют на пользовательский интерфейс, были сделано на MainThread или UIThread. Теперь то, что вам нужно сделать, довольно просто. Всякий раз, когда вы вносите изменение, которое должно повлиять на пользовательский интерфейс, делайте это в потоке пользовательского интерфейса.

Что мне нравится делать, так это вносить все изменения пользовательского интерфейса в метод, а затем мне нравится иметь базовую версию моего класса Activity, в которой есть помощники, которые позволяют мне проверять, является ли это MainThread или нет, и вносить изменения соответствующим образом, используя это метод.

  • Добавьте действие, которое наследуется от AppCompatActivity, а затем добавьте в него следующее.

     public abstract class BaseActivity : AppCompatActivity
     {
       protected override void OnCreate(Bundle savedInstanceState)
       {
           base.OnCreate(savedInstanceState);
       }
    
        public bool IsMainThread => Build.VERSION.SdkInt >= BuildVersionCodes.M
        ? Looper.MainLooper.IsCurrentThread
        : Looper.MyLooper() == Looper.MainLooper;
    
        public void RunOnMainThread(Action action)
        {
          if (IsMainThread) action();
          else RunOnUiThread(action);
        } 
    
    }
    
  • Затем внесите изменения в пользовательский интерфейс, например:

    RunOnMainThread(() => { LabelDoSomething.Text = "New Text"; });
    
...