2

When I open a Fragment I try to show a ProgressBar, populate a RecyclerView, update NotifyChange to RecyclerView and then hide the ProgressBar.

Right now the ProgressBar isn't spinning. I think it has to do with SetRecyclerViewItems being executed on the UI Thread but if I don't do that I get an error saying that the UI can only be updated in the UI thread.

Fragment:

public override View OnCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
        {
            /* Initializing elements code removed */

            SetRecyclerView();

            return view;
        }

    public async override void OnStart()
            {
                base.OnStart();

                ShowProgressBar();
                await LoadAsync();
                HideProgressBar();
            }

            private async Task LoadAsync()
            {
                await Task.Run(() => {
                    SetRecyclerViewItems();
                });

            }

            private void SetRecyclerView()
            {
                mLayoutManager = new LinearLayoutManager(mRecyclerView.Context);
                mRecyclerView.SetLayoutManager(mLayoutManager);
                mAdapter = new TransactionsRecyclerAdapter(this.Activity, mTransactions, dateFormat);
                mAdapter.ItemClick += MAdapter_ItemClick;
                mRecyclerView.SetAdapter(mAdapter);
            }

            private void SetRecyclerViewItems(List<PaymentListItemViewModel> transactions = null)
            {
                Activity.RunOnUiThread(() => {

                    if (transactions == null)
                        transactions = GetTransactions();
                    mAdapter.NotifyChange(transactions);
                    SetTotal();
                });
            }

Adapter.NotifyChange

public void NotifyChange(List<PaymentListItemViewModel> transactions)
        {
            mTransactions = transactions;
            NotifyDataSetChanged();
        }

Why isn't the ProgressBar spinning? Is the way I'm populating new data to the Adapter correct (sending in a new list and then NotifyDataSetChanged?

Layout:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@drawable/login_background">
    <RelativeLayout
        android:layout_height="match_parent"
        android:layout_width="match_parent"
        android:gravity="center"
        android:layout_centerInParent="true"
        android:id="@+id/transactionsProgressBar">
        <ProgressBar
            android:layout_height="wrap_content"
            android:layout_width="wrap_content"
            style="@android:style/Widget.ProgressBar.Large" />
    </RelativeLayout>
    <LinearLayout
        android:orientation="vertical"
        android:minWidth="25px"
        android:minHeight="25px"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/linearLayout4"
        android:layout_weight="1">
        <android.support.v7.widget.RecyclerView
            android:id="@+id/recyclerViewTransactions"
            android:layout_height="match_parent"
            android:layout_width="match_parent"
            android:scrollbars="vertical" />
    </LinearLayout>

</LinearLayout>

In OnCreateView:

mLayoutProgressBar = view.FindViewById<RelativeLayout>(Resource.Id.transactionsProgressBar);

Show/Hide ProgressBar:

private void ShowProgressBar()
                {
                    mLayoutProgressBar.Visibility = ViewStates.Visible;
                }

                private void HideProgressBar()
                {
                    mLayoutProgressBar.Visibility = ViewStates.Gone;
                }
Westerlund.io
  • 2,743
  • 5
  • 30
  • 37
  • Obviously it's because RunOnUiThread inside SetRecyclerViewItems which is just a shortcut for Handler.post which returns immediately and makes those all async, await and task useless – Selvin Jan 26 '17 at 23:07
  • What are GetTransactions and SetTotal and how long do they take? – Luke Jan 26 '17 at 23:08
  • That was what I thought but as stated if I don't run it within the UI thread throws an exception saying that "View can only be changed within the UI thread". How would I run two UI items (ProgressBar and SetRecyclerViewItems) separately? – Westerlund.io Jan 26 '17 at 23:10
  • @Luke On creation the Adapter is populated with an empty list and then I get the data to be used in the ReyclerView using GetTransactions. It takes around 1 second to process. SetTotal is an empty method at the moment. – Westerlund.io Jan 26 '17 at 23:11
  • You obviously should only run GetTransactions in task and await for its results – Selvin Jan 26 '17 at 23:11
  • @Jefecito show your code of progressbar. – XTL Jan 26 '17 at 23:38
  • @VetaLio Post updated – Westerlund.io Jan 27 '17 at 03:05
  • @Jefecito did you try to use "break points"? How looks your axml code with progressBar? I think the main problem is with your axml code,so you need to show your progress bar overlay other views. Or you can just use simple DialogFragment(Or AlertDialog) with Progres Bar. https://cloud.githubusercontent.com/assets/15155286/22170473/6a38a9ec-df86-11e6-9854-9e989f44c370.gif See this gif and tell me if its okay for you. i Can show how to do this. – XTL Jan 27 '17 at 20:32

1 Answers1

2

You put the loading onto a separate thread by using Task.Run() but in there you marshal back to the UI thread to update your adapter (Activity.RunOnUiThread()), this will block the UI thread and your spinner stops running.

Depending on what your SetTotal() method is doing, you should only have the call to mAdapter.NotifyChange(transactions); being executed on the UI thread.

Krumelur
  • 32,180
  • 27
  • 124
  • 263
  • Thanks for your time. I had a lot of calculations going in OnBindViewHolder (which blocked the UI thread) and with your assistance I now load all the data async and only send in the actual data to the RecyclerView. – Westerlund.io Jan 30 '17 at 03:46