I have the following screen:
When I click on Ponentes
ImageButton
, after few seconds SpeakersActivity
opens. After clicking on Ponentes
ImageButton
I don't want to stay on its screen for several seconds, but I want SpeakersActivity
to open immediately with loadingSpinner ProgressBar
while the data in SpeakersActivity
is loading. I put the code which causes the delay in a thread in the OnCreate
method of SpeakersActiviy
:
protected override async void OnCreate(Bundle savedInstanceState) { ..... ..... loadingSpinner.Visibility = ViewStates.Visible; await Task.Run(() => { //get all the speakers from the db allSpeakers = DatabaseHelper.GetAllFromTable<Speaker>("speakers.db"); //get only the international spakers internationalSpeakers = allSpeakers.Where(x => x.Nationality.Equals("international")).ToList(); //get only the national speakers nationalSpeakers = allSpeakers.Where(x => x.Nationality.Equals("national")).ToList(); //fill in the RecyclerView with data speakersRecyclerView = FindViewById<RecyclerView>(Resource.Id.speakersRecyclerView); speakersLayoutManager = new LinearLayoutManager(this); speakersRecyclerView.SetLayoutManager(speakersLayoutManager); speakersAdapter = new SpeakersAdapter(speakers); speakersAdapter.ItemClick += OnItemClick; speakersRecyclerView.SetAdapter(speakersAdapter); loadingSpinner.Visibility = ViewStates.Gone; }); ..... ..... }
I get Only the original thread that created a view hierarchy can touch its views exception
. What is the cause of that exception and how can I achieve what I want? If there is a single command solution as mine:
await Task.Run(() => {.....});
it would be better, so if another person reads my code in the future, he doesn't wonder too much what's going on.
Here is the SpeakersActivity.axml
:
<LinearLayout> <Toolbar> <TextView/> </Toolbar> <LinearLayout> <TextView/> <TextView/> </LinearLayout> <android.support.v7.widget.RecyclerView android:id = "@+id/speakersRecyclerView"/> <ProgressBar android:id = "@+id/loadingSpinner" android:layout_width="match_parent" android:layout_height="match_parent" android:indeterminateDrawable="@drawable/animdraw" android:visibility="gone" android:layout_gravity="center"/> </LinearLayout>
I skipped View's attributes because they are irrelevant.
Answers
It seems that you don't update the UI view in the UI thread. Make sure the related function code executed in main thread.
Tutorial:
https://docs.microsoft.com/en-us/xamarin/essentials/main-thread
Refer to:
https://stackoverflow.com/questions/47041396/only-the-original-thread-that-created-a-view-hierarchy-can-touch-its-views
It's working, the only issue is that the
loadingSpinner ProgressBar
is spinning during half of the loading time. For example, if it takes 4 seconds to loadSpeakersActivity
afterPonentes ImageButton
has been clicked, theloadingSpinner
is spinning for 1 or 2 seconds and then it stays still untilSpeakersActivity
data is shown, like that:Here is the whole
SpeakersActivity
code:Here is
ProgressBar
view fromSpeakersActivity.axml
:And here is
animdraw.xml
:Try to create a custom AsyncTask to load the
ProgressBar
.Check the code:
Refer to:
https://stackoverflow.com/questions/48164058/how-to-show-progressbar-and-make-it-progressxamarin-android/48182963
What do I have to change in the code above to make the text(loading..., 25,50,75 etc.) disappear, only the loading spinner to remain on the screen?
Remove the
TextView
parameter from CustomTask class.