Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I use RunOnUiThread to update some TextViews on a screen

Alrighty, so I understand that this general question has been asked numerous times here, but I have yet to find an answer that makes sense to me. Almost every answer I've seen just says some blurb like, "hey, just throw this in your method and you're good", but I'm not seeing full examples, and what I've tried is not working either.

Here's the error I receive:

[mono] android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.

So, simply put, I have an activity that grabs some information from a web service and then throws the web service results into a couple of TextViews. Could someone please help me figure out where and how I need to use the RunOnUiThread()? Here's the code:


using Android.App;
using Android.OS;
using System;
using System.Web;
using System.Net;
using System.IO;
using Newtonsoft.Json;
using Android.Widget;

namespace DispatchIntranet
{
    [Activity (Label = "@string/Summary")]          
    public class SummaryActivity : Activity
    {
        private static readonly Log LOG = new Log(typeof(SummaryActivity));
        private TextView summaryTotalRegularLabel;
        private TextView summaryTotalRollover;
        private TextView summaryScheduledLabel;
        private TextView summaryRemainingRegular;
        private string url;

        protected override void OnCreate(Bundle bundle)
        {
            base.OnCreate(bundle);

            // SET THE LAYOUT TO BE THE SUMMARY LAYOUT
            SetContentView(Resource.Layout.Summary);

            // INITIALIZE CLASS MEMBERS
            init();

            if (LOG.isInfoEnabled())
            {
                LOG.info("Making call to rest endpoint . . .");

                if (LOG.isDebugEnabled())
                {
                    LOG.debug("url: " + this.url);
                }
            }

            try
            {
                // BUILD REQUEST FROM URL
                HttpWebRequest httpReq = (HttpWebRequest)HttpWebRequest.Create(new Uri(this.url));

                // SET METHOD TO 'GET'
                httpReq.Method = GetString(Resource.String.web_service_method_get);

                // ASK FOR JSON RESPONSE
                httpReq.Accept = GetString(Resource.String.web_service_method_accept);

                // INVOKE ASYNCHRONOUS WEB SERVICE
                httpReq.BeginGetResponse((ar) => {
                    HttpWebRequest request = (HttpWebRequest)ar.AsyncState;

                    using (HttpWebResponse response = (HttpWebResponse)request.EndGetResponse (ar))
                    {
                        using (StreamReader reader = new StreamReader(response.GetResponseStream()))
                        {
                            // PUT RESPONSE INTO STRING
                            string content = reader.ReadToEnd();

                            // CONVERT STRING TO DYNAMIC JSON OBJECT
                            var json = JsonConvert.DeserializeObject<dynamic>(content);

                            if (LOG.isDebugEnabled())
                            {
                                LOG.debug("content: " + content);
                                LOG.debug("json: " + json);

                                LOG.debug("TOTAL_REGULAR_PTO_HOURS: " + json.d[0].TOTAL_REGULAR_PTO_HOURS);
                            }

                            // ** THIS IS WHAT WILL NOT WORK **
                            this.summaryTotalRegularLabel.Text = json.d[0].TOTAL_REGULAR_PTO_HOURS;
                            this.summaryTotalRollover.Text = json.d[0].TOTAL_ROLLOVER_PTO_HOURS;
                            this.summaryScheduledLabel.Text = json.d[0].TOTAL_USED_PTO_HOURS;
                            this.summaryRemainingRegular.Text = json.d[0].TOTAL_REMAINING_PTO_HOURS;
                        }
                    }
                }, httpReq);
            }
            catch (Exception e)
            {
                LOG.error("An exception occurred while attempting to call REST web service!", e);
            }
        }

        private void init()
        {
            // GET GUID FROM PREVIOUS INTENT AND DETERMINE CURRENT YEAR
            string guid = Intent.GetStringExtra("guid");
            int year = DateTime.Now.Year;

            // BUILD URL
            this.url = GetString(Resource.String.web_service_url)
                + GetString(Resource.String.ws_get_pto_summary)
                + "?" + "guid='" + HttpUtility.UrlEncode(guid) + "'"
                + "&" + "year=" + HttpUtility.UrlEncode(year.ToString());

            // GET THE SUMMARY LABELS
            this.summaryTotalRegularLabel = FindViewById<TextView>(Resource.Id.SummaryTotalRegular);
            this.summaryTotalRollover = FindViewById<TextView>(Resource.Id.summaryTotalRollover);
            this.summaryScheduledLabel = FindViewById<TextView>(Resource.Id.summaryScheduledLabel);
            this.summaryRemainingRegular = FindViewById<TextView>(Resource.Id.SummaryRemainingRegular);
        }
    }
}
like image 425
liltitus27 Avatar asked Jan 30 '26 10:01

liltitus27


1 Answers

When you make a web service call, HttpWebRequest creates a new thread to run the operation on. This is done to keep your user interface from locking up or skip frames. Once your web service call is complete, you need to go back to the UI Thread to update the UI components that live on that thread. You can do that a couple of different ways.

First, you can wrap your code in an anonymous function call like so:

RunOnUiThread(()=>{
    this.summaryTotalRegularLabel.Text = json.d[0].TOTAL_REGULAR_PTO_HOURS;
    this.summaryTotalRollover.Text = json.d[0].TOTAL_ROLLOVER_PTO_HOURS;
    this.summaryScheduledLabel.Text = json.d[0].TOTAL_USED_PTO_HOURS;
    this.summaryRemainingRegular.Text = json.d[0].TOTAL_REMAINING_PTO_HOURS;
});

Or you can call a function via RunOnUiThread (jsonPayload is a field on the class):

jsonPayload = json;
RunOnUiThread(UpdateTextViews);

...


void UpdateTextViews()
{
    this.summaryTotalRegularLabel.Text = jsonPayload.d[0].TOTAL_REGULAR_PTO_HOURS;
    this.summaryTotalRollover.Text = jsonPayload.d[0].TOTAL_ROLLOVER_PTO_HOURS;
    this.summaryScheduledLabel.Text = jsonPayload.d[0].TOTAL_USED_PTO_HOURS;
    this.summaryRemainingRegular.Text = jsonPayload.d[0].TOTAL_REMAINING_PTO_HOURS;

}
like image 77
Ben Bishop Avatar answered Feb 02 '26 02:02

Ben Bishop



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!